mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Implement MAC address randomization for Rouvy compatibility (#3999)
* Implement MAC address randomization for Rouvy compatibility When Rouvy compatibility mode is enabled, the dirconmanager now uses a specific MAC address base (24:DC:C3:E3:B5:XX) with the last byte set to the dircon_id value from settings. This allows each instance to have a unique identifier while maintaining compatibility with Rouvy. Changes: - Modified getMacAddress() to accept rouvy_compatibility and dircon_id parameters - Added logic to generate MAC address "24:DC:C3:E3:B5:XX" where XX is dircon_id in hex - Updated constructor to pass settings values to getMacAddress() - Maintained backward compatibility with default parameter values * Refactor getMacAddress to read Rouvy setting internally Modified getMacAddress() to read the rouvy_compatibility setting directly from QSettings instead of receiving it as a parameter. This simplifies the function interface and ensures the setting is always read from the current configuration. Changes: - Removed rouvy_compatibility parameter from getMacAddress() - Added QSettings read inside getMacAddress() function - Updated function call to only pass dircon_id parameter * Simplify getMacAddress to read all settings internally Modified getMacAddress() to be a parameter-free function that reads both rouvy_compatibility and dircon_id settings internally from QSettings. This creates a cleaner, more self-contained interface. Changes: - Removed dircon_id parameter from getMacAddress() - Added dircon_id read inside getMacAddress() function - Removed local dircon_id_value variable from constructor - Function now takes no parameters and reads all needed settings internally * Simplify Rouvy compatibility to advertise only ELITE AVANTI device When Rouvy compatibility mode is enabled, now only the ELITE AVANTI device is created and advertised. Removed WAHOO_BLUEHR (heart rate), WAHOO_RPM_SPEED, and WAHOO_TREADMILL from the Rouvy macro to streamline the device presentation to Rouvy app. This change is safe because: - All enum types remain defined via DM_MACHINE_OP - All services continue to exist - Only runtime device initialization is affected when Rouvy mode is enabled Changes: - Removed WAHOO_BLUEHR, WAHOO_RPM_SPEED, and WAHOO_TREADMILL from DM_MACHINE_OP_ROUVY - Only WAHOO_KICKR (ELITE AVANTI) remains for Rouvy compatibility * Update qmdnsengine submodule to use cagnulein-patch-1 branch Changed qmdnsengine submodule configuration to use the cagnulein-patch-1 branch and commit 5e5469a06d79c1daa31bbc34d48241c53b6d4fea instead of the previous zwift branch and commit 602da51dc43c55bd9aa8a83c47ea3594a9b01b98. Changes: - Updated .gitmodules: branch zwift → cagnulein-patch-1 - Updated GitHub workflows: all refs to "zwift" → "cagnulein-patch-1" - Updated GitHub workflows: git checkout commands to use new commit hash - This ensures all CI/CD builds use the correct qmdnsengine version * Fix qmdnsengine commit SHA to correct version Corrected the qmdnsengine submodule commit SHA from the incorrect 5e5469a06d79c1daa31bbc34d48241c53b6d4fea to the correct 16cf29108dfaf9c26d21038a620332c103a5b4f8 in all GitHub workflow "Fix qmdnsengine submodule" steps. This ensures all CI/CD builds use the correct qmdnsengine version from the cagnulein-patch-1 branch. * adding qmdnsengine as source code directly removing the submodules * Update main.yml --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
3893
.github/workflows/main.yml
vendored
3893
.github/workflows/main.yml
vendored
File diff suppressed because it is too large
Load Diff
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -5,10 +5,6 @@
|
||||
path = src/smtpclient
|
||||
url = https://github.com/cagnulein/SmtpClient-for-Qt.git
|
||||
branch = cagnulein-patch-2
|
||||
[submodule "src/qmdnsengine"]
|
||||
path = src/qmdnsengine
|
||||
url = https://github.com/cagnulein/qmdnsengine.git
|
||||
branch = zwift
|
||||
[submodule "tst/googletest"]
|
||||
path = tst/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
|
||||
@@ -28,10 +28,7 @@ using namespace std::chrono_literals;
|
||||
OP(WAHOO_TREADMILL, "Wahoo TREAD $uuid_hex$", DM_MACHINE_TYPE_TREADMILL, P1, P2, P3)
|
||||
|
||||
#define DM_MACHINE_OP_ROUVY(OP, P1, P2, P3) \
|
||||
OP(WAHOO_KICKR, "ELITE AVANTI $uuid_hex$ W", DM_MACHINE_TYPE_TREADMILL | DM_MACHINE_TYPE_BIKE, P1, P2, P3) \
|
||||
OP(WAHOO_BLUEHR, "Wahoo HRM", DM_MACHINE_TYPE_BIKE | DM_MACHINE_TYPE_TREADMILL, P1, P2, P3) \
|
||||
OP(WAHOO_RPM_SPEED, "Wahoo SPEED $uuid_hex$", DM_MACHINE_TYPE_BIKE, P1, P2, P3) \
|
||||
OP(WAHOO_TREADMILL, "Wahoo TREAD $uuid_hex$", DM_MACHINE_TYPE_TREADMILL, P1, P2, P3)
|
||||
OP(WAHOO_KICKR, "ELITE AVANTI $uuid_hex$ W", DM_MACHINE_TYPE_TREADMILL | DM_MACHINE_TYPE_BIKE, P1, P2, P3)
|
||||
|
||||
#define DP_PROCESS_WRITE_0003() (zwift_play_emulator ? writeP0003 : 0)
|
||||
#define DP_PROCESS_WRITE_2AD9() writeP2AD9
|
||||
@@ -152,6 +149,19 @@ enum {
|
||||
}
|
||||
|
||||
QString DirconManager::getMacAddress() {
|
||||
QSettings settings;
|
||||
bool rouvy_compatibility = settings.value(QZSettings::rouvy_compatibility, QZSettings::default_rouvy_compatibility).toBool();
|
||||
int dircon_id = settings.value(QZSettings::dircon_id, QZSettings::default_dircon_id).toInt();
|
||||
|
||||
// When Rouvy compatibility is enabled, use a specific MAC address with the last byte set to dircon_id
|
||||
if (rouvy_compatibility) {
|
||||
// Use base MAC address "24:DC:C3:E3:B5:XX" where XX is the dircon_id
|
||||
// Ensure dircon_id is in the valid range 0-255
|
||||
int last_byte = dircon_id & 0xFF;
|
||||
return QString("24:DC:C3:E3:B5:%1").arg(last_byte, 2, 16, QChar('0')).toUpper();
|
||||
}
|
||||
|
||||
// Default behavior: get MAC address from network interfaces
|
||||
QString addr;
|
||||
foreach (QNetworkInterface netInterface, QNetworkInterface::allInterfaces()) {
|
||||
// Return only the first non-loopback MAC Address
|
||||
|
||||
Submodule src/qmdnsengine deleted from 575d343444
1
src/qmdnsengine/.gitignore
vendored
Normal file
1
src/qmdnsengine/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/CMakeLists.txt.user
|
||||
67
src/qmdnsengine/CMakeLists.txt
Normal file
67
src/qmdnsengine/CMakeLists.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
cmake_minimum_required(VERSION 3.2.0)
|
||||
project(qmdnsengine)
|
||||
|
||||
set(PROJECT_NAME "QMdnsEngine")
|
||||
set(PROJECT_DESCRIPTION "Multicast DNS library for Qt applications")
|
||||
set(PROJECT_AUTHOR "Nathan Osman")
|
||||
set(PROJECT_URL "https://github.com/nitroshare/qmdnsengine")
|
||||
|
||||
set(PROJECT_VERSION_MAJOR 0)
|
||||
set(PROJECT_VERSION_MINOR 2)
|
||||
set(PROJECT_VERSION_PATCH 0)
|
||||
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
|
||||
# Build a shared library by default
|
||||
option(BUILD_SHARED_LIBS "Build QMdnsEngine as a shared library" ON)
|
||||
|
||||
set(BIN_INSTALL_DIR bin CACHE STRING "Binary installation directory relative to the install prefix")
|
||||
set(LIB_INSTALL_DIR lib CACHE STRING "Library installation directory relative to the install prefix")
|
||||
set(INCLUDE_INSTALL_DIR include CACHE STRING "Header installation directory relative to the install prefix")
|
||||
|
||||
set(DOC_INSTALL_DIR share/doc/qmdnsengine CACHE STRING "Documentation installation directory relative to the install prefix")
|
||||
set(EXAMPLES_INSTALL_DIR "${LIB_INSTALL_DIR}/qmdnsengine/examples" CACHE STRING "Examples installation directory relative to the install prefix")
|
||||
|
||||
find_package(Qt5Network 5.7 REQUIRED)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
# Add compilation flags for warnings
|
||||
if (MSVC)
|
||||
add_compile_options(/W4 /WX)
|
||||
else()
|
||||
add_compile_options(-Wall -Wextra -pedantic -Werror)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
option(BUILD_DOC "Build Doxygen documentation" OFF)
|
||||
if(BUILD_DOC)
|
||||
find_package(Doxygen REQUIRED)
|
||||
add_subdirectory(doc)
|
||||
endif()
|
||||
|
||||
option(BUILD_EXAMPLES "Build example applications" OFF)
|
||||
if(BUILD_EXAMPLES)
|
||||
find_package(Qt5Widgets 5.7)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
option(BUILD_TESTS "Build test suite" OFF)
|
||||
if(BUILD_TESTS)
|
||||
find_package(Qt5Test 5.7 REQUIRED)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}")
|
||||
set(CPACK_PACKAGE_VENDOR "${PROJECT_AUTHOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
|
||||
set(CPACK_COMPONENT_DOCUMENTATION_DISPLAY_NAME "Documentation")
|
||||
set(CPACK_COMPONENT_DOCUMENTATION_DESCRIPTION "Documentation generated for the library")
|
||||
set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Examples")
|
||||
set(CPACK_COMPONENT_EXAMPLES_DESCRIPTION "Sample applications using the library")
|
||||
|
||||
include(CPack)
|
||||
9
src/qmdnsengine/LICENSE.txt
Normal file
9
src/qmdnsengine/LICENSE.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Nathan Osman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
12
src/qmdnsengine/README.md
Normal file
12
src/qmdnsengine/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## QMdnsEngine
|
||||
|
||||
[](https://ci.quickmediasolutions.com/job/qmdnsengine/)
|
||||
[](http://opensource.org/licenses/MIT)
|
||||
|
||||
This library provides an implementation of multicast DNS as per [RFC 6762](https://tools.ietf.org/html/rfc6762).
|
||||
|
||||
### Documentation
|
||||
|
||||
To learn more about building and using the library, please visit this page:
|
||||
|
||||
https://ci.quickmediasolutions.com/job/qmdnsengine-documentation/doxygen/
|
||||
10
src/qmdnsengine/doc/CMakeLists.txt
Normal file
10
src/qmdnsengine/doc/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
configure_file(Doxyfile.in "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
|
||||
|
||||
add_custom_target(doc ALL
|
||||
"${DOXYGEN_EXECUTABLE}" \"${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\"
|
||||
)
|
||||
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
|
||||
DESTINATION "${DOC_INSTALL_DIR}"
|
||||
COMPONENT documentation
|
||||
)
|
||||
2494
src/qmdnsengine/doc/Doxyfile.in
Normal file
2494
src/qmdnsengine/doc/Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
87
src/qmdnsengine/doc/index.md
Normal file
87
src/qmdnsengine/doc/index.md
Normal file
@@ -0,0 +1,87 @@
|
||||
QMdnsEngine provides an implementation of multicast DNS as per RFC 6762.
|
||||
|
||||
Some of QMdnsEngine's features include:
|
||||
|
||||
- Supports Windows, macOS, Linux, and most other platforms supported by Qt
|
||||
- Requires only QtCore and QtNetwork - no other dependencies
|
||||
- Includes an exhaustive set of unit tests
|
||||
|
||||
## Build Requirements
|
||||
|
||||
QMdnsEngine requires the following in order to build the library:
|
||||
|
||||
- CMake 3.2+
|
||||
- Qt 5.4+
|
||||
- C++ compiler with C++11 support
|
||||
|
||||
## Build Instructions
|
||||
|
||||
QMdnsEngine uses CMake for building the library. The options shown below allow the build to be customized:
|
||||
|
||||
- Installation:
|
||||
- `BIN_INSTALL_DIR` - binary installation directory relative to the install prefix
|
||||
- `LIB_INSTALL_DIR` - library installation directory relative to the install prefix
|
||||
- `INCLUDE_INSTALL_DIR` - header installation directory relative to the install prefix
|
||||
- Customization:
|
||||
- `BUILD_DOC` - build the documentation for the library with Doxygen
|
||||
- `BUILD_EXAMPLES` - build example applications that use the library
|
||||
- `BUILD_TESTS` - build the test suite
|
||||
|
||||
## Basic Provider Usage
|
||||
|
||||
To provide a service on the local network, begin by creating a [Server](@ref QMdnsEngine::Server), a [Hostname](@ref QMdnsEngine::Hostname), and a [Provider](@ref QMdnsEngine::Provider):
|
||||
|
||||
@code
|
||||
QMdnsEngine::Server server;
|
||||
QMdnsEngine::Hostname hostname(&server);
|
||||
QMdnsEngine::Provider provider(&server, &hostname);
|
||||
@endcode
|
||||
|
||||
The server sends and receives raw DNS packets. The hostname finds a unique hostname that is not in use to identify the device. Lastly, the provider manages the records for a service.
|
||||
|
||||
The next step is to create the service and update the provider:
|
||||
|
||||
@code
|
||||
QMdnsEngine::Service service;
|
||||
service.setType("_http._tcp.local.");
|
||||
service.setName("My Service");
|
||||
service.setPort(1234);
|
||||
provider.update(service);
|
||||
@endcode
|
||||
|
||||
That's it! As long as the provider remains in scope, the service will be available on the local network and other devices will be able to find it.
|
||||
|
||||
## Basic Browser Usage
|
||||
|
||||
To find services on the local network, begin by creating a [Server](@ref QMdnsEngine::Server) and a [Browser](@ref QMdnsEngine::Browser):
|
||||
|
||||
@code
|
||||
QMdnsEngine::Server server;
|
||||
QMdnsEngine::Cache cache;
|
||||
QMdnsEngine::Browser browser(&server, "_http._tcp.local.", &cache);
|
||||
@endcode
|
||||
|
||||
The cache is optional but helps save time later when resolving services. The browser is provided with a service type which is used to filter services.
|
||||
|
||||
To receive a notification when services are added, connect to the [Browser::serviceAdded()](@ref QMdnsEngine::Browser::serviceAdded) signal:
|
||||
|
||||
@code
|
||||
QObject::connect(&browser, &QMdnsEngine::Browser::serviceAdded,
|
||||
[](const QMdnsEngine::Service &service) {
|
||||
qDebug() << service.name() << "discovered!";
|
||||
}
|
||||
);
|
||||
@endcode
|
||||
|
||||
To resolve the service, use a [Resolver](@ref QMdnsEngine::Resolver):
|
||||
|
||||
@code
|
||||
QMdnsEngine::Resolver resolver(&server, service.hostname(), &cache);
|
||||
QObject::connect(&resolver, &QMdnsEngine::Resolver::resolved,
|
||||
[](const QHostAddress &address) {
|
||||
qDebug() << "resolved to" << address;
|
||||
}
|
||||
);
|
||||
@endcode
|
||||
|
||||
Note that [Resolver::resolved()](@ref QMdnsEngine::Resolver::resolved) may be emitted once for each address provided by the service.
|
||||
34
src/qmdnsengine/doc/overrides.css
Normal file
34
src/qmdnsengine/doc/overrides.css
Normal file
@@ -0,0 +1,34 @@
|
||||
#titlearea {
|
||||
margin: 10px 0;
|
||||
}
|
||||
#projectalign {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
.fragment {
|
||||
padding: 4px !important;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
#top, .header, .contents, .footer {
|
||||
margin: auto !important;
|
||||
max-width: 900px;
|
||||
}
|
||||
#titlearea {
|
||||
border-bottom: none;
|
||||
}
|
||||
#main-nav, #navrow1 {
|
||||
border-radius: 4px 4px 0 0;
|
||||
border-top: 1px solid #c4cfe5;
|
||||
position: relative;
|
||||
}
|
||||
#main-nav, #navrow1, .header, .nav-path, .contents {
|
||||
border-left: 1px solid #c4cfe5;
|
||||
border-right: 1px solid #c4cfe5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.contents {
|
||||
padding: 14px;
|
||||
}
|
||||
hr.footer {
|
||||
border-top: 1px solid #c4cfe5;
|
||||
}
|
||||
}
|
||||
13
src/qmdnsengine/examples/CMakeLists.txt
Normal file
13
src/qmdnsengine/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
set(EXAMPLES
|
||||
browser
|
||||
provider
|
||||
)
|
||||
|
||||
foreach(EXAMPLE ${EXAMPLES})
|
||||
set(EXAMPLE_DIR "${EXAMPLES_INSTALL_DIR}/${EXAMPLE}")
|
||||
add_subdirectory(${EXAMPLE})
|
||||
install(DIRECTORY ${EXAMPLE}
|
||||
DESTINATION "${EXAMPLES_INSTALL_DIR}"
|
||||
COMPONENT examples
|
||||
)
|
||||
endforeach()
|
||||
18
src/qmdnsengine/examples/browser/CMakeLists.txt
Normal file
18
src/qmdnsengine/examples/browser/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
set(SRC
|
||||
browser.cpp
|
||||
mainwindow.cpp
|
||||
servicemodel.cpp
|
||||
)
|
||||
|
||||
add_executable(browser WIN32 ${SRC})
|
||||
|
||||
set_target_properties(browser PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
)
|
||||
|
||||
target_link_libraries(browser qmdnsengine Qt5::Widgets)
|
||||
|
||||
install(TARGETS browser
|
||||
RUNTIME DESTINATION "${EXAMPLE_DIR}"
|
||||
COMPONENT examples
|
||||
)
|
||||
37
src/qmdnsengine/examples/browser/browser.cpp
Normal file
37
src/qmdnsengine/examples/browser/browser.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
145
src/qmdnsengine/examples/browser/mainwindow.cpp
Normal file
145
src/qmdnsengine/examples/browser/mainwindow.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLineEdit>
|
||||
#include <QListView>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QSplitter>
|
||||
#include <QTableWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "servicemodel.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QMdnsEngine::Service)
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: mServiceModel(nullptr),
|
||||
mResolver(nullptr)
|
||||
{
|
||||
setWindowTitle(tr("mDNS Browser"));
|
||||
resize(640, 480);
|
||||
|
||||
mServiceType = new QLineEdit(tr("_http._tcp.local."));
|
||||
mStartStop = new QPushButton(tr("Browse"));
|
||||
mServices = new QListView;
|
||||
mAddresses = new QListWidget;
|
||||
mAttributes = new QTableWidget;
|
||||
mAttributes->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
QVBoxLayout *rootLayout = new QVBoxLayout;
|
||||
QWidget *widget = new QWidget;
|
||||
widget->setLayout(rootLayout);
|
||||
setCentralWidget(widget);
|
||||
|
||||
QCheckBox *any = new QCheckBox(tr("Any"));
|
||||
|
||||
QHBoxLayout *typeLayout = new QHBoxLayout;
|
||||
typeLayout->addWidget(mServiceType, 1);
|
||||
typeLayout->addWidget(any);
|
||||
typeLayout->addWidget(mStartStop);
|
||||
rootLayout->addLayout(typeLayout);
|
||||
|
||||
QSplitter *vSplitter = new QSplitter;
|
||||
vSplitter->setOrientation(Qt::Vertical);
|
||||
vSplitter->addWidget(mAddresses);
|
||||
vSplitter->addWidget(mAttributes);
|
||||
|
||||
QSplitter *hSplitter = new QSplitter;
|
||||
hSplitter->addWidget(mServices);
|
||||
hSplitter->addWidget(vSplitter);
|
||||
|
||||
QHBoxLayout *servicesLayout = new QHBoxLayout;
|
||||
servicesLayout->addWidget(hSplitter);
|
||||
rootLayout->addLayout(servicesLayout);
|
||||
|
||||
connect(any, &QCheckBox::toggled, this, &MainWindow::onToggled);
|
||||
connect(mStartStop, &QPushButton::clicked, this, &MainWindow::onClicked);
|
||||
}
|
||||
|
||||
void MainWindow::onToggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
mServiceType->setText(QMdnsEngine::MdnsBrowseType);
|
||||
}
|
||||
mServiceType->setEnabled(!checked);
|
||||
}
|
||||
|
||||
void MainWindow::onClicked()
|
||||
{
|
||||
if (mServiceModel) {
|
||||
mServices->setModel(nullptr);
|
||||
delete mServiceModel;
|
||||
mAttributes->clear();
|
||||
mAttributes->setColumnCount(0);
|
||||
}
|
||||
|
||||
mServiceModel = new ServiceModel(&mServer, mServiceType->text().toUtf8());
|
||||
mServices->setModel(mServiceModel);
|
||||
|
||||
connect(mServices->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::onSelectionChanged);
|
||||
}
|
||||
|
||||
void MainWindow::onSelectionChanged(const QItemSelection &selected, const QItemSelection &)
|
||||
{
|
||||
mAddresses->clear();
|
||||
mAttributes->clear();
|
||||
mAttributes->setColumnCount(0);
|
||||
|
||||
if (mResolver) {
|
||||
delete mResolver;
|
||||
mResolver = nullptr;
|
||||
}
|
||||
|
||||
if (selected.count()) {
|
||||
auto service = mServiceModel->data(selected.at(0).topLeft(), Qt::UserRole).value<QMdnsEngine::Service>();
|
||||
|
||||
// Show TXT values
|
||||
auto attributes = service.attributes();
|
||||
mAttributes->setRowCount(attributes.keys().count());
|
||||
mAttributes->setColumnCount(2);
|
||||
mAttributes->setHorizontalHeaderLabels({tr("Key"), tr("Value")});
|
||||
mAttributes->horizontalHeader()->setStretchLastSection(true);
|
||||
mAttributes->verticalHeader()->setVisible(false);
|
||||
int row = 0;
|
||||
for (auto i = attributes.constBegin(); i != attributes.constEnd(); ++i, ++row) {
|
||||
mAttributes->setItem(row, 0, new QTableWidgetItem(QString(i.key())));
|
||||
mAttributes->setItem(row, 1, new QTableWidgetItem(QString(i.value())));
|
||||
}
|
||||
|
||||
// Resolve the address
|
||||
mResolver = new QMdnsEngine::Resolver(&mServer, service.hostname(), nullptr, this);
|
||||
connect(mResolver, &QMdnsEngine::Resolver::resolved, [this](const QHostAddress &address) {
|
||||
mAddresses->addItem(address.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
70
src/qmdnsengine/examples/browser/mainwindow.h
Normal file
70
src/qmdnsengine/examples/browser/mainwindow.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <qmdnsengine/server.h>
|
||||
#include <qmdnsengine/resolver.h>
|
||||
|
||||
class QItemSelection;
|
||||
class QLineEdit;
|
||||
class QListView;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
class QTableWidget;
|
||||
|
||||
class ServiceModel;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MainWindow();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onToggled(bool checked);
|
||||
void onClicked();
|
||||
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
|
||||
private:
|
||||
|
||||
QMdnsEngine::Server mServer;
|
||||
ServiceModel *mServiceModel;
|
||||
|
||||
QLineEdit *mServiceType;
|
||||
QPushButton *mStartStop;
|
||||
QListView *mServices;
|
||||
QListWidget *mAddresses;
|
||||
QTableWidget *mAttributes;
|
||||
|
||||
QMdnsEngine::Resolver *mResolver;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
97
src/qmdnsengine/examples/browser/servicemodel.cpp
Normal file
97
src/qmdnsengine/examples/browser/servicemodel.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "servicemodel.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QMdnsEngine::Service)
|
||||
|
||||
ServiceModel::ServiceModel(QMdnsEngine::Server *server, const QByteArray &type)
|
||||
: mBrowser(server, type, &cache)
|
||||
{
|
||||
connect(&mBrowser, &QMdnsEngine::Browser::serviceAdded, this, &ServiceModel::onServiceAdded);
|
||||
connect(&mBrowser, &QMdnsEngine::Browser::serviceUpdated, this, &ServiceModel::onServiceUpdated);
|
||||
connect(&mBrowser, &QMdnsEngine::Browser::serviceRemoved, this, &ServiceModel::onServiceRemoved);
|
||||
}
|
||||
|
||||
int ServiceModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return mServices.count();
|
||||
}
|
||||
|
||||
QVariant ServiceModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
// Ensure the index points to a valid row
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= mServices.count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QMdnsEngine::Service service = mServices.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QString("%1 (%2)")
|
||||
.arg(QString(service.name()))
|
||||
.arg(QString(service.type()));
|
||||
case Qt::UserRole:
|
||||
return QVariant::fromValue(service);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ServiceModel::onServiceAdded(const QMdnsEngine::Service &service)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), mServices.count(), mServices.count());
|
||||
mServices.append(service);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void ServiceModel::onServiceUpdated(const QMdnsEngine::Service &service)
|
||||
{
|
||||
int i = findService(service.name());
|
||||
if (i != -1) {
|
||||
mServices.replace(i, service);
|
||||
emit dataChanged(index(i), index(i));
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceModel::onServiceRemoved(const QMdnsEngine::Service &service)
|
||||
{
|
||||
int i = findService(service.name());
|
||||
if (i != -1) {
|
||||
beginRemoveRows(QModelIndex(), i, i);
|
||||
mServices.removeAt(i);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
int ServiceModel::findService(const QByteArray &name)
|
||||
{
|
||||
for (auto i = mServices.constBegin(); i != mServices.constEnd(); ++i) {
|
||||
if ((*i).name() == name) {
|
||||
return i - mServices.constBegin();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
62
src/qmdnsengine/examples/browser/servicemodel.h
Normal file
62
src/qmdnsengine/examples/browser/servicemodel.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SERVICEMODEL_H
|
||||
#define SERVICEMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
|
||||
#include <qmdnsengine/browser.h>
|
||||
#include <qmdnsengine/cache.h>
|
||||
#include <qmdnsengine/service.h>
|
||||
#include <qmdnsengine/server.h>
|
||||
|
||||
class ServiceModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ServiceModel(QMdnsEngine::Server *server, const QByteArray &type);
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onServiceAdded(const QMdnsEngine::Service &service);
|
||||
void onServiceUpdated(const QMdnsEngine::Service &service);
|
||||
void onServiceRemoved(const QMdnsEngine::Service &service);
|
||||
|
||||
private:
|
||||
|
||||
int findService(const QByteArray &name);
|
||||
|
||||
QMdnsEngine::Cache cache;
|
||||
QMdnsEngine::Browser mBrowser;
|
||||
QList<QMdnsEngine::Service> mServices;
|
||||
};
|
||||
|
||||
#endif // SERVICEMODEL_H
|
||||
13
src/qmdnsengine/examples/provider/CMakeLists.txt
Normal file
13
src/qmdnsengine/examples/provider/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
set(SRC
|
||||
mainwindow.cpp
|
||||
provider.cpp
|
||||
)
|
||||
|
||||
add_executable(provider WIN32 ${SRC})
|
||||
|
||||
target_link_libraries(provider qmdnsengine Qt5::Widgets)
|
||||
|
||||
install(TARGETS provider
|
||||
RUNTIME DESTINATION "${EXAMPLE_DIR}"
|
||||
COMPONENT examples
|
||||
)
|
||||
133
src/qmdnsengine/examples/provider/mainwindow.cpp
Normal file
133
src/qmdnsengine/examples/provider/mainwindow.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QIntValidator>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: mHostname(&mServer),
|
||||
mProvider(0),
|
||||
mServiceName(new QLineEdit(tr("Test Service"))),
|
||||
mServiceType(new QLineEdit(tr("_test._tcp.local."))),
|
||||
mServicePort(new QLineEdit("1234")),
|
||||
mButton(new QPushButton(buttonCaption())),
|
||||
mShowQueries(new QCheckBox(tr("Show queries"))),
|
||||
mLog(new QTextEdit(tr("Initializing application")))
|
||||
{
|
||||
setWindowTitle(tr("mDNS Provider"));
|
||||
resize(640, 480);
|
||||
|
||||
mServicePort->setValidator(new QIntValidator(1, 65535, this));
|
||||
mLog->setReadOnly(true);
|
||||
|
||||
// Create the root layout
|
||||
QVBoxLayout *rootLayout = new QVBoxLayout;
|
||||
QWidget *widget = new QWidget;
|
||||
widget->setLayout(rootLayout);
|
||||
setCentralWidget(widget);
|
||||
|
||||
// Create the horizontal layout for the grid and buttons
|
||||
QHBoxLayout *upperLayout = new QHBoxLayout;
|
||||
rootLayout->addLayout(upperLayout);
|
||||
|
||||
// Create the grid layout for the line edits
|
||||
QGridLayout *gridLayout = new QGridLayout;
|
||||
gridLayout->addWidget(new QLabel(tr("Service name:")), 0, 0);
|
||||
gridLayout->addWidget(mServiceName, 0, 1);
|
||||
gridLayout->addWidget(new QLabel(tr("Service type:")), 1, 0);
|
||||
gridLayout->addWidget(mServiceType, 1, 1);
|
||||
gridLayout->addWidget(new QLabel(tr("Service port:")), 2, 0);
|
||||
gridLayout->addWidget(mServicePort, 2, 1);
|
||||
upperLayout->addLayout(gridLayout);
|
||||
|
||||
// Create the layout for the buttons
|
||||
QVBoxLayout *buttonLayout = new QVBoxLayout;
|
||||
buttonLayout->addWidget(mButton);
|
||||
buttonLayout->addWidget(mShowQueries);
|
||||
buttonLayout->addWidget(new QWidget, 1);
|
||||
upperLayout->addLayout(buttonLayout);
|
||||
|
||||
// Add the log
|
||||
rootLayout->addWidget(mLog, 1);
|
||||
|
||||
connect(mButton, &QPushButton::clicked, this, &MainWindow::onClicked);
|
||||
connect(&mHostname, &QMdnsEngine::Hostname::hostnameChanged, this, &MainWindow::onHostnameChanged);
|
||||
connect(&mServer, &QMdnsEngine::Server::messageReceived, this, &MainWindow::onMessageReceived);
|
||||
}
|
||||
|
||||
void MainWindow::onClicked()
|
||||
{
|
||||
if (mProvider) {
|
||||
mLog->append(tr("Destroying provider"));
|
||||
delete mProvider;
|
||||
mProvider = 0;
|
||||
} else {
|
||||
mLog->append(tr("Creating provider"));
|
||||
QMdnsEngine::Service service;
|
||||
service.setName(mServiceName->text().toUtf8());
|
||||
service.setType(mServiceType->text().toUtf8());
|
||||
service.setPort(mServicePort->text().toUShort());
|
||||
mProvider = new QMdnsEngine::Provider(&mServer, &mHostname, this);
|
||||
mProvider->update(service);
|
||||
}
|
||||
mButton->setText(buttonCaption());
|
||||
}
|
||||
|
||||
void MainWindow::onHostnameChanged(const QByteArray &hostname)
|
||||
{
|
||||
mLog->append(tr("Hostname changed to %1").arg(QString(hostname)));
|
||||
}
|
||||
|
||||
void MainWindow::onMessageReceived(const QMdnsEngine::Message &message)
|
||||
{
|
||||
if (!mShowQueries->isChecked()) {
|
||||
return;
|
||||
}
|
||||
const auto queries = message.queries();
|
||||
for (const QMdnsEngine::Query &query : queries) {
|
||||
mLog->append(
|
||||
tr("[%1] %2")
|
||||
.arg(QMdnsEngine::typeName(query.type()))
|
||||
.arg(QString(query.name()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QString MainWindow::buttonCaption() const
|
||||
{
|
||||
return mProvider ? tr("Stop") : tr("Start");
|
||||
}
|
||||
72
src/qmdnsengine/examples/provider/mainwindow.h
Normal file
72
src/qmdnsengine/examples/provider/mainwindow.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <qmdnsengine/server.h>
|
||||
#include <qmdnsengine/hostname.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/provider.h>
|
||||
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MainWindow();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onClicked();
|
||||
void onHostnameChanged(const QByteArray &hostname);
|
||||
void onMessageReceived(const QMdnsEngine::Message &message);
|
||||
|
||||
private:
|
||||
|
||||
QString buttonCaption() const;
|
||||
|
||||
QMdnsEngine::Server mServer;
|
||||
QMdnsEngine::Hostname mHostname;
|
||||
QMdnsEngine::Provider *mProvider;
|
||||
|
||||
QLineEdit *mServiceName;
|
||||
QLineEdit *mServiceType;
|
||||
QLineEdit *mServicePort;
|
||||
|
||||
QPushButton *mButton;
|
||||
QCheckBox *mShowQueries;
|
||||
|
||||
QTextEdit *mLog;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
37
src/qmdnsengine/examples/provider/provider.cpp
Normal file
37
src/qmdnsengine/examples/provider/provider.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
88
src/qmdnsengine/src/CMakeLists.txt
Normal file
88
src/qmdnsengine/src/CMakeLists.txt
Normal file
@@ -0,0 +1,88 @@
|
||||
configure_file(qmdnsengine_export.h.in "${CMAKE_CURRENT_BINARY_DIR}/qmdnsengine_export.h")
|
||||
|
||||
set(HEADERS
|
||||
include/qmdnsengine/abstractserver.h
|
||||
include/qmdnsengine/bitmap.h
|
||||
include/qmdnsengine/browser.h
|
||||
include/qmdnsengine/cache.h
|
||||
include/qmdnsengine/dns.h
|
||||
include/qmdnsengine/hostname.h
|
||||
include/qmdnsengine/mdns.h
|
||||
include/qmdnsengine/message.h
|
||||
include/qmdnsengine/prober.h
|
||||
include/qmdnsengine/provider.h
|
||||
include/qmdnsengine/query.h
|
||||
include/qmdnsengine/record.h
|
||||
include/qmdnsengine/resolver.h
|
||||
include/qmdnsengine/server.h
|
||||
include/qmdnsengine/service.h
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/qmdnsengine_export.h"
|
||||
)
|
||||
|
||||
set(SRC
|
||||
src/abstractserver.cpp
|
||||
src/bitmap.cpp
|
||||
src/browser.cpp
|
||||
src/cache.cpp
|
||||
src/dns.cpp
|
||||
src/hostname.cpp
|
||||
src/mdns.cpp
|
||||
src/message.cpp
|
||||
src/prober.cpp
|
||||
src/provider.cpp
|
||||
src/query.cpp
|
||||
src/record.cpp
|
||||
src/resolver.cpp
|
||||
src/server.cpp
|
||||
src/service.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
configure_file(resource.rc.in "${CMAKE_CURRENT_BINARY_DIR}/resource.rc")
|
||||
set(SRC ${SRC} "${CMAKE_CURRENT_BINARY_DIR}/resource.rc")
|
||||
endif()
|
||||
|
||||
add_library(qmdnsengine ${HEADERS} ${SRC})
|
||||
|
||||
set_target_properties(qmdnsengine PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
DEFINE_SYMBOL QT_NO_SIGNALS_SLOTS_KEYWORDS
|
||||
DEFINE_SYMBOL QT_NO_FOREACH
|
||||
DEFINE_SYMBOL QMDNSENGINE_LIBRARY
|
||||
PUBLIC_HEADER "${HEADERS}"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
)
|
||||
|
||||
target_include_directories(qmdnsengine PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>"
|
||||
)
|
||||
|
||||
target_link_libraries(qmdnsengine Qt5::Network)
|
||||
|
||||
install(TARGETS qmdnsengine
|
||||
EXPORT qmdnsengine-export
|
||||
RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
|
||||
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
|
||||
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
|
||||
PUBLIC_HEADER DESTINATION "${INCLUDE_INSTALL_DIR}/qmdnsengine"
|
||||
)
|
||||
|
||||
install(EXPORT qmdnsengine-export
|
||||
FILE qmdnsengineConfig.cmake
|
||||
DESTINATION "${LIB_INSTALL_DIR}/cmake/qmdnsengine"
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/qmdnsengineConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qmdnsengineConfigVersion.cmake"
|
||||
DESTINATION "${LIB_INSTALL_DIR}/cmake/qmdnsengine"
|
||||
)
|
||||
88
src/qmdnsengine/src/include/qmdnsengine/abstractserver.h
Normal file
88
src/qmdnsengine/src/include/qmdnsengine/abstractserver.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_ABSTRACTSERVER_H
|
||||
#define QMDNSENGINE_ABSTRACTSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Message;
|
||||
|
||||
/**
|
||||
* @brief Base class for sending and receiving DNS messages
|
||||
*
|
||||
* Many of the other classes in this library require the ability to send and
|
||||
* receive DNS messages. By having them use this base class, they become far
|
||||
* easier to test. Any class derived from this one that implements the pure
|
||||
* virtual methods can be used for sending and receiving DNS messages.
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT AbstractServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Abstract constructor
|
||||
*/
|
||||
explicit AbstractServer(QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief Send a message to its provided destination
|
||||
*
|
||||
* The message should be sent over the IP protocol specified in the
|
||||
* message and to the target address and port specified in the message.
|
||||
*/
|
||||
virtual void sendMessage(const Message &message) = 0;
|
||||
|
||||
/**
|
||||
* @brief Send a message to the multicast address on each interface
|
||||
*
|
||||
* The message should be sent over both IPv4 and IPv6 on all interfaces.
|
||||
*/
|
||||
virtual void sendMessageToAll(const Message &message) = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief Indicate that a DNS message was received
|
||||
* @param message newly received message
|
||||
*/
|
||||
void messageReceived(const Message &message);
|
||||
|
||||
/**
|
||||
* @brief Indicate that an error has occurred
|
||||
* @param message brief description of the error
|
||||
*/
|
||||
void error(const QString &message);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_ABSTRACTSERVER_H
|
||||
100
src/qmdnsengine/src/include/qmdnsengine/bitmap.h
Normal file
100
src/qmdnsengine/src/include/qmdnsengine/bitmap.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_BITMAP_H
|
||||
#define QMDNSENGINE_BITMAP_H
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class QMDNSENGINE_EXPORT BitmapPrivate;
|
||||
|
||||
/**
|
||||
* @brief 256-bit bitmap
|
||||
*
|
||||
* Bitmaps are used in QMdnsEngine::NSEC records to indicate which records are
|
||||
* available. Bitmaps in mDNS records use only the first block (block 0).
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Bitmap
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an empty bitmap
|
||||
*/
|
||||
Bitmap();
|
||||
|
||||
/**
|
||||
* @brief Create a copy of an existing bitmap
|
||||
*/
|
||||
Bitmap(const Bitmap &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
*/
|
||||
Bitmap &operator=(const Bitmap &other);
|
||||
|
||||
/**
|
||||
* @brief Equality operator
|
||||
*/
|
||||
bool operator==(const Bitmap &other);
|
||||
|
||||
/**
|
||||
* @brief Destroy the bitmap
|
||||
*/
|
||||
virtual ~Bitmap();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the length of the block in bytes
|
||||
*
|
||||
* This method indicates how many bytes are pointed to by the data()
|
||||
* method.
|
||||
*/
|
||||
quint8 length() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve a pointer to the underlying data in the bitmap
|
||||
*
|
||||
* Use the length() method to determine how many bytes contain valid data.
|
||||
*/
|
||||
const quint8 *data() const;
|
||||
|
||||
/**
|
||||
* @brief Set the data to be stored in the bitmap
|
||||
*
|
||||
* The length parameter indicates how many bytes of data are valid. The
|
||||
* actual bytes are copied to the bitmap.
|
||||
*/
|
||||
void setData(quint8 length, const quint8 *data);
|
||||
|
||||
private:
|
||||
|
||||
BitmapPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_BITMAP_H
|
||||
122
src/qmdnsengine/src/include/qmdnsengine/browser.h
Normal file
122
src/qmdnsengine/src/include/qmdnsengine/browser.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_BROWSER_H
|
||||
#define QMDNSENGINE_BROWSER_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Cache;
|
||||
class Service;
|
||||
|
||||
class QMDNSENGINE_EXPORT BrowserPrivate;
|
||||
|
||||
/**
|
||||
* @brief %Browser for local services
|
||||
*
|
||||
* This class provides a simple way to discover services on the local network.
|
||||
* A cache may be provided in the constructor to store records for future
|
||||
* queries.
|
||||
*
|
||||
* To browse for services of any type:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Browser browser(&server, QMdnsEngine::MdnsBrowseType);
|
||||
* @endcode
|
||||
*
|
||||
* To browse for services of a specific type:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Browser browser(&server, "_http._tcp.local.");
|
||||
* @endcode
|
||||
*
|
||||
* When a service is found, the serviceAdded() signal is emitted:
|
||||
*
|
||||
* @code
|
||||
* connect(&browser, &QMdnsEngine::Browser::serviceAdded, [](const QMdnsEngine::Service &service) {
|
||||
* qDebug() << "Service added:" << service.name();
|
||||
* });
|
||||
* @endcode
|
||||
*
|
||||
* The serviceUpdated() and serviceRemoved() signals are emitted when services
|
||||
* are updated (their properties change) or are removed, respectively.
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Browser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new browser instance
|
||||
* @param server server to use for receiving and sending mDNS messages
|
||||
* @param type service type to browse for
|
||||
* @param cache DNS cache to use or null to create one
|
||||
* @param parent QObject
|
||||
*/
|
||||
Browser(AbstractServer *server, const QByteArray &type, Cache *cache = 0, QObject *parent = 0);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief Indicate that a new service has been added
|
||||
*
|
||||
* This signal is emitted when the PTR and SRV records for a service are
|
||||
* received. If TXT records are received later, the serviceUpdated()
|
||||
* signal will be emitted.
|
||||
*/
|
||||
void serviceAdded(const Service &service);
|
||||
|
||||
/**
|
||||
* @brief Indicate that the specified service was updated
|
||||
*
|
||||
* This signal is emitted when the SRV record for a service (identified by
|
||||
* its name and type) or a TXT record has changed.
|
||||
*/
|
||||
void serviceUpdated(const Service &service);
|
||||
|
||||
/**
|
||||
* @brief Indicate that the specified service was removed
|
||||
*
|
||||
* This signal is emitted when an essential record (PTR or SRV) is
|
||||
* expiring from the cache. This will also occur when an updated PTR or
|
||||
* SRV record is received with a TTL of 0.
|
||||
*/
|
||||
void serviceRemoved(const Service &service);
|
||||
|
||||
private:
|
||||
|
||||
BrowserPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_BROWSER_H
|
||||
132
src/qmdnsengine/src/include/qmdnsengine/cache.h
Normal file
132
src/qmdnsengine/src/include/qmdnsengine/cache.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_CACHE_H
|
||||
#define QMDNSENGINE_CACHE_H
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Record;
|
||||
|
||||
class QMDNSENGINE_EXPORT CachePrivate;
|
||||
|
||||
/**
|
||||
* @brief %Cache for DNS records
|
||||
*
|
||||
* Records are added to the cache using the addRecord() method which are then
|
||||
* stored in the cache until they are considered to have expired, at which
|
||||
* point they are purged. The shouldQuery() signal is used to indicate when a
|
||||
* record is approaching expiry and the recordExpired() signal indicates when
|
||||
* a record has expired (at which point it is removed).
|
||||
*
|
||||
* The cache can be queried to retrieve one or more records matching a given
|
||||
* type. For example, to retrieve all TXT records that match a given name:
|
||||
*
|
||||
* @code
|
||||
* Cache cache;
|
||||
*
|
||||
* QList<QMdnsEngine::Record> records;
|
||||
* cache.lookupRecords("My Service._http._tcp.local.", QMdnsEngine::TXT, records);
|
||||
*
|
||||
* for (const QMdnsEngine::Record &record : records) {
|
||||
* qDebug() << "Record:" << record.name();
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Alternatively, lookupRecord() can be used to find a single record.
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Cache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an empty cache.
|
||||
*/
|
||||
explicit Cache(QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief Add a record to the cache
|
||||
* @param record add this record to the cache
|
||||
*
|
||||
* The TTL for the record will be added to the current time to calculate
|
||||
* when the record expires. Existing records of the same name and type
|
||||
* will be replaced, resetting their expiration.
|
||||
*/
|
||||
void addRecord(const Record &record);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a single record from the cache
|
||||
* @param name name of record to retrieve or null for any
|
||||
* @param type type of record to retrieve or ANY for all types
|
||||
* @param record storage for the record retrieved
|
||||
* @return true if a record was retrieved
|
||||
*
|
||||
* Some record types allow multiple records to be stored with identical
|
||||
* names and types. This method will only retrieve the first matching
|
||||
* record. Use lookupRecords() to obtain all of the records.
|
||||
*/
|
||||
bool lookupRecord(const QByteArray &name, quint16 type, Record &record) const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve multiple records from the cache
|
||||
* @param name name of records to retrieve or null for any
|
||||
* @param type type of records to retrieve or ANY for all types
|
||||
* @param records storage for the records retrieved
|
||||
* @return true if records were retrieved
|
||||
*/
|
||||
bool lookupRecords(const QByteArray &name, quint16 type, QList<Record> &records) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief Indicate that a record will expire soon and a new query should be issued
|
||||
* @param record reference to the record that will soon expire
|
||||
*
|
||||
* This signal is emitted when a record reaches approximately 50%, 85%,
|
||||
* 90%, and 95% of its lifetime.
|
||||
*/
|
||||
void shouldQuery(const Record &record);
|
||||
|
||||
/**
|
||||
* @brief Indicate that the specified record expired
|
||||
* @param record reference to the record that has expired
|
||||
*/
|
||||
void recordExpired(const Record &record);
|
||||
|
||||
private:
|
||||
|
||||
CachePrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_CACHE_H
|
||||
123
src/qmdnsengine/src/include/qmdnsengine/dns.h
Normal file
123
src/qmdnsengine/src/include/qmdnsengine/dns.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_DNS_H
|
||||
#define QMDNSENGINE_DNS_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMap>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Message;
|
||||
class Record;
|
||||
|
||||
enum {
|
||||
/// IPv4 address record
|
||||
A = 1,
|
||||
/// IPv6 address record
|
||||
AAAA = 28,
|
||||
/// Wildcard for cache lookups
|
||||
ANY = 255,
|
||||
/// List of records
|
||||
NSEC = 47,
|
||||
/// Pointer to hostname
|
||||
PTR = 12,
|
||||
/// %Service information
|
||||
SRV = 33,
|
||||
/// Arbitrary metadata
|
||||
TXT = 16
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Parse a name from a raw DNS packet
|
||||
* @param packet raw DNS packet data
|
||||
* @param offset offset into the packet where the name begins
|
||||
* @param name reference to QByteArray to store the name in
|
||||
* @return true if no errors occurred
|
||||
*
|
||||
* The offset will be incremented by the number of bytes read. Name
|
||||
* compression requires access to the contents of the packet.
|
||||
*/
|
||||
QMDNSENGINE_EXPORT bool parseName(const QByteArray &packet, quint16 &offset, QByteArray &name);
|
||||
|
||||
/**
|
||||
* @brief Write a name to a raw DNS packet
|
||||
* @param packet raw DNS packet to write to
|
||||
* @param offset offset to update with the number of bytes written
|
||||
* @param name name to write to the packet
|
||||
* @param nameMap map of names already written to their offsets
|
||||
*
|
||||
* The offset will be incremented by the number of bytes read. The name map
|
||||
* will be updated with offsets of any names written so that it can be passed
|
||||
* to future invocations of this function.
|
||||
*/
|
||||
QMDNSENGINE_EXPORT void writeName(QByteArray &packet, quint16 &offset, const QByteArray &name, QMap<QByteArray, quint16> &nameMap);
|
||||
|
||||
/**
|
||||
* @brief Parse a record from a raw DNS packet
|
||||
* @param packet raw DNS packet data
|
||||
* @param offset offset into the packet where the record begins
|
||||
* @param record reference to Record to populate
|
||||
* @return true if no errors occurred
|
||||
*/
|
||||
QMDNSENGINE_EXPORT bool parseRecord(const QByteArray &packet, quint16 &offset, Record &record);
|
||||
|
||||
/**
|
||||
* @brief Write a record to a raw DNS packet
|
||||
* @param packet raw DNS packet to write to
|
||||
* @param offset offset to update with the number of bytes written
|
||||
* @param record record to write to the packet
|
||||
* @param nameMap map of names already written to their offsets
|
||||
*/
|
||||
QMDNSENGINE_EXPORT void writeRecord(QByteArray &packet, quint16 &offset, Record &record, QMap<QByteArray, quint16> &nameMap);
|
||||
|
||||
/**
|
||||
* @brief Populate a Message with data from a raw DNS packet
|
||||
* @param packet raw DNS packet data
|
||||
* @param message reference to Message to populate
|
||||
* @return true if no errors occurred
|
||||
*/
|
||||
QMDNSENGINE_EXPORT bool fromPacket(const QByteArray &packet, Message &message);
|
||||
|
||||
/**
|
||||
* @brief Create a raw DNS packet from a Message
|
||||
* @param message Message to create the packet from
|
||||
* @param packet storage for raw DNS packet
|
||||
*/
|
||||
QMDNSENGINE_EXPORT void toPacket(const Message &message, QByteArray &packet);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the string representation of a DNS type
|
||||
* @param type integer type
|
||||
* @return human-readable name for the type
|
||||
*/
|
||||
QMDNSENGINE_EXPORT QString typeName(quint16 type);
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_DNS_H
|
||||
95
src/qmdnsengine/src/include/qmdnsengine/hostname.h
Normal file
95
src/qmdnsengine/src/include/qmdnsengine/hostname.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_HOSTNAME_H
|
||||
#define QMDNSENGINE_HOSTNAME_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine {
|
||||
|
||||
class AbstractServer;
|
||||
|
||||
class QMDNSENGINE_EXPORT HostnamePrivate;
|
||||
|
||||
/**
|
||||
* @brief %Hostname reserved for exclusive use
|
||||
*
|
||||
* In order to provide services on the local network, a unique hostname must
|
||||
* be used. This class asserts a hostname (by first confirming that it is not
|
||||
* in use) and then responds to A and AAAA queries for the hostname.
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Hostname hostname(&server);
|
||||
*
|
||||
* connect(&hostname, &QMdnsEngine::Hostname::hostnameChanged, [](const QByteArray &hostname) {
|
||||
* qDebug() << "New hostname:" << hostname;
|
||||
* });
|
||||
* @endcode
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Hostname : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Create a new hostname
|
||||
*/
|
||||
Hostname(AbstractServer *server, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief Create a new hostname with desired value to register
|
||||
*/
|
||||
Hostname(AbstractServer *server, const QByteArray &desired, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief Determine if a hostname has been registered
|
||||
*
|
||||
* A hostname is not considered registered until a probe for the desired
|
||||
* name has been completed and no matching records were received.
|
||||
*/
|
||||
bool isRegistered() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current hostname
|
||||
*
|
||||
* This value is only valid when isRegistered() returns true.
|
||||
*/
|
||||
QByteArray hostname() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief Indicate that the current hostname has changed
|
||||
* @param hostname new hostname
|
||||
*/
|
||||
void hostnameChanged(const QByteArray &hostname);
|
||||
|
||||
private:
|
||||
HostnamePrivate *const d;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_HOSTNAME_H
|
||||
58
src/qmdnsengine/src/include/qmdnsengine/mdns.h
Normal file
58
src/qmdnsengine/src/include/qmdnsengine/mdns.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_MDNS_H
|
||||
#define QMDNSENGINE_MDNS_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Standard port for mDNS
|
||||
*/
|
||||
QMDNSENGINE_EXPORT extern const quint16 MdnsPort;
|
||||
|
||||
/**
|
||||
* @brief Standard IPv4 address for mDNS
|
||||
*/
|
||||
QMDNSENGINE_EXPORT extern const QHostAddress MdnsIpv4Address;
|
||||
|
||||
/**
|
||||
* @brief Standard IPv6 address for mDNS
|
||||
*/
|
||||
QMDNSENGINE_EXPORT extern const QHostAddress MdnsIpv6Address;
|
||||
|
||||
/**
|
||||
* @brief Service type for browsing service types
|
||||
*/
|
||||
QMDNSENGINE_EXPORT extern const QByteArray MdnsBrowseType;
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_MDNS_H
|
||||
191
src/qmdnsengine/src/include/qmdnsengine/message.h
Normal file
191
src/qmdnsengine/src/include/qmdnsengine/message.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_MESSAGE_H
|
||||
#define QMDNSENGINE_MESSAGE_H
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QList>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Query;
|
||||
class Record;
|
||||
|
||||
class QMDNSENGINE_EXPORT MessagePrivate;
|
||||
|
||||
/**
|
||||
* @brief DNS message
|
||||
*
|
||||
* A DNS message consists of a header and zero or more queries and records.
|
||||
* Instances of this class are created and initialized by
|
||||
* [AbstractServer](@ref QMdnsEngine::AbstractServer) when messages are
|
||||
* received from the network.
|
||||
*
|
||||
* If a message is being constructed in reply to one received from the
|
||||
* network, the reply() method can be used to simplify initialization:
|
||||
*
|
||||
* @code
|
||||
* connect(&server, &QMdnsEngine::Server::messageReceived, [](const QMdnsEngine::Message &message) {
|
||||
* QMdnsEngine::Message reply;
|
||||
* reply.reply(message);
|
||||
* server.sendMessage(reply);
|
||||
* });
|
||||
* @endcode
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Message
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an empty message
|
||||
*/
|
||||
Message();
|
||||
|
||||
/**
|
||||
* @brief Create a copy of an existing message
|
||||
*/
|
||||
Message(const Message &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
*/
|
||||
Message &operator=(const Message &other);
|
||||
|
||||
/**
|
||||
* @brief Destroy the message
|
||||
*/
|
||||
virtual ~Message();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the address for the message
|
||||
*
|
||||
* When receiving messages, this is the address that the message was
|
||||
* received from.
|
||||
*/
|
||||
QHostAddress address() const;
|
||||
|
||||
/**
|
||||
* @brief Set the address for the message
|
||||
*
|
||||
* When sending messages, this is the address that the message will be
|
||||
* sent to. QMdnsEngine::MdnsIpv4Address and QMdnsEngine::MdnsIpv6Address
|
||||
* can be used for mDNS messages.
|
||||
*/
|
||||
void setAddress(const QHostAddress &address);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the port for the message
|
||||
*
|
||||
* When receiving messages, this is the port that the message was received
|
||||
* from. For traditional queries, this will be an ephemeral port. For mDNS
|
||||
* queries, this will always equal QMdnsEngine::MdnsPort.
|
||||
*/
|
||||
quint16 port() const;
|
||||
|
||||
/**
|
||||
* @brief Set the port for the message
|
||||
*
|
||||
* When sending messages, this is the port that the message will be sent
|
||||
* to. This should be set to QMdnsEngine::MdnsPort unless the message is a
|
||||
* reply to a traditional DNS query.
|
||||
*/
|
||||
void setPort(quint16 port);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the transaction ID for the message
|
||||
*
|
||||
* This is always set to 1 for mDNS messages. Traditional DNS queries may
|
||||
* set this to an arbitrary integer.
|
||||
*/
|
||||
quint16 transactionId() const;
|
||||
|
||||
/**
|
||||
* @brief Set the transaction ID for the message
|
||||
*
|
||||
* The default transaction ID is 0. This value should not be changed
|
||||
* unless responding to a traditional DNS query.
|
||||
*/
|
||||
void setTransactionId(quint16 transactionId);
|
||||
|
||||
/**
|
||||
* @brief Determine if the message is a response
|
||||
*/
|
||||
bool isResponse() const;
|
||||
|
||||
/**
|
||||
* @brief Set whether the message is a response
|
||||
*/
|
||||
void setResponse(bool isResponse);
|
||||
|
||||
/**
|
||||
* @brief Determine if the message is truncated
|
||||
*/
|
||||
bool isTruncated() const;
|
||||
|
||||
/**
|
||||
* @brief Set whether the message is truncated
|
||||
*/
|
||||
void setTruncated(bool isTruncated);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a list of queries in the message
|
||||
*/
|
||||
QList<Query> queries() const;
|
||||
|
||||
/**
|
||||
* @brief Add a query to the message
|
||||
*/
|
||||
void addQuery(const Query &query);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a list of records in the message
|
||||
*/
|
||||
QList<Record> records() const;
|
||||
|
||||
/**
|
||||
* @brief Add a record to the message
|
||||
*/
|
||||
void addRecord(const Record &record);
|
||||
|
||||
/**
|
||||
* @brief Reply to another message
|
||||
*
|
||||
* The message will be correctly initialized to respond to the other
|
||||
* message. This includes setting the target address, port, and
|
||||
* transaction ID.
|
||||
*/
|
||||
void reply(const Message &other);
|
||||
|
||||
private:
|
||||
|
||||
MessagePrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_MESSAGE_H
|
||||
88
src/qmdnsengine/src/include/qmdnsengine/prober.h
Normal file
88
src/qmdnsengine/src/include/qmdnsengine/prober.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_PROBER_H
|
||||
#define QMDNSENGINE_PROBER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Record;
|
||||
|
||||
class QMDNSENGINE_EXPORT ProberPrivate;
|
||||
|
||||
/**
|
||||
* @brief %Prober to confirm that a record is unique
|
||||
*
|
||||
* Before responding to queries for a record, its uniqueness on the network
|
||||
* must be confirmed. This class takes care of probing for existing records
|
||||
* that match and adjusts the record's name until a unique one is found.
|
||||
*
|
||||
* For example, to probe for a SRV record:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Record record;
|
||||
* record.setName("My Service._http._tcp.local.");
|
||||
* record.setType(QMdnsEngine::SRV);
|
||||
* record.setPort(1234);
|
||||
* record.setTarget(hostname.hostname());
|
||||
*
|
||||
* QMdnsEngine::Prober prober(&server, record);
|
||||
* connect(&prober, &QMdnsEngine::Prober::nameConfirmed, [](const QByteArray &name) {
|
||||
* qDebug() << "Name confirmed:" << name;
|
||||
* });
|
||||
* @endcode
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Prober : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new prober
|
||||
*/
|
||||
Prober(AbstractServer *server, const Record &record, QObject *parent = 0);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief Indicate that the name has been confirmed unique
|
||||
* @param name that was confirmed to be unique
|
||||
*/
|
||||
void nameConfirmed(const QByteArray &name);
|
||||
|
||||
private:
|
||||
|
||||
ProberPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_PROBER_H
|
||||
90
src/qmdnsengine/src/include/qmdnsengine/provider.h
Normal file
90
src/qmdnsengine/src/include/qmdnsengine/provider.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_PROVIDER_H
|
||||
#define QMDNSENGINE_PROVIDER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Hostname;
|
||||
class Service;
|
||||
|
||||
class QMDNSENGINE_EXPORT ProviderPrivate;
|
||||
|
||||
/**
|
||||
* @brief %Provider for a single mDNS service
|
||||
*
|
||||
* This class provide a [Service](@ref QMdnsEngine::Service) on the local
|
||||
* network by responding to the appropriate DNS queries. A hostname is
|
||||
* required for creating the SRV record.
|
||||
*
|
||||
* The provider needs to be given a reference to the service through the
|
||||
* update() method so that it can construct DNS records:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Service service;
|
||||
* service.setType("_http._tcp.local.");
|
||||
* service.setName("My Service");
|
||||
* service.setPort(1234);
|
||||
*
|
||||
* QMdnsEngine::Provider provider;
|
||||
* provider.update(service);
|
||||
* @endcode
|
||||
*
|
||||
* This method can also be used to update the provider's records.
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Provider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new service provider
|
||||
*/
|
||||
Provider(AbstractServer *server, Hostname *hostname, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief Update the service with the provided information
|
||||
* @param service updated service description
|
||||
*
|
||||
* This class will not respond to any DNS queries until the hostname is
|
||||
* confirmed and this method is called.
|
||||
*/
|
||||
void update(const Service &service);
|
||||
|
||||
private:
|
||||
|
||||
ProviderPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_PROVIDER_H
|
||||
116
src/qmdnsengine/src/include/qmdnsengine/query.h
Normal file
116
src/qmdnsengine/src/include/qmdnsengine/query.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_QUERY_H
|
||||
#define QMDNSENGINE_QUERY_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class QMDNSENGINE_EXPORT QueryPrivate;
|
||||
|
||||
/**
|
||||
* @brief DNS query
|
||||
*
|
||||
* This class represents a query for a DNS record. For example, to query for
|
||||
* the IPv4 address of a local host:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Query query;
|
||||
* query.setName("myserver.local.");
|
||||
* query.setType(QMdnsEngine::A);
|
||||
*
|
||||
* message.addQuery(query);
|
||||
* @endcode
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Query
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an empty query
|
||||
*/
|
||||
Query();
|
||||
|
||||
/**
|
||||
* @brief Create a copy of an existing query
|
||||
*/
|
||||
Query(const Query &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
*/
|
||||
Query &operator=(const Query &other);
|
||||
|
||||
/**
|
||||
* @brief Destroy the query
|
||||
*/
|
||||
virtual ~Query();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the name being queried
|
||||
*/
|
||||
QByteArray name() const;
|
||||
|
||||
/**
|
||||
* @brief Set the name to query
|
||||
*/
|
||||
void setName(const QByteArray &name);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the type of record being queried
|
||||
*/
|
||||
quint16 type() const;
|
||||
|
||||
/**
|
||||
* @brief Set the type of record to query
|
||||
*
|
||||
* Constants, such as QMdnsEngine::SRV are provided for convenience.
|
||||
*/
|
||||
void setType(quint16 type);
|
||||
|
||||
/**
|
||||
* @brief Determine if a unicast response is desired
|
||||
*/
|
||||
bool unicastResponse() const;
|
||||
|
||||
/**
|
||||
* @brief Set whether a unicast response is desired
|
||||
*/
|
||||
void setUnicastResponse(bool unicastResponse);
|
||||
|
||||
private:
|
||||
|
||||
QueryPrivate *const d;
|
||||
};
|
||||
|
||||
QMDNSENGINE_EXPORT QDebug operator<<(QDebug dbg, const Query &query);
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_QUERY_H
|
||||
255
src/qmdnsengine/src/include/qmdnsengine/record.h
Normal file
255
src/qmdnsengine/src/include/qmdnsengine/record.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_RECORD_H
|
||||
#define QMDNSENGINE_RECORD_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
#include <QMap>
|
||||
|
||||
#include <qmdnsengine/bitmap.h>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class QMDNSENGINE_EXPORT RecordPrivate;
|
||||
|
||||
/**
|
||||
* @brief DNS record
|
||||
*
|
||||
* This class maintains information for an individual record. Not all record
|
||||
* types use every field.
|
||||
*
|
||||
* For example, to create a TXT record:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Record record;
|
||||
* record.setName("My Service._http._tcp.local.");
|
||||
* record.setType(QMdnsEngine::TXT);
|
||||
* record.addAttribute("a", "value1");
|
||||
* record.addAttribute("b", "value2");
|
||||
*
|
||||
* message.addRecord(record);
|
||||
* @endcode
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Record
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an uninitialized record
|
||||
*/
|
||||
Record();
|
||||
|
||||
/**
|
||||
* @brief Create a copy of an existing record
|
||||
*/
|
||||
Record(const Record &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
*/
|
||||
Record &operator=(const Record &other);
|
||||
|
||||
/**
|
||||
* @brief Equality operator
|
||||
*/
|
||||
bool operator==(const Record &other) const;
|
||||
|
||||
/**
|
||||
* @brief Inequality operator
|
||||
*/
|
||||
bool operator!=(const Record &other) const;
|
||||
|
||||
/**
|
||||
* @brief Destroy the record
|
||||
*/
|
||||
virtual ~Record();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the name of the record
|
||||
*/
|
||||
QByteArray name() const;
|
||||
|
||||
/**
|
||||
* @brief Set the name of the record
|
||||
*/
|
||||
void setName(const QByteArray &name);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the type of the record
|
||||
*/
|
||||
quint16 type() const;
|
||||
|
||||
/**
|
||||
* @brief Set the type of the record
|
||||
*
|
||||
* For convenience, constants for types used by mDNS, such as
|
||||
* QMdnsEngine::A or QMdnsEngine::PTR, may be used here.
|
||||
*/
|
||||
void setType(quint16 type);
|
||||
|
||||
/**
|
||||
* @brief Determine whether to replace or append to existing records
|
||||
*
|
||||
* If true, this record replaces all previous records of the same name and
|
||||
* type rather than appending to them.
|
||||
*/
|
||||
bool flushCache() const;
|
||||
|
||||
/**
|
||||
* @brief Set whether to replace or append to existing records
|
||||
*/
|
||||
void setFlushCache(bool flushCache);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the TTL (time to live) for the record
|
||||
*/
|
||||
quint32 ttl() const;
|
||||
|
||||
/**
|
||||
* @brief Set the TTL (time to live) for the record
|
||||
*/
|
||||
void setTtl(quint32 ttl);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the address for the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::A and QMdnsEngine::AAAA records.
|
||||
*/
|
||||
QHostAddress address() const;
|
||||
|
||||
/**
|
||||
* @brief Set the address for the record
|
||||
*/
|
||||
void setAddress(const QHostAddress &address);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the target for the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::PTR and QMdnsEngine::SRV records.
|
||||
*/
|
||||
QByteArray target() const;
|
||||
|
||||
/**
|
||||
* @brief Set the target for the record
|
||||
*/
|
||||
void setTarget(const QByteArray &target);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the next domain name
|
||||
*
|
||||
* This field is used by QMdnsEngine::NSEC records.
|
||||
*/
|
||||
QByteArray nextDomainName() const;
|
||||
|
||||
/**
|
||||
* @brief Set the next domain name
|
||||
*/
|
||||
void setNextDomainName(const QByteArray &nextDomainName);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the priority for the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::SRV records.
|
||||
*/
|
||||
quint16 priority() const;
|
||||
|
||||
/**
|
||||
* @brief Set the priority for the record
|
||||
*
|
||||
* Unless more than one QMdnsEngine::SRV record is being sent, this field
|
||||
* should be set to 0.
|
||||
*/
|
||||
void setPriority(quint16 priority);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the weight of the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::SRV records.
|
||||
*/
|
||||
quint16 weight() const;
|
||||
|
||||
/**
|
||||
* @brief Set the weight of the record
|
||||
*
|
||||
* Unless more than one QMdnsEngine::SRV record is being sent, this field
|
||||
* should be set to 0.
|
||||
*/
|
||||
void setWeight(quint16 weight);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the port for the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::SRV records.
|
||||
*/
|
||||
quint16 port() const;
|
||||
|
||||
/**
|
||||
* @brief Set the port for the record
|
||||
*/
|
||||
void setPort(quint16 port);
|
||||
|
||||
/**
|
||||
* @brief Retrieve attributes for the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::TXT records.
|
||||
*/
|
||||
QMap<QByteArray, QByteArray> attributes() const;
|
||||
|
||||
/**
|
||||
* @brief Set attributes for the record
|
||||
*/
|
||||
void setAttributes(const QMap<QByteArray, QByteArray> &attributes);
|
||||
|
||||
/**
|
||||
* @brief Add an attribute to the record
|
||||
*/
|
||||
void addAttribute(const QByteArray &key, const QByteArray &value);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the bitmap for the record
|
||||
*
|
||||
* This field is used by QMdnsEngine::NSEC records.
|
||||
*/
|
||||
Bitmap bitmap() const;
|
||||
|
||||
/**
|
||||
* @brief Set the bitmap for the record
|
||||
*/
|
||||
void setBitmap(const Bitmap &bitmap);
|
||||
|
||||
private:
|
||||
|
||||
RecordPrivate *const d;
|
||||
};
|
||||
|
||||
QMDNSENGINE_EXPORT QDebug operator<<(QDebug dbg, const Record &record);
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_RECORD_H
|
||||
88
src/qmdnsengine/src/include/qmdnsengine/resolver.h
Normal file
88
src/qmdnsengine/src/include/qmdnsengine/resolver.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_RESOLVER_H
|
||||
#define QMDNSENGINE_RESOLVER_H
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QObject>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Cache;
|
||||
|
||||
class QMDNSENGINE_EXPORT ResolverPrivate;
|
||||
|
||||
/**
|
||||
* @brief %Resolver for services
|
||||
*
|
||||
* When [Browser](@ref QMdnsEngine::Browser) indicates that a new service has
|
||||
* been found, it becomes necessary to resolve the service in order to connect
|
||||
* to it. This class serves that role. A [Cache](@ref QMdnsEngine::Cache) can
|
||||
* optionally be provided to speed up the resolving process.
|
||||
*
|
||||
* For example, assuming that `record` is a SRV record:
|
||||
*
|
||||
* @code
|
||||
* QMdnsEngine::Resolver resolver(&server, record.target());
|
||||
* connect(&resolver, &QMdnsEngine::Resolver::resolved, [](const QHostAddress &address) {
|
||||
* qDebug() << "Address:" << address;
|
||||
* });
|
||||
* @endcode
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Resolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new resolver
|
||||
*/
|
||||
Resolver(AbstractServer *server, const QByteArray &name, Cache *cache = 0, QObject *parent = 0);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief Indicate that the host resolved to an address
|
||||
* @param address service address
|
||||
*
|
||||
* This signal will be emitted once for each resolved address. For
|
||||
* example, if a host provides both A and AAAA records, this signal will
|
||||
* be emitted twice.
|
||||
*/
|
||||
void resolved(const QHostAddress &address);
|
||||
|
||||
private:
|
||||
|
||||
ResolverPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_RESOLVER_H
|
||||
78
src/qmdnsengine/src/include/qmdnsengine/server.h
Normal file
78
src/qmdnsengine/src/include/qmdnsengine/server.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_SERVER_H
|
||||
#define QMDNSENGINE_SERVER_H
|
||||
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Message;
|
||||
|
||||
class QMDNSENGINE_EXPORT ServerPrivate;
|
||||
|
||||
/**
|
||||
* @brief mDNS server
|
||||
*
|
||||
* This class provides an implementation of
|
||||
* [AbstractServer](@ref QMdnsEngine::AbstractServer) that uses all available
|
||||
* local network adapters to send and receive mDNS messages.
|
||||
*
|
||||
* The class takes care of watching for the addition and removal of network
|
||||
* interfaces, automatically joining multicast groups when new interfaces are
|
||||
* available.
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Server : public AbstractServer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new server
|
||||
*/
|
||||
explicit Server(QObject *parent = 0);
|
||||
|
||||
/**
|
||||
* @brief Implementation of AbstractServer::sendMessage()
|
||||
*/
|
||||
virtual void sendMessage(const Message &message);
|
||||
|
||||
/**
|
||||
* @brief Implementation of AbstractServer::sendMessageToAll()
|
||||
*/
|
||||
virtual void sendMessageToAll(const Message &message);
|
||||
|
||||
private:
|
||||
|
||||
ServerPrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_SERVER_H
|
||||
154
src/qmdnsengine/src/include/qmdnsengine/service.h
Normal file
154
src/qmdnsengine/src/include/qmdnsengine/service.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_SERVICE_H
|
||||
#define QMDNSENGINE_SERVICE_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
|
||||
#include "qmdnsengine_export.h"
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class QMDNSENGINE_EXPORT ServicePrivate;
|
||||
|
||||
/**
|
||||
* @brief %Service available on the local network
|
||||
*
|
||||
* This class contains the descriptive information necessary to represent an
|
||||
* individual service made available to the local network. Instances are
|
||||
* provided by [Browser](@ref QMdnsEngine::Browser) as services are
|
||||
* discovered. Instances must be created and passed to
|
||||
* [Provider::update()](@ref QMdnsEngine::Provider::update) to provide a
|
||||
* service.
|
||||
*/
|
||||
class QMDNSENGINE_EXPORT Service
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create an uninitialized service
|
||||
*/
|
||||
Service();
|
||||
|
||||
/**
|
||||
* @brief Create a copy of an existing service
|
||||
*/
|
||||
Service(const Service &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
*/
|
||||
Service &operator=(const Service &other);
|
||||
|
||||
/**
|
||||
* @brief Equality operator
|
||||
*/
|
||||
bool operator==(const Service &other) const;
|
||||
|
||||
/**
|
||||
* @brief Inequality operator
|
||||
*/
|
||||
bool operator!=(const Service &other) const;
|
||||
|
||||
/**
|
||||
* @brief Destroy the service
|
||||
*/
|
||||
virtual ~Service();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the service type
|
||||
*/
|
||||
QByteArray type() const;
|
||||
|
||||
/**
|
||||
* @brief Set the service type
|
||||
*
|
||||
* For example, an HTTP service might use "_http._tcp".
|
||||
*/
|
||||
void setType(const QByteArray &type);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the service name
|
||||
*/
|
||||
QByteArray name() const;
|
||||
|
||||
/**
|
||||
* @brief Set the service name
|
||||
*
|
||||
* This is combined with the service type and domain to form the FQDN for
|
||||
* the service.
|
||||
*/
|
||||
void setName(const QByteArray &name);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the hostname of the device providing the service
|
||||
*/
|
||||
QByteArray hostname() const;
|
||||
|
||||
/**
|
||||
* @brief Set the hostname of the device providing the service
|
||||
*/
|
||||
void setHostname(const QByteArray &hostname);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the service port
|
||||
*/
|
||||
quint16 port() const;
|
||||
|
||||
/**
|
||||
* @brief Set the service port
|
||||
*/
|
||||
void setPort(quint16 port);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the attributes for the service
|
||||
*
|
||||
* Boolean attributes will have null values (invoking QByteArray::isNull()
|
||||
* on the value will return true).
|
||||
*/
|
||||
QMap<QByteArray, QByteArray> attributes() const;
|
||||
|
||||
/**
|
||||
* @brief Set the attributes for the service
|
||||
*/
|
||||
void setAttributes(const QMap<QByteArray, QByteArray> &attributes);
|
||||
|
||||
/**
|
||||
* @brief Add an attribute to the service
|
||||
*/
|
||||
void addAttribute(const QByteArray &key, const QByteArray &value);
|
||||
|
||||
private:
|
||||
|
||||
ServicePrivate *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_SERVICE_H
|
||||
42
src/qmdnsengine/src/qmdnsengine_export.h.in
Normal file
42
src/qmdnsengine/src/qmdnsengine_export.h.in
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_EXPORT_H
|
||||
#define QMDNSENGINE_EXPORT_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#cmakedefine BUILD_SHARED_LIBS
|
||||
|
||||
#if defined(BUILD_SHARED_LIBS)
|
||||
# if defined(QMDNSENGINE_LIBRARY)
|
||||
# define QMDNSENGINE_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define QMDNSENGINE_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define QMDNSENGINE_EXPORT
|
||||
#endif
|
||||
|
||||
#endif // QMDNSENGINE_EXPORT_H
|
||||
25
src/qmdnsengine/src/resource.rc.in
Normal file
25
src/qmdnsengine/src/resource.rc.in
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <windows.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0
|
||||
PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904b0"
|
||||
{
|
||||
VALUE "CompanyName", "@PROJECT_AUTHOR@\0"
|
||||
VALUE "FileDescription", "@PROJECT_DESCRIPTION@\0"
|
||||
VALUE "FileVersion", "@PROJECT_VERSION@\0"
|
||||
VALUE "InternalName", "@PROJECT_NAME@\0"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2018 @PROJECT_AUTHOR@\0"
|
||||
VALUE "OriginalFilename", "@OUTPUT_NAME@.dll\0"
|
||||
VALUE "ProductName", "@PROJECT_NAME@\0"
|
||||
VALUE "ProductVersion", "@PROJECT_VERSION@\0"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x409, 1252
|
||||
}
|
||||
}
|
||||
32
src/qmdnsengine/src/src/abstractserver.cpp
Normal file
32
src/qmdnsengine/src/src/abstractserver.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
AbstractServer::AbstractServer(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
108
src/qmdnsengine/src/src/bitmap.cpp
Normal file
108
src/qmdnsengine/src/src/bitmap.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/bitmap.h>
|
||||
|
||||
#include "bitmap_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
BitmapPrivate::BitmapPrivate()
|
||||
: length(0),
|
||||
data(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
BitmapPrivate::~BitmapPrivate()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void BitmapPrivate::free()
|
||||
{
|
||||
if (data) {
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
void BitmapPrivate::fromData(quint8 newLength, const quint8 *newData)
|
||||
{
|
||||
data = new quint8[newLength];
|
||||
for (int i = 0; i < newLength; ++i) {
|
||||
data[i] = newData[i];
|
||||
}
|
||||
length = newLength;
|
||||
}
|
||||
|
||||
Bitmap::Bitmap()
|
||||
: d(new BitmapPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(const Bitmap &other)
|
||||
: d(new BitmapPrivate)
|
||||
{
|
||||
d->fromData(other.d->length, other.d->data);
|
||||
}
|
||||
|
||||
Bitmap &Bitmap::operator=(const Bitmap &other)
|
||||
{
|
||||
d->free();
|
||||
d->fromData(other.d->length, other.d->data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Bitmap::operator==(const Bitmap &other)
|
||||
{
|
||||
if (d->length != other.d->length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < d->length; ++i) {
|
||||
if (d->data[i] != other.d->data[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
quint8 Bitmap::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
const quint8 *Bitmap::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void Bitmap::setData(quint8 length, const quint8 *data)
|
||||
{
|
||||
d->free();
|
||||
d->fromData(length, data);
|
||||
}
|
||||
49
src/qmdnsengine/src/src/bitmap_p.h
Normal file
49
src/qmdnsengine/src/src/bitmap_p.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_BITMAP_P_H
|
||||
#define QMDNSENGINE_BITMAP_P_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class BitmapPrivate
|
||||
{
|
||||
public:
|
||||
|
||||
BitmapPrivate();
|
||||
virtual ~BitmapPrivate();
|
||||
|
||||
void free();
|
||||
void fromData(quint8 newLength, const quint8 *newData);
|
||||
|
||||
quint8 length;
|
||||
quint8 *data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_BITMAP_P_H
|
||||
291
src/qmdnsengine/src/src/browser.cpp
Normal file
291
src/qmdnsengine/src/src/browser.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
#include <qmdnsengine/browser.h>
|
||||
#include <qmdnsengine/cache.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "browser_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
BrowserPrivate::BrowserPrivate(Browser *browser, AbstractServer *server, const QByteArray &type, Cache *existingCache)
|
||||
: QObject(browser),
|
||||
server(server),
|
||||
type(type),
|
||||
cache(existingCache ? existingCache : new Cache(this)),
|
||||
q(browser)
|
||||
{
|
||||
connect(server, &AbstractServer::messageReceived, this, &BrowserPrivate::onMessageReceived);
|
||||
connect(cache, &Cache::shouldQuery, this, &BrowserPrivate::onShouldQuery);
|
||||
connect(cache, &Cache::recordExpired, this, &BrowserPrivate::onRecordExpired);
|
||||
connect(&queryTimer, &QTimer::timeout, this, &BrowserPrivate::onQueryTimeout);
|
||||
connect(&serviceTimer, &QTimer::timeout, this, &BrowserPrivate::onServiceTimeout);
|
||||
|
||||
queryTimer.setInterval(60 * 1000);
|
||||
queryTimer.setSingleShot(true);
|
||||
|
||||
serviceTimer.setInterval(100);
|
||||
serviceTimer.setSingleShot(true);
|
||||
|
||||
// Immediately begin browsing for services
|
||||
onQueryTimeout();
|
||||
}
|
||||
|
||||
// TODO: multiple SRV records not supported
|
||||
|
||||
bool BrowserPrivate::updateService(const QByteArray &fqName)
|
||||
{
|
||||
// Split the FQDN into service name and type
|
||||
int index = fqName.indexOf('.');
|
||||
QByteArray serviceName = fqName.left(index);
|
||||
QByteArray serviceType = fqName.mid(index + 1);
|
||||
|
||||
// Immediately return if a PTR record does not exist
|
||||
Record ptrRecord;
|
||||
if (!cache->lookupRecord(serviceType, PTR, ptrRecord)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If a SRV record is missing, query for it (by returning true)
|
||||
Record srvRecord;
|
||||
if (!cache->lookupRecord(fqName, SRV, srvRecord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Service service;
|
||||
service.setName(serviceName);
|
||||
service.setType(serviceType);
|
||||
service.setHostname(srvRecord.target());
|
||||
service.setPort(srvRecord.port());
|
||||
|
||||
// If TXT records are available for the service, add their values
|
||||
QList<Record> txtRecords;
|
||||
if (cache->lookupRecords(fqName, TXT, txtRecords)) {
|
||||
QMap<QByteArray, QByteArray> attributes;
|
||||
for (const Record &record : qAsConst(txtRecords)) {
|
||||
for (auto i = record.attributes().constBegin();
|
||||
i != record.attributes().constEnd(); ++i) {
|
||||
attributes.insert(i.key(), i.value());
|
||||
}
|
||||
}
|
||||
service.setAttributes(attributes);
|
||||
}
|
||||
|
||||
// If the service existed, this is an update; otherwise it is a new
|
||||
// addition; emit the appropriate signal
|
||||
if (!services.contains(fqName)) {
|
||||
emit q->serviceAdded(service);
|
||||
} else if(services.value(fqName) != service) {
|
||||
emit q->serviceUpdated(service);
|
||||
}
|
||||
|
||||
services.insert(fqName, service);
|
||||
hostnames.insert(service.hostname());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BrowserPrivate::onMessageReceived(const Message &message)
|
||||
{
|
||||
if (!message.isResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool any = type == MdnsBrowseType;
|
||||
|
||||
// Use a set to track all services that are updated in the message to
|
||||
// prevent unnecessary queries for SRV and TXT records
|
||||
QSet<QByteArray> updateNames;
|
||||
const auto records = message.records();
|
||||
for (const Record &record : records) {
|
||||
bool cacheRecord = false;
|
||||
|
||||
switch (record.type()) {
|
||||
case PTR:
|
||||
if (any && record.name() == MdnsBrowseType) {
|
||||
ptrTargets.insert(record.target());
|
||||
serviceTimer.start();
|
||||
cacheRecord = true;
|
||||
} else if (any || record.name() == type) {
|
||||
updateNames.insert(record.target());
|
||||
cacheRecord = true;
|
||||
}
|
||||
break;
|
||||
case SRV:
|
||||
case TXT:
|
||||
if (any || record.name().endsWith("." + type)) {
|
||||
updateNames.insert(record.name());
|
||||
cacheRecord = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cacheRecord) {
|
||||
cache->addRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
// For each of the services marked to be updated, perform the update and
|
||||
// make a list of all missing SRV records
|
||||
QSet<QByteArray> queryNames;
|
||||
for (const QByteArray &name : qAsConst(updateNames)) {
|
||||
if (updateService(name)) {
|
||||
queryNames.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache A / AAAA records after services are processed to ensure hostnames are known
|
||||
for (const Record &record : records) {
|
||||
bool cacheRecord = false;
|
||||
|
||||
switch (record.type()) {
|
||||
case A:
|
||||
case AAAA:
|
||||
cacheRecord = hostnames.contains(record.name());
|
||||
break;
|
||||
}
|
||||
if (cacheRecord) {
|
||||
cache->addRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
// Build and send a query for all of the SRV and TXT records
|
||||
if (queryNames.count()) {
|
||||
Message queryMessage;
|
||||
for (const QByteArray &name : qAsConst(queryNames)) {
|
||||
Query query;
|
||||
query.setName(name);
|
||||
query.setType(SRV);
|
||||
queryMessage.addQuery(query);
|
||||
query.setType(TXT);
|
||||
queryMessage.addQuery(query);
|
||||
}
|
||||
server->sendMessageToAll(queryMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPrivate::onShouldQuery(const Record &record)
|
||||
{
|
||||
// Assume that all messages in the cache are still in use (by the browser)
|
||||
// and attempt to renew them immediately
|
||||
|
||||
Query query;
|
||||
query.setName(record.name());
|
||||
query.setType(record.type());
|
||||
Message message;
|
||||
message.addQuery(query);
|
||||
server->sendMessageToAll(message);
|
||||
}
|
||||
|
||||
void BrowserPrivate::onRecordExpired(const Record &record)
|
||||
{
|
||||
// If the SRV record has expired for a service, then it must be
|
||||
// removed - TXT records on the other hand, cause an update
|
||||
|
||||
QByteArray serviceName;
|
||||
switch (record.type()) {
|
||||
case SRV:
|
||||
serviceName = record.name();
|
||||
break;
|
||||
case TXT:
|
||||
updateService(record.name());
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Service service = services.value(serviceName);
|
||||
if (!service.name().isNull()) {
|
||||
emit q->serviceRemoved(service);
|
||||
services.remove(serviceName);
|
||||
updateHostnames();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPrivate::onQueryTimeout()
|
||||
{
|
||||
Query query;
|
||||
query.setName(type);
|
||||
query.setType(PTR);
|
||||
Message message;
|
||||
message.addQuery(query);
|
||||
|
||||
// TODO: including too many records could cause problems
|
||||
|
||||
// Include PTR records for the target that are already known
|
||||
QList<Record> records;
|
||||
if (cache->lookupRecords(query.name(), PTR, records)) {
|
||||
for (const Record &record : qAsConst(records)) {
|
||||
message.addRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
server->sendMessageToAll(message);
|
||||
queryTimer.start();
|
||||
}
|
||||
|
||||
void BrowserPrivate::onServiceTimeout()
|
||||
{
|
||||
if (ptrTargets.count()) {
|
||||
Message message;
|
||||
for (const QByteArray &target : qAsConst(ptrTargets)) {
|
||||
|
||||
// Add a query for PTR records
|
||||
Query query;
|
||||
query.setName(target);
|
||||
query.setType(PTR);
|
||||
message.addQuery(query);
|
||||
|
||||
// Include PTR records for the target that are already known
|
||||
QList<Record> records;
|
||||
if (cache->lookupRecords(target, PTR, records)) {
|
||||
for (const Record &record : qAsConst(records)) {
|
||||
message.addRecord(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server->sendMessageToAll(message);
|
||||
ptrTargets.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPrivate::updateHostnames()
|
||||
{
|
||||
hostnames.clear();
|
||||
|
||||
for (const auto& service : services) {
|
||||
hostnames.insert(service.hostname());
|
||||
}
|
||||
}
|
||||
|
||||
Browser::Browser(AbstractServer *server, const QByteArray &type, Cache *cache, QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new BrowserPrivate(this, server, type, cache))
|
||||
{
|
||||
}
|
||||
83
src/qmdnsengine/src/src/browser_p.h
Normal file
83
src/qmdnsengine/src/src/browser_p.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_BROWSER_P_H
|
||||
#define QMDNSENGINE_BROWSER_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Browser;
|
||||
class Cache;
|
||||
class Message;
|
||||
class Record;
|
||||
|
||||
class BrowserPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit BrowserPrivate(Browser *browser, AbstractServer *server, const QByteArray &type, Cache *existingCache);
|
||||
|
||||
bool updateService(const QByteArray &fqName);
|
||||
|
||||
AbstractServer *server;
|
||||
QByteArray type;
|
||||
|
||||
Cache *cache;
|
||||
QSet<QByteArray> ptrTargets;
|
||||
QMap<QByteArray, Service> services;
|
||||
QSet<QByteArray> hostnames;
|
||||
|
||||
QTimer queryTimer;
|
||||
QTimer serviceTimer;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onMessageReceived(const Message &message);
|
||||
void onShouldQuery(const Record &record);
|
||||
void onRecordExpired(const Record &record);
|
||||
|
||||
void onQueryTimeout();
|
||||
void onServiceTimeout();
|
||||
|
||||
private:
|
||||
void updateHostnames();
|
||||
|
||||
Browser *const q;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_BROWSER_P_H
|
||||
173
src/qmdnsengine/src/src/cache.cpp
Normal file
173
src/qmdnsengine/src/src/cache.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QtGlobal>
|
||||
#if(QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
#include <QRandomGenerator>
|
||||
#define USE_QRANDOMGENERATOR
|
||||
#endif
|
||||
|
||||
#include <qmdnsengine/cache.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
|
||||
#include "cache_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
CachePrivate::CachePrivate(Cache *cache)
|
||||
: QObject(cache),
|
||||
q(cache)
|
||||
{
|
||||
connect(&timer, &QTimer::timeout, this, &CachePrivate::onTimeout);
|
||||
|
||||
timer.setSingleShot(true);
|
||||
}
|
||||
|
||||
void CachePrivate::onTimeout()
|
||||
{
|
||||
// Loop through all of the records in the cache, emitting the appropriate
|
||||
// signal when a trigger has passed, determining when the next trigger
|
||||
// will occur, and removing records that have expired
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QDateTime newNextTrigger;
|
||||
|
||||
for (auto i = entries.begin(); i != entries.end();) {
|
||||
|
||||
// Loop through the triggers and remove ones that have already
|
||||
// passed
|
||||
bool shouldQuery = false;
|
||||
for (auto j = i->triggers.begin(); j != i->triggers.end();) {
|
||||
if ((*j) <= now) {
|
||||
shouldQuery = true;
|
||||
j = i->triggers.erase(j);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If triggers remain, determine the next earliest one; if none
|
||||
// remain, the record has expired and should be removed
|
||||
if (i->triggers.length()) {
|
||||
if (newNextTrigger.isNull() || i->triggers.at(0) < newNextTrigger) {
|
||||
newNextTrigger = i->triggers.at(0);
|
||||
}
|
||||
if (shouldQuery) {
|
||||
emit q->shouldQuery(i->record);
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
emit q->recordExpired(i->record);
|
||||
i = entries.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
// If newNextTrigger contains a value, it will be the time for the next
|
||||
// trigger and the timer should be started again
|
||||
nextTrigger = newNextTrigger;
|
||||
if (!nextTrigger.isNull()) {
|
||||
timer.start(now.msecsTo(nextTrigger));
|
||||
}
|
||||
}
|
||||
|
||||
Cache::Cache(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new CachePrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
void Cache::addRecord(const Record &record)
|
||||
{
|
||||
// If a record exists that matches, remove it from the cache; if the TTL
|
||||
// is nonzero, it will be added back to the cache with updated times
|
||||
for (auto i = d->entries.begin(); i != d->entries.end();) {
|
||||
if ((record.flushCache() &&
|
||||
(*i).record.name() == record.name() &&
|
||||
(*i).record.type() == record.type()) ||
|
||||
(*i).record == record) {
|
||||
|
||||
// If the TTL is set to 0, indicate that the record was removed
|
||||
if (record.ttl() == 0) {
|
||||
emit recordExpired((*i).record);
|
||||
}
|
||||
|
||||
i = d->entries.erase(i);
|
||||
|
||||
// No need to continue further if the TTL was set to 0
|
||||
if (record.ttl() == 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Use the current time to calculate the triggers and add a random offset
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
#ifdef USE_QRANDOMGENERATOR
|
||||
qint64 random = QRandomGenerator::global()->bounded(20);
|
||||
#else
|
||||
qint64 random = qrand() % 20;
|
||||
#endif
|
||||
|
||||
QList<QDateTime> triggers{
|
||||
now.addMSecs(record.ttl() * 500 + random), // 50%
|
||||
now.addMSecs(record.ttl() * 850 + random), // 85%
|
||||
now.addMSecs(record.ttl() * 900 + random), // 90%
|
||||
now.addMSecs(record.ttl() * 950 + random), // 95%
|
||||
now.addSecs(record.ttl())
|
||||
};
|
||||
|
||||
// Append the record and its triggers
|
||||
d->entries.append({record, triggers});
|
||||
|
||||
// Check if the new record's first trigger is earlier than the next
|
||||
// scheduled trigger; if so, restart the timer
|
||||
if (d->nextTrigger.isNull() || triggers.at(0) < d->nextTrigger) {
|
||||
d->nextTrigger = triggers.at(0);
|
||||
d->timer.start(now.msecsTo(d->nextTrigger));
|
||||
}
|
||||
}
|
||||
|
||||
bool Cache::lookupRecord(const QByteArray &name, quint16 type, Record &record) const
|
||||
{
|
||||
QList<Record> records;
|
||||
if (lookupRecords(name, type, records)) {
|
||||
record = records.at(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Cache::lookupRecords(const QByteArray &name, quint16 type, QList<Record> &records) const
|
||||
{
|
||||
bool recordsAdded = false;
|
||||
for (const CachePrivate::Entry &entry : d->entries) {
|
||||
if ((name.isNull() || entry.record.name() == name) &&
|
||||
(type == ANY || entry.record.type() == type)) {
|
||||
records.append(entry.record);
|
||||
recordsAdded = true;
|
||||
}
|
||||
}
|
||||
return recordsAdded;
|
||||
}
|
||||
69
src/qmdnsengine/src/src/cache_p.h
Normal file
69
src/qmdnsengine/src/src/cache_p.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_CACHE_P_H
|
||||
#define QMDNSENGINE_CACHE_P_H
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Cache;
|
||||
|
||||
class CachePrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
struct Entry
|
||||
{
|
||||
Record record;
|
||||
QList<QDateTime> triggers;
|
||||
};
|
||||
|
||||
CachePrivate(Cache *cache);
|
||||
|
||||
QTimer timer;
|
||||
QList<Entry> entries;
|
||||
QDateTime nextTrigger;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
|
||||
Cache *const q;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_CACHE_P_H
|
||||
376
src/qmdnsengine/src/src/dns.cpp
Normal file
376
src/qmdnsengine/src/src/dns.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QtEndian>
|
||||
|
||||
#include <qmdnsengine/bitmap.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
template<class T>
|
||||
bool parseInteger(const QByteArray &packet, quint16 &offset, T &value)
|
||||
{
|
||||
if (offset + sizeof(T) > static_cast<unsigned int>(packet.length())) {
|
||||
return false; // out-of-bounds
|
||||
}
|
||||
value = qFromBigEndian<T>(reinterpret_cast<const uchar*>(packet.constData() + offset));
|
||||
offset += sizeof(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void writeInteger(QByteArray &packet, quint16 &offset, T value)
|
||||
{
|
||||
value = qToBigEndian<T>(value);
|
||||
packet.append(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||
offset += sizeof(T);
|
||||
}
|
||||
|
||||
bool parseName(const QByteArray &packet, quint16 &offset, QByteArray &name)
|
||||
{
|
||||
quint16 offsetEnd = 0;
|
||||
quint16 offsetPtr = offset;
|
||||
forever {
|
||||
quint8 nBytes;
|
||||
if (!parseInteger<quint8>(packet, offset, nBytes)) {
|
||||
return false;
|
||||
}
|
||||
if (!nBytes) {
|
||||
break;
|
||||
}
|
||||
switch (nBytes & 0xc0) {
|
||||
case 0x00:
|
||||
if (offset + nBytes > packet.length()) {
|
||||
return false; // length exceeds message
|
||||
}
|
||||
name.append(packet.mid(offset, nBytes));
|
||||
name.append('.');
|
||||
offset += nBytes;
|
||||
break;
|
||||
case 0xc0:
|
||||
{
|
||||
quint8 nBytes2;
|
||||
quint16 newOffset;
|
||||
if (!parseInteger<quint8>(packet, offset, nBytes2)) {
|
||||
return false;
|
||||
}
|
||||
newOffset = ((nBytes & ~0xc0) << 8) | nBytes2;
|
||||
if (newOffset >= offsetPtr) {
|
||||
return false; // prevent infinite loop
|
||||
}
|
||||
offsetPtr = newOffset;
|
||||
if (!offsetEnd) {
|
||||
offsetEnd = offset;
|
||||
}
|
||||
offset = newOffset;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false; // no other types supported
|
||||
}
|
||||
}
|
||||
if (offsetEnd) {
|
||||
offset = offsetEnd;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void writeName(QByteArray &packet, quint16 &offset, const QByteArray &name, QMap<QByteArray, quint16> &nameMap)
|
||||
{
|
||||
QByteArray fragment = name;
|
||||
if (fragment.endsWith('.')) {
|
||||
fragment.chop(1);
|
||||
}
|
||||
while (fragment.length()) {
|
||||
if (nameMap.contains(fragment)) {
|
||||
writeInteger<quint16>(packet, offset, nameMap.value(fragment) | 0xc000);
|
||||
return;
|
||||
}
|
||||
nameMap.insert(fragment, offset);
|
||||
int index = fragment.indexOf('.');
|
||||
if (index == -1) {
|
||||
index = fragment.length();
|
||||
}
|
||||
writeInteger<quint8>(packet, offset, index);
|
||||
packet.append(fragment.left(index));
|
||||
offset += index;
|
||||
fragment.remove(0, index + 1);
|
||||
}
|
||||
writeInteger<quint8>(packet, offset, 0);
|
||||
}
|
||||
|
||||
bool parseRecord(const QByteArray &packet, quint16 &offset, Record &record)
|
||||
{
|
||||
QByteArray name;
|
||||
quint16 type, class_, dataLen;
|
||||
quint32 ttl;
|
||||
if (!parseName(packet, offset, name) ||
|
||||
!parseInteger<quint16>(packet, offset, type) ||
|
||||
!parseInteger<quint16>(packet, offset, class_) ||
|
||||
!parseInteger<quint32>(packet, offset, ttl) ||
|
||||
!parseInteger<quint16>(packet, offset, dataLen)) {
|
||||
return false;
|
||||
}
|
||||
record.setName(name);
|
||||
record.setType(type);
|
||||
record.setFlushCache(class_ & 0x8000);
|
||||
record.setTtl(ttl);
|
||||
switch (type) {
|
||||
case A:
|
||||
{
|
||||
quint32 ipv4Addr;
|
||||
if (!parseInteger<quint32>(packet, offset, ipv4Addr)) {
|
||||
return false;
|
||||
}
|
||||
record.setAddress(QHostAddress(ipv4Addr));
|
||||
break;
|
||||
}
|
||||
case AAAA:
|
||||
{
|
||||
if (offset + 16 > packet.length()) {
|
||||
return false;
|
||||
}
|
||||
record.setAddress(QHostAddress(
|
||||
reinterpret_cast<const quint8*>(packet.constData() + offset)
|
||||
));
|
||||
offset += 16;
|
||||
break;
|
||||
}
|
||||
case NSEC:
|
||||
{
|
||||
QByteArray nextDomainName;
|
||||
quint8 number;
|
||||
quint8 length;
|
||||
if (!parseName(packet, offset, nextDomainName) ||
|
||||
!parseInteger<quint8>(packet, offset, number) ||
|
||||
!parseInteger<quint8>(packet, offset, length) ||
|
||||
number != 0 ||
|
||||
offset + length > packet.length()) {
|
||||
return false;
|
||||
}
|
||||
Bitmap bitmap;
|
||||
bitmap.setData(length, reinterpret_cast<const quint8*>(packet.constData() + offset));
|
||||
record.setNextDomainName(nextDomainName);
|
||||
record.setBitmap(bitmap);
|
||||
offset += length;
|
||||
break;
|
||||
}
|
||||
case PTR:
|
||||
{
|
||||
QByteArray target;
|
||||
if (!parseName(packet, offset, target)) {
|
||||
return false;
|
||||
}
|
||||
record.setTarget(target);
|
||||
break;
|
||||
}
|
||||
case SRV:
|
||||
{
|
||||
quint16 priority, weight, port;
|
||||
QByteArray target;
|
||||
if (!parseInteger<quint16>(packet, offset, priority) ||
|
||||
!parseInteger<quint16>(packet, offset, weight) ||
|
||||
!parseInteger<quint16>(packet, offset, port) ||
|
||||
!parseName(packet, offset, target)) {
|
||||
return false;
|
||||
}
|
||||
record.setPriority(priority);
|
||||
record.setWeight(weight);
|
||||
record.setPort(port);
|
||||
record.setTarget(target);
|
||||
break;
|
||||
}
|
||||
case TXT:
|
||||
{
|
||||
quint16 start = offset;
|
||||
while (offset < start + dataLen) {
|
||||
quint8 nBytes;
|
||||
if (!parseInteger<quint8>(packet, offset, nBytes) ||
|
||||
offset + nBytes > packet.length()) {
|
||||
return false;
|
||||
}
|
||||
if (nBytes == 0) {
|
||||
break;
|
||||
}
|
||||
QByteArray attr(packet.constData() + offset, nBytes);
|
||||
offset += nBytes;
|
||||
int splitIndex = attr.indexOf('=');
|
||||
if (splitIndex == -1) {
|
||||
record.addAttribute(attr, QByteArray());
|
||||
} else {
|
||||
record.addAttribute(attr.left(splitIndex), attr.mid(splitIndex + 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
offset += dataLen;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void writeRecord(QByteArray &packet, quint16 &offset, Record &record, QMap<QByteArray, quint16> &nameMap)
|
||||
{
|
||||
writeName(packet, offset, record.name(), nameMap);
|
||||
writeInteger<quint16>(packet, offset, record.type());
|
||||
writeInteger<quint16>(packet, offset, record.flushCache() ? 0x8001 : 1);
|
||||
writeInteger<quint32>(packet, offset, record.ttl());
|
||||
offset += 2;
|
||||
QByteArray data;
|
||||
switch (record.type()) {
|
||||
case A:
|
||||
writeInteger<quint32>(data, offset, record.address().toIPv4Address());
|
||||
break;
|
||||
case AAAA:
|
||||
{
|
||||
Q_IPV6ADDR ipv6Addr = record.address().toIPv6Address();
|
||||
data.append(reinterpret_cast<const char*>(&ipv6Addr), sizeof(Q_IPV6ADDR));
|
||||
offset += data.length();
|
||||
break;
|
||||
}
|
||||
case NSEC:
|
||||
{
|
||||
quint8 length = record.bitmap().length();
|
||||
writeName(data, offset, record.nextDomainName(), nameMap);
|
||||
writeInteger<quint8>(data, offset, 0);
|
||||
writeInteger<quint8>(data, offset, length);
|
||||
data.append(reinterpret_cast<const char*>(record.bitmap().data()), length);
|
||||
offset += length;
|
||||
break;
|
||||
}
|
||||
case PTR:
|
||||
writeName(data, offset, record.target(), nameMap);
|
||||
break;
|
||||
case SRV:
|
||||
writeInteger<quint16>(data, offset, record.priority());
|
||||
writeInteger<quint16>(data, offset, record.weight());
|
||||
writeInteger<quint16>(data, offset, record.port());
|
||||
writeName(data, offset, record.target(), nameMap);
|
||||
break;
|
||||
case TXT:
|
||||
if (!record.attributes().count()) {
|
||||
writeInteger<quint8>(data, offset, 0);
|
||||
break;
|
||||
}
|
||||
for (auto i = record.attributes().constBegin(); i != record.attributes().constEnd(); ++i) {
|
||||
QByteArray entry = i.value().isNull() ? i.key() : i.key() + "=" + i.value();
|
||||
writeInteger<quint8>(data, offset, entry.length());
|
||||
data.append(entry);
|
||||
offset += entry.length();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
offset -= 2;
|
||||
writeInteger<quint16>(packet, offset, data.length());
|
||||
packet.append(data);
|
||||
}
|
||||
|
||||
bool fromPacket(const QByteArray &packet, Message &message)
|
||||
{
|
||||
quint16 offset = 0;
|
||||
quint16 transactionId, flags, nQuestion, nAnswer, nAuthority, nAdditional;
|
||||
if (!parseInteger<quint16>(packet, offset, transactionId) ||
|
||||
!parseInteger<quint16>(packet, offset, flags) ||
|
||||
!parseInteger<quint16>(packet, offset, nQuestion) ||
|
||||
!parseInteger<quint16>(packet, offset, nAnswer) ||
|
||||
!parseInteger<quint16>(packet, offset, nAuthority) ||
|
||||
!parseInteger<quint16>(packet, offset, nAdditional)) {
|
||||
return false;
|
||||
}
|
||||
message.setTransactionId(transactionId);
|
||||
message.setResponse(flags & 0x8400);
|
||||
message.setTruncated(flags & 0x0200);
|
||||
for (int i = 0; i < nQuestion; ++i) {
|
||||
QByteArray name;
|
||||
quint16 type, class_;
|
||||
if (!parseName(packet, offset, name) ||
|
||||
!parseInteger<quint16>(packet, offset, type) ||
|
||||
!parseInteger<quint16>(packet, offset, class_)) {
|
||||
return false;
|
||||
}
|
||||
Query query;
|
||||
query.setName(name);
|
||||
query.setType(type);
|
||||
query.setUnicastResponse(class_ & 0x8000);
|
||||
message.addQuery(query);
|
||||
}
|
||||
quint16 nRecord = nAnswer + nAuthority + nAdditional;
|
||||
for (int i = 0; i < nRecord; ++i) {
|
||||
Record record;
|
||||
if (!parseRecord(packet, offset, record)) {
|
||||
return false;
|
||||
}
|
||||
message.addRecord(record);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void toPacket(const Message &message, QByteArray &packet)
|
||||
{
|
||||
quint16 offset = 0;
|
||||
quint16 flags = (message.isResponse() ? 0x8400 : 0) |
|
||||
(message.isTruncated() ? 0x200 : 0);
|
||||
writeInteger<quint16>(packet, offset, message.transactionId());
|
||||
writeInteger<quint16>(packet, offset, flags);
|
||||
writeInteger<quint16>(packet, offset, message.queries().length());
|
||||
writeInteger<quint16>(packet, offset, message.records().length());
|
||||
writeInteger<quint16>(packet, offset, 0);
|
||||
writeInteger<quint16>(packet, offset, 0);
|
||||
QMap<QByteArray, quint16> nameMap;
|
||||
const auto queries = message.queries();
|
||||
for (const Query &query : queries) {
|
||||
writeName(packet, offset, query.name(), nameMap);
|
||||
writeInteger<quint16>(packet, offset, query.type());
|
||||
writeInteger<quint16>(packet, offset, query.unicastResponse() ? 0x8001 : 1);
|
||||
}
|
||||
const auto records = message.records();
|
||||
for (Record record : records) {
|
||||
writeRecord(packet, offset, record, nameMap);
|
||||
}
|
||||
}
|
||||
|
||||
QString typeName(quint16 type)
|
||||
{
|
||||
switch (type) {
|
||||
case A: return "A";
|
||||
case AAAA: return "AAAA";
|
||||
case ANY: return "ANY";
|
||||
case NSEC: return "NSEC";
|
||||
case PTR: return "PTR";
|
||||
case SRV: return "SRV";
|
||||
case TXT: return "TXT";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
171
src/qmdnsengine/src/src/hostname.cpp
Normal file
171
src/qmdnsengine/src/src/hostname.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QHostInfo>
|
||||
#include <QNetworkAddressEntry>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/hostname.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "hostname_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
HostnamePrivate::HostnamePrivate(Hostname *hostname, AbstractServer *server)
|
||||
: HostnamePrivate(hostname, QByteArray(), server) {}
|
||||
|
||||
HostnamePrivate::HostnamePrivate(Hostname *hostname, const QByteArray &desired, AbstractServer *server)
|
||||
: QObject(hostname), server(server), desiredHostname(desired), q(hostname) {
|
||||
connect(server, &AbstractServer::messageReceived, this, &HostnamePrivate::onMessageReceived);
|
||||
connect(®istrationTimer, &QTimer::timeout, this, &HostnamePrivate::onRegistrationTimeout);
|
||||
connect(&rebroadcastTimer, &QTimer::timeout, this, &HostnamePrivate::onRebroadcastTimeout);
|
||||
|
||||
registrationTimer.setInterval(2 * 1000);
|
||||
registrationTimer.setSingleShot(true);
|
||||
|
||||
rebroadcastTimer.setInterval(5 * 1000); // 5 seconds
|
||||
rebroadcastTimer.setSingleShot(true);
|
||||
|
||||
// Immediately assert the hostname
|
||||
onRebroadcastTimeout();
|
||||
}
|
||||
|
||||
void HostnamePrivate::assertHostname() {
|
||||
// Begin with the local hostname and replace any "." with "-" (I'm looking
|
||||
// at you, macOS)
|
||||
QByteArray localHostname = desiredHostname.isEmpty() ? QHostInfo::localHostName().toUtf8() : desiredHostname;
|
||||
localHostname = localHostname.replace('.', '-');
|
||||
|
||||
// If the suffix > 1, then append a "-2", "-3", etc. to the hostname to
|
||||
// aid in finding one that is unique and not in use
|
||||
hostname =
|
||||
(hostnameSuffix == 1 ? localHostname : localHostname + "-" + QByteArray::number(hostnameSuffix)) + ".local.";
|
||||
|
||||
// Compose a query for A and AAAA records matching the hostname
|
||||
Query ipv4Query;
|
||||
ipv4Query.setName(hostname);
|
||||
ipv4Query.setType(A);
|
||||
Query ipv6Query;
|
||||
ipv6Query.setName(hostname);
|
||||
ipv6Query.setType(AAAA);
|
||||
Message message;
|
||||
message.addQuery(ipv4Query);
|
||||
message.addQuery(ipv6Query);
|
||||
|
||||
server->sendMessageToAll(message);
|
||||
|
||||
// If no reply is received after two seconds, the hostname is available
|
||||
registrationTimer.start();
|
||||
}
|
||||
|
||||
bool HostnamePrivate::generateRecord(const QHostAddress &srcAddress, quint16 type, Record &record) {
|
||||
// Attempt to find the interface that corresponds with the provided
|
||||
// address and determine this device's address from the interface
|
||||
|
||||
const auto interfaces = QNetworkInterface::allInterfaces();
|
||||
for (const QNetworkInterface &networkInterface : interfaces) {
|
||||
const auto entries = networkInterface.addressEntries();
|
||||
for (const QNetworkAddressEntry &entry : entries) {
|
||||
if (srcAddress.isInSubnet(entry.ip(), entry.prefixLength())) {
|
||||
for (const QNetworkAddressEntry &newEntry : entries) {
|
||||
QHostAddress address = newEntry.ip();
|
||||
if ((address.protocol() == QAbstractSocket::IPv4Protocol && type == A) ||
|
||||
(address.protocol() == QAbstractSocket::IPv6Protocol && type == AAAA)) {
|
||||
record.setName(hostname);
|
||||
record.setType(type);
|
||||
record.setAddress(address);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HostnamePrivate::onMessageReceived(const Message &message) {
|
||||
if (message.isResponse()) {
|
||||
if (hostnameRegistered) {
|
||||
return;
|
||||
}
|
||||
const auto records = message.records();
|
||||
for (const Record &record : records) {
|
||||
if ((record.type() == A || record.type() == AAAA) && record.name() == hostname) {
|
||||
++hostnameSuffix;
|
||||
assertHostname();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!hostnameRegistered) {
|
||||
return;
|
||||
}
|
||||
Message reply;
|
||||
reply.reply(message);
|
||||
const auto queries = message.queries();
|
||||
for (const Query &query : queries) {
|
||||
if ((query.type() == A || query.type() == AAAA) && query.name() == hostname) {
|
||||
Record record;
|
||||
if (generateRecord(message.address(), query.type(), record)) {
|
||||
reply.addRecord(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reply.records().count()) {
|
||||
server->sendMessage(reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HostnamePrivate::onRegistrationTimeout() {
|
||||
hostnameRegistered = true;
|
||||
if (hostname != hostnamePrev) {
|
||||
emit q->hostnameChanged(hostname);
|
||||
}
|
||||
|
||||
// Re-assert the hostname in half an hour
|
||||
rebroadcastTimer.start();
|
||||
}
|
||||
|
||||
void HostnamePrivate::onRebroadcastTimeout() {
|
||||
hostnamePrev = hostname;
|
||||
hostnameRegistered = false;
|
||||
hostnameSuffix = 1;
|
||||
|
||||
assertHostname();
|
||||
}
|
||||
|
||||
Hostname::Hostname(AbstractServer *server, QObject *parent) : QObject(parent), d(new HostnamePrivate(this, server)) {}
|
||||
|
||||
Hostname::Hostname(AbstractServer *server, const QByteArray &desired, QObject *parent)
|
||||
: QObject(parent), d(new HostnamePrivate(this, desired, server)) {}
|
||||
|
||||
bool Hostname::isRegistered() const { return d->hostnameRegistered; }
|
||||
|
||||
QByteArray Hostname::hostname() const { return d->hostname; }
|
||||
72
src/qmdnsengine/src/src/hostname_p.h
Normal file
72
src/qmdnsengine/src/src/hostname_p.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_HOSTNAME_P_H
|
||||
#define QMDNSENGINE_HOSTNAME_P_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
class QHostAddress;
|
||||
|
||||
namespace QMdnsEngine {
|
||||
|
||||
class AbstractServer;
|
||||
class Hostname;
|
||||
class Message;
|
||||
class Record;
|
||||
|
||||
class HostnamePrivate : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HostnamePrivate(Hostname *hostname, AbstractServer *server);
|
||||
HostnamePrivate(Hostname *hostname, const QByteArray &desired, AbstractServer *server);
|
||||
|
||||
void assertHostname();
|
||||
bool generateRecord(const QHostAddress &srcAddress, quint16 type, Record &record);
|
||||
|
||||
AbstractServer *server;
|
||||
|
||||
QByteArray hostnamePrev;
|
||||
QByteArray hostname;
|
||||
QByteArray desiredHostname;
|
||||
bool hostnameRegistered;
|
||||
int hostnameSuffix;
|
||||
|
||||
QTimer registrationTimer;
|
||||
QTimer rebroadcastTimer;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onMessageReceived(const Message &message);
|
||||
void onRegistrationTimeout();
|
||||
void onRebroadcastTimeout();
|
||||
|
||||
private:
|
||||
Hostname *const q;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_HOSTNAME_P_H
|
||||
35
src/qmdnsengine/src/src/mdns.cpp
Normal file
35
src/qmdnsengine/src/src/mdns.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/mdns.h>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
const quint16 MdnsPort = 5353;
|
||||
const QHostAddress MdnsIpv4Address("224.0.0.251");
|
||||
const QHostAddress MdnsIpv6Address("ff02::fb");
|
||||
const QByteArray MdnsBrowseType("_services._dns-sd._udp.local.");
|
||||
|
||||
}
|
||||
148
src/qmdnsengine/src/src/message.cpp
Normal file
148
src/qmdnsengine/src/src/message.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "message_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
MessagePrivate::MessagePrivate()
|
||||
: port(0),
|
||||
transactionId(0),
|
||||
isResponse(false),
|
||||
isTruncated(false)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message()
|
||||
: d(new MessagePrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(const Message &other)
|
||||
: d(new MessagePrivate)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Message &Message::operator=(const Message &other)
|
||||
{
|
||||
*d = *other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message::~Message()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QHostAddress Message::address() const
|
||||
{
|
||||
return d->address;
|
||||
}
|
||||
|
||||
void Message::setAddress(const QHostAddress &address)
|
||||
{
|
||||
d->address = address;
|
||||
}
|
||||
|
||||
quint16 Message::port() const
|
||||
{
|
||||
return d->port;
|
||||
}
|
||||
|
||||
void Message::setPort(quint16 port)
|
||||
{
|
||||
d->port = port;
|
||||
}
|
||||
|
||||
quint16 Message::transactionId() const
|
||||
{
|
||||
return d->transactionId;
|
||||
}
|
||||
|
||||
void Message::setTransactionId(quint16 transactionId)
|
||||
{
|
||||
d->transactionId = transactionId;
|
||||
}
|
||||
|
||||
bool Message::isResponse() const
|
||||
{
|
||||
return d->isResponse;
|
||||
}
|
||||
|
||||
void Message::setResponse(bool isResponse)
|
||||
{
|
||||
d->isResponse = isResponse;
|
||||
}
|
||||
|
||||
bool Message::isTruncated() const
|
||||
{
|
||||
return d->isTruncated;
|
||||
}
|
||||
|
||||
void Message::setTruncated(bool isTruncated)
|
||||
{
|
||||
d->isTruncated = isTruncated;
|
||||
}
|
||||
|
||||
QList<Query> Message::queries() const
|
||||
{
|
||||
return d->queries;
|
||||
}
|
||||
|
||||
void Message::addQuery(const Query &query)
|
||||
{
|
||||
d->queries.append(query);
|
||||
}
|
||||
|
||||
QList<Record> Message::records() const
|
||||
{
|
||||
return d->records;
|
||||
}
|
||||
|
||||
void Message::addRecord(const Record &record)
|
||||
{
|
||||
d->records.append(record);
|
||||
}
|
||||
|
||||
void Message::reply(const Message &other)
|
||||
{
|
||||
if (other.port() == MdnsPort) {
|
||||
if (other.address().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
setAddress(MdnsIpv4Address);
|
||||
} else {
|
||||
setAddress(MdnsIpv6Address);
|
||||
}
|
||||
} else {
|
||||
setAddress(other.address());
|
||||
}
|
||||
setPort(other.port());
|
||||
setTransactionId(other.transactionId());
|
||||
setResponse(true);
|
||||
}
|
||||
54
src/qmdnsengine/src/src/message_p.h
Normal file
54
src/qmdnsengine/src/src/message_p.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_MESSAGE_P_H
|
||||
#define QMDNSENGINE_MESSAGE_P_H
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QList>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Query;
|
||||
class Record;
|
||||
|
||||
class MessagePrivate
|
||||
{
|
||||
public:
|
||||
|
||||
MessagePrivate();
|
||||
|
||||
QHostAddress address;
|
||||
quint16 port;
|
||||
quint16 transactionId;
|
||||
bool isResponse;
|
||||
bool isTruncated;
|
||||
QList<Query> queries;
|
||||
QList<Record> records;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_MESSAGE_P_H
|
||||
107
src/qmdnsengine/src/src/prober.cpp
Normal file
107
src/qmdnsengine/src/src/prober.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/prober.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
|
||||
#include "prober_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
ProberPrivate::ProberPrivate(Prober *prober, AbstractServer *server, const Record &record)
|
||||
: QObject(prober),
|
||||
server(server),
|
||||
confirmed(false),
|
||||
proposedRecord(record),
|
||||
suffix(1),
|
||||
q(prober)
|
||||
{
|
||||
// All records should contain at least one "."
|
||||
int index = record.name().indexOf('.');
|
||||
name = record.name().left(index);
|
||||
type = record.name().mid(index);
|
||||
|
||||
connect(server, &AbstractServer::messageReceived, this, &ProberPrivate::onMessageReceived);
|
||||
connect(&timer, &QTimer::timeout, this, &ProberPrivate::onTimeout);
|
||||
|
||||
timer.setSingleShot(true);
|
||||
|
||||
qDebug() << "ProberPrivate::ProberPrivate()" << record.name();
|
||||
assertRecord();
|
||||
}
|
||||
|
||||
void ProberPrivate::assertRecord()
|
||||
{
|
||||
// Use the current suffix to set the name of the proposed record
|
||||
proposedRecord.setName(suffix == 1 ?
|
||||
name + type : name + "-" + QByteArray::number(suffix) + type);
|
||||
|
||||
// Broadcast a query for the proposed name (using an ANY query) and
|
||||
// include the proposed record in the query
|
||||
Query query;
|
||||
query.setName(proposedRecord.name());
|
||||
query.setType(ANY);
|
||||
Message message;
|
||||
message.addQuery(query);
|
||||
message.addRecord(proposedRecord);
|
||||
server->sendMessageToAll(message);
|
||||
|
||||
// Wait two seconds to confirm it is unique
|
||||
timer.stop();
|
||||
timer.start(2 * 1000);
|
||||
}
|
||||
|
||||
void ProberPrivate::onMessageReceived(const Message &message)
|
||||
{
|
||||
// If the response matches the proposed record, increment the suffix and
|
||||
// try with the new name
|
||||
|
||||
if (confirmed || !message.isResponse()) {
|
||||
return;
|
||||
}
|
||||
const auto records = message.records();
|
||||
for (const Record &record : records) {
|
||||
if (record.name() == proposedRecord.name() && record.type() == proposedRecord.type()) {
|
||||
++suffix;
|
||||
assertRecord();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProberPrivate::onTimeout()
|
||||
{
|
||||
confirmed = true;
|
||||
qDebug() << "ProberPrivate::onTimeout()";
|
||||
emit q->nameConfirmed(proposedRecord.name());
|
||||
}
|
||||
|
||||
Prober::Prober(AbstractServer *server, const Record &record, QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new ProberPrivate(this, server, record))
|
||||
{
|
||||
}
|
||||
72
src/qmdnsengine/src/src/prober_p.h
Normal file
72
src/qmdnsengine/src/src/prober_p.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_PROBER_P_H
|
||||
#define QMDNSENGINE_PROBER_P_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Message;
|
||||
class Prober;
|
||||
|
||||
class ProberPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ProberPrivate(Prober *prober, AbstractServer *server, const Record &record);
|
||||
|
||||
void assertRecord();
|
||||
|
||||
AbstractServer *server;
|
||||
QTimer timer;
|
||||
|
||||
bool confirmed;
|
||||
|
||||
Record proposedRecord;
|
||||
QByteArray name;
|
||||
QByteArray type;
|
||||
int suffix;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onMessageReceived(const Message &message);
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
|
||||
Prober *const q;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_PROBER_P_H
|
||||
242
src/qmdnsengine/src/src/provider.cpp
Normal file
242
src/qmdnsengine/src/src/provider.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QNetworkInterface>
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/hostname.h>
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/prober.h>
|
||||
#include <qmdnsengine/provider.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
|
||||
#include "provider_p.h"
|
||||
#include "localipaddress.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
ProviderPrivate::ProviderPrivate(QObject *parent, AbstractServer *server, Hostname *hostname)
|
||||
: QObject(parent), server(server), hostname(hostname), prober(nullptr), initialized(false), confirmed(false) {
|
||||
connect(server, &AbstractServer::messageReceived, this, &ProviderPrivate::onMessageReceived);
|
||||
connect(hostname, &Hostname::hostnameChanged, this, &ProviderPrivate::onHostnameChanged);
|
||||
|
||||
browsePtrProposed.setName(MdnsBrowseType);
|
||||
browsePtrProposed.setType(PTR);
|
||||
ptrProposed.setType(PTR);
|
||||
srvProposed.setType(SRV);
|
||||
txtProposed.setType(TXT);
|
||||
}
|
||||
|
||||
ProviderPrivate::~ProviderPrivate() {
|
||||
if (confirmed) {
|
||||
farewell();
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderPrivate::announce() {
|
||||
// Broadcast a message with each of the records
|
||||
|
||||
Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(ptrRecord);
|
||||
message.addRecord(srvRecord);
|
||||
message.addRecord(ARecord);
|
||||
message.addRecord(txtRecord);
|
||||
server->sendMessageToAll(message);
|
||||
}
|
||||
|
||||
void ProviderPrivate::confirm() {
|
||||
// Confirm that the desired name is unique through probing
|
||||
|
||||
if (prober) {
|
||||
delete prober;
|
||||
}
|
||||
prober = new Prober(server, srvProposed, this);
|
||||
qDebug() << "ProviderPrivate::confirm()";
|
||||
connect(prober, &Prober::nameConfirmed, [this](const QByteArray &name) {
|
||||
// If existing records were confirmed, indicate that they are no
|
||||
// longer valid
|
||||
|
||||
qDebug() << "Prober::nameConfirmed" << confirmed;
|
||||
|
||||
if (confirmed) {
|
||||
farewell();
|
||||
} else {
|
||||
confirmed = true;
|
||||
}
|
||||
|
||||
// Update the proposed records
|
||||
ptrProposed.setTarget(name);
|
||||
srvProposed.setName(name);
|
||||
txtProposed.setName(name);
|
||||
|
||||
// Publish the proposed records and announce them
|
||||
publish();
|
||||
|
||||
delete prober;
|
||||
prober = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
void ProviderPrivate::farewell() {
|
||||
// Send a message indicating that the existing records are no longer valid
|
||||
// by setting their TTL to 0
|
||||
|
||||
ptrRecord.setTtl(0);
|
||||
srvRecord.setTtl(0);
|
||||
txtRecord.setTtl(0);
|
||||
announce();
|
||||
}
|
||||
|
||||
void ProviderPrivate::publish() {
|
||||
// Copy the proposed records over and announce them
|
||||
|
||||
browsePtrRecord = browsePtrProposed;
|
||||
ptrRecord = ptrProposed;
|
||||
srvRecord = srvProposed;
|
||||
txtRecord = txtProposed;
|
||||
|
||||
// zwift
|
||||
ARecord.setType(A);
|
||||
ARecord.setName(srvRecord.target());
|
||||
// set directly when we receive a message
|
||||
//ARecord.setAddress(QHostAddress("172.31.100.161"));
|
||||
|
||||
QHostAddress r = localipaddress::getIP(QHostAddress());
|
||||
qDebug() << "ProviderPrivate::publish" << r;
|
||||
if(!r.isNull())
|
||||
ARecord.setAddress(r);
|
||||
|
||||
announce();
|
||||
}
|
||||
|
||||
void ProviderPrivate::onMessageReceived(const Message &message) {
|
||||
if (!confirmed || message.isResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool sendBrowsePtr = false;
|
||||
bool sendPtr = false;
|
||||
bool sendSrv = false;
|
||||
bool sendTxt = false;
|
||||
|
||||
ARecord.setAddress(localipaddress::getIP(message.address()));
|
||||
|
||||
// Determine which records to send based on the queries
|
||||
const auto queries = message.queries();
|
||||
for (const Query &query : queries) {
|
||||
if (query.type() == PTR && query.name() == MdnsBrowseType) {
|
||||
sendBrowsePtr = true;
|
||||
} else if (query.type() == PTR && query.name() == ptrRecord.name()) {
|
||||
sendPtr = true;
|
||||
} else if (query.type() == SRV && query.name() == srvRecord.name()) {
|
||||
sendSrv = true;
|
||||
} else if (query.type() == TXT && query.name() == txtRecord.name()) {
|
||||
sendTxt = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove records to send if they are already known
|
||||
const auto records = message.records();
|
||||
for (const Record &record : records) {
|
||||
if (record == ptrRecord) {
|
||||
sendPtr = false;
|
||||
} else if (record == srvRecord) {
|
||||
sendSrv = false;
|
||||
} else if (record == txtRecord) {
|
||||
sendTxt = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Include the SRV and TXT if the PTR is being sent
|
||||
if (sendPtr) {
|
||||
sendSrv = sendTxt = true;
|
||||
}
|
||||
|
||||
// If any records should be sent, compose a message reply
|
||||
if (sendBrowsePtr || sendPtr || sendSrv || sendTxt) {
|
||||
Message reply;
|
||||
reply.reply(message);
|
||||
if (sendBrowsePtr) {
|
||||
reply.addRecord(browsePtrRecord);
|
||||
}
|
||||
if (sendPtr) {
|
||||
reply.addRecord(ptrRecord);
|
||||
}
|
||||
if (sendSrv) {
|
||||
reply.addRecord(srvRecord);
|
||||
|
||||
// zwift need it
|
||||
reply.addRecord(ARecord);
|
||||
}
|
||||
if (sendTxt) {
|
||||
reply.addRecord(txtRecord);
|
||||
}
|
||||
server->sendMessage(reply);
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderPrivate::onHostnameChanged(const QByteArray &newHostname) {
|
||||
// Update the proposed SRV record
|
||||
srvProposed.setTarget(newHostname);
|
||||
|
||||
// If initialized, confirm the record
|
||||
if (initialized) {
|
||||
confirm();
|
||||
}
|
||||
}
|
||||
|
||||
Provider::Provider(AbstractServer *server, Hostname *hostname, QObject *parent)
|
||||
: QObject(parent), d(new ProviderPrivate(this, server, hostname)) {}
|
||||
|
||||
void Provider::update(const Service &service) {
|
||||
d->initialized = true;
|
||||
|
||||
// Clean the service name
|
||||
QByteArray serviceName = service.name();
|
||||
serviceName = serviceName.replace('.', '-');
|
||||
|
||||
// Update the proposed records
|
||||
QByteArray fqName = serviceName + "." + service.type();
|
||||
d->browsePtrProposed.setTarget(service.type());
|
||||
d->ptrProposed.setName(service.type());
|
||||
d->ptrProposed.setTarget(fqName);
|
||||
d->srvProposed.setName(fqName);
|
||||
d->srvProposed.setPort(service.port());
|
||||
d->srvProposed.setTarget(d->hostname->hostname());
|
||||
d->txtProposed.setName(fqName);
|
||||
d->txtProposed.setAttributes(service.attributes());
|
||||
|
||||
// Assuming a valid hostname exists, check to see if the new service uses
|
||||
// a different name - if so, it must first be confirmed
|
||||
if (d->hostname->isRegistered()) {
|
||||
if (!d->confirmed || fqName != d->srvRecord.name()) {
|
||||
d->confirm();
|
||||
} else {
|
||||
d->publish();
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/qmdnsengine/src/src/provider_p.h
Normal file
79
src/qmdnsengine/src/src/provider_p.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_PROVIDER_P_H
|
||||
#define QMDNSENGINE_PROVIDER_P_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <qmdnsengine/record.h>
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
namespace QMdnsEngine {
|
||||
|
||||
class AbstractServer;
|
||||
class Hostname;
|
||||
class Message;
|
||||
class Prober;
|
||||
|
||||
class ProviderPrivate : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ProviderPrivate(QObject *parent, AbstractServer *server, Hostname *hostname);
|
||||
virtual ~ProviderPrivate();
|
||||
|
||||
void announce();
|
||||
void confirm();
|
||||
void farewell();
|
||||
void publish();
|
||||
|
||||
AbstractServer *server;
|
||||
Hostname *hostname;
|
||||
Prober *prober;
|
||||
|
||||
Service service;
|
||||
bool initialized;
|
||||
bool confirmed;
|
||||
|
||||
Record browsePtrRecord;
|
||||
Record ptrRecord;
|
||||
Record srvRecord;
|
||||
Record txtRecord;
|
||||
Record ARecord;
|
||||
|
||||
Record browsePtrProposed;
|
||||
Record ptrProposed;
|
||||
Record srvProposed;
|
||||
Record txtProposed;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onMessageReceived(const Message &message);
|
||||
void onHostnameChanged(const QByteArray &hostname);
|
||||
};
|
||||
|
||||
} // namespace QMdnsEngine
|
||||
|
||||
#endif // QMDNSENGINE_PROVIDER_P_H
|
||||
100
src/qmdnsengine/src/src/query.cpp
Normal file
100
src/qmdnsengine/src/src/query.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
|
||||
#include "query_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
QueryPrivate::QueryPrivate()
|
||||
: type(0),
|
||||
unicastResponse(false)
|
||||
{
|
||||
}
|
||||
|
||||
Query::Query()
|
||||
: d(new QueryPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Query::Query(const Query &other)
|
||||
: d(new QueryPrivate)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Query &Query::operator=(const Query &other)
|
||||
{
|
||||
*d = *other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Query::~Query()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QByteArray Query::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
void Query::setName(const QByteArray &name)
|
||||
{
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
quint16 Query::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void Query::setType(quint16 type)
|
||||
{
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
bool Query::unicastResponse() const
|
||||
{
|
||||
return d->unicastResponse;
|
||||
}
|
||||
|
||||
void Query::setUnicastResponse(bool unicastResponse)
|
||||
{
|
||||
d->unicastResponse = unicastResponse;
|
||||
}
|
||||
|
||||
QDebug QMdnsEngine::operator<<(QDebug dbg, const Query &query)
|
||||
{
|
||||
QDebugStateSaver saver(dbg);
|
||||
Q_UNUSED(saver);
|
||||
|
||||
dbg.noquote().nospace() << "Query(" << typeName(query.type()) << " " << query.name() << ")";
|
||||
|
||||
return dbg;
|
||||
}
|
||||
46
src/qmdnsengine/src/src/query_p.h
Normal file
46
src/qmdnsengine/src/src/query_p.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_QUERY_P_H
|
||||
#define QMDNSENGINE_QUERY_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class QueryPrivate
|
||||
{
|
||||
public:
|
||||
|
||||
QueryPrivate();
|
||||
|
||||
QByteArray name;
|
||||
quint16 type;
|
||||
bool unicastResponse;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_QUERY_P_H
|
||||
218
src/qmdnsengine/src/src/record.cpp
Normal file
218
src/qmdnsengine/src/src/record.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "record_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
RecordPrivate::RecordPrivate()
|
||||
: type(0),
|
||||
flushCache(false),
|
||||
ttl(3600),
|
||||
priority(0),
|
||||
weight(0),
|
||||
port(0)
|
||||
{
|
||||
}
|
||||
|
||||
Record::Record()
|
||||
: d(new RecordPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Record::Record(const Record &other)
|
||||
: d(new RecordPrivate)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Record &Record::operator=(const Record &other)
|
||||
{
|
||||
*d = *other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Record::operator==(const Record &other) const
|
||||
{
|
||||
return d->name == other.d->name &&
|
||||
d->type == other.d->type &&
|
||||
d->address == other.d->address &&
|
||||
d->target == other.d->target &&
|
||||
d->nextDomainName == other.d->nextDomainName &&
|
||||
d->priority == other.d->priority &&
|
||||
d->weight == other.d->weight &&
|
||||
d->port == other.d->port &&
|
||||
d->attributes == other.d->attributes &&
|
||||
d->bitmap == other.d->bitmap;
|
||||
}
|
||||
|
||||
bool Record::operator!=(const Record &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
Record::~Record()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QByteArray Record::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
void Record::setName(const QByteArray &name)
|
||||
{
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
quint16 Record::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void Record::setType(quint16 type)
|
||||
{
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
bool Record::flushCache() const
|
||||
{
|
||||
return d->flushCache;
|
||||
}
|
||||
|
||||
void Record::setFlushCache(bool flushCache)
|
||||
{
|
||||
d->flushCache = flushCache;
|
||||
}
|
||||
|
||||
quint32 Record::ttl() const
|
||||
{
|
||||
return d->ttl;
|
||||
}
|
||||
|
||||
void Record::setTtl(quint32 ttl)
|
||||
{
|
||||
d->ttl = ttl;
|
||||
}
|
||||
|
||||
QHostAddress Record::address() const
|
||||
{
|
||||
return d->address;
|
||||
}
|
||||
|
||||
void Record::setAddress(const QHostAddress &address)
|
||||
{
|
||||
d->address = address;
|
||||
}
|
||||
|
||||
QByteArray Record::target() const
|
||||
{
|
||||
return d->target;
|
||||
}
|
||||
|
||||
void Record::setTarget(const QByteArray &target)
|
||||
{
|
||||
d->target = target;
|
||||
}
|
||||
|
||||
QByteArray Record::nextDomainName() const
|
||||
{
|
||||
return d->nextDomainName;
|
||||
}
|
||||
|
||||
void Record::setNextDomainName(const QByteArray &nextDomainName)
|
||||
{
|
||||
d->nextDomainName = nextDomainName;
|
||||
}
|
||||
|
||||
quint16 Record::priority() const
|
||||
{
|
||||
return d->priority;
|
||||
}
|
||||
|
||||
void Record::setPriority(quint16 priority)
|
||||
{
|
||||
d->priority = priority;
|
||||
}
|
||||
|
||||
quint16 Record::weight() const
|
||||
{
|
||||
return d->weight;
|
||||
}
|
||||
|
||||
void Record::setWeight(quint16 weight)
|
||||
{
|
||||
d->weight = weight;
|
||||
}
|
||||
|
||||
quint16 Record::port() const
|
||||
{
|
||||
return d->port;
|
||||
}
|
||||
|
||||
void Record::setPort(quint16 port)
|
||||
{
|
||||
d->port = port;
|
||||
}
|
||||
|
||||
QMap<QByteArray, QByteArray> Record::attributes() const
|
||||
{
|
||||
return d->attributes;
|
||||
}
|
||||
|
||||
void Record::setAttributes(const QMap<QByteArray, QByteArray> &attributes)
|
||||
{
|
||||
d->attributes = attributes;
|
||||
}
|
||||
|
||||
void Record::addAttribute(const QByteArray &key, const QByteArray &value)
|
||||
{
|
||||
d->attributes.insert(key, value);
|
||||
}
|
||||
|
||||
Bitmap Record::bitmap() const
|
||||
{
|
||||
return d->bitmap;
|
||||
}
|
||||
|
||||
void Record::setBitmap(const Bitmap &bitmap)
|
||||
{
|
||||
d->bitmap = bitmap;
|
||||
}
|
||||
|
||||
QDebug QMdnsEngine::operator<<(QDebug dbg, const Record &record)
|
||||
{
|
||||
QDebugStateSaver saver(dbg);
|
||||
Q_UNUSED(saver);
|
||||
|
||||
dbg.noquote().nospace() << "Record(" << typeName(record.type()) << " " << record.name() << ")";
|
||||
|
||||
return dbg;
|
||||
}
|
||||
59
src/qmdnsengine/src/src/record_p.h
Normal file
59
src/qmdnsengine/src/src/record_p.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_RECORD_P_H
|
||||
#define QMDNSENGINE_RECORD_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
#include <QMap>
|
||||
|
||||
#include <qmdnsengine/bitmap.h>
|
||||
|
||||
namespace QMdnsEngine {
|
||||
|
||||
class RecordPrivate
|
||||
{
|
||||
public:
|
||||
|
||||
RecordPrivate();
|
||||
|
||||
QByteArray name;
|
||||
quint16 type;
|
||||
bool flushCache;
|
||||
quint32 ttl;
|
||||
|
||||
QHostAddress address;
|
||||
QByteArray target;
|
||||
QByteArray nextDomainName;
|
||||
quint16 priority;
|
||||
quint16 weight;
|
||||
quint16 port;
|
||||
QMap<QByteArray, QByteArray> attributes;
|
||||
Bitmap bitmap;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_RECORD_P_H
|
||||
116
src/qmdnsengine/src/src/resolver.cpp
Normal file
116
src/qmdnsengine/src/src/resolver.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/cache.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
#include <qmdnsengine/resolver.h>
|
||||
|
||||
#include "resolver_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
ResolverPrivate::ResolverPrivate(Resolver *resolver, AbstractServer *server, const QByteArray &name, Cache *cache)
|
||||
: QObject(resolver),
|
||||
server(server),
|
||||
name(name),
|
||||
cache(cache ? cache : new Cache(this)),
|
||||
q(resolver)
|
||||
{
|
||||
connect(server, &AbstractServer::messageReceived, this, &ResolverPrivate::onMessageReceived);
|
||||
connect(&timer, &QTimer::timeout, this, &ResolverPrivate::onTimeout);
|
||||
|
||||
// Query for new records
|
||||
query();
|
||||
|
||||
// Pull the existing records from the cache
|
||||
timer.setSingleShot(true);
|
||||
timer.start(0);
|
||||
}
|
||||
|
||||
QList<Record> ResolverPrivate::existing() const
|
||||
{
|
||||
QList<Record> records;
|
||||
cache->lookupRecords(name, A, records);
|
||||
cache->lookupRecords(name, AAAA, records);
|
||||
return records;
|
||||
}
|
||||
|
||||
void ResolverPrivate::query() const
|
||||
{
|
||||
Message message;
|
||||
|
||||
// Add a query for A and AAAA records
|
||||
Query query;
|
||||
query.setName(name);
|
||||
query.setType(A);
|
||||
message.addQuery(query);
|
||||
query.setType(AAAA);
|
||||
message.addQuery(query);
|
||||
|
||||
// Add existing (known) records to the query
|
||||
const auto records = existing();
|
||||
for (const Record &record : records) {
|
||||
message.addRecord(record);
|
||||
}
|
||||
|
||||
// Send the query
|
||||
server->sendMessageToAll(message);
|
||||
}
|
||||
|
||||
void ResolverPrivate::onMessageReceived(const Message &message)
|
||||
{
|
||||
if (!message.isResponse()) {
|
||||
return;
|
||||
}
|
||||
const auto records = message.records();
|
||||
for (const Record &record : records) {
|
||||
if (record.name() == name && (record.type() == A || record.type() == AAAA)) {
|
||||
cache->addRecord(record);
|
||||
if (!addresses.contains(record.address())) {
|
||||
emit q->resolved(record.address());
|
||||
addresses.insert(record.address());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResolverPrivate::onTimeout()
|
||||
{
|
||||
const auto records = existing();
|
||||
for (const Record &record : records) {
|
||||
emit q->resolved(record.address());
|
||||
}
|
||||
}
|
||||
|
||||
Resolver::Resolver(AbstractServer *server, const QByteArray &name, Cache *cache, QObject *parent)
|
||||
: QObject(parent),
|
||||
d(new ResolverPrivate(this, server, name, cache))
|
||||
{
|
||||
}
|
||||
71
src/qmdnsengine/src/src/resolver_p.h
Normal file
71
src/qmdnsengine/src/src/resolver_p.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_RESOLVER_P_H
|
||||
#define QMDNSENGINE_RESOLVER_P_H
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class AbstractServer;
|
||||
class Cache;
|
||||
class Message;
|
||||
class Record;
|
||||
class Resolver;
|
||||
|
||||
class ResolverPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit ResolverPrivate(Resolver *resolver, AbstractServer *server, const QByteArray &name, Cache *cache);
|
||||
|
||||
QList<Record> existing() const;
|
||||
void query() const;
|
||||
|
||||
AbstractServer *server;
|
||||
QByteArray name;
|
||||
Cache *cache;
|
||||
QSet<QHostAddress> addresses;
|
||||
QTimer timer;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onMessageReceived(const Message &message);
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
|
||||
Resolver *const q;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_RESOLVER_P_H
|
||||
159
src/qmdnsengine/src/src/server.cpp
Normal file
159
src/qmdnsengine/src/src/server.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <cerrno>
|
||||
# include <cstring>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/server.h>
|
||||
|
||||
#include "server_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
ServerPrivate::ServerPrivate(Server *server)
|
||||
: QObject(server),
|
||||
q(server)
|
||||
{
|
||||
connect(&timer, &QTimer::timeout, this, &ServerPrivate::onTimeout);
|
||||
connect(&ipv4Socket, &QUdpSocket::readyRead, this, &ServerPrivate::onReadyRead);
|
||||
connect(&ipv6Socket, &QUdpSocket::readyRead, this, &ServerPrivate::onReadyRead);
|
||||
|
||||
timer.setInterval(60 * 1000);
|
||||
timer.setSingleShot(true);
|
||||
onTimeout();
|
||||
}
|
||||
|
||||
bool ServerPrivate::bindSocket(QUdpSocket &socket, const QHostAddress &address)
|
||||
{
|
||||
// Exit early if the socket is already bound
|
||||
if (socket.state() == QAbstractSocket::BoundState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// I cannot find the correct combination of flags that allows the socket
|
||||
// to bind properly on Linux, so on that platform, we must manually create
|
||||
// the socket and initialize the QUdpSocket with it
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
if (!socket.bind(address, MdnsPort, QAbstractSocket::ShareAddress)) {
|
||||
int arg = 1;
|
||||
if (setsockopt(socket.socketDescriptor(), SOL_SOCKET, SO_REUSEADDR,
|
||||
reinterpret_cast<char*>(&arg), sizeof(int))) {
|
||||
emit q->error(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (!socket.bind(address, MdnsPort, QAbstractSocket::ReuseAddressHint)) {
|
||||
emit q->error(socket.errorString());
|
||||
return false;
|
||||
}
|
||||
#ifdef Q_OS_UNIX
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerPrivate::onTimeout()
|
||||
{
|
||||
// A timer is used to run a set of operations once per minute; first, the
|
||||
// two sockets are bound - if this fails, another attempt is made once per
|
||||
// timeout; secondly, all network interfaces are enumerated; if the
|
||||
// interface supports multicast, the socket will join the mDNS multicast
|
||||
// groups
|
||||
|
||||
bool ipv4Bound = bindSocket(ipv4Socket, QHostAddress::AnyIPv4);
|
||||
bool ipv6Bound = bindSocket(ipv6Socket, QHostAddress::AnyIPv6);
|
||||
|
||||
if (ipv4Bound || ipv6Bound) {
|
||||
const auto interfaces = QNetworkInterface::allInterfaces();
|
||||
for (const QNetworkInterface &networkInterface : interfaces) {
|
||||
if (networkInterface.flags() & QNetworkInterface::CanMulticast) {
|
||||
if (ipv4Bound) {
|
||||
ipv4Socket.joinMulticastGroup(MdnsIpv4Address, networkInterface);
|
||||
}
|
||||
if (ipv6Bound) {
|
||||
ipv6Socket.joinMulticastGroup(MdnsIpv6Address, networkInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void ServerPrivate::onReadyRead()
|
||||
{
|
||||
// Read the packet from the socket
|
||||
QUdpSocket *socket = qobject_cast<QUdpSocket*>(sender());
|
||||
QByteArray packet;
|
||||
packet.resize(socket->pendingDatagramSize());
|
||||
QHostAddress address;
|
||||
quint16 port;
|
||||
socket->readDatagram(packet.data(), packet.size(), &address, &port);
|
||||
|
||||
// Attempt to decode the packet
|
||||
Message message;
|
||||
if (fromPacket(packet, message)) {
|
||||
message.setAddress(address);
|
||||
message.setPort(port);
|
||||
emit q->messageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
Server::Server(QObject *parent)
|
||||
: AbstractServer(parent),
|
||||
d(new ServerPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
void Server::sendMessage(const Message &message)
|
||||
{
|
||||
QByteArray packet;
|
||||
toPacket(message, packet);
|
||||
if (message.address().protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
d->ipv4Socket.writeDatagram(packet, message.address(), message.port());
|
||||
} else {
|
||||
d->ipv6Socket.writeDatagram(packet, message.address(), message.port());
|
||||
}
|
||||
}
|
||||
|
||||
void Server::sendMessageToAll(const Message &message)
|
||||
{
|
||||
QByteArray packet;
|
||||
toPacket(message, packet);
|
||||
d->ipv4Socket.writeDatagram(packet, MdnsIpv4Address, MdnsPort);
|
||||
d->ipv6Socket.writeDatagram(packet, MdnsIpv6Address, MdnsPort);
|
||||
}
|
||||
65
src/qmdnsengine/src/src/server_p.h
Normal file
65
src/qmdnsengine/src/src/server_p.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_SERVER_P_H
|
||||
#define QMDNSENGINE_SERVER_P_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QUdpSocket>
|
||||
|
||||
class QHostAddress;
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class Server;
|
||||
|
||||
class ServerPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit ServerPrivate(Server *server);
|
||||
|
||||
bool bindSocket(QUdpSocket &socket, const QHostAddress &address);
|
||||
|
||||
QTimer timer;
|
||||
QUdpSocket ipv4Socket;
|
||||
QUdpSocket ipv6Socket;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void onTimeout();
|
||||
void onReadyRead();
|
||||
|
||||
private:
|
||||
|
||||
Server *const q;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_SERVER_P_H
|
||||
123
src/qmdnsengine/src/src/service.cpp
Normal file
123
src/qmdnsengine/src/src/service.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
#include "service_p.h"
|
||||
|
||||
using namespace QMdnsEngine;
|
||||
|
||||
ServicePrivate::ServicePrivate()
|
||||
{
|
||||
}
|
||||
|
||||
Service::Service()
|
||||
: d(new ServicePrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Service::Service(const Service &other)
|
||||
: d(new ServicePrivate)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Service &Service::operator=(const Service &other)
|
||||
{
|
||||
*d = *other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Service::operator==(const Service &other) const
|
||||
{
|
||||
return d->type == other.d->type &&
|
||||
d->name == other.d->name &&
|
||||
d->port == other.d->port &&
|
||||
d->attributes == other.d->attributes;
|
||||
}
|
||||
|
||||
bool Service::operator!=(const Service &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
Service::~Service()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QByteArray Service::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void Service::setType(const QByteArray &type)
|
||||
{
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
QByteArray Service::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
void Service::setName(const QByteArray &name)
|
||||
{
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
QByteArray Service::hostname() const
|
||||
{
|
||||
return d->hostname;
|
||||
}
|
||||
|
||||
void Service::setHostname(const QByteArray &hostname)
|
||||
{
|
||||
d->hostname = hostname;
|
||||
}
|
||||
|
||||
quint16 Service::port() const
|
||||
{
|
||||
return d->port;
|
||||
}
|
||||
|
||||
void Service::setPort(quint16 port)
|
||||
{
|
||||
d->port = port;
|
||||
}
|
||||
|
||||
QMap<QByteArray, QByteArray> Service::attributes() const
|
||||
{
|
||||
return d->attributes;
|
||||
}
|
||||
|
||||
void Service::setAttributes(const QMap<QByteArray, QByteArray> &attributes)
|
||||
{
|
||||
d->attributes = attributes;
|
||||
}
|
||||
|
||||
void Service::addAttribute(const QByteArray &key, const QByteArray &value)
|
||||
{
|
||||
d->attributes.insert(key, value);
|
||||
}
|
||||
49
src/qmdnsengine/src/src/service_p.h
Normal file
49
src/qmdnsengine/src/src/service_p.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMDNSENGINE_SERVICE_P_H
|
||||
#define QMDNSENGINE_SERVICE_P_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMap>
|
||||
|
||||
namespace QMdnsEngine
|
||||
{
|
||||
|
||||
class ServicePrivate
|
||||
{
|
||||
public:
|
||||
|
||||
ServicePrivate();
|
||||
|
||||
QByteArray type;
|
||||
QByteArray name;
|
||||
QByteArray hostname;
|
||||
quint16 port;
|
||||
QMap<QByteArray, QByteArray> attributes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QMDNSENGINE_SERVICE_P_H
|
||||
33
src/qmdnsengine/tests/CMakeLists.txt
Normal file
33
src/qmdnsengine/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
add_subdirectory(common)
|
||||
|
||||
set(TESTS
|
||||
TestBrowser
|
||||
TestCache
|
||||
TestDns
|
||||
TestHostname
|
||||
TestProber
|
||||
TestProvider
|
||||
TestResolver
|
||||
)
|
||||
|
||||
foreach(_test ${TESTS})
|
||||
add_executable(${_test} ${_test}.cpp)
|
||||
set_target_properties(${_test} PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
target_include_directories(${_test} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
target_link_libraries(${_test} qmdnsengine Qt5::Test common)
|
||||
add_test(NAME ${_test}
|
||||
COMMAND ${_test}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# On Windows, the tests will not run without the DLL located in the current
|
||||
# directory - a target must be used to copy it here once built
|
||||
if(WIN32)
|
||||
add_custom_target(qmdnsengine-copy ALL
|
||||
"${CMAKE_COMMAND}" -E copy_if_different \"$<TARGET_FILE:qmdnsengine>\" \"${CMAKE_CURRENT_BINARY_DIR}\"
|
||||
DEPENDS qmdnsengine
|
||||
)
|
||||
endif()
|
||||
171
src/qmdnsengine/tests/TestBrowser.cpp
Normal file
171
src/qmdnsengine/tests/TestBrowser.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/browser.h>
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
#include "common/testserver.h"
|
||||
#include "common/util.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QMdnsEngine::Service)
|
||||
|
||||
const QByteArray Name = "Test";
|
||||
const QByteArray Type = "_test._tcp.local.";
|
||||
const QByteArray Fqdn = Name + "." + Type;
|
||||
const QByteArray Target = "Test.local.";
|
||||
const quint16 Port = 1234;
|
||||
const QByteArray Key = "key";
|
||||
const QByteArray Value = "value";
|
||||
|
||||
class TestBrowser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void initTestCase();
|
||||
void testBrowser();
|
||||
void testBrowsePtr();
|
||||
};
|
||||
|
||||
void TestBrowser::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<QMdnsEngine::Service>("Service");
|
||||
}
|
||||
|
||||
void TestBrowser::testBrowser()
|
||||
{
|
||||
TestServer server;
|
||||
QMdnsEngine::Browser browser(&server, Type);
|
||||
|
||||
QSignalSpy serviceAddedSpy(&browser, SIGNAL(serviceAdded(Service)));
|
||||
QSignalSpy serviceUpdatedSpy(&browser, SIGNAL(serviceUpdated(Service)));
|
||||
QSignalSpy serviceRemovedSpy(&browser, SIGNAL(serviceRemoved(Service)));
|
||||
|
||||
// Wait for the PTR query
|
||||
QTRY_VERIFY(queryReceived(&server, Type, QMdnsEngine::PTR));
|
||||
server.clearReceivedMessages();
|
||||
|
||||
// Transmit the PTR record
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Type);
|
||||
record.setType(QMdnsEngine::PTR);
|
||||
record.setTarget(Fqdn);
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
}
|
||||
|
||||
// Wait for a SRV query
|
||||
QTRY_VERIFY(queryReceived(&server, Fqdn, QMdnsEngine::SRV));
|
||||
server.clearReceivedMessages();
|
||||
|
||||
// Nothing should have been added yet
|
||||
QCOMPARE(serviceAddedSpy.count(), 0);
|
||||
|
||||
// Transmit the SRV record
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Fqdn);
|
||||
record.setType(QMdnsEngine::SRV);
|
||||
record.setTarget(Target);
|
||||
record.setPort(Port);
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
}
|
||||
|
||||
// The serviceAdded signal should have been emitted
|
||||
QCOMPARE(serviceAddedSpy.count(), 1);
|
||||
|
||||
// Transmit a TXT record
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Fqdn);
|
||||
record.setType(QMdnsEngine::TXT);
|
||||
record.setAttributes({{Key, Value}});
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
}
|
||||
|
||||
// The serviceAdded signal should NOT have been emitted and the
|
||||
// serviceUpdated signal should have been
|
||||
QCOMPARE(serviceAddedSpy.count(), 1);
|
||||
QCOMPARE(serviceUpdatedSpy.count(), 1);
|
||||
|
||||
// Remove the PTR record
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Type);
|
||||
record.setType(QMdnsEngine::PTR);
|
||||
record.setTtl(0);
|
||||
record.setTarget(Fqdn);
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
}
|
||||
|
||||
// The serviceRemoved signal should have been emitted
|
||||
QCOMPARE(serviceRemovedSpy.count(), 1);
|
||||
}
|
||||
|
||||
void TestBrowser::testBrowsePtr()
|
||||
{
|
||||
TestServer server;
|
||||
QMdnsEngine::Browser browser(&server, QMdnsEngine::MdnsBrowseType);
|
||||
Q_UNUSED(browser);
|
||||
|
||||
// Wait for a query for service types
|
||||
QTRY_VERIFY(queryReceived(&server, QMdnsEngine::MdnsBrowseType, QMdnsEngine::PTR));
|
||||
|
||||
// Send a PTR and SRV record
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(QMdnsEngine::MdnsBrowseType);
|
||||
record.setType(QMdnsEngine::PTR);
|
||||
record.setTarget(Type);
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
|
||||
// Wait for the query for records of the specified type
|
||||
QTRY_VERIFY(queryReceived(&server, Type, QMdnsEngine::PTR));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestBrowser)
|
||||
#include "TestBrowser.moc"
|
||||
137
src/qmdnsengine/tests/TestCache.cpp
Normal file
137
src/qmdnsengine/tests/TestCache.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/cache.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
Q_DECLARE_METATYPE(QMdnsEngine::Record)
|
||||
|
||||
const QByteArray Name = "Test";
|
||||
const quint16 Type = QMdnsEngine::TXT;
|
||||
|
||||
class TestCache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
TestCache() : mCounter(0) {}
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void initTestCase();
|
||||
void testExpiry();
|
||||
void testRemoval();
|
||||
void testCacheFlush();
|
||||
|
||||
private:
|
||||
|
||||
QMdnsEngine::Record createRecord();
|
||||
|
||||
int mCounter;
|
||||
};
|
||||
|
||||
void TestCache::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<QMdnsEngine::Record>("Record");
|
||||
}
|
||||
|
||||
void TestCache::testExpiry()
|
||||
{
|
||||
QMdnsEngine::Cache cache;
|
||||
cache.addRecord(createRecord());
|
||||
|
||||
QSignalSpy shouldQuerySpy(&cache, SIGNAL(shouldQuery(Record)));
|
||||
QSignalSpy recordExpiredSpy(&cache, SIGNAL(recordExpired(Record)));
|
||||
|
||||
// The record should be in the cache
|
||||
QMdnsEngine::Record record;
|
||||
QVERIFY(cache.lookupRecord(Name, Type, record));
|
||||
|
||||
// After entering the event loop, the record should be purged when its TTL
|
||||
// expires in 1s
|
||||
QTRY_VERIFY(!cache.lookupRecord(Name, Type, record));
|
||||
|
||||
// Ensure that the shouldQuery() signal was emitted at least once and the
|
||||
// recordExpired() signal was eventually emitted as well
|
||||
QVERIFY(shouldQuerySpy.count() > 0);
|
||||
QCOMPARE(recordExpiredSpy.count(), 1);
|
||||
}
|
||||
|
||||
void TestCache::testRemoval()
|
||||
{
|
||||
QMdnsEngine::Cache cache;
|
||||
QMdnsEngine::Record record = createRecord();
|
||||
cache.addRecord(record);
|
||||
|
||||
QSignalSpy recordExpiredSpy(&cache, SIGNAL(recordExpired(Record)));
|
||||
|
||||
// Purge the record from the cache by setting its TTL to 0
|
||||
record.setTtl(0);
|
||||
cache.addRecord(record);
|
||||
|
||||
// Verify that the record is gone
|
||||
QVERIFY(!cache.lookupRecord(Name, Type, record));
|
||||
QCOMPARE(recordExpiredSpy.count(), 1);
|
||||
}
|
||||
|
||||
void TestCache::testCacheFlush()
|
||||
{
|
||||
QMdnsEngine::Cache cache;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
cache.addRecord(createRecord());
|
||||
}
|
||||
|
||||
QList<QMdnsEngine::Record> records;
|
||||
QVERIFY(cache.lookupRecords(Name, Type, records));
|
||||
QCOMPARE(records.length(), 2);
|
||||
|
||||
// Insert a new record with the cache clear bit set
|
||||
QMdnsEngine::Record record = createRecord();
|
||||
record.setFlushCache(true);
|
||||
cache.addRecord(record);
|
||||
|
||||
// Confirm that only a single record exists
|
||||
records.clear();
|
||||
QVERIFY(cache.lookupRecords(Name, Type, records));
|
||||
QCOMPARE(records.length(), 1);
|
||||
}
|
||||
|
||||
QMdnsEngine::Record TestCache::createRecord()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(Type);
|
||||
record.setTtl(1);
|
||||
record.addAttribute("key", QByteArray::number(mCounter++));
|
||||
return record;
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestCache)
|
||||
#include "TestCache.moc"
|
||||
368
src/qmdnsengine/tests/TestDns.cpp
Normal file
368
src/qmdnsengine/tests/TestDns.cpp
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#define PARSE_RECORD(r) \
|
||||
quint16 offset = 0; \
|
||||
QMdnsEngine::Record record; \
|
||||
bool result = QMdnsEngine::parseRecord( \
|
||||
QByteArray(r, sizeof(r)), \
|
||||
offset, \
|
||||
record \
|
||||
)
|
||||
|
||||
#define WRITE_RECORD() \
|
||||
QByteArray packet; \
|
||||
quint16 offset; \
|
||||
NameMap nameMap; \
|
||||
QMdnsEngine::writeRecord(packet, offset, record, nameMap)
|
||||
|
||||
typedef QMap<QByteArray, quint16> NameMap;
|
||||
|
||||
const char NameSimple[] = {
|
||||
'\x04', '_', 't', 'c', 'p',
|
||||
'\x05', 'l', 'o', 'c', 'a', 'l',
|
||||
'\0'
|
||||
};
|
||||
|
||||
const char NamePointer[] = {
|
||||
'\x04', '_', 't', 'c', 'p',
|
||||
'\x05', 'l', 'o', 'c', 'a', 'l',
|
||||
'\0',
|
||||
'\x04', 't', 'e', 's', 't',
|
||||
'\xc0', '\0'
|
||||
};
|
||||
|
||||
const char NameCorrupt[] = {
|
||||
'\x03', '1', '2'
|
||||
};
|
||||
|
||||
const char RecordA[] = {
|
||||
'\x04', 't', 'e', 's', 't', '\0',
|
||||
'\x00', '\x01',
|
||||
'\x80', '\x01',
|
||||
'\x00', '\x00', '\x0e', '\x10',
|
||||
'\x00', '\x04',
|
||||
'\x7f', '\x00', '\x00', '\x01'
|
||||
};
|
||||
|
||||
const char RecordAAAA[] = {
|
||||
'\x04', 't', 'e', 's', 't', '\0',
|
||||
'\x00', '\x1c',
|
||||
'\x00', '\x01',
|
||||
'\x00', '\x00', '\x0e', '\x10',
|
||||
'\x00', '\x10',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01'
|
||||
};
|
||||
|
||||
const char RecordPTR[] = {
|
||||
'\x04', 't', 'e', 's', 't', '\0',
|
||||
'\x00', '\x0c',
|
||||
'\x00', '\x01',
|
||||
'\x00', '\x00', '\x0e', '\x10',
|
||||
'\x00', '\x07',
|
||||
'\x05', 't', 'e', 's', 't', '2', '\0',
|
||||
};
|
||||
|
||||
const char RecordSRV[] = {
|
||||
'\x04', 't', 'e', 's', 't', '\0',
|
||||
'\x00', '\x21',
|
||||
'\x00', '\x01',
|
||||
'\x00', '\x00', '\x0e', '\x10',
|
||||
'\x00', '\x0d',
|
||||
'\x00', '\x01', '\x00', '\x02', '\x00', '\x03',
|
||||
'\x05', 't', 'e', 's', 't', '2', '\0',
|
||||
};
|
||||
|
||||
const char RecordTXT[] = {
|
||||
'\x04', 't', 'e', 's', 't', '\0',
|
||||
'\x00', '\x10',
|
||||
'\x00', '\x01',
|
||||
'\x00', '\x00', '\x0e', '\x10',
|
||||
'\x00', '\x06',
|
||||
'\x03', 'a', '=', 'a',
|
||||
'\x01', 'b'
|
||||
};
|
||||
|
||||
const QByteArray Name("test.");
|
||||
const quint32 Ttl = 3600;
|
||||
const QHostAddress Ipv4Address("127.0.0.1");
|
||||
const QHostAddress Ipv6Address("::1");
|
||||
const QByteArray Target("test2.");
|
||||
const quint16 Priority = 1;
|
||||
const quint16 Weight = 2;
|
||||
const quint16 Port = 3;
|
||||
const QMap<QByteArray, QByteArray> Attributes{
|
||||
{"a", "a"},
|
||||
{"b", QByteArray()}
|
||||
};
|
||||
|
||||
class TestDns : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void testParseName_data();
|
||||
void testParseName();
|
||||
|
||||
void testWriteName_data();
|
||||
void testWriteName();
|
||||
|
||||
void testParseRecordA();
|
||||
void testParseRecordAAAA();
|
||||
void testParseRecordPTR();
|
||||
void testParseRecordSRV();
|
||||
void testParseRecordTXT();
|
||||
|
||||
void testWriteRecordA();
|
||||
void testWriteRecordAAAA();
|
||||
void testWriteRecordPTR();
|
||||
void testWriteRecordSRV();
|
||||
void testWriteRecordTXT();
|
||||
};
|
||||
|
||||
void TestDns::testParseName_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("packet");
|
||||
QTest::addColumn<quint16>("initialOffset");
|
||||
QTest::addColumn<quint16>("correctOffset");
|
||||
QTest::addColumn<QByteArray>("correctName");
|
||||
QTest::addColumn<bool>("correctResult");
|
||||
|
||||
QTest::newRow("simple")
|
||||
<< QByteArray(NameSimple, sizeof(NameSimple))
|
||||
<< static_cast<quint16>(0)
|
||||
<< static_cast<quint16>(12)
|
||||
<< QByteArray("_tcp.local.")
|
||||
<< true;
|
||||
|
||||
QTest::newRow("pointer")
|
||||
<< QByteArray(NamePointer, sizeof(NamePointer))
|
||||
<< static_cast<quint16>(12)
|
||||
<< static_cast<quint16>(19)
|
||||
<< QByteArray("test._tcp.local.")
|
||||
<< true;
|
||||
|
||||
QTest::newRow("corrupt data")
|
||||
<< QByteArray(NameCorrupt, sizeof(NameCorrupt))
|
||||
<< static_cast<quint16>(0)
|
||||
<< static_cast<quint16>(0)
|
||||
<< QByteArray()
|
||||
<< false;
|
||||
}
|
||||
|
||||
void TestDns::testParseName()
|
||||
{
|
||||
QFETCH(QByteArray, packet);
|
||||
QFETCH(quint16, initialOffset);
|
||||
QFETCH(quint16, correctOffset);
|
||||
QFETCH(QByteArray, correctName);
|
||||
QFETCH(bool, correctResult);
|
||||
|
||||
quint16 offset = initialOffset;
|
||||
QByteArray name;
|
||||
bool result = QMdnsEngine::parseName(packet, offset, name);
|
||||
|
||||
QCOMPARE(result, correctResult);
|
||||
if (result) {
|
||||
QCOMPARE(offset, correctOffset);
|
||||
QCOMPARE(name, correctName);
|
||||
}
|
||||
}
|
||||
|
||||
void TestDns::testWriteName_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("initialPacket");
|
||||
QTest::addColumn<quint16>("initialOffset");
|
||||
QTest::addColumn<quint16>("correctOffset");
|
||||
QTest::addColumn<QByteArray>("name");
|
||||
QTest::addColumn<NameMap>("nameMap");
|
||||
QTest::addColumn<QByteArray>("correctPacket");
|
||||
|
||||
QTest::newRow("simple")
|
||||
<< QByteArray()
|
||||
<< static_cast<quint16>(0)
|
||||
<< static_cast<quint16>(12)
|
||||
<< QByteArray("_tcp.local.")
|
||||
<< NameMap()
|
||||
<< QByteArray(NameSimple, sizeof(NameSimple));
|
||||
|
||||
QTest::newRow("pointer")
|
||||
<< QByteArray(NameSimple, sizeof(NameSimple))
|
||||
<< static_cast<quint16>(sizeof(NameSimple))
|
||||
<< static_cast<quint16>(19)
|
||||
<< QByteArray("test._tcp.local.")
|
||||
<< NameMap{{"_tcp.local", 0}}
|
||||
<< QByteArray(NamePointer, sizeof(NamePointer));
|
||||
}
|
||||
|
||||
void TestDns::testWriteName()
|
||||
{
|
||||
QFETCH(QByteArray, initialPacket);
|
||||
QFETCH(quint16, initialOffset);
|
||||
QFETCH(quint16, correctOffset);
|
||||
QFETCH(QByteArray, name);
|
||||
QFETCH(NameMap, nameMap);
|
||||
QFETCH(QByteArray, correctPacket);
|
||||
|
||||
QByteArray packet = initialPacket;
|
||||
quint16 offset = initialOffset;
|
||||
QMdnsEngine::writeName(packet, offset, name, nameMap);
|
||||
|
||||
QCOMPARE(packet, correctPacket);
|
||||
}
|
||||
|
||||
void TestDns::testParseRecordA()
|
||||
{
|
||||
PARSE_RECORD(RecordA);
|
||||
|
||||
QCOMPARE(result, true);
|
||||
QCOMPARE(record.name(), Name);
|
||||
QCOMPARE(record.type(), static_cast<quint16>(QMdnsEngine::A));
|
||||
QCOMPARE(record.flushCache(), true);
|
||||
QCOMPARE(record.ttl(), Ttl);
|
||||
QCOMPARE(record.address(), Ipv4Address);
|
||||
}
|
||||
|
||||
void TestDns::testParseRecordAAAA()
|
||||
{
|
||||
PARSE_RECORD(RecordAAAA);
|
||||
|
||||
QCOMPARE(result, true);
|
||||
QCOMPARE(record.type(), static_cast<quint16>(QMdnsEngine::AAAA));
|
||||
QCOMPARE(record.address(), Ipv6Address);
|
||||
}
|
||||
|
||||
void TestDns::testParseRecordPTR()
|
||||
{
|
||||
PARSE_RECORD(RecordPTR);
|
||||
|
||||
QCOMPARE(result, true);
|
||||
QCOMPARE(record.type(), static_cast<quint16>(QMdnsEngine::PTR));
|
||||
QCOMPARE(record.target(), QByteArray("test2."));
|
||||
}
|
||||
|
||||
void TestDns::testParseRecordSRV()
|
||||
{
|
||||
PARSE_RECORD(RecordSRV);
|
||||
|
||||
QCOMPARE(result, true);
|
||||
QCOMPARE(record.type(), static_cast<quint16>(QMdnsEngine::SRV));
|
||||
QCOMPARE(record.priority(), Priority);
|
||||
QCOMPARE(record.weight(), Weight);
|
||||
QCOMPARE(record.port(), Port);
|
||||
QCOMPARE(record.target(), Target);
|
||||
}
|
||||
|
||||
void TestDns::testParseRecordTXT()
|
||||
{
|
||||
PARSE_RECORD(RecordTXT);
|
||||
|
||||
QCOMPARE(result, true);
|
||||
QCOMPARE(record.type(), static_cast<quint16>(QMdnsEngine::TXT));
|
||||
QCOMPARE(record.attributes(), Attributes);
|
||||
}
|
||||
|
||||
void TestDns::testWriteRecordA()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(QMdnsEngine::A);
|
||||
record.setFlushCache(true);
|
||||
record.setTtl(Ttl);
|
||||
record.setAddress(Ipv4Address);
|
||||
|
||||
WRITE_RECORD();
|
||||
|
||||
QCOMPARE(packet, QByteArray(RecordA, sizeof(RecordA)));
|
||||
}
|
||||
|
||||
void TestDns::testWriteRecordAAAA()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(QMdnsEngine::AAAA);
|
||||
record.setTtl(Ttl);
|
||||
record.setAddress(Ipv6Address);
|
||||
|
||||
WRITE_RECORD();
|
||||
|
||||
QCOMPARE(packet, QByteArray(RecordAAAA, sizeof(RecordAAAA)));
|
||||
}
|
||||
|
||||
void TestDns::testWriteRecordPTR()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(QMdnsEngine::PTR);
|
||||
record.setTtl(Ttl);
|
||||
record.setTarget(Target);
|
||||
|
||||
WRITE_RECORD();
|
||||
|
||||
QCOMPARE(packet, QByteArray(RecordPTR, sizeof(RecordPTR)));
|
||||
}
|
||||
|
||||
void TestDns::testWriteRecordSRV()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(QMdnsEngine::SRV);
|
||||
record.setTtl(Ttl);
|
||||
record.setPriority(Priority);
|
||||
record.setWeight(Weight);
|
||||
record.setPort(Port);
|
||||
record.setTarget(Target);
|
||||
|
||||
WRITE_RECORD();
|
||||
|
||||
QCOMPARE(packet, QByteArray(RecordSRV, sizeof(RecordSRV)));
|
||||
}
|
||||
|
||||
void TestDns::testWriteRecordTXT()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(QMdnsEngine::TXT);
|
||||
record.setTtl(Ttl);
|
||||
for (auto i = Attributes.constBegin(); i != Attributes.constEnd(); ++i) {
|
||||
record.addAttribute(i.key(), i.value());
|
||||
}
|
||||
|
||||
WRITE_RECORD();
|
||||
|
||||
QCOMPARE(packet, QByteArray(RecordTXT, sizeof(RecordTXT)));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestDns)
|
||||
#include "TestDns.moc"
|
||||
109
src/qmdnsengine/tests/TestHostname.cpp
Normal file
109
src/qmdnsengine/tests/TestHostname.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkInterface>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/hostname.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "common/testserver.h"
|
||||
|
||||
const quint16 Port = 1234;
|
||||
|
||||
class TestHostname : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void testAcquire();
|
||||
void testAnswer();
|
||||
};
|
||||
|
||||
void TestHostname::testAcquire()
|
||||
{
|
||||
TestServer server;
|
||||
QMdnsEngine::Hostname hostname(&server);
|
||||
QSignalSpy hostnameChangedSpy(&hostname, SIGNAL(hostnameChanged(QByteArray)));
|
||||
|
||||
// Wait for the first query
|
||||
QTRY_VERIFY(server.receivedMessages().count() > 0);
|
||||
QMdnsEngine::Message probe = server.receivedMessages().at(0);
|
||||
QVERIFY(probe.queries().count() > 0);
|
||||
|
||||
// Immediately indicate that name is taken
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(probe.queries().at(0).name());
|
||||
record.setType(QMdnsEngine::A);
|
||||
record.setAddress(QHostAddress("127.0.0.1"));
|
||||
QMdnsEngine::Message message;
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
|
||||
// Wait for another attempt and verify the name is different
|
||||
QTRY_VERIFY(hostname.isRegistered());
|
||||
QCOMPARE(hostname.hostname(), probe.queries().at(0).name());
|
||||
QCOMPARE(hostnameChangedSpy.count(), 1);
|
||||
}
|
||||
|
||||
void TestHostname::testAnswer()
|
||||
{
|
||||
if (!QNetworkInterface::allAddresses().count()) {
|
||||
QSKIP("no addresses available");
|
||||
}
|
||||
QHostAddress address = QNetworkInterface::allAddresses().at(0);
|
||||
|
||||
TestServer server;
|
||||
QMdnsEngine::Hostname hostname(&server);
|
||||
|
||||
// Wait for the hostname to be acquired
|
||||
QTRY_VERIFY(hostname.isRegistered());
|
||||
server.clearReceivedMessages();
|
||||
|
||||
// Build a query for the host appearing to come from the first address
|
||||
QMdnsEngine::Query query;
|
||||
query.setName(hostname.hostname());
|
||||
query.setType(QMdnsEngine::A);
|
||||
QMdnsEngine::Message message;
|
||||
message.setAddress(address);
|
||||
message.setPort(Port);
|
||||
message.addQuery(query);
|
||||
server.deliverMessage(message);
|
||||
|
||||
// Ensure a valid reply was received
|
||||
QTRY_VERIFY(server.receivedMessages().count() > 0);
|
||||
QMdnsEngine::Message reply = server.receivedMessages().at(0);
|
||||
QCOMPARE(reply.address(), address);
|
||||
QCOMPARE(reply.port(), Port);
|
||||
QVERIFY(reply.records().count() > 0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestHostname)
|
||||
#include "TestHostname.moc"
|
||||
69
src/qmdnsengine/tests/TestProber.cpp
Normal file
69
src/qmdnsengine/tests/TestProber.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/prober.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "common/testserver.h"
|
||||
|
||||
const QByteArray Name = "Test._http._tcp.local.";
|
||||
const quint16 Type = QMdnsEngine::SRV;
|
||||
|
||||
class TestProber : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void testProbe();
|
||||
};
|
||||
|
||||
void TestProber::testProbe()
|
||||
{
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(Type);
|
||||
|
||||
TestServer server;
|
||||
QMdnsEngine::Prober prober(&server, record);
|
||||
QSignalSpy nameConfirmedSpy(&prober, SIGNAL(nameConfirmed(QByteArray)));
|
||||
|
||||
// Return an existing record to signal a conflict
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
|
||||
// Wait for the replacement name to be confirmed
|
||||
QTRY_COMPARE(nameConfirmedSpy.count(), 1);
|
||||
QVERIFY(nameConfirmedSpy.at(0).at(0).toByteArray() != Name);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestProber)
|
||||
#include "TestProber.moc"
|
||||
77
src/qmdnsengine/tests/TestProvider.cpp
Normal file
77
src/qmdnsengine/tests/TestProvider.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/hostname.h>
|
||||
#include <qmdnsengine/provider.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
#include <qmdnsengine/service.h>
|
||||
|
||||
#include "common/testserver.h"
|
||||
|
||||
const QByteArray Name = "Test";
|
||||
const QByteArray Type = "_test._tcp.local.";
|
||||
const QByteArray Fqdn = Name + "." + Type;
|
||||
const quint16 Port = 1234;
|
||||
const QByteArray Key = "key";
|
||||
const QByteArray Value = "value";
|
||||
|
||||
class TestProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void testProvider();
|
||||
};
|
||||
|
||||
void TestProvider::testProvider()
|
||||
{
|
||||
TestServer server;
|
||||
QMdnsEngine::Hostname hostname(&server);
|
||||
QMdnsEngine::Provider provider(&server, &hostname);
|
||||
|
||||
// Create a service description and provide it
|
||||
QMdnsEngine::Service service;
|
||||
service.setName(Name);
|
||||
service.setType(Type);
|
||||
service.setPort(Port);
|
||||
service.setAttributes({{Key, Value}});
|
||||
provider.update(service);
|
||||
|
||||
// Wait for the three records to be announced (3 on each protocol)
|
||||
QMdnsEngine::Record record;
|
||||
QTRY_VERIFY(server.cache()->lookupRecord(Type, QMdnsEngine::PTR, record));
|
||||
QCOMPARE(record.target(), Fqdn);
|
||||
QTRY_VERIFY(server.cache()->lookupRecord(Fqdn, QMdnsEngine::SRV, record));
|
||||
QCOMPARE(record.target(), hostname.hostname());
|
||||
QCOMPARE(record.port(), Port);
|
||||
QTRY_VERIFY(server.cache()->lookupRecord(Fqdn, QMdnsEngine::TXT, record));
|
||||
QCOMPARE(record.attributes(), service.attributes());
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestProvider)
|
||||
#include "TestProvider.moc"
|
||||
84
src/qmdnsengine/tests/TestResolver.cpp
Normal file
84
src/qmdnsengine/tests/TestResolver.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <qmdnsengine/dns.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
#include <qmdnsengine/resolver.h>
|
||||
|
||||
#include "common/testserver.h"
|
||||
#include "common/util.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QHostAddress)
|
||||
|
||||
const QByteArray Name = "test.localhost.";
|
||||
const QHostAddress Address("127.0.0.1");
|
||||
|
||||
class TestResolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void initTestCase();
|
||||
void testResolver();
|
||||
};
|
||||
|
||||
void TestResolver::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<QHostAddress>("QHostAddress");
|
||||
}
|
||||
|
||||
void TestResolver::testResolver()
|
||||
{
|
||||
TestServer server;
|
||||
QMdnsEngine::Resolver resolver(&server, Name);
|
||||
QSignalSpy resolvedSpy(&resolver, SIGNAL(resolved(QHostAddress)));
|
||||
|
||||
// Ensure two queries were dispatched
|
||||
QTRY_VERIFY(queryReceived(&server, Name, QMdnsEngine::A));
|
||||
QVERIFY(queryReceived(&server, Name, QMdnsEngine::AAAA));
|
||||
|
||||
// Send a record with an address
|
||||
QMdnsEngine::Record record;
|
||||
record.setName(Name);
|
||||
record.setType(QMdnsEngine::A);
|
||||
record.setAddress(Address);
|
||||
QMdnsEngine::Message message;
|
||||
message.setResponse(true);
|
||||
message.addRecord(record);
|
||||
message.addRecord(record);
|
||||
server.deliverMessage(message);
|
||||
|
||||
// Ensure resolved() was emitted with the right address
|
||||
QTRY_COMPARE(resolvedSpy.count(), 1);
|
||||
QCOMPARE(resolvedSpy.at(0).at(0).value<QHostAddress>(), Address);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestResolver)
|
||||
#include "TestResolver.moc"
|
||||
11
src/qmdnsengine/tests/common/CMakeLists.txt
Normal file
11
src/qmdnsengine/tests/common/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
set(SRC
|
||||
testserver.cpp
|
||||
util.cpp
|
||||
)
|
||||
|
||||
add_library(common STATIC ${SRC})
|
||||
set_target_properties(common PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
target_link_libraries(common qmdnsengine)
|
||||
76
src/qmdnsengine/tests/common/testserver.cpp
Normal file
76
src/qmdnsengine/tests/common/testserver.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/mdns.h>
|
||||
#include <qmdnsengine/record.h>
|
||||
|
||||
#include "testserver.h"
|
||||
|
||||
void TestServer::sendMessage(const QMdnsEngine::Message &message)
|
||||
{
|
||||
saveMessage(message);
|
||||
}
|
||||
|
||||
void TestServer::sendMessageToAll(const QMdnsEngine::Message &message)
|
||||
{
|
||||
QMdnsEngine::Message ipv4Message = message;
|
||||
ipv4Message.setAddress(QMdnsEngine::MdnsIpv4Address);
|
||||
ipv4Message.setPort(QMdnsEngine::MdnsPort);
|
||||
saveMessage(ipv4Message);
|
||||
QMdnsEngine::Message ipv6Message = message;
|
||||
ipv4Message.setAddress(QMdnsEngine::MdnsIpv6Address);
|
||||
ipv4Message.setPort(QMdnsEngine::MdnsPort);
|
||||
saveMessage(ipv6Message);
|
||||
}
|
||||
|
||||
void TestServer::deliverMessage(const QMdnsEngine::Message &message)
|
||||
{
|
||||
emit messageReceived(message);
|
||||
}
|
||||
|
||||
QList<QMdnsEngine::Message> TestServer::receivedMessages() const
|
||||
{
|
||||
return mMessages;
|
||||
}
|
||||
|
||||
void TestServer::clearReceivedMessages()
|
||||
{
|
||||
mMessages.clear();
|
||||
}
|
||||
|
||||
const QMdnsEngine::Cache *TestServer::cache() const
|
||||
{
|
||||
return &mCache;
|
||||
}
|
||||
|
||||
void TestServer::saveMessage(const QMdnsEngine::Message &message)
|
||||
{
|
||||
mMessages.append(message);
|
||||
if (message.isResponse()) {
|
||||
const auto records = message.records();
|
||||
for (const QMdnsEngine::Record &record : records) {
|
||||
mCache.addRecord(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
src/qmdnsengine/tests/common/testserver.h
Normal file
61
src/qmdnsengine/tests/common/testserver.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_TESTSERVER_H
|
||||
#define COMMON_TESTSERVER_H
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include <qmdnsengine/abstractserver.h>
|
||||
#include <qmdnsengine/cache.h>
|
||||
#include <qmdnsengine/message.h>
|
||||
|
||||
/**
|
||||
* @brief Test server that stores sent messages and enables manual message delivery
|
||||
*/
|
||||
class TestServer : public QMdnsEngine::AbstractServer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
virtual void sendMessage(const QMdnsEngine::Message &message);
|
||||
virtual void sendMessageToAll(const QMdnsEngine::Message &message);
|
||||
|
||||
void deliverMessage(const QMdnsEngine::Message &message);
|
||||
|
||||
QList<QMdnsEngine::Message> receivedMessages() const;
|
||||
void clearReceivedMessages();
|
||||
|
||||
const QMdnsEngine::Cache *cache() const;
|
||||
|
||||
private:
|
||||
|
||||
void saveMessage(const QMdnsEngine::Message &message);
|
||||
|
||||
QList<QMdnsEngine::Message> mMessages;
|
||||
QMdnsEngine::Cache mCache;
|
||||
};
|
||||
|
||||
#endif // COMMON_TESTSERVER_H
|
||||
44
src/qmdnsengine/tests/common/util.cpp
Normal file
44
src/qmdnsengine/tests/common/util.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <qmdnsengine/message.h>
|
||||
#include <qmdnsengine/query.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
bool queryReceived(TestServer *server, const QByteArray &name, quint16 type)
|
||||
{
|
||||
const auto messages = server->receivedMessages();
|
||||
for (const QMdnsEngine::Message &message : messages) {
|
||||
if (!message.isResponse()) {
|
||||
const auto queries = message.queries();
|
||||
for (const QMdnsEngine::Query &query : queries) {
|
||||
if (query.name() == name && query.type() == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
34
src/qmdnsengine/tests/common/util.h
Normal file
34
src/qmdnsengine/tests/common/util.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Nathan Osman
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_UTIL_H
|
||||
#define COMMON_UTIL_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "testserver.h"
|
||||
|
||||
bool queryReceived(TestServer *server, const QByteArray &name, quint16 type);
|
||||
|
||||
#endif // COMMON_UTIL_H
|
||||
Reference in New Issue
Block a user