diff --git a/FactoryTestTool/FactoryTestTool.vcxproj b/FactoryTestTool/FactoryTestTool.vcxproj
index af0257a..d35f1d7 100644
--- a/FactoryTestTool/FactoryTestTool.vcxproj
+++ b/FactoryTestTool/FactoryTestTool.vcxproj
@@ -42,22 +42,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
input
@@ -77,12 +62,14 @@
+
+
@@ -98,6 +85,8 @@
+
+
@@ -105,37 +94,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -231,22 +191,22 @@
/utf-8
- D:\QT\qt\5.15.2\msvc2019_64\include\QtNetwork;D:\QT\qt\5.15.2\msvc2019_64\include\QtGui;D:\QT\qt\5.15.2\msvc2019_64\include\QtCore;D:\QT\qt\5.15.2\msvc2019_64\include\QtWidgets;D:\QT\qt\5.15.2\msvc2019_64\include
+ D:\QT\qt\5.15.2\msvc2019_64\include\QtNetwork;D:\QT\qt\5.15.2\msvc2019_64\include\QtGui;D:\QT\qt\5.15.2\msvc2019_64\include\QtCore;D:\QT\qt\5.15.2\msvc2019_64\include\QtWidgets;D:\QT\qt\5.15.2\msvc2019_64\include;E:\facttest\new_factest\FactoryTestTool\ThirdParty\libqrencode\include
- libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;%(AdditionalDependencies)
- D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;%(AdditionalLibraryDirectories)
+ libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;ErWeiMaLib.lib;Iphlpapi.lib;Ws2_32.lib;%(AdditionalDependencies)
+ D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;E:\facttest\new_factest\FactoryTestTool\ThirdParty\libqrencode\lib;%(AdditionalLibraryDirectories)
/utf-8
DEBUG;%(PreprocessorDefinitions)
- D:\QT\qt\5.15.2\msvc2019_64\include\QtNetwork;D:\QT\qt\5.15.2\msvc2019_64\include\QtGui;D:\QT\qt\5.15.2\msvc2019_64\include\QtCore;D:\QT\qt\5.15.2\msvc2019_64\include\QtWidgets;D:\QT\qt\5.15.2\msvc2019_64\include
+ D:\QT\qt\5.15.2\msvc2019_64\include\QtNetwork;D:\QT\qt\5.15.2\msvc2019_64\include\QtGui;D:\QT\qt\5.15.2\msvc2019_64\include\QtCore;D:\QT\qt\5.15.2\msvc2019_64\include\QtWidgets;D:\QT\qt\5.15.2\msvc2019_64\include;E:\facttest\new_factest\FactoryTestTool\ThirdParty\libqrencode\include
- libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;%(AdditionalDependencies)
- D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;%(AdditionalLibraryDirectories)
+ libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;ErWeiMaLib.lib;Iphlpapi.lib;Ws2_32.lib;%(AdditionalDependencies)
+ D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;E:\facttest\new_factest\FactoryTestTool\ThirdParty\libqrencode\lib;%(AdditionalLibraryDirectories)
diff --git a/FactoryTestTool/FactoryTestTool.vcxproj.filters b/FactoryTestTool/FactoryTestTool.vcxproj.filters
index ef5633a..a5d0c01 100644
--- a/FactoryTestTool/FactoryTestTool.vcxproj.filters
+++ b/FactoryTestTool/FactoryTestTool.vcxproj.filters
@@ -26,60 +26,15 @@
LicenseGenerate
-
- Network\mdns
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
Widget\UI_Widget
Network
+
+ Network\mdns
+
@@ -106,60 +61,15 @@
Network
-
- Network\mdns
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
Network
Media\VideoDecoder
+
+ Network\mdns
+
@@ -212,6 +122,12 @@
Json\JsonFile
+
+ Json\JsonFile
+
+
+ Json\JsonFile
+
@@ -241,15 +157,6 @@
{3570ab1e-6ede-402b-8dd0-1c53afff0bd8}
-
- {d437b89e-76f2-495a-9434-e6ab8479c960}
-
-
- {7f4c4097-0c9f-4b37-967c-5efae6108a91}
-
-
- {e8857e15-2519-4a60-9fd5-eff901a76ba6}
-
{ca263230-ea2f-4140-82aa-19b06eca1b1e}
@@ -273,48 +180,12 @@
LicenseGenerate
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\include
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\src
-
-
- Network\mdns\qmdnsengine\include
-
Widget\UI_Widget
+
+ Network\mdns
+
diff --git a/FactoryTestTool/FileName.cpp b/FactoryTestTool/FileName.cpp
new file mode 100644
index 0000000..e69de29
diff --git a/FactoryTestTool/SourceCode/Json/JsonFile/backCmd_config.json b/FactoryTestTool/SourceCode/Json/JsonFile/backCmd_config.json
new file mode 100644
index 0000000..863c444
--- /dev/null
+++ b/FactoryTestTool/SourceCode/Json/JsonFile/backCmd_config.json
@@ -0,0 +1,7 @@
+{
+ "cmds": {
+ "GET_FRONT_V851_VERSION": "0x0400",
+ "GET_REAR_V851_VERSION": "0x0401",
+ "START_PROCESS": "0x0500"
+ }
+}
diff --git a/FactoryTestTool/SourceCode/Json/JsonFile/frontBoardTest.json b/FactoryTestTool/SourceCode/Json/JsonFile/frontBoardTest.json
index e3b189f..adbede5 100644
--- a/FactoryTestTool/SourceCode/Json/JsonFile/frontBoardTest.json
+++ b/FactoryTestTool/SourceCode/Json/JsonFile/frontBoardTest.json
@@ -61,7 +61,7 @@
},
{
"cmd": "IMG_ENROLL",
- "val": 0,
+ "val": "",
"lable": "图片注册",
"timeout": 2000
},
diff --git a/FactoryTestTool/SourceCode/Json/JsonFile/frontCmd_config.json b/FactoryTestTool/SourceCode/Json/JsonFile/frontCmd_config.json
new file mode 100644
index 0000000..87bbd2d
--- /dev/null
+++ b/FactoryTestTool/SourceCode/Json/JsonFile/frontCmd_config.json
@@ -0,0 +1,65 @@
+{
+ "cmds": {
+ "FACE_ENROLL_SINGLE": "0x0200",
+ "FACE_ENROLL": "0x0201",
+ "HAND_ENROLL": "0x0202",
+ "FACE_VERIFY": "0x0203",
+ "HAND_VERIFY": "0x0204",
+ "DEL_USER": "0x0205",
+ "DEL_ALLUSER": "0x0206",
+ "GET_USER": "0x0207",
+ "GET_ALLUSER": "0x0208",
+ "PASSWD_ENROLL": "0x0209",
+ "IMG_ENROLL": "0x020A",
+
+ "GET_IMG": "0x0220",
+ "START_VIDEO": "0x0221",
+ "STOP_VIDEO": "0x0222",
+
+ "TOUCH_TEST": "0x0240",
+ "MIC_TEST": "0x0241",
+ "SPK_TEST": "0x0242",
+ "RADAR_TEST": "0x0243",
+ "NFC_TEST": "0x0244",
+ "PR_SWITCH": "0x0245",
+ "PS_TEST": "0x0246",
+ "BACKLIGHT": "0x0247",
+ "IR_LED": "0x0248",
+ "UART_TEST": "0x0249",
+ "PIR_TEST": "0x024A",
+
+ "FACE_VERIFY_THRES": "0x0300",
+ "FACE_THRES_LEVEL": "0x0301",
+ "FACE_LIVE_THRES": "0x0302",
+ "FACE_ACC_THRES": "0x0303",
+ "FACE_ACC_LEVEL": "0x0304",
+ "FACE_DIS_RANGE": "0x0305",
+ "FACE_ANGLE_RANGE": "0x0306",
+ "HAND_VERIFY_THRES": "0x0307",
+ "HANS_THRES_LEVEL": "0x0308",
+ "HAND_LIVE_THRES": "0x0309",
+ "USER_MAX_NUM": "0x030A",
+ "ADMI_USER_MAX_NUM": "0x030B",
+ "FACE_REPEAT": "0x030C",
+ "HAND_REPEAT": "0x030D",
+
+ "SET_IP": "0x0320",
+ "SET_PORT": "0x0321",
+
+ "SET_VOLUME": "0x0340",
+ "SET_BACKLIGHT": "0x0341",
+ "SET_RADAR_DIS": "0x0342",
+ "SET_UART_BARTRATE": "0x0343",
+
+ "SET_LOG_LEVEL": "0x0360",
+
+ "GET_FRONT_V851_VERSION": "0x0400",
+ "GET_FRONT_MCU_VERSION": "0x0401",
+ "GET_FRONT_HW_VERSION": "0x0402",
+ "GET_FRONT_ALGO_VERSION": "0x0403",
+ "GET_FRONT_SN": "0x0404",
+
+ "GET_FRONT_HW_INFO": "0x0420",
+ "WRITE_FRONT_LICENSE": "0x0421"
+ }
+}
diff --git a/FactoryTestTool/SourceCode/Json/readJsonFile.cpp b/FactoryTestTool/SourceCode/Json/readJsonFile.cpp
index 9ae560e..311d28f 100644
--- a/FactoryTestTool/SourceCode/Json/readJsonFile.cpp
+++ b/FactoryTestTool/SourceCode/Json/readJsonFile.cpp
@@ -82,3 +82,11 @@ QJsonArray readJson_getVideo() {
QJsonArray readJson_factoryProductInfo() {
return readJsonArrayFromFile("./SourceCode/Json/JsonFile/factoryProductInfo.json");
}
+
+QJsonArray readJson_frontCmd_config() {
+ return readJsonArrayFromFile("./SourceCode/Json/JsonFile/frontCmd_config.json");
+}
+
+QJsonArray readJson_backCmd_config() {
+ return readJsonArrayFromFile("./SourceCode/Json/JsonFile/backCmd_config.json");
+}
diff --git a/FactoryTestTool/SourceCode/Json/readJsonFile.h b/FactoryTestTool/SourceCode/Json/readJsonFile.h
index 629af58..f0bef87 100644
--- a/FactoryTestTool/SourceCode/Json/readJsonFile.h
+++ b/FactoryTestTool/SourceCode/Json/readJsonFile.h
@@ -12,12 +12,14 @@ QJsonArray readJson_frontBoardTest();
QJsonArray readJson_frontBoardFuncConfig();
QJsonArray readJson_frontDevInfo();
QJsonArray readJson_frontLicense();
+QJsonArray readJson_frontCmd_config();
QJsonArray readJson_backBoardOneClickTest();
QJsonArray readJson_backBoardTest();
QJsonArray readJson_backBoardFuncConfig();
QJsonArray readJson_backDevInfo();
QJsonArray readJson_backUuid();
+QJsonArray readJson_backCmd_config();
QJsonArray readJson_factoryProductInfo();
@@ -27,4 +29,7 @@ QJsonArray readJson_funcConfig();
QJsonArray readJson_getPic();
QJsonArray readJson_getVideo();
+
+
+
#endif // READJSONFILE_H
diff --git a/FactoryTestTool/SourceCode/LicenseGenerate/加密狗驱动_20220110.zip b/FactoryTestTool/SourceCode/LicenseGenerate/加密狗驱动_20220110.zip
index 73e1285..ed136ea 100644
Binary files a/FactoryTestTool/SourceCode/LicenseGenerate/加密狗驱动_20220110.zip and b/FactoryTestTool/SourceCode/LicenseGenerate/加密狗驱动_20220110.zip differ
diff --git a/FactoryTestTool/SourceCode/Network/ClientHandler.cpp b/FactoryTestTool/SourceCode/Network/ClientHandler.cpp
index c4e5646..e9f76ec 100644
--- a/FactoryTestTool/SourceCode/Network/ClientHandler.cpp
+++ b/FactoryTestTool/SourceCode/Network/ClientHandler.cpp
@@ -112,7 +112,7 @@ QString ClientHandler::getCurrentFuncItemData() const
QString ClientHandler::getCurrentItemLable() const
{
QString lable = currentItem.value("lable").toString();
- //qDebug() << "Getting current item lable:" << lable;
+ qDebug() << "Getting current item lable:" << lable;
return lable; // 返回当前项的 "data" 字段
}
@@ -157,13 +157,16 @@ void ClientHandler::sendDataToClient(const QByteArray& data)
emit sendData(data, isBackBoardOrAllBoard);
}
+void ClientHandler::onCommandError() {
+ isCommandError = true;
+}
+
void ClientHandler::sendJsonItem(const QJsonArray& jsonArray, int itemIndex, const QString text, const QString backBoardSn, const QString& itemType)
{
startReadVideoDataTimer(preVideoClientId);
currentJson = jsonArray;
currentJsonItem = itemIndex;
QMutexLocker locker(&mutex);
-
if (itemType == "License") {
}
@@ -260,6 +263,7 @@ void ClientHandler::sendJsonItem(const QJsonArray& jsonArray, int itemIndex, con
}
}
QString itemData = QJsonDocument(currentItem).toJson();
+ emit currentSendItem(currentItem["cmd"].toString());
if (isBackBoardOrAllBoard) {
emit sendDataToSomeClient(isBackBoardOrAllBoard, itemData.toUtf8());
}
@@ -363,20 +367,21 @@ void ClientHandler::sendFrontItem(int itemIndex)
return;
}
else {
- QString text = "";
+ QString text = "";
QJsonObject currentItem = frontBoardTest[itemIndex].toObject();
if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "IMG_ENROLL") {
- ImageEnrollWindow dialog;
- if (dialog.exec() == QDialog::Accepted) {
- text = dialog.getFilePath();
- QByteArray imageData = dialog.getImageData();
- if (!imageData.isEmpty()) {
- text = QString::fromUtf8(imageData);
- }
- }
- else {
- return;
+ QString downloadUrl;
+ QEventLoop loop;
+ emit startImageSharing(IMG_ENROLL_W, IMG_ENROLL_H, "enroll", [&downloadUrl, &loop](QString responseUrl) {
+ //qDebug() << "Received response from slot:" << responseUrl;
+ downloadUrl = responseUrl; // 更新局部变量
+ loop.quit(); // 退出事件循环
+ });
+ //loop.exec(); // 等待回调执行完成
+ if (!downloadUrl.isEmpty()) {
+ qDebug() << "Image available at:" << downloadUrl;
}
+ text = downloadUrl;
}
else if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "DEL_USER") {
DelUserWindow dialog;
@@ -412,18 +417,22 @@ void ClientHandler::sendBackItem(int itemIndex)
else {
QString text = "";
QJsonObject currentItem = backBoardTest[itemIndex].toObject();
- if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "IMG_ENROLL") {
- ImageEnrollWindow dialog;
- if (dialog.exec() == QDialog::Accepted) {
- text = dialog.getFilePath();
- QByteArray imageData = dialog.getImageData();
- if (!imageData.isEmpty()) {
- text = QString::fromUtf8(imageData);
- }
+ if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "CHANGE_THEME") {
+ QString downloadUrl;
+ QEventLoop loop;
+ emit startImageSharing(CHANGE_THEME_W, CHANGE_THEME_H, "theme", [&downloadUrl, &loop](QString responseUrl) {
+ //qDebug() << "Received response from slot:" << responseUrl;
+ downloadUrl = responseUrl; // 更新局部变量
+ loop.quit(); // 退出事件循环
+ });
+ //loop.exec(); // 等待回调执行完成
+ if (!downloadUrl.isEmpty()) {
+ qDebug() << "Image available at:" << downloadUrl;
}
else {
return;
}
+ text = downloadUrl;
}
else if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "DEL_USER") {
DelUserWindow dialog;
@@ -485,11 +494,13 @@ void ClientHandler::sendDevInfoItem()
currentJson = backBoardDevInfoJson;
currentJsonItem = currentBackBoardIndex;
if (currentBackBoardIndex < backBoardDevInfoJson.size()) {
+ isRecvVideoData = false;
sendDevInfoJsonItem(backBoardDevInfoJson[currentBackBoardIndex ++].toObject(), 1);
}
- else
- isPowerOnSend = false;
-
+ else {
+ isRecvVideoData = true;
+ isPowerOnSend = false;
+ }
}
else {
currentJson = frontBoardDevInfoJson;
@@ -688,10 +699,13 @@ void ClientHandler::onDataReceived()
}
}
getCurrentItemLable();
+ //qDebug() << "------- currentItem.value(timeout):" << currentItem.value("timeout").toInt();
if ((currentItem.contains("timeout")) || (currentFuncItem.contains("timeout"))) {
+ //qDebug() << "currentItem.contains(timeout):" << currentItem.contains("timeout");
emit startTimeout(0);
}
QJsonObject currentTempItem = currentJson[currentItemIndex].toObject();
+ //qDebug() << "---Received allData size:" << allData.size();
if (!allData.isEmpty()) {
emit dataReceived(getClientAddress(), allData, 0xFF, currentItemIndex, currentFuncItemIndex, getCurrentItemLable(), "", currentJson, currentJsonItem);
if (!isSingleSend && !isPowerOnSend && (currentTempItem["cmd"] != "GET_IMG")) {
@@ -750,9 +764,12 @@ void ClientHandler::onDataReceived()
if (preVideoClientId == clientId) {
qDebug() << "-----------------" << preVideoClientId << "isRecvVideoData:" << isRecvVideoData;
}
- socket->readAll();
- //QByteArray data = socket->readAll();
- //qDebug() << "--------- socket->readAll()" ;
+ QByteArray AllData = socket->readAll();
+ if (isCommandError) {
+ isCommandError = false;
+ emit dataReceived(getClientAddress(), AllData, 0xFF, currentItemIndex, currentFuncItemIndex, "", "", currentJson, currentJsonItem);
+ }
+ //qDebug() << "--------- AllData.size():" << AllData.size();
}
}
diff --git a/FactoryTestTool/SourceCode/Network/ClientHandler.h b/FactoryTestTool/SourceCode/Network/ClientHandler.h
index fca6a31..38bdb5f 100644
--- a/FactoryTestTool/SourceCode/Network/ClientHandler.h
+++ b/FactoryTestTool/SourceCode/Network/ClientHandler.h
@@ -21,11 +21,16 @@
#include
#include
#include
+#include
#include "DelUserWindows.h"
#define TEST_TCP_MOVE_TO_MAIN 0
#define GET_PIC_DATA_SIZE (480 * 640 * 1.5)
+#define IMG_ENROLL_W 480
+#define IMG_ENROLL_H 640
+#define CHANGE_THEME_W 720
+#define CHANGE_THEME_H 1280
class ClientHandler : public QObject, public QRunnable
{
@@ -98,6 +103,7 @@ public:
void setThreadPriority(QThread::Priority priority);
signals:
+ void startImageSharing(int width, int height, QString img_type, std::function callback);
// 数据接收信号
void dataReceived(const QString& client, const QByteArray& data, unsigned char msg_id, int currentRecvItemIndex,
int currentRecvFuncItemIndex, const QString& itemData, const QString& funcItemData,
@@ -119,6 +125,7 @@ signals:
void stopReadTimer(int client_Id);
void sendDataToSomeClient(int client_Id, const QByteArray& data);
void openFocusWindowRequested(int itemIndex);
+ void currentSendItem(const QString& text);
public slots:
#if !TEST_TCP_MOVE_TO_MAIN
@@ -137,6 +144,7 @@ public slots:
void processPendingData();
void startReadVideoDataTimer(int client_Id);
void stopReadVideoDataTimer(int client_Id);
+ void onCommandError();
private:
QTcpSocket* socket; // 客户端 socket
@@ -171,9 +179,10 @@ private:
bool isSingleSend; // 单独点击按键发送的标志
bool isClickedSend; // 点击按键发送的标志,没有点击不接收数据
bool isRecvVideoData;
- bool isRecvImgData = false;
- bool isStartVideo = false;
- bool isPowerOnSend = false; // 上电发送设备信息
+ bool isRecvImgData = false;
+ bool isStartVideo = false;
+ bool isPowerOnSend = false; // 上电发送设备信息
+ bool isCommandError = false;
//QTimer* timeoutTimer; // 超时定时器
int size;
diff --git a/FactoryTestTool/SourceCode/Network/mdns/MdnsServiceThread.h b/FactoryTestTool/SourceCode/Network/mdns/MdnsServiceThread.h
new file mode 100644
index 0000000..bcf356c
--- /dev/null
+++ b/FactoryTestTool/SourceCode/Network/mdns/MdnsServiceThread.h
@@ -0,0 +1,44 @@
+#include
+#include
+#include
+
+#include "mdns.h"
+
+// 添加一个类来运行 mDNS 服务
+class MdnsServiceThread : public QThread {
+ Q_OBJECT
+public:
+ MdnsServiceThread(const QString& hostname, const QString& serviceName, int servicePort, QObject* parent = nullptr)
+ : QThread(parent),
+ m_hostname(hostname),
+ m_serviceName(serviceName),
+ m_servicePort(servicePort) {}
+
+ void stop() {
+ extern volatile sig_atomic_t running;
+ running = 0; // 停止 mDNS 主循环
+ m_running = false; // 设置运行标志为 false
+ }
+
+protected:
+ void run() override {
+ qDebug() << "Starting mDNS service...";
+ extern volatile sig_atomic_t running; // 使用全局变量控制运行状态
+ running = 1;
+
+ // 调用阻塞的 service_mdns 方法
+ int result = service_mdns(m_hostname.toStdString().c_str(), m_serviceName.toStdString().c_str(), m_servicePort);
+ if (result < 0) {
+ qDebug() << "Failed to start mDNS service";
+ }
+ else {
+ qDebug() << "mDNS service stopped";
+ }
+ }
+
+private:
+ QString m_hostname;
+ QString m_serviceName;
+ int m_servicePort;
+ bool m_running = true; // 默认运行状态
+};
diff --git a/FactoryTestTool/SourceCode/Network/mdns/mdns.c b/FactoryTestTool/SourceCode/Network/mdns/mdns.c
new file mode 100644
index 0000000..57614d0
--- /dev/null
+++ b/FactoryTestTool/SourceCode/Network/mdns/mdns.c
@@ -0,0 +1,1291 @@
+
+#ifdef _WIN32
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include
+
+#include
+#include
+
+#ifdef _WIN32
+#include
+#include
+#include
+#define sleep(x) Sleep(x * 1000)
+#else
+#include
+#include
+#include
+#include
+#endif
+
+// Alias some things to simulate recieving data to fuzz library
+#if defined(MDNS_FUZZING)
+#define recvfrom(sock, buffer, capacity, flags, src_addr, addrlen) ((mdns_ssize_t)capacity)
+#define printf
+#endif
+
+#include "mdns.h"
+
+#if defined(MDNS_FUZZING)
+#undef recvfrom
+#endif
+
+static char addrbuffer[64];
+static char entrybuffer[256];
+static char namebuffer[256];
+static char sendbuffer[1024];
+static mdns_record_txt_t txtbuffer[128];
+
+static struct sockaddr_in service_address_ipv4;
+static struct sockaddr_in6 service_address_ipv6;
+
+static int has_ipv4;
+static int has_ipv6;
+
+volatile sig_atomic_t running = 1;
+
+// Data for our service including the mDNS records
+typedef struct {
+ mdns_string_t service;
+ mdns_string_t hostname;
+ mdns_string_t service_instance;
+ mdns_string_t hostname_qualified;
+ struct sockaddr_in address_ipv4;
+ struct sockaddr_in6 address_ipv6;
+ int port;
+ mdns_record_t record_ptr;
+ mdns_record_t record_srv;
+ mdns_record_t record_a;
+ mdns_record_t record_aaaa;
+ mdns_record_t txt_record[2];
+} service_t;
+
+typedef struct
+{
+ int port;
+ char ip[32];
+ char domain[32];
+}server_info_t;
+
+static mdns_string_t
+ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr,
+ size_t addrlen) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
+ service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin_port != 0)
+ len = snprintf(buffer, capacity, "%s:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str;
+ str.str = buffer;
+ str.length = len;
+ return str;
+}
+
+static mdns_string_t
+ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr,
+ size_t addrlen) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
+ service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin6_port != 0)
+ len = snprintf(buffer, capacity, "[%s]:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str;
+ str.str = buffer;
+ str.length = len;
+ return str;
+}
+
+static mdns_string_t
+ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr, size_t addrlen) {
+ if (addr->sa_family == AF_INET6)
+ return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr, addrlen);
+ return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr, addrlen);
+}
+
+// Callback handling parsing answers to queries sent
+static int
+query_callback(int sock, const struct sockaddr* from, size_t addrlen, mdns_entry_type_t entry,
+ uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl, const void* data,
+ size_t size, size_t name_offset, size_t name_length, size_t record_offset,
+ size_t record_length, void* user_data) {
+ (void)sizeof(sock);
+ (void)sizeof(query_id);
+ (void)sizeof(name_length);
+ (void)sizeof(user_data);
+ server_info_t *server_info = (server_info_t *)user_data;
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);
+ const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ?
+ "answer" :
+ ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
+ mdns_string_t entrystr =
+ mdns_string_extract(data, size, &name_offset, entrybuffer, sizeof(entrybuffer));
+ if (rtype == MDNS_RECORDTYPE_PTR) {
+ mdns_string_t namestr = mdns_record_parse_ptr(data, size, record_offset, record_length,
+ namebuffer, sizeof(namebuffer));
+ printf("%.*s : %s %.*s PTR %.*s rclass 0x%x ttl %u length %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr),
+ MDNS_STRING_FORMAT(namestr), rclass, ttl, (int)record_length);
+ } else if (rtype == MDNS_RECORDTYPE_SRV) {
+ mdns_record_srv_t srv = mdns_record_parse_srv(data, size, record_offset, record_length,
+ namebuffer, sizeof(namebuffer));
+ server_info->port = srv.port;
+ memcpy(server_info->domain, srv.name.str, srv.name.length - 1);
+ printf("%.*s : %s %.*s SRV %.*s priority %d weight %d port %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr),
+ MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
+ } else if (rtype == MDNS_RECORDTYPE_A) {
+ struct sockaddr_in addr;
+ mdns_record_parse_a(data, size, record_offset, record_length, &addr);
+ mdns_string_t addrstr =
+ ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr));
+ memcpy(server_info->ip, addrstr.str, addrstr.length);
+ printf("%.*s : %s %.*s A %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
+ } else if (rtype == MDNS_RECORDTYPE_AAAA) {
+ struct sockaddr_in6 addr;
+ mdns_record_parse_aaaa(data, size, record_offset, record_length, &addr);
+ mdns_string_t addrstr =
+ ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr));
+ printf("%.*s : %s %.*s AAAA %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
+ } else if (rtype == MDNS_RECORDTYPE_TXT) {
+ size_t parsed = mdns_record_parse_txt(data, size, record_offset, record_length, txtbuffer,
+ sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
+ for (size_t itxt = 0; itxt < parsed; ++itxt) {
+ if (txtbuffer[itxt].value.length) {
+ printf("%.*s : %s %.*s TXT %.*s = %.*s\n", MDNS_STRING_FORMAT(fromaddrstr),
+ entrytype, MDNS_STRING_FORMAT(entrystr),
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key),
+ MDNS_STRING_FORMAT(txtbuffer[itxt].value));
+ } else {
+ printf("%.*s : %s %.*s TXT %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(txtbuffer[itxt].key));
+ }
+ }
+ } else {
+ printf("%.*s : %s %.*s type %u rclass 0x%x ttl %u length %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype, MDNS_STRING_FORMAT(entrystr), rtype,
+ rclass, ttl, (int)record_length);
+ }
+ return 0;
+}
+
+// Callback handling questions incoming on service sockets
+static int
+service_callback(int sock, const struct sockaddr* from, size_t addrlen, mdns_entry_type_t entry,
+ uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl, const void* data,
+ size_t size, size_t name_offset, size_t name_length, size_t record_offset,
+ size_t record_length, void* user_data) {
+ (void)sizeof(ttl);
+ if (entry != MDNS_ENTRYTYPE_QUESTION)
+ return 0;
+
+ const char dns_sd[] = "_services._dns-sd._udp.local.";
+ const service_t* service = (const service_t*)user_data;
+
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);
+
+ size_t offset = name_offset;
+ mdns_string_t name = mdns_string_extract(data, size, &offset, namebuffer, sizeof(namebuffer));
+
+ const char* record_name = 0;
+ if (rtype == MDNS_RECORDTYPE_PTR)
+ record_name = "PTR";
+ else if (rtype == MDNS_RECORDTYPE_SRV)
+ record_name = "SRV";
+ else if (rtype == MDNS_RECORDTYPE_A)
+ record_name = "A";
+ else if (rtype == MDNS_RECORDTYPE_AAAA)
+ record_name = "AAAA";
+ else if (rtype == MDNS_RECORDTYPE_TXT)
+ record_name = "TXT";
+ else if (rtype == MDNS_RECORDTYPE_ANY)
+ record_name = "ANY";
+ else
+ return 0;
+ //printf("Query ---3--- %s %.*s\n", record_name, MDNS_STRING_FORMAT(name));
+
+ if ((name.length == (sizeof(dns_sd) - 1)) &&
+ (strncmp(name.str, dns_sd, sizeof(dns_sd) - 1) == 0)) {
+ if ((rtype == MDNS_RECORDTYPE_PTR) || (rtype == MDNS_RECORDTYPE_ANY)) {
+ // The PTR query was for the DNS-SD domain, send answer with a PTR record for the
+ // service name we advertise, typically on the "<_service-name>._tcp.local." format
+
+ // Answer PTR record reverse mapping "<_service-name>._tcp.local." to
+ // ".<_service-name>._tcp.local."
+ mdns_record_t answer = {
+ .name = name, .type = MDNS_RECORDTYPE_PTR, .data.ptr.name = service->service};
+
+ // Send the answer, unicast or multicast depending on flag in query
+ uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
+ printf(" --> answer %.*s (%s)\n", MDNS_STRING_FORMAT(answer.data.ptr.name),
+ (unicast ? "unicast" : "multicast"));
+
+ if (unicast) {
+ mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
+ query_id, rtype, name.str, name.length, answer, 0, 0, 0,
+ 0);
+ } else {
+ mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0, 0,
+ 0);
+ }
+ }
+ } else if ((name.length == service->service.length) &&
+ (strncmp(name.str, service->service.str, name.length) == 0)) {
+ if ((rtype == MDNS_RECORDTYPE_PTR) || (rtype == MDNS_RECORDTYPE_ANY)) {
+ // The PTR query was for our service (usually "<_service-name._tcp.local"), answer a PTR
+ // record reverse mapping the queried service name to our service instance name
+ // (typically on the ".<_service-name>._tcp.local." format), and add
+ // additional records containing the SRV record mapping the service instance name to our
+ // qualified hostname (typically ".local.") and port, as well as any IPv4/IPv6
+ // address for the hostname as A/AAAA records, and two test TXT records
+
+ // Answer PTR record reverse mapping "<_service-name>._tcp.local." to
+ // ".<_service-name>._tcp.local."
+ mdns_record_t answer = service->record_ptr;
+
+ mdns_record_t additional[5] = {0};
+ size_t additional_count = 0;
+
+ // SRV record mapping ".<_service-name>._tcp.local." to
+ // ".local." with port. Set weight & priority to 0.
+ additional[additional_count++] = service->record_srv;
+
+ // A/AAAA records mapping ".local." to IPv4/IPv6 addresses
+ if (service->address_ipv4.sin_family == AF_INET)
+ additional[additional_count++] = service->record_a;
+ if (service->address_ipv6.sin6_family == AF_INET6)
+ additional[additional_count++] = service->record_aaaa;
+
+ // Add two test TXT records for our service instance name, will be coalesced into
+ // one record with both key-value pair strings by the library
+ additional[additional_count++] = service->txt_record[0];
+ additional[additional_count++] = service->txt_record[1];
+
+ // Send the answer, unicast or multicast depending on flag in query
+ uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
+ printf(" --> answer %.*s (%s)\n",
+ MDNS_STRING_FORMAT(service->record_ptr.data.ptr.name),
+ (unicast ? "unicast" : "multicast"));
+
+ if (unicast) {
+ mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
+ query_id, rtype, name.str, name.length, answer, 0, 0,
+ additional, additional_count);
+ } else {
+ mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
+ additional, additional_count);
+ }
+ }
+ } else if ((name.length == service->service_instance.length) &&
+ (strncmp(name.str, service->service_instance.str, name.length) == 0)) {
+ if ((rtype == MDNS_RECORDTYPE_SRV) || (rtype == MDNS_RECORDTYPE_ANY)) {
+ // The SRV query was for our service instance (usually
+ // ".<_service-name._tcp.local"), answer a SRV record mapping the service
+ // instance name to our qualified hostname (typically ".local.") and port, as
+ // well as any IPv4/IPv6 address for the hostname as A/AAAA records, and two test TXT
+ // records
+
+ // Answer PTR record reverse mapping "<_service-name>._tcp.local." to
+ // ".<_service-name>._tcp.local."
+ mdns_record_t answer = service->record_srv;
+
+ mdns_record_t additional[5] = {0};
+ size_t additional_count = 0;
+
+ // A/AAAA records mapping ".local." to IPv4/IPv6 addresses
+ if (service->address_ipv4.sin_family == AF_INET)
+ additional[additional_count++] = service->record_a;
+ if (service->address_ipv6.sin6_family == AF_INET6)
+ additional[additional_count++] = service->record_aaaa;
+
+ // Add two test TXT records for our service instance name, will be coalesced into
+ // one record with both key-value pair strings by the library
+ additional[additional_count++] = service->txt_record[0];
+ additional[additional_count++] = service->txt_record[1];
+
+ // Send the answer, unicast or multicast depending on flag in query
+ uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
+ printf(" --> answer %.*s port %d (%s)\n",
+ MDNS_STRING_FORMAT(service->record_srv.data.srv.name), service->port,
+ (unicast ? "unicast" : "multicast"));
+
+ if (unicast) {
+ mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
+ query_id, rtype, name.str, name.length, answer, 0, 0,
+ additional, additional_count);
+ } else {
+ mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
+ additional, additional_count);
+ }
+ }
+ } else if ((name.length == service->hostname_qualified.length) &&
+ (strncmp(name.str, service->hostname_qualified.str, name.length) == 0)) {
+ if (((rtype == MDNS_RECORDTYPE_A) || (rtype == MDNS_RECORDTYPE_ANY)) &&
+ (service->address_ipv4.sin_family == AF_INET)) {
+ // The A query was for our qualified hostname (typically ".local.") and we
+ // have an IPv4 address, answer with an A record mappiing the hostname to an IPv4
+ // address, as well as any IPv6 address for the hostname, and two test TXT records
+
+ // Answer A records mapping ".local." to IPv4 address
+ mdns_record_t answer = service->record_a;
+
+ mdns_record_t additional[5] = {0};
+ size_t additional_count = 0;
+
+ // AAAA record mapping ".local." to IPv6 addresses
+ if (service->address_ipv6.sin6_family == AF_INET6)
+ additional[additional_count++] = service->record_aaaa;
+
+ // Add two test TXT records for our service instance name, will be coalesced into
+ // one record with both key-value pair strings by the library
+ additional[additional_count++] = service->txt_record[0];
+ additional[additional_count++] = service->txt_record[1];
+
+ // Send the answer, unicast or multicast depending on flag in query
+ uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
+ mdns_string_t addrstr = ip_address_to_string(
+ addrbuffer, sizeof(addrbuffer), (struct sockaddr*)&service->record_a.data.a.addr,
+ sizeof(service->record_a.data.a.addr));
+ printf(" --> answer %.*s IPv4 %.*s (%s)\n", MDNS_STRING_FORMAT(service->record_a.name),
+ MDNS_STRING_FORMAT(addrstr), (unicast ? "unicast" : "multicast"));
+
+ if (unicast) {
+ mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
+ query_id, rtype, name.str, name.length, answer, 0, 0,
+ additional, additional_count);
+ } else {
+ mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
+ additional, additional_count);
+ }
+ } else if (((rtype == MDNS_RECORDTYPE_AAAA) || (rtype == MDNS_RECORDTYPE_ANY)) &&
+ (service->address_ipv6.sin6_family == AF_INET6)) {
+ // The AAAA query was for our qualified hostname (typically ".local.") and we
+ // have an IPv6 address, answer with an AAAA record mappiing the hostname to an IPv6
+ // address, as well as any IPv4 address for the hostname, and two test TXT records
+
+ // Answer AAAA records mapping ".local." to IPv6 address
+ mdns_record_t answer = service->record_aaaa;
+
+ mdns_record_t additional[5] = {0};
+ size_t additional_count = 0;
+
+ // A record mapping ".local." to IPv4 addresses
+ if (service->address_ipv4.sin_family == AF_INET)
+ additional[additional_count++] = service->record_a;
+
+ // Add two test TXT records for our service instance name, will be coalesced into
+ // one record with both key-value pair strings by the library
+ additional[additional_count++] = service->txt_record[0];
+ additional[additional_count++] = service->txt_record[1];
+
+ // Send the answer, unicast or multicast depending on flag in query
+ uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
+ mdns_string_t addrstr =
+ ip_address_to_string(addrbuffer, sizeof(addrbuffer),
+ (struct sockaddr*)&service->record_aaaa.data.aaaa.addr,
+ sizeof(service->record_aaaa.data.aaaa.addr));
+ printf(" --> answer %.*s IPv6 %.*s (%s)\n",
+ MDNS_STRING_FORMAT(service->record_aaaa.name), MDNS_STRING_FORMAT(addrstr),
+ (unicast ? "unicast" : "multicast"));
+
+ if (unicast) {
+ mdns_query_answer_unicast(sock, from, addrlen, sendbuffer, sizeof(sendbuffer),
+ query_id, rtype, name.str, name.length, answer, 0, 0,
+ additional, additional_count);
+ } else {
+ mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
+ additional, additional_count);
+ }
+ }
+ }
+ return 0;
+}
+
+// Callback handling questions and answers dump
+static int
+dump_callback(int sock, const struct sockaddr* from, size_t addrlen, mdns_entry_type_t entry,
+ uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl, const void* data,
+ size_t size, size_t name_offset, size_t name_length, size_t record_offset,
+ size_t record_length, void* user_data) {
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);
+
+ size_t offset = name_offset;
+ mdns_string_t name = mdns_string_extract(data, size, &offset, namebuffer, sizeof(namebuffer));
+
+ const char* record_name = 0;
+ if (rtype == MDNS_RECORDTYPE_PTR)
+ record_name = "PTR";
+ else if (rtype == MDNS_RECORDTYPE_SRV)
+ record_name = "SRV";
+ else if (rtype == MDNS_RECORDTYPE_A)
+ record_name = "A";
+ else if (rtype == MDNS_RECORDTYPE_AAAA)
+ record_name = "AAAA";
+ else if (rtype == MDNS_RECORDTYPE_TXT)
+ record_name = "TXT";
+ else if (rtype == MDNS_RECORDTYPE_ANY)
+ record_name = "ANY";
+ else
+ record_name = "";
+
+ const char* entry_type = "Question";
+ if (entry == MDNS_ENTRYTYPE_ANSWER)
+ entry_type = "Answer";
+ else if (entry == MDNS_ENTRYTYPE_AUTHORITY)
+ entry_type = "Authority";
+ else if (entry == MDNS_ENTRYTYPE_ADDITIONAL)
+ entry_type = "Additional";
+
+ printf("%.*s: %s %s %.*s rclass 0x%x ttl %u\n", MDNS_STRING_FORMAT(fromaddrstr), entry_type,
+ record_name, MDNS_STRING_FORMAT(name), (unsigned int)rclass, ttl);
+
+ return 0;
+}
+
+// Open sockets for sending one-shot multicast queries from an ephemeral port
+static int
+open_client_sockets(int* sockets, int max_sockets, int port) {
+ // When sending, each socket can only send to one network interface
+ // Thus we need to open one socket for each interface and address family
+ int num_sockets = 0;
+
+#ifdef _WIN32
+
+ IP_ADAPTER_ADDRESSES* adapter_address = 0;
+ ULONG address_size = 8000;
+ unsigned int ret;
+ unsigned int num_retries = 4;
+ do {
+ adapter_address = (IP_ADAPTER_ADDRESSES*)malloc(address_size);
+ ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST, 0,
+ adapter_address, &address_size);
+ if (ret == ERROR_BUFFER_OVERFLOW) {
+ free(adapter_address);
+ adapter_address = 0;
+ address_size *= 2;
+ } else {
+ break;
+ }
+ } while (num_retries-- > 0);
+
+ if (!adapter_address || (ret != NO_ERROR)) {
+ free(adapter_address);
+ printf("Failed to get network adapter addresses\n");
+ return num_sockets;
+ }
+
+ int first_ipv4 = 1;
+ int first_ipv6 = 1;
+ for (PIP_ADAPTER_ADDRESSES adapter = adapter_address; adapter; adapter = adapter->Next) {
+ if (adapter->TunnelType == TUNNEL_TYPE_TEREDO)
+ continue;
+ if (adapter->OperStatus != IfOperStatusUp)
+ continue;
+
+ for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast;
+ unicast = unicast->Next) {
+ if (unicast->Address.lpSockaddr->sa_family == AF_INET) {
+ struct sockaddr_in* saddr = (struct sockaddr_in*)unicast->Address.lpSockaddr;
+ if ((saddr->sin_addr.S_un.S_un_b.s_b1 != 127) ||
+ (saddr->sin_addr.S_un.S_un_b.s_b2 != 0) ||
+ (saddr->sin_addr.S_un.S_un_b.s_b3 != 0) ||
+ (saddr->sin_addr.S_un.S_un_b.s_b4 != 1)) {
+ int log_addr = 0;
+ if (first_ipv4) {
+ service_address_ipv4 = *saddr;
+ first_ipv4 = 0;
+ log_addr = 1;
+ }
+ has_ipv4 = 1;
+ if (num_sockets < max_sockets) {
+ saddr->sin_port = htons((unsigned short)port);
+ int sock = mdns_socket_open_ipv4(saddr);
+ if (sock >= 0) {
+ sockets[num_sockets++] = sock;
+ log_addr = 1;
+ } else {
+ log_addr = 0;
+ }
+ }
+ if (log_addr) {
+ char buffer[128];
+ mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), saddr,
+ sizeof(struct sockaddr_in));
+ printf("Local IPv4 address: %.*s\n", MDNS_STRING_FORMAT(addr));
+ }
+ }
+ } else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) {
+ struct sockaddr_in6* saddr = (struct sockaddr_in6*)unicast->Address.lpSockaddr;
+ // Ignore link-local addresses
+ if (saddr->sin6_scope_id)
+ continue;
+ static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1};
+ static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
+ if ((unicast->DadState == NldsPreferred) &&
+ memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
+ memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
+ int log_addr = 0;
+ if (first_ipv6) {
+ service_address_ipv6 = *saddr;
+ first_ipv6 = 0;
+ log_addr = 1;
+ }
+ has_ipv6 = 1;
+ if (num_sockets < max_sockets) {
+ saddr->sin6_port = htons((unsigned short)port);
+ int sock = mdns_socket_open_ipv6(saddr);
+ if (sock >= 0) {
+ sockets[num_sockets++] = sock;
+ log_addr = 1;
+ } else {
+ log_addr = 0;
+ }
+ }
+ if (log_addr) {
+ char buffer[128];
+ mdns_string_t addr = ipv6_address_to_string(buffer, sizeof(buffer), saddr,
+ sizeof(struct sockaddr_in6));
+ printf("Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
+ }
+ }
+ }
+ }
+ }
+
+ free(adapter_address);
+
+#else
+
+ struct ifaddrs* ifaddr = 0;
+ struct ifaddrs* ifa = 0;
+
+ if (getifaddrs(&ifaddr) < 0)
+ printf("Unable to get interface addresses\n");
+
+ int first_ipv4 = 1;
+ int first_ipv6 = 1;
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+ if (!(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST))
+ continue;
+ if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT))
+ continue;
+
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ struct sockaddr_in* saddr = (struct sockaddr_in*)ifa->ifa_addr;
+ if (saddr->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
+ int log_addr = 0;
+ if (first_ipv4) {
+ service_address_ipv4 = *saddr;
+ first_ipv4 = 0;
+ log_addr = 1;
+ }
+ has_ipv4 = 1;
+ if (num_sockets < max_sockets) {
+ saddr->sin_port = htons(port);
+ int sock = mdns_socket_open_ipv4(saddr);
+ if (sock >= 0) {
+ sockets[num_sockets++] = sock;
+ log_addr = 1;
+ } else {
+ log_addr = 0;
+ }
+ }
+ if (log_addr) {
+ char buffer[128];
+ mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), saddr,
+ sizeof(struct sockaddr_in));
+ printf("Local IPv4 address: %.*s\n", MDNS_STRING_FORMAT(addr));
+ }
+ }
+ } else if (ifa->ifa_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6* saddr = (struct sockaddr_in6*)ifa->ifa_addr;
+ // Ignore link-local addresses
+ if (saddr->sin6_scope_id)
+ continue;
+ static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1};
+ static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
+ if (memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
+ memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
+ int log_addr = 0;
+ if (first_ipv6) {
+ service_address_ipv6 = *saddr;
+ first_ipv6 = 0;
+ log_addr = 1;
+ }
+ has_ipv6 = 1;
+ if (num_sockets < max_sockets) {
+ saddr->sin6_port = htons(port);
+ int sock = mdns_socket_open_ipv6(saddr);
+ if (sock >= 0) {
+ sockets[num_sockets++] = sock;
+ log_addr = 1;
+ } else {
+ log_addr = 0;
+ }
+ }
+ if (log_addr) {
+ char buffer[128];
+ mdns_string_t addr = ipv6_address_to_string(buffer, sizeof(buffer), saddr,
+ sizeof(struct sockaddr_in6));
+ printf("Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
+ }
+ }
+ }
+ }
+
+ freeifaddrs(ifaddr);
+
+#endif
+
+ return num_sockets;
+}
+
+// Open sockets to listen to incoming mDNS queries on port 5353
+static int
+open_service_sockets(int* sockets, int max_sockets) {
+ // When recieving, each socket can recieve data from all network interfaces
+ // Thus we only need to open one socket for each address family
+ int num_sockets = 0;
+
+ // Call the client socket function to enumerate and get local addresses,
+ // but not open the actual sockets
+ open_client_sockets(0, 0, 0);
+
+ if (num_sockets < max_sockets) {
+ struct sockaddr_in sock_addr;
+ memset(&sock_addr, 0, sizeof(struct sockaddr_in));
+ sock_addr.sin_family = AF_INET;
+#ifdef _WIN32
+ sock_addr.sin_addr = in4addr_any;
+#else
+ sock_addr.sin_addr.s_addr = INADDR_ANY;
+#endif
+ sock_addr.sin_port = htons(MDNS_PORT);
+#ifdef __APPLE__
+ sock_addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ int sock = mdns_socket_open_ipv4(&sock_addr);
+ if (sock >= 0) {
+ sockets[num_sockets++] = sock;
+ printf("IPv4 socket opened successfully on port %d\n", MDNS_PORT);
+ }
+ else {
+ printf("Failed to open IPv4 socket on port %d\n", MDNS_PORT);
+ }
+ }
+
+ if (num_sockets < max_sockets) {
+ struct sockaddr_in6 sock_addr;
+ memset(&sock_addr, 0, sizeof(struct sockaddr_in6));
+ sock_addr.sin6_family = AF_INET6;
+ sock_addr.sin6_addr = in6addr_any;
+ sock_addr.sin6_port = htons(MDNS_PORT);
+#ifdef __APPLE__
+ sock_addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ int sock = mdns_socket_open_ipv6(&sock_addr);
+ if (sock >= 0){
+ sockets[num_sockets++] = sock;
+ printf("IPv6 socket opened successfully on port %d\n", MDNS_PORT);
+ }
+ else {
+ printf("Failed to open IPv6 socket on port %d\n", MDNS_PORT);
+ }
+ }
+
+ return num_sockets;
+}
+
+// Send a DNS-SD query
+static int
+send_dns_sd(void) {
+ int sockets[32];
+ int num_sockets = open_client_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]), 0);
+ if (num_sockets <= 0) {
+ printf("Failed to open any client sockets\n");
+ return -1;
+ }
+ printf("Opened %d socket%s for DNS-SD\n", num_sockets, num_sockets > 1 ? "s" : "");
+
+ printf("Sending DNS-SD discovery\n");
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (mdns_discovery_send(sockets[isock]))
+ printf("Failed to send DNS-DS discovery: %s\n", strerror(errno));
+ }
+
+ size_t capacity = 2048;
+ void* buffer = malloc(capacity);
+ void* user_data = 0;
+ size_t records;
+
+ // This is a simple implementation that loops for 5 seconds or as long as we get replies
+ int res;
+ printf("Reading DNS-SD replies\n");
+ do {
+ struct timeval timeout;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ int nfds = 0;
+ fd_set readfs;
+ FD_ZERO(&readfs);
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (sockets[isock] >= nfds)
+ nfds = sockets[isock] + 1;
+ FD_SET(sockets[isock], &readfs);
+ }
+
+ records = 0;
+ res = select(nfds, &readfs, 0, 0, &timeout);
+ if (res > 0) {
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (FD_ISSET(sockets[isock], &readfs)) {
+ records += mdns_discovery_recv(sockets[isock], buffer, capacity, query_callback,
+ user_data);
+ }
+ }
+ }
+ } while (res > 0);
+
+ free(buffer);
+
+ for (int isock = 0; isock < num_sockets; ++isock)
+ mdns_socket_close(sockets[isock]);
+ printf("Closed socket%s\n", num_sockets ? "s" : "");
+
+ return 0;
+}
+
+// Send a mDNS query
+static int
+send_mdns_query(mdns_query_t* query, size_t count, void* user_data) {
+ int sockets[32];
+ int query_id[32];
+ int num_sockets = open_client_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]), 0);
+ if (num_sockets <= 0) {
+ printf("Failed to open any client sockets\n");
+ return -1;
+ }
+ printf("Opened %d socket%s for mDNS query\n", num_sockets, num_sockets ? "s" : "");
+
+ size_t capacity = 2048;
+ void* buffer = malloc(capacity);
+ //void* user_data = 0;
+
+ printf("Sending mDNS query");
+ for (size_t iq = 0; iq < count; ++iq) {
+ const char* record_name = "PTR";
+ if (query[iq].type == MDNS_RECORDTYPE_SRV)
+ record_name = "SRV";
+ else if (query[iq].type == MDNS_RECORDTYPE_A)
+ record_name = "A";
+ else if (query[iq].type == MDNS_RECORDTYPE_AAAA)
+ record_name = "AAAA";
+ else
+ query[iq].type = MDNS_RECORDTYPE_PTR;
+ printf(" : %s %s", query[iq].name, record_name);
+ }
+ printf("\n");
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ query_id[isock] =
+ mdns_multiquery_send(sockets[isock], query, count, buffer, capacity, 0);
+ if (query_id[isock] < 0)
+ printf("Failed to send mDNS query: %s\n", strerror(errno));
+ }
+
+ // This is a simple implementation that loops for 5 seconds or as long as we get replies
+ int res;
+ printf("Reading mDNS query replies\n");
+ int records = 0;
+ do {
+ struct timeval timeout;
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 0;
+
+ int nfds = 0;
+ fd_set readfs;
+ FD_ZERO(&readfs);
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (sockets[isock] >= nfds)
+ nfds = sockets[isock] + 1;
+ FD_SET(sockets[isock], &readfs);
+ }
+
+ res = select(nfds, &readfs, 0, 0, &timeout);
+ if (res > 0) {
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (FD_ISSET(sockets[isock], &readfs)) {
+ size_t rec = mdns_query_recv(sockets[isock], buffer, capacity, query_callback,
+ user_data, query_id[isock]);
+ if (rec > 0)
+ records += rec;
+ }
+ FD_SET(sockets[isock], &readfs);
+ }
+ }
+ } while (res > 0);
+
+ printf("Read %d records\n", records);
+
+ free(buffer);
+
+ for (int isock = 0; isock < num_sockets; ++isock)
+ mdns_socket_close(sockets[isock]);
+ printf("Closed socket%s\n", num_sockets ? "s" : "");
+
+ return 0;
+}
+
+// Provide a mDNS service, answering incoming DNS-SD and mDNS queries
+int
+service_mdns(const char* hostname, const char* service_name, int service_port) {
+ int sockets[32];
+ int num_sockets = open_service_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]));
+ if (num_sockets <= 0) {
+ printf("Failed to open any client sockets\n");
+ return -1;
+ }
+ printf("Opened %d socket%s for mDNS service\n", num_sockets, num_sockets ? "s" : "");
+
+ size_t service_name_length = strlen(service_name);
+ if (!service_name_length) {
+ printf("Invalid service name\n");
+ return -1;
+ }
+
+ char* service_name_buffer = malloc(service_name_length + 2);
+ memcpy(service_name_buffer, service_name, service_name_length);
+ if (service_name_buffer[service_name_length - 1] != '.')
+ service_name_buffer[service_name_length++] = '.';
+ service_name_buffer[service_name_length] = 0;
+ service_name = service_name_buffer;
+
+ printf("Service mDNS: %s:%d\n", service_name, service_port);
+ printf("Hostname: %s\n", hostname);
+
+ size_t capacity = 2048;
+ void* buffer = malloc(capacity);
+
+ mdns_string_t service_string = (mdns_string_t){service_name, strlen(service_name)};
+ mdns_string_t hostname_string = (mdns_string_t){hostname, strlen(hostname)};
+
+ // Build the service instance ".<_service-name>._tcp.local." string
+ char service_instance_buffer[256] = {0};
+ snprintf(service_instance_buffer, sizeof(service_instance_buffer) - 1, "%.*s.%.*s",
+ MDNS_STRING_FORMAT(hostname_string), MDNS_STRING_FORMAT(service_string));
+ mdns_string_t service_instance_string =
+ (mdns_string_t){service_instance_buffer, strlen(service_instance_buffer)};
+
+ // Build the ".local." string
+ char qualified_hostname_buffer[256] = {0};
+ snprintf(qualified_hostname_buffer, sizeof(qualified_hostname_buffer) - 1, "%.*s.local.",
+ MDNS_STRING_FORMAT(hostname_string));
+ mdns_string_t hostname_qualified_string =
+ (mdns_string_t){qualified_hostname_buffer, strlen(qualified_hostname_buffer)};
+
+ service_t service = {0};
+ service.service = service_string;
+ service.hostname = hostname_string;
+ service.service_instance = service_instance_string;
+ service.hostname_qualified = hostname_qualified_string;
+ service.address_ipv4 = service_address_ipv4;
+ service.address_ipv6 = service_address_ipv6;
+ service.port = service_port;
+
+ // Setup our mDNS records
+
+ // PTR record reverse mapping "<_service-name>._tcp.local." to
+ // ".<_service-name>._tcp.local."
+ service.record_ptr = (mdns_record_t){.name = service.service,
+ .type = MDNS_RECORDTYPE_PTR,
+ .data.ptr.name = service.service_instance,
+ .rclass = 0,
+ .ttl = 0};
+
+ // SRV record mapping ".<_service-name>._tcp.local." to
+ // ".local." with port. Set weight & priority to 0.
+ service.record_srv = (mdns_record_t){.name = service.service_instance,
+ .type = MDNS_RECORDTYPE_SRV,
+ .data.srv.name = service.hostname_qualified,
+ .data.srv.port = service.port,
+ .data.srv.priority = 0,
+ .data.srv.weight = 0,
+ .rclass = 0,
+ .ttl = 0};
+
+ // A/AAAA records mapping ".local." to IPv4/IPv6 addresses
+ service.record_a = (mdns_record_t){.name = service.hostname_qualified,
+ .type = MDNS_RECORDTYPE_A,
+ .data.a.addr = service.address_ipv4,
+ .rclass = 0,
+ .ttl = 0};
+
+ service.record_aaaa = (mdns_record_t){.name = service.hostname_qualified,
+ .type = MDNS_RECORDTYPE_AAAA,
+ .data.aaaa.addr = service.address_ipv6,
+ .rclass = 0,
+ .ttl = 0};
+
+ // Add two test TXT records for our service instance name, will be coalesced into
+ // one record with both key-value pair strings by the library
+ service.txt_record[0] = (mdns_record_t){.name = service.service_instance,
+ .type = MDNS_RECORDTYPE_TXT,
+ .data.txt.key = {MDNS_STRING_CONST("test")},
+ .data.txt.value = {MDNS_STRING_CONST("1")},
+ .rclass = 0,
+ .ttl = 0};
+ service.txt_record[1] = (mdns_record_t){.name = service.service_instance,
+ .type = MDNS_RECORDTYPE_TXT,
+ .data.txt.key = {MDNS_STRING_CONST("other")},
+ .data.txt.value = {MDNS_STRING_CONST("value")},
+ .rclass = 0,
+ .ttl = 0};
+
+ // Send an announcement on startup of service
+ {
+ printf("Sending announce\n");
+ mdns_record_t additional[5] = {0};
+ size_t additional_count = 0;
+ additional[additional_count++] = service.record_srv;
+ if (service.address_ipv4.sin_family == AF_INET)
+ additional[additional_count++] = service.record_a;
+ if (service.address_ipv6.sin6_family == AF_INET6)
+ additional[additional_count++] = service.record_aaaa;
+ additional[additional_count++] = service.txt_record[0];
+ additional[additional_count++] = service.txt_record[1];
+
+ for (int isock = 0; isock < num_sockets; ++isock)
+ mdns_announce_multicast(sockets[isock], buffer, capacity, service.record_ptr, 0, 0,
+ additional, additional_count);
+ }
+
+ // This is a crude implementation that checks for incoming queries
+ while (running) {
+ int nfds = 0;
+ fd_set readfs;
+ FD_ZERO(&readfs);
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (sockets[isock] >= nfds)
+ nfds = sockets[isock] + 1;
+ FD_SET(sockets[isock], &readfs);
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+
+ if (select(nfds, &readfs, 0, 0, &timeout) >= 0) {
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (FD_ISSET(sockets[isock], &readfs)) {
+ mdns_socket_listen(sockets[isock], buffer, capacity, service_callback,
+ &service);
+ }
+ FD_SET(sockets[isock], &readfs);
+ }
+ } else {
+ break;
+ }
+ }
+
+ // Send a goodbye on end of service
+ {
+ printf("Sending goodbye\n");
+ mdns_record_t additional[5] = {0};
+ size_t additional_count = 0;
+ additional[additional_count++] = service.record_srv;
+ if (service.address_ipv4.sin_family == AF_INET)
+ additional[additional_count++] = service.record_a;
+ if (service.address_ipv6.sin6_family == AF_INET6)
+ additional[additional_count++] = service.record_aaaa;
+ additional[additional_count++] = service.txt_record[0];
+ additional[additional_count++] = service.txt_record[1];
+
+ for (int isock = 0; isock < num_sockets; ++isock)
+ mdns_goodbye_multicast(sockets[isock], buffer, capacity, service.record_ptr, 0, 0,
+ additional, additional_count);
+ }
+
+ free(buffer);
+ free(service_name_buffer);
+
+ for (int isock = 0; isock < num_sockets; ++isock)
+ mdns_socket_close(sockets[isock]);
+ printf("Closed socket%s\n", num_sockets ? "s" : "");
+
+ return 0;
+}
+
+
+// Dump all incoming mDNS queries and answers
+static int
+dump_mdns(void) {
+ int sockets[32];
+ int num_sockets = open_service_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]));
+ if (num_sockets <= 0) {
+ printf("Failed to open any client sockets\n");
+ return -1;
+ }
+ printf("Opened %d socket%s for mDNS dump\n", num_sockets, num_sockets ? "s" : "");
+
+ size_t capacity = 2048;
+ void* buffer = malloc(capacity);
+
+ // This is a crude implementation that checks for incoming queries and answers
+ while (running) {
+ int nfds = 0;
+ fd_set readfs;
+ FD_ZERO(&readfs);
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (sockets[isock] >= nfds)
+ nfds = sockets[isock] + 1;
+ FD_SET(sockets[isock], &readfs);
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+
+ if (select(nfds, &readfs, 0, 0, &timeout) >= 0) {
+ for (int isock = 0; isock < num_sockets; ++isock) {
+ if (FD_ISSET(sockets[isock], &readfs)) {
+ mdns_socket_listen(sockets[isock], buffer, capacity, dump_callback, 0);
+ }
+ FD_SET(sockets[isock], &readfs);
+ }
+ } else {
+ break;
+ }
+ }
+
+ free(buffer);
+
+ for (int isock = 0; isock < num_sockets; ++isock)
+ mdns_socket_close(sockets[isock]);
+ printf("Closed socket%s\n", num_sockets ? "s" : "");
+
+ return 0;
+}
+
+#ifdef MDNS_FUZZING
+
+#undef printf
+
+// Fuzzing by piping random data into the recieve functions
+static void
+fuzz_mdns(void) {
+#define MAX_FUZZ_SIZE 4096
+#define MAX_PASSES (1024 * 1024 * 1024)
+
+ static uint8_t fuzz_mdns_services_query[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, '_',
+ 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', 0x07, '_', 'd', 'n', 's', '-',
+ 's', 'd', 0x04, '_', 'u', 'd', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00};
+
+ uint8_t* buffer = malloc(MAX_FUZZ_SIZE);
+ uint8_t* strbuffer = malloc(MAX_FUZZ_SIZE);
+ for (int ipass = 0; ipass < MAX_PASSES; ++ipass) {
+ size_t size = rand() % MAX_FUZZ_SIZE;
+ for (size_t i = 0; i < size; ++i)
+ buffer[i] = rand() & 0xFF;
+
+ if (ipass % 4) {
+ // Crafted fuzzing, make sure header is reasonable
+ memcpy(buffer, fuzz_mdns_services_query, sizeof(fuzz_mdns_services_query));
+ uint16_t* header = (uint16_t*)buffer;
+ header[0] = 0;
+ header[1] = htons(0x8400);
+ for (int ival = 2; ival < 6; ++ival)
+ header[ival] = rand() & 0xFF;
+ }
+ mdns_discovery_recv(0, (void*)buffer, size, query_callback, 0);
+
+ mdns_socket_listen(0, (void*)buffer, size, service_callback, 0);
+
+ if (ipass % 4) {
+ // Crafted fuzzing, make sure header is reasonable (1 question claimed).
+ // Earlier passes will have done completely random data
+ uint16_t* header = (uint16_t*)buffer;
+ header[2] = htons(1);
+ }
+ mdns_query_recv(0, (void*)buffer, size, query_callback, 0, 0);
+
+ // Fuzzing by piping random data into the parse functions
+ size_t offset = size ? (rand() % size) : 0;
+ size_t length = size ? (rand() % (size - offset)) : 0;
+ mdns_record_parse_ptr(buffer, size, offset, length, strbuffer, MAX_FUZZ_SIZE);
+
+ offset = size ? (rand() % size) : 0;
+ length = size ? (rand() % (size - offset)) : 0;
+ mdns_record_parse_srv(buffer, size, offset, length, strbuffer, MAX_FUZZ_SIZE);
+
+ struct sockaddr_in addr_ipv4;
+ offset = size ? (rand() % size) : 0;
+ length = size ? (rand() % (size - offset)) : 0;
+ mdns_record_parse_a(buffer, size, offset, length, &addr_ipv4);
+
+ struct sockaddr_in6 addr_ipv6;
+ offset = size ? (rand() % size) : 0;
+ length = size ? (rand() % (size - offset)) : 0;
+ mdns_record_parse_aaaa(buffer, size, offset, length, &addr_ipv6);
+
+ offset = size ? (rand() % size) : 0;
+ length = size ? (rand() % (size - offset)) : 0;
+ mdns_record_parse_txt(buffer, size, offset, length, (mdns_record_txt_t*)strbuffer,
+ MAX_FUZZ_SIZE);
+
+ if (ipass && !(ipass % 10000))
+ printf("Completed fuzzing pass %d\n", ipass);
+ }
+
+ free(buffer);
+ free(strbuffer);
+}
+
+#endif
+
+#ifdef _WIN32
+BOOL console_handler(DWORD signal) {
+ if (signal == CTRL_C_EVENT) {
+ running = 0;
+ }
+ return TRUE;
+}
+#else
+void signal_handler(int signal) {
+ running = 0;
+}
+#endif
+
+/*
+int
+main(int argc, const char* const* argv) {
+ int mode = 0;
+ const char* service = "_test-mdns._tcp.local.";
+ const char* hostname = "dummy-host";
+ mdns_query_t query[16];
+ size_t query_count = 0;
+ int service_port = 42424;
+ server_info_t server_info;
+ memset(&server_info, 0, sizeof(server_info_t));
+
+#ifdef _WIN32
+
+ WORD versionWanted = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ if (WSAStartup(versionWanted, &wsaData)) {
+ printf("Failed to initialize WinSock\n");
+ return -1;
+ }
+
+ char hostname_buffer[256];
+ DWORD hostname_size = (DWORD)sizeof(hostname_buffer);
+ if (GetComputerNameA(hostname_buffer, &hostname_size))
+ hostname = hostname_buffer;
+
+ SetConsoleCtrlHandler(console_handler, TRUE);
+#else
+
+ char hostname_buffer[256];
+ size_t hostname_size = sizeof(hostname_buffer);
+ if (gethostname(hostname_buffer, hostname_size) == 0)
+ hostname = hostname_buffer;
+ signal(SIGINT, signal_handler);
+#endif
+
+ for (int iarg = 0; iarg < argc; ++iarg) {
+ if (strcmp(argv[iarg], "--discovery") == 0) {
+ mode = 0;
+ } else if (strcmp(argv[iarg], "--query") == 0) {
+ // Each query is either a service name, or a pair of record type and a service name
+ // For example:
+ // mdns --query _foo._tcp.local.
+ // mdns --query SRV myhost._foo._tcp.local.
+ // mdns --query A myhost._tcp.local. _service._tcp.local.
+ mode = 1;
+ ++iarg;
+ while ((iarg < argc) && (query_count < 16)) {
+ query[query_count].name = argv[iarg++];
+ query[query_count].type = MDNS_RECORDTYPE_PTR;
+ if (iarg < argc) {
+ mdns_record_type_t record_type = 0;
+ if (strcmp(query[query_count].name, "PTR") == 0)
+ record_type = MDNS_RECORDTYPE_PTR;
+ else if (strcmp(query[query_count].name, "SRV") == 0)
+ record_type = MDNS_RECORDTYPE_SRV;
+ else if (strcmp(query[query_count].name, "A") == 0)
+ record_type = MDNS_RECORDTYPE_A;
+ else if (strcmp(query[query_count].name, "AAAA") == 0)
+ record_type = MDNS_RECORDTYPE_AAAA;
+ if (record_type != 0) {
+ query[query_count].type = record_type;
+ query[query_count].name = argv[iarg++];
+ }
+ }
+ query[query_count].length = strlen(query[query_count].name);
+ ++query_count;
+ }
+ } else if (strcmp(argv[iarg], "--service") == 0) {
+ mode = 2;
+ ++iarg;
+ if (iarg < argc)
+ service = argv[iarg];
+ } else if (strcmp(argv[iarg], "--dump") == 0) {
+ mode = 3;
+ } else if (strcmp(argv[iarg], "--hostname") == 0) {
+ ++iarg;
+ if (iarg < argc)
+ hostname = argv[iarg];
+ } else if (strcmp(argv[iarg], "--port") == 0) {
+ ++iarg;
+ if (iarg < argc)
+ service_port = atoi(argv[iarg]);
+ }
+ }
+
+#ifdef MDNS_FUZZING
+ fuzz_mdns();
+#else
+ int ret;
+ if (mode == 0)
+ ret = send_dns_sd();
+ else if (mode == 1)
+ ret = send_mdns_query(query, query_count, &server_info);
+ else if (mode == 2)
+ ret = service_mdns(hostname, service, service_port);
+ else if (mode == 3)
+ ret = dump_mdns();
+#endif
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ printf("ip %s, port %d, domain %s\n", server_info.ip, server_info.port, server_info.domain);
+ return 0;
+}
+*/
diff --git a/FactoryTestTool/SourceCode/Network/mdns/mdns.h b/FactoryTestTool/SourceCode/Network/mdns/mdns.h
new file mode 100644
index 0000000..d2ddf7e
--- /dev/null
+++ b/FactoryTestTool/SourceCode/Network/mdns/mdns.h
@@ -0,0 +1,1626 @@
+/* mdns.h - mDNS/DNS-SD library - Public Domain - 2017 Mattias Jansson
+ *
+ * This library provides a cross-platform mDNS and DNS-SD library in C.
+ * The implementation is based on RFC 6762 and RFC 6763.
+ *
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/mdns
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any
+ * restrictions.
+ *
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include
+#ifdef _WIN32
+#include
+#include
+#define strncasecmp _strnicmp
+#else
+#include
+#include
+#include
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MDNS_INVALID_POS ((size_t)-1)
+
+#define MDNS_STRING_CONST(s) (s), (sizeof((s)) - 1)
+#define MDNS_STRING_ARGS(s) s.str, s.length
+#define MDNS_STRING_FORMAT(s) (int)((s).length), s.str
+
+#define MDNS_POINTER_OFFSET(p, ofs) ((void*)((char*)(p) + (ptrdiff_t)(ofs)))
+#define MDNS_POINTER_OFFSET_CONST(p, ofs) ((const void*)((const char*)(p) + (ptrdiff_t)(ofs)))
+#define MDNS_POINTER_DIFF(a, b) ((size_t)((const char*)(a) - (const char*)(b)))
+
+#define MDNS_PORT 5353
+#define MDNS_UNICAST_RESPONSE 0x8000U
+#define MDNS_CACHE_FLUSH 0x8000U
+#define MDNS_MAX_SUBSTRINGS 64
+
+enum mdns_record_type {
+ MDNS_RECORDTYPE_IGNORE = 0,
+ // Address
+ MDNS_RECORDTYPE_A = 1,
+ // Domain Name pointer
+ MDNS_RECORDTYPE_PTR = 12,
+ // Arbitrary text string
+ MDNS_RECORDTYPE_TXT = 16,
+ // IP6 Address [Thomson]
+ MDNS_RECORDTYPE_AAAA = 28,
+ // Server Selection [RFC2782]
+ MDNS_RECORDTYPE_SRV = 33,
+ // Any available records
+ MDNS_RECORDTYPE_ANY = 255
+};
+
+enum mdns_entry_type {
+ MDNS_ENTRYTYPE_QUESTION = 0,
+ MDNS_ENTRYTYPE_ANSWER = 1,
+ MDNS_ENTRYTYPE_AUTHORITY = 2,
+ MDNS_ENTRYTYPE_ADDITIONAL = 3
+};
+
+enum mdns_class { MDNS_CLASS_IN = 1, MDNS_CLASS_ANY = 255 };
+
+typedef enum mdns_record_type mdns_record_type_t;
+typedef enum mdns_entry_type mdns_entry_type_t;
+typedef enum mdns_class mdns_class_t;
+
+typedef int (*mdns_record_callback_fn)(int sock, const struct sockaddr* from, size_t addrlen,
+ mdns_entry_type_t entry, uint16_t query_id, uint16_t rtype,
+ uint16_t rclass, uint32_t ttl, const void* data, size_t size,
+ size_t name_offset, size_t name_length, size_t record_offset,
+ size_t record_length, void* user_data);
+
+typedef struct mdns_string_t mdns_string_t;
+typedef struct mdns_string_pair_t mdns_string_pair_t;
+typedef struct mdns_string_table_item_t mdns_string_table_item_t;
+typedef struct mdns_string_table_t mdns_string_table_t;
+typedef struct mdns_record_t mdns_record_t;
+typedef struct mdns_record_srv_t mdns_record_srv_t;
+typedef struct mdns_record_ptr_t mdns_record_ptr_t;
+typedef struct mdns_record_a_t mdns_record_a_t;
+typedef struct mdns_record_aaaa_t mdns_record_aaaa_t;
+typedef struct mdns_record_txt_t mdns_record_txt_t;
+typedef struct mdns_query_t mdns_query_t;
+
+extern volatile sig_atomic_t running; // 声明全局变量
+
+#ifdef _WIN32
+typedef int mdns_size_t;
+typedef int mdns_ssize_t;
+#else
+typedef size_t mdns_size_t;
+typedef ssize_t mdns_ssize_t;
+#endif
+
+struct mdns_string_t {
+ const char* str;
+ size_t length;
+};
+
+struct mdns_string_pair_t {
+ size_t offset;
+ size_t length;
+ int ref;
+};
+
+struct mdns_string_table_t {
+ size_t offset[16];
+ size_t count;
+ size_t next;
+};
+
+struct mdns_record_srv_t {
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ mdns_string_t name;
+};
+
+struct mdns_record_ptr_t {
+ mdns_string_t name;
+};
+
+struct mdns_record_a_t {
+ struct sockaddr_in addr;
+};
+
+struct mdns_record_aaaa_t {
+ struct sockaddr_in6 addr;
+};
+
+struct mdns_record_txt_t {
+ mdns_string_t key;
+ mdns_string_t value;
+};
+
+struct mdns_record_t {
+ mdns_string_t name;
+ mdns_record_type_t type;
+ union mdns_record_data {
+ mdns_record_ptr_t ptr;
+ mdns_record_srv_t srv;
+ mdns_record_a_t a;
+ mdns_record_aaaa_t aaaa;
+ mdns_record_txt_t txt;
+ } data;
+ uint16_t rclass;
+ uint32_t ttl;
+};
+
+struct mdns_header_t {
+ uint16_t query_id;
+ uint16_t flags;
+ uint16_t questions;
+ uint16_t answer_rrs;
+ uint16_t authority_rrs;
+ uint16_t additional_rrs;
+};
+
+struct mdns_query_t {
+ mdns_record_type_t type;
+ const char* name;
+ size_t length;
+};
+
+int
+service_mdns(const char* hostname, const char* service_name, int service_port);
+
+// mDNS/DNS-SD public API
+
+//! Open and setup a IPv4 socket for mDNS/DNS-SD. To bind the socket to a specific interface, pass
+//! in the appropriate socket address in saddr, otherwise pass a null pointer for INADDR_ANY. To
+//! send one-shot discovery requests and queries pass a null pointer or set 0 as port to assign a
+//! random user level ephemeral port. To run discovery service listening for incoming discoveries
+//! and queries, you must set MDNS_PORT as port.
+static inline int
+mdns_socket_open_ipv4(const struct sockaddr_in* saddr);
+
+//! Setup an already opened IPv4 socket for mDNS/DNS-SD. To bind the socket to a specific interface,
+//! pass in the appropriate socket address in saddr, otherwise pass a null pointer for INADDR_ANY.
+//! To send one-shot discovery requests and queries pass a null pointer or set 0 as port to assign a
+//! random user level ephemeral port. To run discovery service listening for incoming discoveries
+//! and queries, you must set MDNS_PORT as port.
+static inline int
+mdns_socket_setup_ipv4(int sock, const struct sockaddr_in* saddr);
+
+//! Open and setup a IPv6 socket for mDNS/DNS-SD. To bind the socket to a specific interface, pass
+//! in the appropriate socket address in saddr, otherwise pass a null pointer for in6addr_any. To
+//! send one-shot discovery requests and queries pass a null pointer or set 0 as port to assign a
+//! random user level ephemeral port. To run discovery service listening for incoming discoveries
+//! and queries, you must set MDNS_PORT as port.
+static inline int
+mdns_socket_open_ipv6(const struct sockaddr_in6* saddr);
+
+//! Setup an already opened IPv6 socket for mDNS/DNS-SD. To bind the socket to a specific interface,
+//! pass in the appropriate socket address in saddr, otherwise pass a null pointer for in6addr_any.
+//! To send one-shot discovery requests and queries pass a null pointer or set 0 as port to assign a
+//! random user level ephemeral port. To run discovery service listening for incoming discoveries
+//! and queries, you must set MDNS_PORT as port.
+static inline int
+mdns_socket_setup_ipv6(int sock, const struct sockaddr_in6* saddr);
+
+//! Close a socket opened with mdns_socket_open_ipv4 and mdns_socket_open_ipv6.
+static inline void
+mdns_socket_close(int sock);
+
+//! Listen for incoming multicast DNS-SD and mDNS query requests. The socket should have been opened
+//! on port MDNS_PORT using one of the mdns open or setup socket functions. Buffer must be 32 bit
+//! aligned. Parsing is stopped when callback function returns non-zero. Returns the number of
+//! queries parsed.
+static inline size_t
+mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+ void* user_data);
+
+//! Send a multicast DNS-SD reqeuest on the given socket to discover available services. Returns 0
+//! on success, or <0 if error.
+static inline int
+mdns_discovery_send(int sock);
+
+//! Recieve unicast responses to a DNS-SD sent with mdns_discovery_send. Any data will be piped to
+//! the given callback for parsing. Buffer must be 32 bit aligned. Parsing is stopped when callback
+//! function returns non-zero. Returns the number of responses parsed.
+static inline size_t
+mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+ void* user_data);
+
+//! Send a multicast mDNS query on the given socket for the given service name. The supplied buffer
+//! will be used to build the query packet and must be 32 bit aligned. The query ID can be set to
+//! non-zero to filter responses, however the RFC states that the query ID SHOULD be set to 0 for
+//! multicast queries. The query will request a unicast response if the socket is bound to an
+//! ephemeral port, or a multicast response if the socket is bound to mDNS port 5353. Returns the
+//! used query ID, or <0 if error.
+static inline int
+mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,
+ size_t capacity, uint16_t query_id);
+
+//! Send a multicast mDNS query on the given socket for the given service names. The supplied buffer
+//! will be used to build the query packet and must be 32 bit aligned. The query ID can be set to
+//! non-zero to filter responses, however the RFC states that the query ID SHOULD be set to 0 for
+//! multicast queries. Each additional service name query consists of a triplet - a record type
+//! (mdns_record_type_t), a name string pointer (const char*) and a name length (size_t). The list
+//! of variable arguments should be terminated with a record type of 0. The query will request a
+//! unicast response if the socket is bound to an ephemeral port, or a multicast response if the
+//! socket is bound to mDNS port 5353. Returns the used query ID, or <0 if error.
+static inline int
+mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* buffer,
+ size_t capacity, uint16_t query_id);
+
+//! Receive unicast responses to a mDNS query sent with mdns_[multi]query_send, optionally filtering
+//! out any responses not matching the given query ID. Set the query ID to 0 to parse all responses,
+//! even if it is not matching the query ID set in a specific query. Any data will be piped to the
+//! given callback for parsing. Buffer must be 32 bit aligned. Parsing is stopped when callback
+//! function returns non-zero. Returns the number of responses parsed.
+static inline size_t
+mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+ void* user_data, int query_id);
+
+//! Send a variable unicast mDNS query answer to any question with variable number of records to the
+//! given address. Use the top bit of the query class field (MDNS_UNICAST_RESPONSE) in the query
+//! recieved to determine if the answer should be sent unicast (bit set) or multicast (bit not set).
+//! Buffer must be 32 bit aligned. The record type and name should match the data from the query
+//! recieved. Returns 0 if success, or <0 if error.
+static inline int
+mdns_query_answer_unicast(int sock, const void* address, size_t address_size, void* buffer,
+ size_t capacity, uint16_t query_id, mdns_record_type_t record_type,
+ const char* name, size_t name_length, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count);
+
+//! Send a variable multicast mDNS query answer to any question with variable number of records. Use
+//! the top bit of the query class field (MDNS_UNICAST_RESPONSE) in the query recieved to determine
+//! if the answer should be sent unicast (bit set) or multicast (bit not set). Buffer must be 32 bit
+//! aligned. Returns 0 if success, or <0 if error.
+static inline int
+mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count);
+
+//! Send a variable multicast mDNS announcement (as an unsolicited answer) with variable number of
+//! records.Buffer must be 32 bit aligned. Returns 0 if success, or <0 if error. Use this on service
+//! startup to announce your instance to the local network.
+static inline int
+mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count);
+
+//! Send a variable multicast mDNS announcement. Use this on service end for removing the resource
+//! from the local network. The records must be identical to the according announcement.
+static inline int
+mdns_goodbye_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count);
+
+// Parse records functions
+
+//! Parse a PTR record, returns the name in the record
+static inline mdns_string_t
+mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity);
+
+//! Parse a SRV record, returns the priority, weight, port and name in the record
+static inline mdns_record_srv_t
+mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity);
+
+//! Parse an A record, returns the IPv4 address in the record
+static inline struct sockaddr_in*
+mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in* addr);
+
+//! Parse an AAAA record, returns the IPv6 address in the record
+static inline struct sockaddr_in6*
+mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in6* addr);
+
+//! Parse a TXT record, returns the number of key=value records parsed and stores the key-value
+//! pairs in the supplied buffer
+static inline size_t
+mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,
+ mdns_record_txt_t* records, size_t capacity);
+
+// Internal functions
+
+static inline mdns_string_t
+mdns_string_extract(const void* buffer, size_t size, size_t* offset, char* str, size_t capacity);
+
+static inline int
+mdns_string_skip(const void* buffer, size_t size, size_t* offset);
+
+static inline size_t
+mdns_string_find(const char* str, size_t length, char c, size_t offset);
+
+//! Compare if two strings are equal. If the strings are equal it returns >0 and the offset variables are
+//! updated to the end of the corresponding strings. If the strings are not equal it returns 0 and
+//! the offset variables are NOT updated.
+static inline int
+mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs, const void* buffer_rhs,
+ size_t size_rhs, size_t* ofs_rhs);
+
+static inline void*
+mdns_string_make(void* buffer, size_t capacity, void* data, const char* name, size_t length,
+ mdns_string_table_t* string_table);
+
+static inline size_t
+mdns_string_table_find(mdns_string_table_t* string_table, const void* buffer, size_t capacity,
+ const char* str, size_t first_length, size_t total_length);
+
+// Implementations
+
+static inline uint16_t
+mdns_ntohs(const void* data) {
+ uint16_t aligned;
+ memcpy(&aligned, data, sizeof(uint16_t));
+ return ntohs(aligned);
+}
+
+static inline uint32_t
+mdns_ntohl(const void* data) {
+ uint32_t aligned;
+ memcpy(&aligned, data, sizeof(uint32_t));
+ return ntohl(aligned);
+}
+
+static inline void*
+mdns_htons(void* data, uint16_t val) {
+ val = htons(val);
+ memcpy(data, &val, sizeof(uint16_t));
+ return MDNS_POINTER_OFFSET(data, sizeof(uint16_t));
+}
+
+static inline void*
+mdns_htonl(void* data, uint32_t val) {
+ val = htonl(val);
+ memcpy(data, &val, sizeof(uint32_t));
+ return MDNS_POINTER_OFFSET(data, sizeof(uint32_t));
+}
+
+static inline int
+mdns_socket_open_ipv4(const struct sockaddr_in* saddr) {
+ int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return -1;
+ if (mdns_socket_setup_ipv4(sock, saddr)) {
+ mdns_socket_close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+static inline int
+mdns_socket_setup_ipv4(int sock, const struct sockaddr_in* saddr) {
+ unsigned char ttl = 1;
+ unsigned char loopback = 1;
+ unsigned int reuseaddr = 1;
+ struct ip_mreq req;
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr));
+#ifdef SO_REUSEPORT
+ setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuseaddr, sizeof(reuseaddr));
+#endif
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl));
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback));
+
+ memset(&req, 0, sizeof(req));
+ req.imr_multiaddr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ if (saddr)
+ req.imr_interface = saddr->sin_addr;
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&req, sizeof(req)))
+ return -1;
+
+ struct sockaddr_in sock_addr;
+ if (!saddr) {
+ memset(&sock_addr, 0, sizeof(struct sockaddr_in));
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_addr.s_addr = INADDR_ANY;
+#ifdef __APPLE__
+ sock_addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ } else {
+ memcpy(&sock_addr, saddr, sizeof(struct sockaddr_in));
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&sock_addr.sin_addr,
+ sizeof(sock_addr.sin_addr));
+#ifndef _WIN32
+ sock_addr.sin_addr.s_addr = INADDR_ANY;
+#endif
+ }
+
+ if (bind(sock, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr_in)))
+ return -1;
+
+#ifdef _WIN32
+ unsigned long param = 1;
+ ioctlsocket(sock, FIONBIO, ¶m);
+#else
+ const int flags = fcntl(sock, F_GETFL, 0);
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#endif
+
+ return 0;
+}
+
+static inline int
+mdns_socket_open_ipv6(const struct sockaddr_in6* saddr) {
+ int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return -1;
+ if (mdns_socket_setup_ipv6(sock, saddr)) {
+ mdns_socket_close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+static inline int
+mdns_socket_setup_ipv6(int sock, const struct sockaddr_in6* saddr) {
+ int hops = 1;
+ unsigned int loopback = 1;
+ unsigned int reuseaddr = 1;
+ struct ipv6_mreq req;
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr));
+#ifdef SO_REUSEPORT
+ setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuseaddr, sizeof(reuseaddr));
+#endif
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&hops, sizeof(hops));
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback));
+
+ memset(&req, 0, sizeof(req));
+ req.ipv6mr_multiaddr.s6_addr[0] = 0xFF;
+ req.ipv6mr_multiaddr.s6_addr[1] = 0x02;
+ req.ipv6mr_multiaddr.s6_addr[15] = 0xFB;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&req, sizeof(req)))
+ return -1;
+
+ struct sockaddr_in6 sock_addr;
+ if (!saddr) {
+ memset(&sock_addr, 0, sizeof(struct sockaddr_in6));
+ sock_addr.sin6_family = AF_INET6;
+ sock_addr.sin6_addr = in6addr_any;
+#ifdef __APPLE__
+ sock_addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ } else {
+ memcpy(&sock_addr, saddr, sizeof(struct sockaddr_in6));
+ unsigned int ifindex = 0;
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char*)&ifindex, sizeof(ifindex));
+#ifndef _WIN32
+ sock_addr.sin6_addr = in6addr_any;
+#endif
+ }
+
+ if (bind(sock, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr_in6)))
+ return -1;
+
+#ifdef _WIN32
+ unsigned long param = 1;
+ ioctlsocket(sock, FIONBIO, ¶m);
+#else
+ const int flags = fcntl(sock, F_GETFL, 0);
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#endif
+
+ return 0;
+}
+
+static inline void
+mdns_socket_close(int sock) {
+#ifdef _WIN32
+ closesocket(sock);
+#else
+ close(sock);
+#endif
+}
+
+static inline int
+mdns_is_string_ref(uint8_t val) {
+ return (0xC0 == (val & 0xC0));
+}
+
+static inline mdns_string_pair_t
+mdns_get_next_substring(const void* rawdata, size_t size, size_t offset) {
+ const uint8_t* buffer = (const uint8_t*)rawdata;
+ mdns_string_pair_t pair = {MDNS_INVALID_POS, 0, 0};
+ if (offset >= size)
+ return pair;
+ if (!buffer[offset]) {
+ pair.offset = offset;
+ return pair;
+ }
+ int recursion = 0;
+ while (mdns_is_string_ref(buffer[offset])) {
+ if (size < offset + 2)
+ return pair;
+
+ offset = mdns_ntohs(MDNS_POINTER_OFFSET(buffer, offset)) & 0x3fff;
+ if (offset >= size)
+ return pair;
+
+ pair.ref = 1;
+ if (++recursion > 16)
+ return pair;
+ }
+
+ size_t length = (size_t)buffer[offset++];
+ if (size < offset + length)
+ return pair;
+
+ pair.offset = offset;
+ pair.length = length;
+
+ return pair;
+}
+
+static inline int
+mdns_string_skip(const void* buffer, size_t size, size_t* offset) {
+ size_t cur = *offset;
+ mdns_string_pair_t substr;
+ unsigned int counter = 0;
+ do {
+ substr = mdns_get_next_substring(buffer, size, cur);
+ if ((substr.offset == MDNS_INVALID_POS) || (counter++ > MDNS_MAX_SUBSTRINGS))
+ return 0;
+ if (substr.ref) {
+ *offset = cur + 2;
+ return 1;
+ }
+ cur = substr.offset + substr.length;
+ } while (substr.length);
+
+ *offset = cur + 1;
+ return 1;
+}
+
+static inline int
+mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs, const void* buffer_rhs,
+ size_t size_rhs, size_t* ofs_rhs) {
+ size_t lhs_cur = *ofs_lhs;
+ size_t rhs_cur = *ofs_rhs;
+ size_t lhs_end = MDNS_INVALID_POS;
+ size_t rhs_end = MDNS_INVALID_POS;
+ mdns_string_pair_t lhs_substr;
+ mdns_string_pair_t rhs_substr;
+ unsigned int counter = 0;
+ do {
+ lhs_substr = mdns_get_next_substring(buffer_lhs, size_lhs, lhs_cur);
+ rhs_substr = mdns_get_next_substring(buffer_rhs, size_rhs, rhs_cur);
+ if ((lhs_substr.offset == MDNS_INVALID_POS) || (rhs_substr.offset == MDNS_INVALID_POS) ||
+ (counter++ > MDNS_MAX_SUBSTRINGS))
+ return 0;
+ if (lhs_substr.length != rhs_substr.length)
+ return 0;
+ if (strncasecmp((const char*)MDNS_POINTER_OFFSET_CONST(buffer_rhs, rhs_substr.offset),
+ (const char*)MDNS_POINTER_OFFSET_CONST(buffer_lhs, lhs_substr.offset),
+ rhs_substr.length))
+ return 0;
+ if (lhs_substr.ref && (lhs_end == MDNS_INVALID_POS))
+ lhs_end = lhs_cur + 2;
+ if (rhs_substr.ref && (rhs_end == MDNS_INVALID_POS))
+ rhs_end = rhs_cur + 2;
+ lhs_cur = lhs_substr.offset + lhs_substr.length;
+ rhs_cur = rhs_substr.offset + rhs_substr.length;
+ } while (lhs_substr.length);
+
+ if (lhs_end == MDNS_INVALID_POS)
+ lhs_end = lhs_cur + 1;
+ *ofs_lhs = lhs_end;
+
+ if (rhs_end == MDNS_INVALID_POS)
+ rhs_end = rhs_cur + 1;
+ *ofs_rhs = rhs_end;
+
+ return 1;
+}
+
+static inline mdns_string_t
+mdns_string_extract(const void* buffer, size_t size, size_t* offset, char* str, size_t capacity) {
+ size_t cur = *offset;
+ size_t end = MDNS_INVALID_POS;
+ mdns_string_pair_t substr;
+ mdns_string_t result;
+ result.str = str;
+ result.length = 0;
+ char* dst = str;
+ unsigned int counter = 0;
+ size_t remain = capacity;
+ do {
+ substr = mdns_get_next_substring(buffer, size, cur);
+ if ((substr.offset == MDNS_INVALID_POS) || (counter++ > MDNS_MAX_SUBSTRINGS))
+ return result;
+ if (substr.ref && (end == MDNS_INVALID_POS))
+ end = cur + 2;
+ if (substr.length) {
+ size_t to_copy = (substr.length < remain) ? substr.length : remain;
+ memcpy(dst, (const char*)buffer + substr.offset, to_copy);
+ dst += to_copy;
+ remain -= to_copy;
+ if (remain) {
+ *dst++ = '.';
+ --remain;
+ }
+ }
+ cur = substr.offset + substr.length;
+ } while (substr.length);
+
+ if (end == MDNS_INVALID_POS)
+ end = cur + 1;
+ *offset = end;
+
+ result.length = capacity - remain;
+ return result;
+}
+
+static inline size_t
+mdns_string_table_find(mdns_string_table_t* string_table, const void* buffer, size_t capacity,
+ const char* str, size_t first_length, size_t total_length) {
+ if (!string_table)
+ return MDNS_INVALID_POS;
+
+ for (size_t istr = 0; istr < string_table->count; ++istr) {
+ if (string_table->offset[istr] >= capacity)
+ continue;
+ size_t offset = 0;
+ mdns_string_pair_t sub_string =
+ mdns_get_next_substring(buffer, capacity, string_table->offset[istr]);
+ if (!sub_string.length || (sub_string.length != first_length))
+ continue;
+ if (memcmp(str, MDNS_POINTER_OFFSET(buffer, sub_string.offset), sub_string.length))
+ continue;
+
+ // Initial substring matches, now match all remaining substrings
+ offset += first_length + 1;
+ while (offset < total_length) {
+ size_t dot_pos = mdns_string_find(str, total_length, '.', offset);
+ if (dot_pos == MDNS_INVALID_POS)
+ dot_pos = total_length;
+ size_t current_length = dot_pos - offset;
+
+ sub_string =
+ mdns_get_next_substring(buffer, capacity, sub_string.offset + sub_string.length);
+ if (!sub_string.length || (sub_string.length != current_length))
+ break;
+ if (memcmp(str + offset, MDNS_POINTER_OFFSET(buffer, sub_string.offset),
+ sub_string.length))
+ break;
+
+ offset = dot_pos + 1;
+ }
+
+ // Return reference offset if entire string matches
+ if (offset >= total_length)
+ return string_table->offset[istr];
+ }
+
+ return MDNS_INVALID_POS;
+}
+
+static inline void
+mdns_string_table_add(mdns_string_table_t* string_table, size_t offset) {
+ if (!string_table)
+ return;
+
+ string_table->offset[string_table->next] = offset;
+
+ size_t table_capacity = sizeof(string_table->offset) / sizeof(string_table->offset[0]);
+ if (++string_table->count > table_capacity)
+ string_table->count = table_capacity;
+ if (++string_table->next >= table_capacity)
+ string_table->next = 0;
+}
+
+static inline size_t
+mdns_string_find(const char* str, size_t length, char c, size_t offset) {
+ const void* found;
+ if (offset >= length)
+ return MDNS_INVALID_POS;
+ found = memchr(str + offset, c, length - offset);
+ if (found)
+ return (size_t)MDNS_POINTER_DIFF(found, str);
+ return MDNS_INVALID_POS;
+}
+
+static inline void*
+mdns_string_make_ref(void* data, size_t capacity, size_t ref_offset) {
+ if (capacity < 2)
+ return 0;
+ return mdns_htons(data, 0xC000 | (uint16_t)ref_offset);
+}
+
+static inline void*
+mdns_string_make(void* buffer, size_t capacity, void* data, const char* name, size_t length,
+ mdns_string_table_t* string_table) {
+ size_t last_pos = 0;
+ size_t remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ if (name[length - 1] == '.')
+ --length;
+ while (last_pos < length) {
+ size_t pos = mdns_string_find(name, length, '.', last_pos);
+ size_t sub_length = ((pos != MDNS_INVALID_POS) ? pos : length) - last_pos;
+ size_t total_length = length - last_pos;
+
+ size_t ref_offset =
+ mdns_string_table_find(string_table, buffer, capacity,
+ (char*)MDNS_POINTER_OFFSET(name, last_pos), sub_length,
+ total_length);
+ if (ref_offset != MDNS_INVALID_POS)
+ return mdns_string_make_ref(data, remain, ref_offset);
+
+ if (remain <= (sub_length + 1))
+ return 0;
+
+ *(unsigned char*)data = (unsigned char)sub_length;
+ memcpy(MDNS_POINTER_OFFSET(data, 1), name + last_pos, sub_length);
+ mdns_string_table_add(string_table, MDNS_POINTER_DIFF(data, buffer));
+
+ data = MDNS_POINTER_OFFSET(data, sub_length + 1);
+ last_pos = ((pos != MDNS_INVALID_POS) ? pos + 1 : length);
+ remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ }
+
+ if (!remain)
+ return 0;
+
+ *(unsigned char*)data = 0;
+ return MDNS_POINTER_OFFSET(data, 1);
+}
+
+static inline size_t
+mdns_records_parse(int sock, const struct sockaddr* from, size_t addrlen, const void* buffer,
+ size_t size, size_t* offset, mdns_entry_type_t type, uint16_t query_id,
+ size_t records, mdns_record_callback_fn callback, void* user_data) {
+ size_t parsed = 0;
+ for (size_t i = 0; i < records; ++i) {
+ size_t name_offset = *offset;
+ mdns_string_skip(buffer, size, offset);
+ if (((*offset) + 10) > size)
+ return parsed;
+ size_t name_length = (*offset) - name_offset;
+ const uint16_t* data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, *offset);
+
+ uint16_t rtype = mdns_ntohs(data++);
+ uint16_t rclass = mdns_ntohs(data++);
+ uint32_t ttl = mdns_ntohl(data);
+ data += 2;
+ uint16_t length = mdns_ntohs(data++);
+
+ *offset += 10;
+
+ if (length <= (size - (*offset))) {
+ ++parsed;
+ if (callback &&
+ callback(sock, from, addrlen, type, query_id, rtype, rclass, ttl, buffer, size,
+ name_offset, name_length, *offset, length, user_data))
+ break;
+ }
+
+ *offset += length;
+ }
+ return parsed;
+}
+
+static inline int
+mdns_unicast_send(int sock, const void* address, size_t address_size, const void* buffer,
+ size_t size) {
+ if (sendto(sock, (const char*)buffer, (mdns_size_t)size, 0, (const struct sockaddr*)address,
+ (socklen_t)address_size) < 0)
+ return -1;
+ return 0;
+}
+
+static inline int
+mdns_multicast_send(int sock, const void* buffer, size_t size) {
+ struct sockaddr_storage addr_storage;
+ struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+ struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
+ socklen_t saddrlen = sizeof(struct sockaddr_storage);
+ if (getsockname(sock, saddr, &saddrlen))
+ return -1;
+ if (saddr->sa_family == AF_INET6) {
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr6.sin6_len = sizeof(addr6);
+#endif
+ addr6.sin6_addr.s6_addr[0] = 0xFF;
+ addr6.sin6_addr.s6_addr[1] = 0x02;
+ addr6.sin6_addr.s6_addr[15] = 0xFB;
+ addr6.sin6_port = htons((unsigned short)MDNS_PORT);
+ saddr = (struct sockaddr*)&addr6;
+ saddrlen = sizeof(addr6);
+ } else {
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+#ifdef __APPLE__
+ addr.sin_len = sizeof(addr);
+#endif
+ addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ addr.sin_port = htons((unsigned short)MDNS_PORT);
+ saddr = (struct sockaddr*)&addr;
+ saddrlen = sizeof(addr);
+ }
+
+ if (sendto(sock, (const char*)buffer, (mdns_size_t)size, 0, saddr, saddrlen) < 0)
+ return -1;
+ return 0;
+}
+
+static const uint8_t mdns_services_query[] = {
+ // Query ID
+ 0x00, 0x00,
+ // Flags
+ 0x00, 0x00,
+ // 1 question
+ 0x00, 0x01,
+ // No answer, authority or additional RRs
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // _services._dns-sd._udp.local.
+ 0x09, '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', 0x07, '_', 'd', 'n', 's', '-', 's', 'd',
+ 0x04, '_', 'u', 'd', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
+ // PTR record
+ 0x00, MDNS_RECORDTYPE_PTR,
+ // QU (unicast response) and class IN
+ 0x80, MDNS_CLASS_IN};
+
+static inline int
+mdns_discovery_send(int sock) {
+ return mdns_multicast_send(sock, mdns_services_query, sizeof(mdns_services_query));
+}
+
+static inline size_t
+mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+ void* user_data) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ socklen_t addrlen = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ size_t records = 0;
+ const uint16_t* data = (uint16_t*)buffer;
+
+ uint16_t query_id = mdns_ntohs(data++);
+ uint16_t flags = mdns_ntohs(data++);
+ uint16_t questions = mdns_ntohs(data++);
+ uint16_t answer_rrs = mdns_ntohs(data++);
+ uint16_t authority_rrs = mdns_ntohs(data++);
+ uint16_t additional_rrs = mdns_ntohs(data++);
+
+ // According to RFC 6762 the query ID MUST match the sent query ID (which is 0 in our case)
+ if (query_id || (flags != 0x8400))
+ return 0; // Not a reply to our question
+
+ // It seems some implementations do not fill the correct questions field,
+ // so ignore this check for now and only validate answer string
+ // if (questions != 1)
+ // return 0;
+
+ int i;
+ for (i = 0; i < questions; ++i) {
+ size_t offset = MDNS_POINTER_DIFF(data, buffer);
+ size_t verify_offset = 12;
+ // Verify it's our question, _services._dns-sd._udp.local.
+ if (!mdns_string_equal(buffer, data_size, &offset, mdns_services_query,
+ sizeof(mdns_services_query), &verify_offset))
+ return 0;
+ data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, offset);
+
+ uint16_t rtype = mdns_ntohs(data++);
+ uint16_t rclass = mdns_ntohs(data++);
+
+ // Make sure we get a reply based on our PTR question for class IN
+ if ((rtype != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN))
+ return 0;
+ }
+
+ for (i = 0; i < answer_rrs; ++i) {
+ size_t offset = MDNS_POINTER_DIFF(data, buffer);
+ size_t verify_offset = 12;
+ // Verify it's an answer to our question, _services._dns-sd._udp.local.
+ size_t name_offset = offset;
+ int is_answer = mdns_string_equal(buffer, data_size, &offset, mdns_services_query,
+ sizeof(mdns_services_query), &verify_offset);
+ if (!is_answer && !mdns_string_skip(buffer, data_size, &offset))
+ break;
+ size_t name_length = offset - name_offset;
+ if ((offset + 10) > data_size)
+ return records;
+ data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, offset);
+
+ uint16_t rtype = mdns_ntohs(data++);
+ uint16_t rclass = mdns_ntohs(data++);
+ uint32_t ttl = mdns_ntohl(data);
+ data += 2;
+ uint16_t length = mdns_ntohs(data++);
+ if (length > (data_size - offset))
+ return 0;
+
+ if (is_answer) {
+ ++records;
+ offset = MDNS_POINTER_DIFF(data, buffer);
+ if (callback &&
+ callback(sock, saddr, addrlen, MDNS_ENTRYTYPE_ANSWER, query_id, rtype, rclass, ttl,
+ buffer, data_size, name_offset, name_length, offset, length, user_data))
+ return records;
+ }
+ data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(data, length);
+ }
+
+ size_t total_records = records;
+ size_t offset = MDNS_POINTER_DIFF(data, buffer);
+ records =
+ mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, query_id, authority_rrs, callback, user_data);
+ total_records += records;
+ if (records != authority_rrs)
+ return total_records;
+
+ records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, query_id, additional_rrs, callback,
+ user_data);
+ total_records += records;
+ if (records != additional_rrs)
+ return total_records;
+
+ return total_records;
+}
+
+static inline size_t
+mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+ void* user_data) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ socklen_t addrlen = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ const uint16_t* data = (const uint16_t*)buffer;
+
+ uint16_t query_id = mdns_ntohs(data++);
+ uint16_t flags = mdns_ntohs(data++);
+ uint16_t questions = mdns_ntohs(data++);
+ uint16_t answer_rrs = mdns_ntohs(data++);
+ uint16_t authority_rrs = mdns_ntohs(data++);
+ uint16_t additional_rrs = mdns_ntohs(data++);
+
+ size_t records;
+ size_t total_records = 0;
+ for (int iquestion = 0; iquestion < questions; ++iquestion) {
+ size_t question_offset = MDNS_POINTER_DIFF(data, buffer);
+ size_t offset = question_offset;
+ size_t verify_offset = 12;
+ int dns_sd = 0;
+ if (mdns_string_equal(buffer, data_size, &offset, mdns_services_query,
+ sizeof(mdns_services_query), &verify_offset)) {
+ dns_sd = 1;
+ } else if (!mdns_string_skip(buffer, data_size, &offset)) {
+ break;
+ }
+ size_t length = offset - question_offset;
+ data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, offset);
+
+ uint16_t rtype = mdns_ntohs(data++);
+ uint16_t rclass = mdns_ntohs(data++);
+ uint16_t class_without_flushbit = rclass & ~MDNS_CACHE_FLUSH;
+
+ // Make sure we get a question of class IN or ANY
+ if (!((class_without_flushbit == MDNS_CLASS_IN) ||
+ (class_without_flushbit == MDNS_CLASS_ANY))) {
+ break;
+ }
+
+ if (dns_sd && flags)
+ continue;
+
+ ++total_records;
+ if (callback && callback(sock, saddr, addrlen, MDNS_ENTRYTYPE_QUESTION, query_id, rtype,
+ rclass, 0, buffer, data_size, question_offset, length,
+ question_offset, length, user_data))
+ return total_records;
+ }
+
+ size_t offset = MDNS_POINTER_DIFF(data, buffer);
+ records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ANSWER, query_id, answer_rrs, callback, user_data);
+ total_records += records;
+ if (records != answer_rrs)
+ return total_records;
+
+ records =
+ mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, query_id, authority_rrs, callback, user_data);
+ total_records += records;
+ if (records != authority_rrs)
+ return total_records;
+
+ records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, query_id, additional_rrs, callback,
+ user_data);
+
+ return total_records;
+}
+
+static inline int
+mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,
+ size_t capacity, uint16_t query_id) {
+ mdns_query_t query;
+ query.type = type;
+ query.name = name;
+ query.length = length;
+ return mdns_multiquery_send(sock, &query, 1, buffer, capacity, query_id);
+}
+
+static inline int
+mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* buffer, size_t capacity,
+ uint16_t query_id) {
+ if (!count || (capacity < (sizeof(struct mdns_header_t) + (6 * count))))
+ return -1;
+
+ // Ask for a unicast response since it's a one-shot query
+ uint16_t rclass = MDNS_CLASS_IN | MDNS_UNICAST_RESPONSE;
+
+ struct sockaddr_storage addr_storage;
+ struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
+ socklen_t saddrlen = sizeof(addr_storage);
+ if (getsockname(sock, saddr, &saddrlen) == 0) {
+ if ((saddr->sa_family == AF_INET) &&
+ (ntohs(((struct sockaddr_in*)saddr)->sin_port) == MDNS_PORT))
+ rclass &= ~MDNS_UNICAST_RESPONSE;
+ else if ((saddr->sa_family == AF_INET6) &&
+ (ntohs(((struct sockaddr_in6*)saddr)->sin6_port) == MDNS_PORT))
+ rclass &= ~MDNS_UNICAST_RESPONSE;
+ }
+
+ struct mdns_header_t* header = (struct mdns_header_t*)buffer;
+ // Query ID
+ header->query_id = htons((unsigned short)query_id);
+ // Flags
+ header->flags = 0;
+ // Questions
+ header->questions = htons((unsigned short)count);
+ // No answer, authority or additional RRs
+ header->answer_rrs = 0;
+ header->authority_rrs = 0;
+ header->additional_rrs = 0;
+ // Fill in questions
+ void* data = MDNS_POINTER_OFFSET(buffer, sizeof(struct mdns_header_t));
+ for (size_t iq = 0; iq < count; ++iq) {
+ // Name string
+ data = mdns_string_make(buffer, capacity, data, query[iq].name, query[iq].length, 0);
+ if (!data)
+ return -1;
+ size_t remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ if (remain < 4)
+ return -1;
+ // Record type
+ data = mdns_htons(data, query[iq].type);
+ //! Optional unicast response based on local port, class IN
+ data = mdns_htons(data, rclass);
+ }
+
+ size_t tosend = MDNS_POINTER_DIFF(data, buffer);
+ if (mdns_multicast_send(sock, buffer, (size_t)tosend))
+ return -1;
+ return query_id;
+}
+
+static inline size_t
+mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+ void* user_data, int only_query_id) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ socklen_t addrlen = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ const uint16_t* data = (const uint16_t*)buffer;
+
+ uint16_t query_id = mdns_ntohs(data++);
+ uint16_t flags = mdns_ntohs(data++);
+ uint16_t questions = mdns_ntohs(data++);
+ uint16_t answer_rrs = mdns_ntohs(data++);
+ uint16_t authority_rrs = mdns_ntohs(data++);
+ uint16_t additional_rrs = mdns_ntohs(data++);
+ (void)sizeof(flags);
+
+ if ((only_query_id > 0) && (query_id != only_query_id))
+ return 0; // Not a reply to the wanted one-shot query
+
+ // Skip questions part
+ int i;
+ for (i = 0; i < questions; ++i) {
+ size_t offset = MDNS_POINTER_DIFF(data, buffer);
+ if (!mdns_string_skip(buffer, data_size, &offset))
+ return 0;
+ data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, offset);
+ // Record type and class not used, skip
+ // uint16_t rtype = mdns_ntohs(data++);
+ // uint16_t rclass = mdns_ntohs(data++);
+ data += 2;
+ }
+
+ size_t records = 0;
+ size_t total_records = 0;
+ size_t offset = MDNS_POINTER_DIFF(data, buffer);
+ records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ANSWER, query_id, answer_rrs, callback, user_data);
+ total_records += records;
+ if (records != answer_rrs)
+ return total_records;
+
+ records =
+ mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, query_id, authority_rrs, callback, user_data);
+ total_records += records;
+ if (records != authority_rrs)
+ return total_records;
+
+ records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, query_id, additional_rrs, callback,
+ user_data);
+ total_records += records;
+ if (records != additional_rrs)
+ return total_records;
+
+ return total_records;
+}
+
+static inline void*
+mdns_answer_add_question_unicast(void* buffer, size_t capacity, void* data,
+ mdns_record_type_t record_type, const char* name,
+ size_t name_length, mdns_string_table_t* string_table) {
+ data = mdns_string_make(buffer, capacity, data, name, name_length, string_table);
+ if (!data)
+ return 0;
+ size_t remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ if (remain < 4)
+ return 0;
+
+ data = mdns_htons(data, record_type);
+ data = mdns_htons(data, MDNS_UNICAST_RESPONSE | MDNS_CLASS_IN);
+
+ return data;
+}
+
+static inline void*
+mdns_answer_add_record_header(void* buffer, size_t capacity, void* data, mdns_record_t record,
+ mdns_string_table_t* string_table) {
+ data = mdns_string_make(buffer, capacity, data, record.name.str, record.name.length, string_table);
+ if (!data)
+ return 0;
+ size_t remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ if (remain < 10)
+ return 0;
+
+ data = mdns_htons(data, record.type);
+ data = mdns_htons(data, record.rclass);
+ data = mdns_htonl(data, record.ttl);
+ data = mdns_htons(data, 0); // Length, to be filled later
+ return data;
+}
+
+static inline void*
+mdns_answer_add_record(void* buffer, size_t capacity, void* data, mdns_record_t record,
+ mdns_string_table_t* string_table) {
+ // TXT records will be coalesced into one record later
+ if (!data || (record.type == MDNS_RECORDTYPE_TXT))
+ return data;
+
+ data = mdns_answer_add_record_header(buffer, capacity, data, record, string_table);
+ if (!data)
+ return 0;
+
+ // Pointer to length of record to be filled at end
+ void* record_length = MDNS_POINTER_OFFSET(data, -2);
+ void* record_data = data;
+
+ size_t remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ switch (record.type) {
+ case MDNS_RECORDTYPE_PTR:
+ data = mdns_string_make(buffer, capacity, data, record.data.ptr.name.str,
+ record.data.ptr.name.length, string_table);
+ break;
+
+ case MDNS_RECORDTYPE_SRV:
+ if (remain <= 6)
+ return 0;
+ data = mdns_htons(data, record.data.srv.priority);
+ data = mdns_htons(data, record.data.srv.weight);
+ data = mdns_htons(data, record.data.srv.port);
+ data = mdns_string_make(buffer, capacity, data, record.data.srv.name.str,
+ record.data.srv.name.length, string_table);
+ break;
+
+ case MDNS_RECORDTYPE_A:
+ if (remain < 4)
+ return 0;
+ memcpy(data, &record.data.a.addr.sin_addr.s_addr, 4);
+ data = MDNS_POINTER_OFFSET(data, 4);
+ break;
+
+ case MDNS_RECORDTYPE_AAAA:
+ if (remain < 16)
+ return 0;
+ memcpy(data, &record.data.aaaa.addr.sin6_addr, 16); // ipv6 address
+ data = MDNS_POINTER_OFFSET(data, 16);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!data)
+ return 0;
+
+ // Fill record length
+ mdns_htons(record_length, (uint16_t)MDNS_POINTER_DIFF(data, record_data));
+ return data;
+}
+
+static inline void
+mdns_record_update_rclass_ttl(mdns_record_t* record, uint16_t rclass, uint32_t ttl) {
+ if (!record->rclass)
+ record->rclass = rclass;
+ if (!record->ttl || !ttl)
+ record->ttl = ttl;
+ record->rclass &= (uint16_t)(MDNS_CLASS_IN | MDNS_CACHE_FLUSH);
+ // Never flush PTR record
+ if (record->type == MDNS_RECORDTYPE_PTR)
+ record->rclass &= ~(uint16_t)MDNS_CACHE_FLUSH;
+}
+
+static inline void*
+mdns_answer_add_txt_record(void* buffer, size_t capacity, void* data, const mdns_record_t* records,
+ size_t record_count, uint16_t rclass, uint32_t ttl,
+ mdns_string_table_t* string_table) {
+ // Pointer to length of record to be filled at end
+ void* record_length = 0;
+ void* record_data = 0;
+
+ size_t remain = 0;
+ for (size_t irec = 0; data && (irec < record_count); ++irec) {
+ if (records[irec].type != MDNS_RECORDTYPE_TXT)
+ continue;
+
+ mdns_record_t record = records[irec];
+ mdns_record_update_rclass_ttl(&record, rclass, ttl);
+ if (!record_data) {
+ data = mdns_answer_add_record_header(buffer, capacity, data, record, string_table);
+ if (!data)
+ return data;
+ record_length = MDNS_POINTER_OFFSET(data, -2);
+ record_data = data;
+ }
+
+ // TXT strings are unlikely to be shared, just make then raw. Also need one byte for
+ // termination, thus the <= check
+ size_t string_length = record.data.txt.key.length + record.data.txt.value.length + 1;
+ if (!data)
+ return 0;
+ remain = capacity - MDNS_POINTER_DIFF(data, buffer);
+ if ((remain <= string_length) || (string_length > 0x3FFF))
+ return 0;
+
+ unsigned char* strdata = (unsigned char*)data;
+ *strdata++ = (unsigned char)string_length;
+ memcpy(strdata, record.data.txt.key.str, record.data.txt.key.length);
+ strdata += record.data.txt.key.length;
+ *strdata++ = '=';
+ memcpy(strdata, record.data.txt.value.str, record.data.txt.value.length);
+ strdata += record.data.txt.value.length;
+
+ data = strdata;
+ }
+
+ // Fill record length
+ if (record_data)
+ mdns_htons(record_length, (uint16_t)MDNS_POINTER_DIFF(data, record_data));
+
+ return data;
+}
+
+static inline uint16_t
+mdns_answer_get_record_count(const mdns_record_t* records, size_t record_count) {
+ // TXT records will be coalesced into one record
+ uint16_t total_count = 0;
+ uint16_t txt_record = 0;
+ for (size_t irec = 0; irec < record_count; ++irec) {
+ if (records[irec].type == MDNS_RECORDTYPE_TXT)
+ txt_record = 1;
+ else
+ ++total_count;
+ }
+ return total_count + txt_record;
+}
+
+static inline int
+mdns_query_answer_unicast(int sock, const void* address, size_t address_size, void* buffer,
+ size_t capacity, uint16_t query_id, mdns_record_type_t record_type,
+ const char* name, size_t name_length, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count) {
+ if (capacity < (sizeof(struct mdns_header_t) + 32 + 4))
+ return -1;
+
+ // According to RFC 6762:
+ // The cache-flush bit MUST NOT be set in any resource records in a response message
+ // sent in legacy unicast responses to UDP ports other than 5353.
+ uint16_t rclass = MDNS_CLASS_IN;
+ uint32_t ttl = 10;
+
+ // Basic answer structure
+ struct mdns_header_t* header = (struct mdns_header_t*)buffer;
+ header->query_id = htons(query_id);
+ header->flags = htons(0x8400);
+ header->questions = htons(1);
+ header->answer_rrs = htons(1);
+ header->authority_rrs = htons(mdns_answer_get_record_count(authority, authority_count));
+ header->additional_rrs = htons(mdns_answer_get_record_count(additional, additional_count));
+
+ mdns_string_table_t string_table = {{0}, 0, 0};
+ void* data = MDNS_POINTER_OFFSET(buffer, sizeof(struct mdns_header_t));
+
+ // Fill in question
+ data = mdns_answer_add_question_unicast(buffer, capacity, data, record_type, name, name_length,
+ &string_table);
+
+ // Fill in answer
+ answer.rclass = rclass;
+ answer.ttl = ttl;
+ data = mdns_answer_add_record(buffer, capacity, data, answer, &string_table);
+
+ // Fill in authority records
+ for (size_t irec = 0; data && (irec < authority_count); ++irec) {
+ mdns_record_t record = authority[irec];
+ record.rclass = rclass;
+ if (!record.ttl)
+ record.ttl = ttl;
+ data = mdns_answer_add_record(buffer, capacity, data, record, &string_table);
+ }
+ data = mdns_answer_add_txt_record(buffer, capacity, data, authority, authority_count,
+ rclass, ttl, &string_table);
+
+ // Fill in additional records
+ for (size_t irec = 0; data && (irec < additional_count); ++irec) {
+ mdns_record_t record = additional[irec];
+ record.rclass = rclass;
+ if (!record.ttl)
+ record.ttl = ttl;
+ data = mdns_answer_add_record(buffer, capacity, data, record, &string_table);
+ }
+ data = mdns_answer_add_txt_record(buffer, capacity, data, additional, additional_count,
+ rclass, ttl, &string_table);
+ if (!data)
+ return -1;
+
+ size_t tosend = MDNS_POINTER_DIFF(data, buffer);
+ return mdns_unicast_send(sock, address, address_size, buffer, tosend);
+}
+
+static inline int
+mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count,
+ uint16_t rclass, uint32_t ttl) {
+ if (capacity < (sizeof(struct mdns_header_t) + 32 + 4))
+ return -1;
+
+ // Basic answer structure
+ struct mdns_header_t* header = (struct mdns_header_t*)buffer;
+ header->query_id = 0;
+ header->flags = htons(0x8400);
+ header->questions = 0;
+ header->answer_rrs = htons(1);
+ header->authority_rrs = htons(mdns_answer_get_record_count(authority, authority_count));
+ header->additional_rrs = htons(mdns_answer_get_record_count(additional, additional_count));
+
+ mdns_string_table_t string_table = {{0}, 0, 0};
+ void* data = MDNS_POINTER_OFFSET(buffer, sizeof(struct mdns_header_t));
+
+ // Fill in answer
+ mdns_record_t record = answer;
+ mdns_record_update_rclass_ttl(&record, rclass, ttl);
+ data = mdns_answer_add_record(buffer, capacity, data, record, &string_table);
+
+ // Fill in authority records
+ for (size_t irec = 0; data && (irec < authority_count); ++irec) {
+ record = authority[irec];
+ mdns_record_update_rclass_ttl(&record, rclass, ttl);
+ data = mdns_answer_add_record(buffer, capacity, data, record, &string_table);
+ }
+ data = mdns_answer_add_txt_record(buffer, capacity, data, authority, authority_count,
+ rclass, ttl, &string_table);
+
+ // Fill in additional records
+ for (size_t irec = 0; data && (irec < additional_count); ++irec) {
+ record = additional[irec];
+ mdns_record_update_rclass_ttl(&record, rclass, ttl);
+ data = mdns_answer_add_record(buffer, capacity, data, record, &string_table);
+ }
+ data = mdns_answer_add_txt_record(buffer, capacity, data, additional, additional_count,
+ rclass, ttl, &string_table);
+ if (!data)
+ return -1;
+
+ size_t tosend = MDNS_POINTER_DIFF(data, buffer);
+ return mdns_multicast_send(sock, buffer, tosend);
+}
+
+static inline int
+mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count) {
+ return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority,
+ authority_count, additional, additional_count,
+ MDNS_CLASS_IN, 60);
+}
+
+static inline int
+mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count) {
+ return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority,
+ authority_count, additional, additional_count,
+ MDNS_CLASS_IN | MDNS_CACHE_FLUSH, 60);
+}
+
+static inline int
+mdns_goodbye_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+ const mdns_record_t* authority, size_t authority_count,
+ const mdns_record_t* additional, size_t additional_count) {
+ // Goodbye should have ttl of 0
+ return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority,
+ authority_count, additional, additional_count,
+ MDNS_CLASS_IN, 0);
+}
+
+static inline mdns_string_t
+mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity) {
+ // PTR record is just a string
+ if ((size >= offset + length) && (length >= 2))
+ return mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
+ mdns_string_t empty = {0, 0};
+ return empty;
+}
+
+static inline mdns_record_srv_t
+mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity) {
+ mdns_record_srv_t srv;
+ memset(&srv, 0, sizeof(mdns_record_srv_t));
+ // Read the service priority, weight, port number and the discovery name
+ // SRV record format (http://www.ietf.org/rfc/rfc2782.txt):
+ // 2 bytes network-order unsigned priority
+ // 2 bytes network-order unsigned weight
+ // 2 bytes network-order unsigned port
+ // string: discovery (domain) name, minimum 2 bytes when compressed
+ if ((size >= offset + length) && (length >= 8)) {
+ const uint16_t* recorddata = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, offset);
+ srv.priority = mdns_ntohs(recorddata++);
+ srv.weight = mdns_ntohs(recorddata++);
+ srv.port = mdns_ntohs(recorddata++);
+ offset += 6;
+ srv.name = mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
+ }
+ return srv;
+}
+
+static inline struct sockaddr_in*
+mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+#ifdef __APPLE__
+ addr->sin_len = sizeof(struct sockaddr_in);
+#endif
+ if ((size >= offset + length) && (length == 4))
+ memcpy(&addr->sin_addr.s_addr, MDNS_POINTER_OFFSET(buffer, offset), 4);
+ return addr;
+}
+
+static inline struct sockaddr_in6*
+mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in6* addr) {
+ memset(addr, 0, sizeof(struct sockaddr_in6));
+ addr->sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ if ((size >= offset + length) && (length == 16))
+ memcpy(&addr->sin6_addr, MDNS_POINTER_OFFSET(buffer, offset), 16);
+ return addr;
+}
+
+static inline size_t
+mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,
+ mdns_record_txt_t* records, size_t capacity) {
+ size_t parsed = 0;
+ const char* strdata;
+ size_t end = offset + length;
+
+ if (size < end)
+ end = size;
+
+ while ((offset < end) && (parsed < capacity)) {
+ strdata = (const char*)MDNS_POINTER_OFFSET(buffer, offset);
+ size_t sublength = *(const unsigned char*)strdata;
+
+ if (sublength >= (end - offset))
+ break;
+
+ ++strdata;
+ offset += sublength + 1;
+
+ size_t separator = sublength;
+ for (size_t c = 0; c < sublength; ++c) {
+ // DNS-SD TXT record keys MUST be printable US-ASCII, [0x20, 0x7E]
+ if ((strdata[c] < 0x20) || (strdata[c] > 0x7E)) {
+ separator = 0;
+ break;
+ }
+ if (strdata[c] == '=') {
+ separator = c;
+ break;
+ }
+ }
+
+ if (!separator)
+ continue;
+
+ if (separator < sublength) {
+ records[parsed].key.str = strdata;
+ records[parsed].key.length = separator;
+ records[parsed].value.str = strdata + separator + 1;
+ records[parsed].value.length = sublength - (separator + 1);
+ } else {
+ records[parsed].key.str = strdata;
+ records[parsed].key.length = sublength;
+ records[parsed].value.str = 0;
+ records[parsed].value.length = 0;
+ }
+
+ ++parsed;
+ }
+
+ return parsed;
+}
+
+#ifdef _WIN32
+#undef strncasecmp
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/abstractserver.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/abstractserver.h
deleted file mode 100644
index ca42ed2..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/abstractserver.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/bitmap.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/bitmap.h
deleted file mode 100644
index 460f1c7..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/bitmap.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/browser.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/browser.h
deleted file mode 100644
index 7cecee3..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/browser.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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
-#include
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/cache.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/cache.h
deleted file mode 100644
index cecfddd..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/cache.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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
-#include
-
-#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 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 &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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/dns.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/dns.h
deleted file mode 100644
index f19d275..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/dns.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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
-#include
-
-#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 &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 &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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/hostname.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/hostname.h
deleted file mode 100644
index fe3c79b..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/hostname.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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
-
-#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 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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/mdns.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/mdns.h
deleted file mode 100644
index 339f28e..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/mdns.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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
-#include
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/message.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/message.h
deleted file mode 100644
index e89e3f5..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/message.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * 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
-#include
-
-#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 queries() const;
-
- /**
- * @brief Add a query to the message
- */
- void addQuery(const Query &query);
-
- /**
- * @brief Retrieve a list of records in the message
- */
- QList 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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/prober.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/prober.h
deleted file mode 100644
index 8a7b1e9..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/prober.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/provider.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/provider.h
deleted file mode 100644
index 7990005..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/provider.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/qmdnsengine_export.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/qmdnsengine_export.h
deleted file mode 100644
index 93343e1..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/qmdnsengine_export.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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
-
-#define BUILD_SHARED_LIBS
-#define QMDNSENGINE_LIBRARY
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/query.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/query.h
deleted file mode 100644
index d54899b..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/query.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/record.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/record.h
deleted file mode 100644
index 21d36f3..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/record.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * 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
-#include
-#include
-
-#include "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 attributes() const;
-
- /**
- * @brief Set attributes for the record
- */
- void setAttributes(const QMap &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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/resolver.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/resolver.h
deleted file mode 100644
index b393b66..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/resolver.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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
-#include
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/server.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/server.h
deleted file mode 100644
index e3689ec..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/server.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 "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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/service.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/service.h
deleted file mode 100644
index 48d7d10..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/include/service.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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
-#include
-#include
-#include
-
-#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 attributes() const;
-
- /**
- * @brief Set the attributes for the service
- */
- void setAttributes(const QMap &attributes);
-
- /**
- * @brief Add an attribute to the service
- */
- void addAttribute(const QByteArray &key, const QByteArray &value);
-
-private:
-
- ServicePrivate *const d;
-};
-
-QMDNSENGINE_EXPORT QDebug operator<<(QDebug debug, const Service &service);
-
-}
-
-#endif // QMDNSENGINE_SERVICE_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/qmdnsengine_export.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/qmdnsengine_export.h
deleted file mode 100644
index da22671..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/qmdnsengine_export.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
-
-#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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/abstractserver.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/abstractserver.cpp
deleted file mode 100644
index 628b42f..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/abstractserver.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 "../include/abstractserver.h"
-
-using namespace QMdnsEngine;
-
-AbstractServer::AbstractServer(QObject *parent)
- : QObject(parent)
-{
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/bitmap.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/bitmap.cpp
deleted file mode 100644
index f786bfb..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/bitmap.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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 "../include/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);
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/bitmap_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/bitmap_p.h
deleted file mode 100644
index 2444124..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/bitmap_p.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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
-
-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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/browser.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/browser.cpp
deleted file mode 100644
index 2c48c89..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/browser.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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 "../include/abstractserver.h"
-#include "../include/browser.h"
-#include "../include/cache.h"
-#include "../include/dns.h"
-#include "../include/mdns.h"
-#include "../include/message.h"
-#include "../include/query.h"
-#include "../include/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 txtRecords;
- if (cache->lookupRecords(fqName, TXT, txtRecords)) {
- QMap 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 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 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 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 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))
-{
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/browser_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/browser_p.h
deleted file mode 100644
index 91e6cbd..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/browser_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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
-#include
-#include
-#include
-#include
-
-#include "../include/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 ptrTargets;
- QMap services;
- QSet 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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/cache.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/cache.cpp
deleted file mode 100644
index 69a4830..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/cache.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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
-#if(QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
-#include
-#define USE_QRANDOMGENERATOR
-#endif
-
-#include "../include/cache.h"
-#include "../include/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 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 records;
- if (lookupRecords(name, type, records)) {
- record = records.at(0);
- return true;
- }
- return false;
-}
-
-bool Cache::lookupRecords(const QByteArray &name, quint16 type, QList &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;
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/cache_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/cache_p.h
deleted file mode 100644
index 6c71879..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/cache_p.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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
-#include
-#include
-#include
-
-#include "../include/record.h"
-
-namespace QMdnsEngine
-{
-
-class Cache;
-
-class CachePrivate : public QObject
-{
- Q_OBJECT
-
-public:
-
- struct Entry
- {
- Record record;
- QList triggers;
- };
-
- CachePrivate(Cache *cache);
-
- QTimer timer;
- QList entries;
- QDateTime nextTrigger;
-
-private Q_SLOTS:
-
- void onTimeout();
-
-private:
-
- Cache *const q;
-};
-
-}
-
-#endif // QMDNSENGINE_CACHE_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/dns.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/dns.cpp
deleted file mode 100644
index a17bfcd..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/dns.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * 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
-#include
-
-#include "../include/bitmap.h"
-#include "../include/dns.h"
-#include "../include/message.h"
-#include "../include/query.h"
-#include "../include/record.h"
-
-namespace QMdnsEngine
-{
-
-template
-bool parseInteger(const QByteArray &packet, quint16 &offset, T &value)
-{
- if (offset + sizeof(T) > static_cast(packet.length())) {
- return false; // out-of-bounds
- }
- value = qFromBigEndian(reinterpret_cast(packet.constData() + offset));
- offset += sizeof(T);
- return true;
-}
-
-template
-void writeInteger(QByteArray &packet, quint16 &offset, T value)
-{
- value = qToBigEndian(value);
- packet.append(reinterpret_cast(&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(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(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 &nameMap)
-{
- QByteArray fragment = name;
- if (fragment.endsWith('.')) {
- fragment.chop(1);
- }
- while (fragment.length()) {
- if (nameMap.contains(fragment)) {
- writeInteger(packet, offset, nameMap.value(fragment) | 0xc000);
- return;
- }
- nameMap.insert(fragment, offset);
- int index = fragment.indexOf('.');
- if (index == -1) {
- index = fragment.length();
- }
- writeInteger(packet, offset, index);
- packet.append(fragment.left(index));
- offset += index;
- fragment.remove(0, index + 1);
- }
- writeInteger(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(packet, offset, type) ||
- !parseInteger(packet, offset, class_) ||
- !parseInteger(packet, offset, ttl) ||
- !parseInteger(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(packet, offset, ipv4Addr)) {
- return false;
- }
- record.setAddress(QHostAddress(ipv4Addr));
- break;
- }
- case AAAA:
- {
- if (offset + 16 > packet.length()) {
- return false;
- }
- record.setAddress(QHostAddress(
- reinterpret_cast(packet.constData() + offset)
- ));
- offset += 16;
- break;
- }
- case NSEC:
- {
- QByteArray nextDomainName;
- quint8 number;
- quint8 length;
- if (!parseName(packet, offset, nextDomainName) ||
- !parseInteger(packet, offset, number) ||
- !parseInteger(packet, offset, length) ||
- number != 0 ||
- offset + length > packet.length()) {
- return false;
- }
- Bitmap bitmap;
- bitmap.setData(length, reinterpret_cast(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(packet, offset, priority) ||
- !parseInteger(packet, offset, weight) ||
- !parseInteger(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(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 &nameMap)
-{
- writeName(packet, offset, record.name(), nameMap);
- writeInteger(packet, offset, record.type());
- writeInteger(packet, offset, record.flushCache() ? 0x8001 : 1);
- writeInteger(packet, offset, record.ttl());
- offset += 2;
- QByteArray data;
- switch (record.type()) {
- case A:
- writeInteger(data, offset, record.address().toIPv4Address());
- break;
- case AAAA:
- {
- Q_IPV6ADDR ipv6Addr = record.address().toIPv6Address();
- data.append(reinterpret_cast(&ipv6Addr), sizeof(Q_IPV6ADDR));
- offset += data.length();
- break;
- }
- case NSEC:
- {
- quint8 length = record.bitmap().length();
- writeName(data, offset, record.nextDomainName(), nameMap);
- writeInteger(data, offset, 0);
- writeInteger(data, offset, length);
- data.append(reinterpret_cast(record.bitmap().data()), length);
- offset += length;
- break;
- }
- case PTR:
- writeName(data, offset, record.target(), nameMap);
- break;
- case SRV:
- writeInteger(data, offset, record.priority());
- writeInteger(data, offset, record.weight());
- writeInteger(data, offset, record.port());
- writeName(data, offset, record.target(), nameMap);
- break;
- case TXT:
- if (!record.attributes().count()) {
- writeInteger(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(data, offset, entry.length());
- data.append(entry);
- offset += entry.length();
- }
- break;
- default:
- break;
- }
- offset -= 2;
- writeInteger(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(packet, offset, transactionId) ||
- !parseInteger(packet, offset, flags) ||
- !parseInteger(packet, offset, nQuestion) ||
- !parseInteger(packet, offset, nAnswer) ||
- !parseInteger(packet, offset, nAuthority) ||
- !parseInteger(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(packet, offset, type) ||
- !parseInteger(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);
-
- qDebug() << "Flags set in toPacket:" << QString::number(flags, 16);
-
- writeInteger(packet, offset, message.transactionId());
- writeInteger(packet, offset, flags);
- writeInteger(packet, offset, message.queries().length());
- writeInteger(packet, offset, message.records().length());
- writeInteger(packet, offset, 0);
- writeInteger(packet, offset, 0);
- QMap nameMap;
- const auto queries = message.queries();
- for (const Query &query : queries) {
- writeName(packet, offset, query.name(), nameMap);
- writeInteger(packet, offset, query.type());
- writeInteger(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 "?";
- }
-}
-
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/hostname.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/hostname.cpp
deleted file mode 100644
index 5d6c92c..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/hostname.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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
-#include
-#include
-#include
-
-#include "../include/abstractserver.h"
-#include "../include/dns.h"
-#include "../include/hostname.h"
-#include "../include/message.h"
-#include "../include/query.h"
-#include "../include/record.h"
-
-#include "hostname_p.h"
-
-using namespace QMdnsEngine;
-
-HostnamePrivate::HostnamePrivate(Hostname *hostname, AbstractServer *server)
- : QObject(hostname),
- server(server),
- 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(30 * 60 * 1000);
- 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 = QHostInfo::localHostName().toUtf8();
- 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))
-{
-}
-
-bool Hostname::isRegistered() const
-{
- return d->hostnameRegistered;
-}
-
-QByteArray Hostname::hostname() const
-{
- return d->hostname;
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/hostname_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/hostname_p.h
deleted file mode 100644
index 33261db..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/hostname_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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
-#include
-
-class QHostAddress;
-
-namespace QMdnsEngine
-{
-
-class AbstractServer;
-class Hostname;
-class Message;
-class Record;
-
-class HostnamePrivate : public QObject
-{
- Q_OBJECT
-
-public:
-
- HostnamePrivate(Hostname *hostname, AbstractServer *server);
-
- void assertHostname();
- bool generateRecord(const QHostAddress &srcAddress, quint16 type, Record &record);
-
- AbstractServer *server;
-
- QByteArray hostnamePrev;
- QByteArray hostname;
- 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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/mdns.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/mdns.cpp
deleted file mode 100644
index af6e449..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/mdns.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 "../include/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.");
-
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/message.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/message.cpp
deleted file mode 100644
index f273863..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/message.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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 "../include/mdns.h"
-#include "../include/message.h"
-#include "../include/query.h"
-#include "../include/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 Message::queries() const
-{
- return d->queries;
-}
-
-void Message::addQuery(const Query &query)
-{
- d->queries.append(query);
-}
-
-QList 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);
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/message_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/message_p.h
deleted file mode 100644
index 665d194..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/message_p.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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
-#include
-
-namespace QMdnsEngine
-{
-
-class Query;
-class Record;
-
-class MessagePrivate
-{
-public:
-
- MessagePrivate();
-
- QHostAddress address;
- quint16 port;
- quint16 transactionId;
- bool isResponse;
- bool isTruncated;
- QList queries;
- QList records;
-};
-
-}
-
-#endif // QMDNSENGINE_MESSAGE_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/prober.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/prober.cpp
deleted file mode 100644
index 60ecb5a..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/prober.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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 "../include/abstractserver.h"
-#include "../include/dns.h"
-#include "../include/message.h"
-#include "../include/prober.h"
-#include "../include/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);
-
- assertRecord();
-}
-
-void ProberPrivate::assertRecord()
-{
- // Use the current suffix to set the name of the proposed record
- QString tmpName = suffix == 1
- ? QString("%1%2").arg(name, type.constData())
- : QString("%1-%2%3").arg(name.constData(), QByteArray::number(suffix), type);
-
- proposedRecord.setName(tmpName.toUtf8());
-
- // 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()) {
- if (confirmed) {
- return;
- }
- const auto records = message.records();
- for (const Record &record : records) {
- if (record.name() == proposedRecord.name() && record.type() == proposedRecord.type()) {
- qDebug() << "Conflict detected for name:" << proposedRecord.name() << "with type:" << record.type();
- ++suffix;
- assertRecord();
- }
- }
-}
-
-void ProberPrivate::onTimeout()
-{
- confirmed = true;
- emit q->nameConfirmed(proposedRecord.name());
-}
-
-Prober::Prober(AbstractServer *server, const Record &record, QObject *parent)
- : QObject(parent),
- d(new ProberPrivate(this, server, record))
-{
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/prober_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/prober_p.h
deleted file mode 100644
index f82f9bc..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/prober_p.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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
-#include
-
-#include "../include/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
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/provider.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/provider.cpp
deleted file mode 100644
index 7c24e2d..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/provider.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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 "../include/abstractserver.h"
-#include "../include/dns.h"
-#include "../include/hostname.h"
-#include "../include/mdns.h"
-#include "../include/message.h"
-#include "../include/prober.h"
-#include "../include/provider.h"
-#include "../include/query.h"
-
-#include "provider_p.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(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);
-
- connect(prober, &Prober::nameConfirmed, [this](const QByteArray &name) {
- // If existing records were confirmed, indicate that they are no
- // longer valid
- 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;
- announce();
-
-}
-
-void ProviderPrivate::onMessageReceived(const Message &message)
-{
- if (!confirmed || message.isResponse()) {
- return;
- }
- //qDebug() << "Failed to start server. Error:" << server->errorString();
- bool sendBrowsePtr = false;
- bool sendPtr = false;
- bool sendSrv = false;
- bool sendTxt = false;
-
- // 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);
- }
- 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 == nullptr) {
- qDebug() << "hostname is nullptr";
- return;
- }
- bool registered = d->hostname->isRegistered();
- if(registered) {
- // 不确认服务名称,直接进行广播
- d->publish();
- //if (d->hostname->isRegistered()) {
- /*if (!d->confirmed || fqName != d->srvRecord.name()) {
- qDebug() << "confirm()";
- d->confirm();
- } else {
- qDebug() << "publish()";
- d->publish();
- }*/
- }
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/provider_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/provider_p.h
deleted file mode 100644
index 86454d1..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/provider_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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
-
-#include "../include/record.h"
-#include "../include/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 browsePtrProposed;
- Record ptrProposed;
- Record srvProposed;
- Record txtProposed;
-
-private Q_SLOTS:
-
- void onMessageReceived(const Message &message);
- void onHostnameChanged(const QByteArray &hostname);
-};
-
-}
-
-#endif // QMDNSENGINE_PROVIDER_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/query.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/query.cpp
deleted file mode 100644
index 8b54b94..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/query.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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
-
-#include "../include/dns.h"
-#include "../include/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;
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/query_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/query_p.h
deleted file mode 100644
index 23d01f0..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/query_p.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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
-
-namespace QMdnsEngine
-{
-
-class QueryPrivate
-{
-public:
-
- QueryPrivate();
-
- QByteArray name;
- quint16 type;
- bool unicastResponse;
-};
-
-}
-
-#endif // QMDNSENGINE_QUERY_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/record.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/record.cpp
deleted file mode 100644
index 42009b8..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/record.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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
-
-#include "../include/dns.h"
-#include "../include/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 Record::attributes() const
-{
- return d->attributes;
-}
-
-void Record::setAttributes(const QMap &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;
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/record_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/record_p.h
deleted file mode 100644
index 674830a..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/record_p.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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
-#include
-#include
-
-#include "../include/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 attributes;
- Bitmap bitmap;
-};
-
-}
-
-#endif // QMDNSENGINE_RECORD_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/resolver.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/resolver.cpp
deleted file mode 100644
index 99ecc6b..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/resolver.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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
-
-#include "../include/abstractserver.h"
-#include "../include/dns.h"
-#include "../include/cache.h"
-#include "../include/message.h"
-#include "../include/query.h"
-#include "../include/record.h"
-#include "../include/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 ResolverPrivate::existing() const
-{
- QList 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))
-{
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/resolver_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/resolver_p.h
deleted file mode 100644
index 0110d47..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/resolver_p.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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
-#include
-#include
-#include
-
-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 existing() const;
- void query() const;
-
- AbstractServer *server;
- QByteArray name;
- Cache *cache;
- QSet addresses;
- QTimer timer;
-
-private Q_SLOTS:
-
- void onMessageReceived(const Message &message);
- void onTimeout();
-
-private:
-
- Resolver *const q;
-};
-
-}
-
-#endif // QMDNSENGINE_RESOLVER_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/server.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/server.cpp
deleted file mode 100644
index 036b7ae..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/server.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#include
-
-#ifdef Q_OS_UNIX
-# include
-# include
-# include
-#endif
-
-#include
-#include
-
-#include "../include/dns.h"
-#include "../include/mdns.h"
-#include "../include/message.h"
-#include "../include/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(&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(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);
- //qDebug() << "packet:" << packet;
- qint64 sentBytes = d->ipv4Socket.writeDatagram(packet, MdnsIpv4Address, MdnsPort);
- qDebug() << "ipv4Socket sentBytes:" << sentBytes;
- sentBytes = d->ipv6Socket.writeDatagram(packet, MdnsIpv6Address, MdnsPort);
- qDebug() << "ipv6Socket sentBytes:" << sentBytes;
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/server_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/server_p.h
deleted file mode 100644
index 1158eec..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/server_p.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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
-#include
-#include
-
-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{ this };
- QUdpSocket ipv6Socket{ this };
-
-private Q_SLOTS:
-
- void onTimeout();
- void onReadyRead();
-
-private:
-
- Server *const q;
-};
-
-}
-
-#endif // QMDNSENGINE_SERVER_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/service.cpp b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/service.cpp
deleted file mode 100644
index dd4fa0e..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/service.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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 "../include/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 Service::attributes() const
-{
- return d->attributes;
-}
-
-void Service::setAttributes(const QMap &attributes)
-{
- d->attributes = attributes;
-}
-
-void Service::addAttribute(const QByteArray &key, const QByteArray &value)
-{
- d->attributes.insert(key, value);
-}
-
-QDebug QMdnsEngine::operator<<(QDebug debug, const Service &service)
-{
- QDebugStateSaver saver(debug);
- Q_UNUSED(saver);
-
- debug.noquote().nospace()
- << "Service(name: " << service.name()
- << ", type: " << service.type()
- << ", hostname: " << service.hostname()
- << ", port: " << service.port()
- << ", attributes: " << service.attributes()
- << ")";
-
- return debug;
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/service_p.h b/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/service_p.h
deleted file mode 100644
index ffa2e4d..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/qmdnsengine/src/service_p.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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
-#include
-
-namespace QMdnsEngine
-{
-
-class ServicePrivate
-{
-public:
-
- ServicePrivate();
-
- QByteArray type;
- QByteArray name;
- QByteArray hostname;
- quint16 port;
- QMap attributes;
-};
-
-}
-
-#endif // QMDNSENGINE_SERVICE_P_H
diff --git a/FactoryTestTool/SourceCode/Network/mdns/servicemodel.cpp b/FactoryTestTool/SourceCode/Network/mdns/servicemodel.cpp
deleted file mode 100644
index de3d148..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/servicemodel.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// servicemodel.cpp
-#include "servicemodel.h"
-
-Q_DECLARE_METATYPE(QMdnsEngine::Service)
-
-ServiceProvider::ServiceProvider(QObject* parent)
- : QObject(parent), mHostname(&mServer), mProvider(nullptr)
-{
- // Initialize the provider when the ServiceProvider is created
-}
-
-void ServiceProvider::startServiceBroadcast(const QString& serviceName, const QString& serviceType, quint16 port)
-{
- if (mProvider) {
- delete mProvider;
- mProvider = nullptr;
- }
- // Set up the service with the specified name, type, and port
- mService.setName(serviceName.toUtf8());
- mService.setType(serviceType.toUtf8());
- mService.setPort(port);
- // Create a new provider for this service
- mProvider = new QMdnsEngine::Provider(&mServer, &mHostname, this);
- mProvider->update(mService);
-
- qDebug() << "mDNS service broadcast started:" << serviceName << serviceType << "on port" << port;
-}
-
-void ServiceProvider::stopServiceBroadcast()
-{
- if (mProvider) {
- delete mProvider;
- mProvider = nullptr;
- qDebug() << "mDNS service broadcast stopped.";
- }
-}
diff --git a/FactoryTestTool/SourceCode/Network/mdns/servicemodel.h b/FactoryTestTool/SourceCode/Network/mdns/servicemodel.h
deleted file mode 100644
index ed1d958..0000000
--- a/FactoryTestTool/SourceCode/Network/mdns/servicemodel.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// servicemodel.h
-#ifndef SERVICEMODEL_H
-#define SERVICEMODEL_H
-
-#include
-
-#include "qmdnsengine/include/server.h"
-#include "qmdnsengine/include/hostname.h"
-#include "qmdnsengine/include/provider.h"
-#include "qmdnsengine/include/service.h"
-#include "qmdnsengine/include/message.h"
-#include "qmdnsengine/include/query.h"
-
-class ServiceProvider : public QObject
-{
- Q_OBJECT
-
-public:
- explicit ServiceProvider(QObject* parent = nullptr);
-
- void startServiceBroadcast(const QString& serviceName, const QString& serviceType, quint16 port);
- void stopServiceBroadcast();
-
-private:
- QMdnsEngine::Server mServer;
- QMdnsEngine::Hostname mHostname;
- QMdnsEngine::Provider* mProvider;
- QMdnsEngine::Service mService;
-};
-
-#endif // SERVICEPROVIDER_H
diff --git a/FactoryTestTool/SourceCode/RecvDataHandler/MsgTpye.h b/FactoryTestTool/SourceCode/RecvDataHandler/MsgTpye.h
index 4eb2ec7..84d8325 100644
--- a/FactoryTestTool/SourceCode/RecvDataHandler/MsgTpye.h
+++ b/FactoryTestTool/SourceCode/RecvDataHandler/MsgTpye.h
@@ -56,7 +56,7 @@
#define SET_LOG_LEVEL 0x0360
-// 前后板设备信息
+// 前板设备信息
#define GET_FRONT_V851_VERSION 0x0400
#define GET_FRONT_MCU_VERSION 0x0401
#define GET_FRONT_HW_VERSION 0x0402
@@ -66,6 +66,7 @@
#define GET_FRONT_HW_INFO 0x0420
#define WRITE_FRONT_LICENSE 0x0421
+// 后板设备信息
#define GET_BACK_V851_VERSION 0x0450
#define GET_BACK_806_VERSION 0x0451
#define GET_BACK_HW_VERSION 0x0452
@@ -77,4 +78,5 @@
#define VIDEO_TEST 0x050A
+
#endif
diff --git a/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.cpp b/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.cpp
index 41706e0..b8906ff 100644
--- a/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.cpp
+++ b/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.cpp
@@ -108,8 +108,8 @@ void DataHandler::updateLineEdit(int msg_id, const QByteArray& actual_data) {
void DataHandler::clearAllRecvData() {
allRecvData = QByteArray();
- remain = 0;
- dataLen = 0;
+ remain = 0;
+ dataLen = 0;
}
// 处理接收到的数据
@@ -145,11 +145,20 @@ void DataHandler::handleData(const QString& client, const QByteArray& recv
(static_cast(buffer->at(7)) << 8) |
(static_cast(buffer->at(6)));
//qDebug() << "---Received dataSize:" << dataSize;
+ //qDebug() << "---Received buffer->size():" << buffer->size();
//qDebug() << "---msg_id:" << QString::number(msg_id, 16).toUpper();
// 第11字节为返回 OK/NG
- bool success = (static_cast(buffer->at(10)) == 0x00);
+ bool success = (static_cast(buffer->at(10)) != 0x00);
int totalSize = 10 + dataSize; // 数据头大小(10字节) + 实际数据大小
-
+ if (CurrentCommand == "GET_BACK_MAC") {
+ //qDebug() << "--- getCommandNameFromValue:" << msg_id;
+ if (!getCommandNameFromValue(msg_id)) {
+ //qDebug() << "--- getCommandNameFromValue:" << msg_id;
+ buffer->remove(0, buffer->size());
+ emit commandError();
+ break;
+ }
+ }
if (buffer->size() >= totalSize) {
// 调试查看收到的前19个字节
/*for (int i = 0; i < 19; i++) {
@@ -158,7 +167,7 @@ void DataHandler::handleData(const QString& client, const QByteArray& recv
QByteArray data = buffer->mid(11, dataSize);
QString hexString = QString::fromUtf8(data.toHex().data());
QByteArray actual_data = hexStringToByteArray(hexString);
- buffer->remove(0, totalSize); // 移除已处理的数据
+ buffer->remove(0, totalSize); // 移除已处理的数据
if(msg_id != 0x0040 && msg_id != START_VIDEO && msg_id != GET_IMG && msg_id != VIDEO_TEST &&
msg_id != STOP_VIDEO) {
qDebug() << "--- msg_id:" << msg_id;
@@ -167,7 +176,7 @@ void DataHandler::handleData(const QString& client, const QByteArray& recv
(msg_id != 0x0021 || clientLastMsgId.value(client, 0) != 0x0021) &&
(msg_id != START_VIDEO || clientLastMsgId.value(client, 0) != START_VIDEO)) {
//qDebug() << "Emitting statusUpdated for client:" << client << "with msg_id:" << QString::number(msg_id, 16).toUpper();
- emit statusUpdated(client, true, jsonArray, itemJsonIndex);
+ emit statusUpdated(client, success, jsonArray, itemJsonIndex);
}
clientLastMsgId[client] = msg_id;
}
@@ -183,6 +192,68 @@ void DataHandler::handleData(const QString& client, const QByteArray& recv
}
}
+void DataHandler::getCurrentSendItem(const QString& text) {
+ CurrentCommand = text;
+}
+
+// 初始化映射表
+std::map commandValueMap = {
+ {"FACE_ENROLL_SINGLE", FACE_ENROLL_SINGLE},
+ {"FACE_ENROLL", FACE_ENROLL},
+ {"HAND_ENROLL", HAND_ENROLL},
+ {"FACE_VERIFY", FACE_VERIFY},
+ {"HAND_VERIFY", HAND_VERIFY},
+ {"DEL_USER", DEL_USER},
+ {"DEL_ALLUSER", DEL_ALLUSER},
+ {"GET_USER", GET_USER},
+ {"GET_ALLUSER", GET_ALLUSER},
+ {"PASSWD_ENROLL", PASSWD_ENROLL},
+ {"IMG_ENROLL", IMG_ENROLL},
+ {"GET_IMG", GET_IMG},
+ {"START_VIDEO", START_VIDEO},
+ {"STOP_VIDEO", STOP_VIDEO},
+ {"TOUCH_TEST", TOUCH_TEST},
+ {"MIC_TEST", MIC_TEST},
+ {"SPK_TEST", SPK_TEST},
+ {"RADAR_TEST", RADAR_TEST},
+ {"NFC_TEST", NFC_TEST},
+ {"PR_SWITCH", PR_SWITCH},
+ {"PS_TEST", PS_TEST},
+ {"BACKLIGHT", BACKLIGHT},
+ {"IR_LED", IR_LED},
+ {"UART_TEST", UART_TEST},
+ {"PIR_TEST", PIR_TEST},
+ {"FACE_VERIFY_THRES", FACE_VERIFY_THRES},
+ {"FACE_THRES_LEVEL", FACE_THRES_LEVEL},
+ {"FACE_LIVE_THRES", FACE_LIVE_THRES},
+ {"FACE_ACC_THRES", FACE_ACC_THRES},
+ {"FACE_ACC_LEVEL", FACE_ACC_LEVEL},
+ {"FACE_DIS_RANGE", FACE_DIS_RANGE},
+ {"FACE_ANGLE_RANGE", FACE_ANGLE_RANGE},
+
+ {"GET_BACK_MAC", GET_BACK_MAC},
+ {"WRITE_BACK_UID_SN", WRITE_BACK_UID_SN}
+};
+
+bool DataHandler::getCommandNameFromValue(int receivedValue) {
+ auto it = commandValueMap.find(CurrentCommand);
+ if (it != commandValueMap.end()) {
+ int expectedValue = it->second;
+ if (expectedValue == receivedValue) {
+ std::cout << "Match found: " << CurrentCommand.toStdString() << " corresponds to value " << std::hex << expectedValue << std::endl;
+ return true;
+ }
+ else {
+ std::cout << "Value mismatch: Expected " << std::hex << expectedValue << ", but received " << std::hex << receivedValue << std::endl;
+ return false;
+ }
+ }
+ else {
+ std::cout << "Unknown command: " << CurrentCommand.toStdString() << std::endl;
+ return false;
+ }
+}
+
void DataHandler::initializeMsgIdToCmdMap() {
msgIdToCmdMap[GET_FRONT_V851_VERSION] = "GET_FRONT_V851_VERSION";
msgIdToCmdMap[GET_FRONT_MCU_VERSION] = "GET_FRONT_MCU_VERSION";
diff --git a/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.h b/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.h
index b623cd2..4c2e41d 100644
--- a/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.h
+++ b/FactoryTestTool/SourceCode/RecvDataHandler/RecvDataHandler.h
@@ -28,7 +28,7 @@
#define YUV420 1
#define YUV422 2
-#define BACK_MAC_ADDRESS_LEN 11
+#define BACK_MAC_ADDRESS_LEN 17
class DataHandler : public QObject
{
@@ -48,6 +48,7 @@ public slots:
void handleData(const QString& client, const QByteArray& data, int msg_id, int currentRecvItemIndex,
int currentRecvFuncItemIndex, const QString& itemData, const QString& funcItemData,
const QJsonArray& jsonArray, int itemJsonIndex);
+ void getCurrentSendItem(const QString& text);
signals:
void statusUpdated(const QString& clientAddress, bool success, const QJsonArray& jsonArray, int itemJsonIndex);
void updateLicenseHwInfoEdit(const QString& text);
@@ -57,6 +58,7 @@ signals:
void updateVideoLabel(const QPixmap& pixmap);
void updateVideoResolution(const QString& resolutionText);
void picRecvFinished();
+ void commandError();
private:
QJsonArray frontBoardOneClickTest; // 前板一键功能测试 JSON
QJsonArray frontBoardTest; // 前板单项测试 JSON
@@ -91,8 +93,9 @@ private:
QMap msgIdToCmdMap;
QSize labelSize;
bool isStartVideo = false;
+ QString CurrentCommand = "";
- // 如果接收十六进制数据,转为二进制
+ bool getCommandNameFromValue(int receivedValue);
QByteArray hexStringToByteArray(const QString& hexString);
void showVideo(const QString& client, const QByteArray& valData);
void clearAllRecvData();
diff --git a/FactoryTestTool/SourceCode/Widget/MainWidget.cpp b/FactoryTestTool/SourceCode/Widget/MainWidget.cpp
index 7f7ca2c..a1ffffc 100644
--- a/FactoryTestTool/SourceCode/Widget/MainWidget.cpp
+++ b/FactoryTestTool/SourceCode/Widget/MainWidget.cpp
@@ -1,6 +1,6 @@
// MainWidget.cpp
#include "MainWidget.h"
-
+#include
void onThreadFinished(QThread* thread, ClientHandler* handler, DataHandler* dataHandler)
{
qDebug() << "Thread finished. Deleting handler and thread.";
@@ -9,6 +9,25 @@ void onThreadFinished(QThread* thread, ClientHandler* handler, DataHandler* data
thread->deleteLater();
}
+bool initializeMdns() {
+#ifdef _WIN32
+ WORD versionWanted = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ if (WSAStartup(versionWanted, &wsaData)) {
+ qDebug() << "Failed to initialize WinSock";
+ return false;
+ }
+#else
+ // 设置中断信号处理器
+ signal(SIGINT, [](int signal) {
+ qDebug() << "SIGINT received, cleaning up...";
+ // 处理退出信号的资源释放逻辑(如果需要)
+ });
+#endif
+ qDebug() << "mDNS initialization completed.";
+ return true;
+}
+
// 初始化 UI 组件和服务器
MainWidget::MainWidget(QWidget* parent) :
QWidget(parent),
@@ -19,15 +38,16 @@ MainWidget::MainWidget(QWidget* parent) :
lastClickedGetPicDevIndex(-1),
lastClickedGetVideoCamIndex(-1),
lastClickedGetVideoDevIndex(-1),
- mServiceProvider(new ServiceProvider(this)),
+ //mServiceProvider(new ServiceProvider(this)),
mdnsTimer(new QTimer(this)),
- httpClient(new HttpClient(this))
+ httpClient(new HttpClient(this)),
+ httpServer(new QTcpServer(this)),
+ mdnsThread(nullptr)
#if TEST_UDP_BROADCAST
,multicastSocket(new QUdpSocket(this)),
multicastTimer(new QTimer(this))
#endif
{
-
QString configFilePath = QDir::currentPath() + "/UI_config.ini";
TOOL_UI = loadConfig(configFilePath);
@@ -46,6 +66,12 @@ MainWidget::MainWidget(QWidget* parent) :
UuidHwInfoEdit = new QTextEdit(this);
setupUI();
+ // 初始化 mDNS
+ if (!initializeMdns()) {
+ qDebug() << "Failed to initialize mDNS. Exiting...";
+ return;
+ }
+ setupHttpServer();
// 打印线程池状态信息
setupTimerForThreadPoolInfo();
server = new QTcpServer(this);
@@ -58,6 +84,7 @@ MainWidget::MainWidget(QWidget* parent) :
QHostAddress clientIp = socket->peerAddress();
quint16 clientPort = socket->peerPort();
QString ipString = clientIp.toString();
+ isReplyOrTimeout = true;
if (ipString.startsWith("::ffff:")) {
ipString = ipString.mid(7);
}
@@ -67,14 +94,16 @@ MainWidget::MainWidget(QWidget* parent) :
qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
if (ipString.startsWith("10.10.10")) {
+ //if (1) {
qDebug() << "The client IP address is front board !!!";
isBackBoardOrAllBoard = 0;
}
else {
+ onDisconnectClient(clientId - 1);
qDebug() << "The client IP address is back board or all board";
isBackBoardOrAllBoard = clientId;
}
- stopMdnsService();
+ //stopMdnsService();
connectedClientsCount ++;
updateServerButtonText();
@@ -126,12 +155,14 @@ MainWidget::MainWidget(QWidget* parent) :
connect(handler, &ClientHandler::HandleInvalidOperate, this, &MainWidget::onHandleInvalidOperate);
connect(handler, &ClientHandler::clientDisconnected, this, &MainWidget::onClientDisconnected);
connect(handler, &ClientHandler::allItemsProcessed, this, &MainWidget::onAllItemsProcessed);
- connect(handler, &ClientHandler::selectClientDisconnected, this, &MainWidget::onDisconnectClient);
+ //connect(handler, &ClientHandler::selectClientDisconnected, this, &MainWidget::onDisconnectClient);
dataHandlers[clientId] = dataHandler;
- connect(handler, &ClientHandler::dataReceived, dataHandler, &DataHandler::handleData);
- connect(dataHandler, &DataHandler::picRecvFinished, handler, &ClientHandler::onPicRecvFinished);
- connect(dataHandler, &DataHandler::statusUpdated, this, &MainWidget::onStatusUpdated);
+ connect(handler, &ClientHandler::dataReceived, dataHandler, &DataHandler::handleData);
+ connect(handler, &ClientHandler::currentSendItem, dataHandler, &DataHandler::getCurrentSendItem);
+ connect(dataHandler, &DataHandler::picRecvFinished, handler, &ClientHandler::onPicRecvFinished);
+ connect(dataHandler, &DataHandler::commandError, handler, &ClientHandler::onCommandError);
+ connect(dataHandler, &DataHandler::statusUpdated, this, &MainWidget::onStatusUpdated);
// 当线程结束时删除 handler
connect(thread, &QThread::finished, this, [=]() {
onThreadFinished(thread, handler, dataHandler);
@@ -163,7 +194,9 @@ MainWidget::MainWidget(QWidget* parent) :
clientReadTimers[clientId] = readTimer;
connect(handler, &ClientHandler::sendDataToSomeClient, this, &MainWidget::sendDataToClient);
- if (isBackBoardOrAllBoard == 1) {
+ connect(handler, &ClientHandler::startImageSharing, this, &MainWidget::onStartImageSharing);
+
+ if (isBackBoardOrAllBoard != 0) {
handler->sendDevInfoItem();
}
}
@@ -178,8 +211,6 @@ MainWidget::MainWidget(QWidget* parent) :
connectionStatusCheckTimer = new QTimer(this);
connect(connectionStatusCheckTimer, &QTimer::timeout, this, &MainWidget::onCheckConnectionStatus);
- //connectionStatusCheckTimer->start(100); // 每100ms检查一次连接状态
- connect(mdnsTimer, &QTimer::timeout, this, &MainWidget::startMdnsService);
#if TEST_UDP_BROADCAST
// 设置组播地址
@@ -205,15 +236,6 @@ MainWidget::MainWidget(QWidget* parent) :
MainWidget::~MainWidget()
{
-#if TEST_UDP_BROADCAST
- multicastTimer->stop();
- multicastSocket->leaveMulticastGroup(QHostAddress("224.0.0.251"));
- multicastSocket->close();
-#endif
- if (mdnsTimer->isActive()) {
- mdnsTimer->stop();
- }
- delete mdnsTimer;
stopMdnsService();
for (auto timer : clientReadTimers) {
timer->stop();
@@ -283,7 +305,7 @@ void MainWidget::onClientDisconnected(ClientHandler* handler)
// 更新连接数并更新按键文本
connectedClientsCount--;
- qDebug() << " connectedClientsCount :" << connectedClientsCount;
+ //qDebug() << " connectedClientsCount :" << connectedClientsCount;
if (nextClientId <= 2) nextClientId --;
deviceConnected = true;
@@ -311,6 +333,60 @@ void MainWidget::onClientDisconnected(ClientHandler* handler)
}
}
+void MainWidget::onDisconnectClient(int clientId)
+{
+ for (ClientHandler* handler : clients) {
+ if (handler->getClientId() == clientId) {
+ // 断开与该客户端的连接
+ if (clientTimers.contains(clientId)) {
+ QTimer* timer = clientTimers[clientId];
+ timer->stop();
+ delete timer;
+ clientTimers.remove(clientId);
+ }
+ clients.removeOne(handler);
+ handler->deleteLater();
+
+ if (dataHandlers.contains(clientId)) {
+ DataHandler* dataHandler = dataHandlers[clientId];
+ dataHandlers.remove(clientId); // 从容器中移除
+ dataHandler->deleteLater(); // 延迟删除 DataHandler 对象
+ }
+ int count = 200;
+ int preVideoId = handler->preVideoClientId;
+ int boardTpye = isBackBoardOrAllBoard;
+ while (count--);
+ qDebug() << " preVideoClientId :" << preVideoId;
+ qDebug() << " clientId :" << clientId;
+ if ((boardTpye != 0) || (preVideoId == clientId)) {
+ qDebug() << "Current path: " << QDir::currentPath();
+ QString filePath = QDir::currentPath() + "/add1.h264";
+ if (QFile::exists(filePath)) {
+ QFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qDebug() << "File add1.h264 cleared successfully.";
+ }
+ else {
+ qDebug() << "Failed to clear file add1.h264:" << file.errorString();
+ }
+ }
+ else {
+ qDebug() << "File add1.h264 does not exist.";
+ }
+ }
+ connectedClientsCount--;
+ //qDebug() << " connectedClientsCount :" << connectedClientsCount;
+ updateServerButtonText();
+ break;
+ }
+ }
+ stopMdnsService();
+ //if (connectedClientsCount == 0) {
+ // // 启动 mDNS 服务广播
+ // startMdnsService();
+ //}
+}
+
// 更新按键文本的函数
void MainWidget::updateServerButtonText()
{
@@ -428,6 +504,201 @@ void MainWidget::setupUI()
connect(saveCheckBox, &QCheckBox::stateChanged, this, &MainWidget::onSaveCheckBoxStateChanged);
}
+void MainWidget::onStartImageSharing(int width, int height, QString img_type, std::function callback) {
+ imagePath = QFileDialog::getOpenFileName(this, "选择图片", QDir::homePath(), "Images (*.png *.jpg *.jpeg)");
+
+ if (imagePath.isEmpty()) {
+ qDebug() << "No image selected.";
+ return;
+ }
+
+ // 加载图片并获取尺寸
+ QImage image(imagePath);
+ if (image.isNull()) {
+ qDebug() << "Failed to load image.";
+ return;
+ }
+ QSize imageSize = image.size();
+ qDebug() << "Original image dimensions:" << imageSize.width() << "x" << imageSize.height();
+ // 判断是否需要裁剪
+ if (imageSize.width() > width || imageSize.height() > height) {
+ int x = (imageSize.width() - width) / 2; // 左右裁剪
+ int y = (imageSize.height() - height) / 2; // 上下裁剪
+
+ // 裁剪图片中间部分
+ image = image.copy(x, y, width, height);
+ qDebug() << "Cropped image dimensions:" << image.width() << "x" << image.height();
+ }
+ else if(imageSize.width() < width || imageSize.height() < height) {
+ isReplyOrTimeout = true;
+ QString info = QString("您选择的图片尺寸小于 %1 x %2,请重新操作并选择正确的尺寸的图片!!!").arg(width).arg(height);
+ LicenseConfirmWindow dialog(info);
+ dialog.exec();
+ callback("");
+ return;
+ }
+
+ // 保存裁剪后的图片到服务器目录
+ QString croppedImagePath = QCoreApplication::applicationDirPath() + QString("/%1_image.jpg").arg(img_type);
+ if (!image.save(croppedImagePath, "JPEG")) {
+ qDebug() << "Failed to save cropped image.";
+ return;
+ }
+ qDebug() << "Cropped image saved to:" << croppedImagePath;
+
+ // 更新服务使用裁剪后的图片路径
+ this->imagePath = croppedImagePath;
+
+ // 获取本地 IP 地址
+ QString localIP;
+ QList addresses = QNetworkInterface::allAddresses();
+ for (const QHostAddress& addr : addresses) {
+ if (addr.protocol() == QAbstractSocket::IPv4Protocol && addr != QHostAddress::LocalHost) {
+ localIP = addr.toString();
+ break;
+ }
+ }
+
+ if (localIP.isEmpty()) {
+ qDebug() << "Failed to determine local IP address.";
+ return;
+ }
+
+ // 构建下载 URL
+ QString downloadUrl = QString("http://%1:%2/%3_image.jpg").arg(localIP).arg(serverPort).arg(img_type);
+ qDebug() << "Download URL:" << downloadUrl;
+
+ // 回调返回下载地址
+ callback(downloadUrl);
+}
+
+void MainWidget::setupHttpServer() {
+ connect(httpServer, &QTcpServer::newConnection, this, [this]() {
+ QTcpSocket* clientSocket = httpServer->nextPendingConnection();
+ connect(clientSocket, &QTcpSocket::readyRead, this, [this, clientSocket]() {
+ handleHttpRequest(clientSocket);
+ });
+ });
+
+ if (!httpServer->listen(QHostAddress::Any, serverPort)) {
+ qDebug() << "Failed to start HTTP server:" << httpServer->errorString();
+ }
+ else {
+ qDebug() << "HTTP server started on port" << serverPort;
+ }
+}
+
+void MainWidget::handleHttpRequest(QTcpSocket* clientSocket) {
+ QByteArray requestData = clientSocket->readAll();
+ qDebug() << "HTTP Request:" << requestData;
+
+ if (imagePath.isEmpty()) {
+ clientSocket->write("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
+ clientSocket->disconnectFromHost();
+ return;
+ }
+
+ QFile file(imagePath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ clientSocket->write("HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n");
+ clientSocket->disconnectFromHost();
+ return;
+ }
+
+ QByteArray imageData = file.readAll();
+ file.close();
+
+ QString response = QString("HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-Length: %1\r\n\r\n")
+ .arg(imageData.size());
+ clientSocket->write(response.toUtf8());
+ clientSocket->write(imageData);
+ clientSocket->disconnectFromHost();
+}
+
+
+//void MainWidget::setupHttpServer() {
+// connect(httpServer, &QTcpServer::newConnection, this, [this]() {
+// QTcpSocket* clientSocket = httpServer->nextPendingConnection();
+// connect(clientSocket, &QTcpSocket::readyRead, this, [this, clientSocket]() {
+// handleHttpRequest(clientSocket);
+// });
+// });
+//
+// if (!httpServer->listen(QHostAddress::Any, serverPort)) {
+// qDebug() << "Failed to start HTTP server:" << httpServer->errorString();
+// }
+// else {
+// qDebug() << "HTTP server started on port" << serverPort;
+// }
+//}
+//
+//void MainWidget::handleHttpRequest(QTcpSocket* clientSocket) {
+// QByteArray requestData = clientSocket->readAll();
+// //qDebug() << "HTTP Request:" << requestData;
+// if (imagePath.isEmpty()) {
+// clientSocket->write("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
+// clientSocket->disconnectFromHost();
+// return;
+// }
+//
+// QFile file(imagePath);
+// if (!file.open(QIODevice::ReadOnly)) {
+// clientSocket->write("HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n");
+// clientSocket->disconnectFromHost();
+// return;
+// }
+//
+// QByteArray imageData = file.readAll();
+// file.close();
+//
+// QString response = QString("HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-Length: %1\r\n\r\n")
+// .arg(imageData.size());
+// clientSocket->write(response.toUtf8());
+// clientSocket->write(imageData);
+// clientSocket->disconnectFromHost();
+//}
+//
+////注意事项
+////端口冲突:确保 8080 端口未被其他程序占用,可以更换为其他端口。
+////防火墙规则:确保防火墙允许外部设备访问该端口。
+////图片格式:上述代码默认处理 PNG/JPG/JPEG 格式,如果需要支持其他格式,可根据 MIME 类型调整 Content - Type
+//void MainWidget::onStartImageSharing(int width, int height, std::function callback) {
+// imagePath = QFileDialog::getOpenFileName(this, "选择图片", QDir::homePath(), "Images (*.png *.jpg *.jpeg)");
+//
+// if (imagePath.isEmpty()) {
+// qDebug() << "No image selected.";
+// return;
+// }
+//
+// // 加载图片并获取尺寸
+// QImage image(imagePath);
+// if (image.isNull()) {
+// qDebug() << "Failed to load image.";
+// return;
+// }
+// QSize imageSize = image.size();
+// qDebug() << "Image dimensions:" << imageSize.width() << "x" << imageSize.height();
+//
+// QString localIP;
+// QList addresses = QNetworkInterface::allAddresses();
+// for (const QHostAddress& addr : addresses) {
+// if (addr.protocol() == QAbstractSocket::IPv4Protocol && addr != QHostAddress::LocalHost) {
+// localIP = addr.toString();
+// break;
+// }
+// }
+//
+// if (localIP.isEmpty()) {
+// qDebug() << "Failed to determine local IP address.";
+// return;
+// }
+//
+// QString downloadUrl = QString("http://%1:%2/").arg(localIP).arg(serverPort);
+// qDebug() << "Download URL:" << downloadUrl;
+//
+// callback(downloadUrl);
+//}
+
// 服务器响应
void MainWidget::onHttpRequestFinished(const QJsonObject& response)
{
@@ -501,9 +772,10 @@ QString calculateSignature(const QMap& params, const QString&
// 3. 构造 BaseString
//QString baseString = params["batch"] + params["label"] + params["model"] + params["request_id"] + params["timestamp"] + params["factory_id"];
- QString baseString = "1TEST_SL100_20240826SL100" + request_id + timestamp + "TEST";
+ //QString baseString = "1TEST_SL100_20240826SL100" + request_id + timestamp + FACTORY_ID;
+ QString baseString = QString::number(BATCH) + QString(LABEL) + QString(MODEL) + request_id + timestamp + QString(FACTORY_ID);
qDebug() << "baseString:" << baseString;
-
+
// 4. 构造 stringToSign
QString stringToSign = httpMethod + "&" + baseString + "&" + canonicalizedQueryString.replace("+", "%20");
qDebug() << "stringToSign:" << stringToSign;
@@ -513,10 +785,10 @@ QString calculateSignature(const QMap& params, const QString&
// 请求头
void prepareRequestHeaders(QNetworkRequest& request, const QString& sign, const QString& request_id) {
- request.setRawHeader("factory_id", "TEST");
- request.setRawHeader("label", "TEST_SL100_20240826");
- request.setRawHeader("batch", QString::number(1).toUtf8());
- request.setRawHeader("model", "SL100");
+ request.setRawHeader("factory_id", QByteArray(FACTORY_ID));
+ request.setRawHeader("label", QByteArray(LABEL));
+ request.setRawHeader("batch", QString::number(BATCH).toUtf8());
+ request.setRawHeader("model", QByteArray(MODEL));
request.setRawHeader("timestamp", QString::number(QDateTime::currentSecsSinceEpoch()).toUtf8());
request.setRawHeader("request_id", request_id.toUtf8());
request.setRawHeader("sign", sign.toUtf8());
@@ -602,8 +874,6 @@ void MainWidget::FactoryToolSendPostTestToHttpServer() {
{"id", "123456"},
{"location", "allMachine"}
};
- //QString itemString = "function=faceVerify,result=false,msg=timeout";
- //QString itemString = "function=faceVerify,result=false,msg=timeout";
QString itemString = "[{\"function\":\"faceVerify\",\"msg\":\"timeout\",\"result\":false}]";
params["items"] = itemString;
@@ -724,25 +994,28 @@ void MainWidget::setupTimerForThreadPoolInfo()
void MainWidget::readJsonConfig()
{
- frontBoardOneClickTest = readJson_frontBoardOneClickTest();
- frontBoardTest = readJson_frontBoardTest();
- frontBoardFuncConfig = readJson_frontBoardFuncConfig();
- frontBoardDevInfoJson = readJson_frontDevInfo();
- frontBoardLicenseJson = readJson_frontLicense();
+ frontBoardOneClickTest = readJson_frontBoardOneClickTest();
+ frontBoardTest = readJson_frontBoardTest();
+ frontBoardFuncConfig = readJson_frontBoardFuncConfig();
+ frontBoardDevInfoJson = readJson_frontDevInfo();
+ frontBoardLicenseJson = readJson_frontLicense();
+ //frontBoardCmdConfigJson = readJson_frontCmd_config();
- backBoardOneClickTest = readJson_backBoardOneClickTest();
- backBoardTest = readJson_backBoardTest();
- backBoardFuncConfig = readJson_backBoardFuncConfig();
- backBoardDevInfoJson = readJson_backDevInfo();
- backBoardUuidJson = readJson_backUuid();
+ backBoardOneClickTest = readJson_backBoardOneClickTest();
+ backBoardTest = readJson_backBoardTest();
+ backBoardFuncConfig = readJson_backBoardFuncConfig();
+ backBoardDevInfoJson = readJson_backDevInfo();
+ backBoardUuidJson = readJson_backUuid();
+ //backBoardCmdConfigJson = readJson_backCmd_config();
- factoryProductInfo = readJson_factoryProductInfo();
+ factoryProductInfo = readJson_factoryProductInfo();
testJsonConfig = readJson_testConfig();
funcJsonConfig = readJson_funcConfig();
getPicJson = readJson_getPic();
getVideoJson = readJson_getVideo();
+
}
void MainWidget::onSelectFileButtonClicked()
@@ -813,32 +1086,6 @@ void MainWidget::scrollToBottom()
statusListWidget->scrollToBottom();
}
-void MainWidget::onDisconnectClient(int clientId)
-{
- for (ClientHandler* handler : clients) {
- if (handler->getClientId() == clientId) {
- // 断开与该客户端的连接
- handler->getSocket()->disconnectFromHost();
- handler->getSocket()->waitForDisconnected();
- clients.removeOne(handler);
- if (clientTimers.contains(clientId)) {
- QTimer* timer = clientTimers[clientId];
- timer->stop();
- delete timer;
- clientTimers.remove(clientId);
- }
- handler->deleteLater();
- connectedClientsCount --;
- updateServerButtonText();
- break;
- }
- }
- if (connectedClientsCount == 0) {
- // 启动 mDNS 服务广播
- startMdnsService();
- }
-}
-
QString formatLicenseKey(const QString& licenseKey) {
QString formattedKey;
qDebug() << "licenseKey.length():" << licenseKey.length();
@@ -1061,27 +1308,41 @@ void MainWidget::onUuidButtonClicked()
}
}
-void MainWidget::startMdnsService()
-{
- QDateTime currentTime = QDateTime::currentDateTime();
- QString formattedTime = currentTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
- qDebug() << "[" << formattedTime << "]:" << "Start Mdns Broadcast Service";
- QString serviceName = "SL100 FactoryTool Mdns Broadcast Service";
- QString serviceType = "_myservice._tcp.local";
- quint16 port = TCP_CONNECT_PORT;
- mServiceProvider->startServiceBroadcast(serviceName, serviceType, port);
+void MainWidget::startMdnsService() {
+ const char* hostname = "SL100-FactoryTool-Mdns";
+ const char* service_name = "_myservice._tcp.local.";
+ int service_port = TCP_CONNECT_PORT;
- if (!mdnsTimer->isActive()) {
- mdnsTimer->start(1000);
+ // 如果线程已经存在且正在运行,先停止
+ if (mdnsThread && mdnsThread->isRunning()) {
+ qDebug() << "Stopping previous mDNS service thread...";
+ mdnsThread->stop();
+ mdnsThread->quit();
+ mdnsThread->wait();
+ delete mdnsThread;
}
+
+ // 创建新的线程并启动
+ mdnsThread = new MdnsServiceThread(hostname, service_name, service_port, this);
+ connect(mdnsThread, &QThread::finished, mdnsThread, &QObject::deleteLater); // 确保线程资源释放
+ mdnsThread->start();
}
-void MainWidget::stopMdnsService()
-{
- if (mdnsTimer->isActive()) {
- mdnsTimer->stop(); // 停止定时器
+void MainWidget::stopMdnsService() {
+ if (mdnsThread) {
+ qDebug() << "Stopping mDNS service...";
+ mdnsThread->stop(); // 通知线程退出
+ if (mdnsThread->isRunning()) {
+ mdnsThread->quit(); // 退出线程事件循环
+ mdnsThread->wait(); // 等待线程完全退出
+ }
+ delete mdnsThread; // 释放线程资源
+ mdnsThread = nullptr;
+ qDebug() << "mDNS service stopped.";
+ }
+ else {
+ qDebug() << "mDNS service is not running.";
}
- mServiceProvider->stopServiceBroadcast();
}
// 处理开始服务器按键点击事件
@@ -1409,10 +1670,11 @@ void MainWidget::onSendFrontFuncItemClicked()
QPushButton* button = qobject_cast(sender());
int itemIndex = button->property("frontBoardFuncConfig").toInt();
for (ClientHandler* handler : clients) {
- if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) {
+ if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) {
QString text = frontFuncConfigLineEdit->text();
qDebug() << "Text in frontFuncConfigLineEdit:" << text;
handler->sendFrontFuncItem(itemIndex, text);
+ isReplyOrTimeout = false;
break;
}
}
@@ -1429,10 +1691,11 @@ void MainWidget::onSendBackFuncItemClicked()
QPushButton* button = qobject_cast(sender());
int itemIndex = button->property("backBoardFuncConfig").toInt();
for (ClientHandler* handler : clients) {
- if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) {
+ if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) {
QString text = backFuncConfigLineEdit->text();
qDebug() << "Text in backFuncConfigLineEdit:" << text;
handler->sendBackFuncItem(itemIndex, text);
+ isReplyOrTimeout = false;
break;
}
}
@@ -1451,8 +1714,9 @@ void MainWidget::onSendFrontItemClicked()
QPushButton* button = qobject_cast(sender());
int itemIndex = button->property("frontBoardTest").toInt();
for (ClientHandler* handler : clients) {
- if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) {
+ if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) {
handler->sendFrontItem(itemIndex);
+ isReplyOrTimeout = false;
break;
}
}
@@ -1470,8 +1734,9 @@ void MainWidget::onSendBackItemClicked()
QPushButton* button = qobject_cast(sender());
int itemIndex = button->property("backBoardTest").toInt();
for (ClientHandler* handler : clients) {
- if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) {
+ if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) {
handler->sendBackItem(itemIndex);
+ isReplyOrTimeout = false;
break;
}
}
@@ -1484,6 +1749,7 @@ void MainWidget::onSendBackItemClicked()
void MainWidget::onStatusUpdated(const QString& client, bool success, const QJsonArray& jsonArray, int itemJsonIndex)
{
+ isReplyOrTimeout = true;
int clientId = -1;
QString label;
for (ClientHandler* handler : clients) {
diff --git a/FactoryTestTool/SourceCode/Widget/MainWidget.h b/FactoryTestTool/SourceCode/Widget/MainWidget.h
index 87a8a0e..5a0f74a 100644
--- a/FactoryTestTool/SourceCode/Widget/MainWidget.h
+++ b/FactoryTestTool/SourceCode/Widget/MainWidget.h
@@ -44,22 +44,29 @@
#include
#include
#include
+#include
+#include
+
+#include
+#include
#include "./UI_Widget/UI_Name.h"
#include "../Json/readJsonFile.h"
#include "../RecvDataHandler/RecvDataHandler.h"
#include "../LicenseGenerate/LicenseGenerate.h"
#include "../LicenseGenerate/LicenseConfirmWindow.h"
-#include "../Network/mdns/servicemodel.h"
+//#include "../Network/mdns/servicemodel.h"
#include "../Network/ClientHandler.h"
#include "../Network/httpClient.h"
+#include "../Network/mdns/MdnsServiceThread.h"
+#include "../Network/mdns/mdns.h"
-#include "../Network/mdns/qmdnsengine/include/server.h"
-#include "../Network/mdns/qmdnsengine/include/hostname.h"
-#include "../Network/mdns/qmdnsengine/include/provider.h"
-#include "../Network/mdns/qmdnsengine/include/service.h"
-#include "../Network/mdns/qmdnsengine/include/message.h"
-#include "../Network/mdns/qmdnsengine/include/query.h"
+//#include "../Network/mdns/qmdnsengine/include/server.h"
+//#include "../Network/mdns/qmdnsengine/include/hostname.h"
+//#include "../Network/mdns/qmdnsengine/include/provider.h"
+//#include "../Network/mdns/qmdnsengine/include/service.h"
+//#include "../Network/mdns/qmdnsengine/include/message.h"
+//#include "../Network/mdns/qmdnsengine/include/query.h"
#define TEST_UDP_BROADCAST 0 // 用于测试 UDP 组播实现 mdns 功能 非标准 mdns
#define MANUAL_UPLOAD_LICENSE 0 // 打开手动上传 License的功能
@@ -70,6 +77,12 @@
#define NEW_MAP 1
+
+#define FACTORY_ID "TEST" // 工厂ID
+#define LABEL "TEST_SL100_20240826" // 出货标签
+#define BATCH 1 // 出货批次
+#define MODEL "SL100" // 出货型号
+
class MainWidget : public QWidget
{
Q_OBJECT
@@ -79,6 +92,8 @@ public:
explicit MainWidget(QWidget* parent = nullptr);
~MainWidget();
+ void startHttpServer(const QString& imagePath);
+
signals:
void openFocusWindowRequested(int itemIndex);
@@ -86,6 +101,8 @@ private slots:
// 发送HTTP请求
//void onSomeButtonClicked();
// 处理HTTP响应
+ // 启动图片共享服务
+ void onStartImageSharing(int width, int height, QString img_type, std::function callback);
void onHttpRequestFinished(const QJsonObject& response);
// 处理HTTP错误
void onHttpRequestError(const QString& errorString);
@@ -187,11 +204,13 @@ private:
QJsonArray frontBoardFuncConfig; // 前板功能配置参数 JSON
QJsonArray frontBoardDevInfoJson; // 前板设备信息参数 JSON
QJsonArray frontBoardLicenseJson; // 前板License JSON
+ QJsonArray frontBoardCmdConfigJson;
QJsonArray backBoardOneClickTest; // 后板一键功能测试 JSON
QJsonArray backBoardTest; // 后板单项测试 JSON
QJsonArray backBoardFuncConfig; // 后板功能配置参数 JSON
QJsonArray backBoardDevInfoJson; // 后板设备信息参数 JSON
QJsonArray backBoardUuidJson; // 后板UUID JSON
+ QJsonArray backBoardCmdConfigJson;
QJsonArray factoryProductInfo; // 整机:工厂生产信息
QJsonArray testJsonConfig; // 功能测试区 JSON 配置
QJsonArray funcJsonConfig; // 功能配置区 JSON 配置
@@ -213,6 +232,7 @@ private:
bool deviceConnected = false; // 判断是否有设备连接过
bool isSendingAll; // 一键功能测试 状态
bool checkBoxState = true;
+ bool isReplyOrTimeout = true;
QJsonObject licenseDataArray; // 用于保存从服务器获取的 data 字段对象
@@ -266,7 +286,7 @@ private:
QMap clientReadTimers;
QMap clients_1;
- ServiceProvider* mServiceProvider;
+ //ServiceProvider* mServiceProvider;
QTimer* mdnsTimer;
void startMdnsService();
void stopMdnsService();
@@ -274,6 +294,14 @@ private:
QUdpSocket* multicastSocket;
QTimer* multicastTimer;
#endif
+
+ QTcpServer* httpServer; // HTTP 服务器
+ QString imagePath; // 当前选择的图片路径
+ quint16 serverPort = 8080; // HTTP 服务器端口
+
+ void setupHttpServer(); // 初始化 HTTP 服务器
+ void handleHttpRequest(QTcpSocket* clientSocket); // 处理 HTTP 请求
+ MdnsServiceThread* mdnsThread; // mDNS 线程指针
};
#endif // MAINWIDGET_H
diff --git a/FactoryTestTool/SourceCode/Widget/UI_Widget/UI_Widget.cpp b/FactoryTestTool/SourceCode/Widget/UI_Widget/UI_Widget.cpp
index e79d5fa..a9a285e 100644
--- a/FactoryTestTool/SourceCode/Widget/UI_Widget/UI_Widget.cpp
+++ b/FactoryTestTool/SourceCode/Widget/UI_Widget/UI_Widget.cpp
@@ -41,10 +41,12 @@ UI_config loadConfig(const QString& filePath)
{
UI_config config;
QMap settings = parseIniFile(filePath);
-
+ // 可直接修改 UI_config.ini 文件
+ // 如果删除 UI_config.ini 文件中的 Labels 项,则使用如下代码的默认命名配置
+ // Labels 项 默认命名配置
config.SL100_FACTORY_TOOL_W = settings.value("Window/width", "1340").toInt();
config.SL100_FACTORY_TOOL_H = settings.value("Window/height", "900").toInt();
- config.TOOL_VERSION = settings.value("Labels/tool_version", "SL100 工厂产测工具 - V0.0.8");
+ config.TOOL_VERSION = settings.value("Labels/tool_version", "SL100 工厂产测工具 - V0.0.10");
config.START_LISTENING = settings.value("Labels/start_listening", "开始监听\n(Start Listening...)");
config.ONE_CLICKED_TEST = settings.value("Labels/one_clicked_test", "一键功能测试");
config.FRONT_BOARD_NAME = settings.value("Labels/front_board_name", "前 板");
diff --git a/FactoryTestTool/TestLog/20240906_111117.txt b/FactoryTestTool/TestLog/20240906_111117.txt
deleted file mode 100644
index 042d505..0000000
--- a/FactoryTestTool/TestLog/20240906_111117.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-device ID: 1 - Item 2: ֹͣƵ ---> OK
-device ID: 1 - Item 2: ֹͣƵ ---> OK
-device ID: 1 - Item 2: ֹͣƵ ---> OK
-device ID: 1 - Item 2: ֹͣƵ ---> OK
-device ID: 1 - Item 1: Ƕע ---> NG
-device ID: 1 - Item 23: IRƹ ---> OK
-device ID: 1 - Item 24: ڲ ---> NG
-device ID: 1 - Item 1: get_hw_info ---> OK
-device ID: 1 - Item 1: Ƕע ---> NG
-device ID: 1 - Item 2: Ƕע ---> NG
-device ID: 1 - Item 3: ƾע ---> NG
-device ID: 1 - Item 4: ʶ ---> NG
-device ID: 1 - Item 5: ƾʶ ---> NG
-device ID: 1 - Item 6: ɾû ---> NG
-device ID: 1 - Item 7: ɾû ---> NG
-device ID: 1 - Item 8: ȡû ---> NG
-device ID: 1 - Item 9: ȡû ---> NG
-device ID: 1 - Item 10: ע ---> NG
-device ID: 1 - Item 11: ͼƬע ---> NG
-device ID: 1 - Item 12: ߾ͷȡͼ ---> OK
-device ID: 1 - Item 13: ұ߾ͷȡͼ ---> OK
-device ID: 1 - Item 14: ǰ ---> NG
-device ID: 1 - Item 15: MIC ---> NG
-device ID: 1 - Item 16: SPK ---> NG
-device ID: 1 - Item 17: ״ ---> NG
-device ID: 1 - Item 18: NFC ---> NG
-device ID: 1 - Item 19: ˿ ---> NG
-device ID: 1 - Item 20: ---> NG
-device ID: 1 - Item 21: ǰ ---> NG
-device ID: 1 - Item 22: IRƿ ---> OK
-device ID: 1 - Item 23: IRƹ ---> OK
-device ID: 1 - Item 24: ڲ ---> NG
-device ID: 1 - Item 25: PIR ---> NG
-device ID:-1 ---> All 25 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_101855.txt b/FactoryTestTool/TestLog/20240910_101855.txt
deleted file mode 100644
index 3109fde..0000000
--- a/FactoryTestTool/TestLog/20240910_101855.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-device ID: 1 - Item 1: V851SPK ---> NG
-device ID: 1 - Item 2: 806SPK ---> NG
-device ID: 1 - Item 3: MIC ---> NG
-device ID: 1 - Item 4: ---> NG
-device ID: 1 - Item 5: ---> NG
-device ID: 1 - Item 6: ---> NG
-device ID: 1 - Item 7: ---> NG
-device ID: 1 - Item 8: è۰ ---> NG
-device ID: 1 - Item 9: ---> NG
-device ID: 1 - Item 10: ---> NG
-device ID: 1 - Item 11: è۲ ---> NG
-device ID: 1 - Item 12: ڲ ---> NG
-device ID: 1 - Item 13: Ƶ ---> NG
-device ID: 1 - Item 14: رƵ ---> NG
-device ID: 1 - Item 15: wifiźŲ ---> NG
-device ID: 1 - Item 16: ---> NG
-device ID: 1 - Item 17: ---> NG
-device ID:-1 ---> All 17 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_102025.txt b/FactoryTestTool/TestLog/20240910_102025.txt
deleted file mode 100644
index f463d7f..0000000
--- a/FactoryTestTool/TestLog/20240910_102025.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-device ID: 1 - Item 1: Ƕע ---> NG
-device ID: 1 - Item 2: Ƕע ---> NG
-device ID: 1 - Item 3: ƾע ---> NG
-device ID: 1 - Item 4: ʶ ---> NG
-device ID: 1 - Item 5: ƾʶ ---> NG
-device ID: 1 - Item 6: ɾû ---> NG
-device ID: 1 - Item 7: ɾû ---> NG
-device ID: 1 - Item 8: ȡû ---> NG
-device ID: 1 - Item 9: ȡû ---> NG
-device ID: 1 - Item 10: ע ---> NG
-device ID: 1 - Item 11: ͼƬע ---> NG
-device ID: 1 - Item 12: ߾ͷȡͼ ---> OK
-device ID: 1 - Item 13: ұ߾ͷȡͼ ---> OK
-device ID: 1 - Item 14: ǰ ---> NG
-device ID: 1 - Item 15: MIC ---> NG
-device ID: 1 - Item 16: SPK ---> NG
-device ID: 1 - Item 17: ״ ---> NG
-device ID: 1 - Item 18: NFC ---> NG
-device ID: 1 - Item 19: ˿ ---> NG
-device ID: 1 - Item 20: ---> NG
-device ID: 1 - Item 21: ǰ ---> NG
-device ID: 1 - Item 22: IRƿ ---> OK
-device ID: 1 - Item 23: IRƹ ---> OK
-device ID: 1 - Item 24: ڲ ---> NG
-device ID: 1 - Item 25: PIR ---> NG
-device ID:-1 ---> All 25 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_104328.txt b/FactoryTestTool/TestLog/20240910_104328.txt
deleted file mode 100644
index f463d7f..0000000
--- a/FactoryTestTool/TestLog/20240910_104328.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-device ID: 1 - Item 1: Ƕע ---> NG
-device ID: 1 - Item 2: Ƕע ---> NG
-device ID: 1 - Item 3: ƾע ---> NG
-device ID: 1 - Item 4: ʶ ---> NG
-device ID: 1 - Item 5: ƾʶ ---> NG
-device ID: 1 - Item 6: ɾû ---> NG
-device ID: 1 - Item 7: ɾû ---> NG
-device ID: 1 - Item 8: ȡû ---> NG
-device ID: 1 - Item 9: ȡû ---> NG
-device ID: 1 - Item 10: ע ---> NG
-device ID: 1 - Item 11: ͼƬע ---> NG
-device ID: 1 - Item 12: ߾ͷȡͼ ---> OK
-device ID: 1 - Item 13: ұ߾ͷȡͼ ---> OK
-device ID: 1 - Item 14: ǰ ---> NG
-device ID: 1 - Item 15: MIC ---> NG
-device ID: 1 - Item 16: SPK ---> NG
-device ID: 1 - Item 17: ״ ---> NG
-device ID: 1 - Item 18: NFC ---> NG
-device ID: 1 - Item 19: ˿ ---> NG
-device ID: 1 - Item 20: ---> NG
-device ID: 1 - Item 21: ǰ ---> NG
-device ID: 1 - Item 22: IRƿ ---> OK
-device ID: 1 - Item 23: IRƹ ---> OK
-device ID: 1 - Item 24: ڲ ---> NG
-device ID: 1 - Item 25: PIR ---> NG
-device ID:-1 ---> All 25 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_112340.txt b/FactoryTestTool/TestLog/20240910_112340.txt
deleted file mode 100644
index 5002db5..0000000
--- a/FactoryTestTool/TestLog/20240910_112340.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
-device ID: 1 - Item 1: Ƕע ---> NG
-device ID: 1 - Item 2: Ƕע ---> NG
-device ID: 1 - Item 3: ƾע ---> NG
-device ID: 1 - Item 4: ʶ ---> NG
-device ID: 1 - Item 5: ƾʶ ---> NG
-device ID: 1 - Item 6: ɾû ---> NG
-device ID: 1 - Item 7: ɾû ---> NG
-device ID: 1 - Item 8: ȡû ---> NG
-device ID: 1 - Item 9: ȡû ---> NG
-device ID: 1 - Item 10: ע ---> NG
-device ID: 1 - Item 11: ͼƬע ---> NG
-device ID: 1 - Item 12: ߾ͷȡͼ ---> OK
-device ID: 1 - Item 13: ұ߾ͷȡͼ ---> OK
-device ID: 1 - Item 14: ǰ ---> NG
-device ID: 1 - Item 15: MIC ---> NG
-device ID: 1 - Item 16: SPK ---> NG
-device ID: 1 - Item 17: ״ ---> NG
-device ID: 1 - Item 18: NFC ---> NG
-device ID: 1 - Item 19: ˿ ---> NG
-device ID: 1 - Item 20: ---> NG
-device ID: 1 - Item 21: ǰ ---> NG
-device ID: 1 - Item 22: IRƿ ---> OK
-device ID: 1 - Item 23: IRƹ ---> OK
-device ID: 1 - Item 24: ڲ ---> NG
-device ID: 1 - Item 25: PIR ---> NG
-device ID:-1 ---> All 25 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_175315.txt b/FactoryTestTool/TestLog/20240910_175315.txt
deleted file mode 100644
index 4850346..0000000
--- a/FactoryTestTool/TestLog/20240910_175315.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_175933.txt b/FactoryTestTool/TestLog/20240910_175933.txt
deleted file mode 100644
index 5002db5..0000000
--- a/FactoryTestTool/TestLog/20240910_175933.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
-device ID: 1 - Item 1: Ƕע ---> NG
-device ID: 1 - Item 2: Ƕע ---> NG
-device ID: 1 - Item 3: ƾע ---> NG
-device ID: 1 - Item 4: ʶ ---> NG
-device ID: 1 - Item 5: ƾʶ ---> NG
-device ID: 1 - Item 6: ɾû ---> NG
-device ID: 1 - Item 7: ɾû ---> NG
-device ID: 1 - Item 8: ȡû ---> NG
-device ID: 1 - Item 9: ȡû ---> NG
-device ID: 1 - Item 10: ע ---> NG
-device ID: 1 - Item 11: ͼƬע ---> NG
-device ID: 1 - Item 12: ߾ͷȡͼ ---> OK
-device ID: 1 - Item 13: ұ߾ͷȡͼ ---> OK
-device ID: 1 - Item 14: ǰ ---> NG
-device ID: 1 - Item 15: MIC ---> NG
-device ID: 1 - Item 16: SPK ---> NG
-device ID: 1 - Item 17: ״ ---> NG
-device ID: 1 - Item 18: NFC ---> NG
-device ID: 1 - Item 19: ˿ ---> NG
-device ID: 1 - Item 20: ---> NG
-device ID: 1 - Item 21: ǰ ---> NG
-device ID: 1 - Item 22: IRƿ ---> OK
-device ID: 1 - Item 23: IRƹ ---> OK
-device ID: 1 - Item 24: ڲ ---> NG
-device ID: 1 - Item 25: PIR ---> NG
-device ID:-1 ---> All 25 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_101030.txt b/FactoryTestTool/TestLog/20240912_101030.txt
deleted file mode 100644
index 93e3a71..0000000
--- a/FactoryTestTool/TestLog/20240912_101030.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-device ID: 1 - Item 1: Ƶ ---> NG
-device ID: 3 - Item 1: Ƶ ---> OK
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_103950.txt b/FactoryTestTool/TestLog/20240912_103950.txt
deleted file mode 100644
index 4e03407..0000000
--- a/FactoryTestTool/TestLog/20240912_103950.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 3 - Item 1: Ƶ ---> OK
-device ID: 1 - Item 1: Ƶ ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_115543.txt b/FactoryTestTool/TestLog/20240912_115543.txt
deleted file mode 100644
index 64017b5..0000000
--- a/FactoryTestTool/TestLog/20240912_115543.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_133603.txt b/FactoryTestTool/TestLog/20240912_133603.txt
deleted file mode 100644
index 64017b5..0000000
--- a/FactoryTestTool/TestLog/20240912_133603.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_134525.txt b/FactoryTestTool/TestLog/20240912_134525.txt
deleted file mode 100644
index 64017b5..0000000
--- a/FactoryTestTool/TestLog/20240912_134525.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_134541.txt b/FactoryTestTool/TestLog/20240912_134541.txt
deleted file mode 100644
index d38661f..0000000
--- a/FactoryTestTool/TestLog/20240912_134541.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
-device ID: 1 - Item 1: V851汾: ---> NG
-device ID: 1 - Item 2: 806汾: ---> NG
-device ID: 1 - Item 3: Ӳ汾: ---> NG
-device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_134651.txt b/FactoryTestTool/TestLog/20240912_134651.txt
deleted file mode 100644
index 518ca25..0000000
--- a/FactoryTestTool/TestLog/20240912_134651.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_135002.txt b/FactoryTestTool/TestLog/20240912_135002.txt
deleted file mode 100644
index 50189c1..0000000
--- a/FactoryTestTool/TestLog/20240912_135002.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> OK
-device ID: 1 - Item 3: ǰӲ汾: ---> OK
-device ID: 1 - Item 4: 㷨汾: ---> OK
-device ID: 1 - Item 5: SN: ---> OK
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_135420.txt b/FactoryTestTool/TestLog/20240912_135420.txt
deleted file mode 100644
index 475fbe6..0000000
--- a/FactoryTestTool/TestLog/20240912_135420.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> OK
-device ID: 1 - Item 2: ǰMCU汾: ---> OK
-device ID: 1 - Item 3: ǰӲ汾: ---> OK
-device ID: 1 - Item 4: 㷨汾: ---> OK
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_135443.txt b/FactoryTestTool/TestLog/20240912_135443.txt
deleted file mode 100644
index 475fbe6..0000000
--- a/FactoryTestTool/TestLog/20240912_135443.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> OK
-device ID: 1 - Item 2: ǰMCU汾: ---> OK
-device ID: 1 - Item 3: ǰӲ汾: ---> OK
-device ID: 1 - Item 4: 㷨汾: ---> OK
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_140546.txt b/FactoryTestTool/TestLog/20240912_140546.txt
deleted file mode 100644
index 64017b5..0000000
--- a/FactoryTestTool/TestLog/20240912_140546.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_141720.txt b/FactoryTestTool/TestLog/20240912_141720.txt
deleted file mode 100644
index bc66a66..0000000
--- a/FactoryTestTool/TestLog/20240912_141720.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> OK
-device ID: 1 - Item 2: ǰMCU汾: ---> OK
-device ID: 1 - Item 3: ǰӲ汾: ---> OK
-device ID: 1 - Item 4: 㷨汾: ---> OK
-device ID: 1 - Item 5: SN: ---> OK
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_142059.txt b/FactoryTestTool/TestLog/20240912_142059.txt
deleted file mode 100644
index 64017b5..0000000
--- a/FactoryTestTool/TestLog/20240912_142059.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_143059.txt b/FactoryTestTool/TestLog/20240912_143059.txt
deleted file mode 100644
index 68856a9..0000000
--- a/FactoryTestTool/TestLog/20240912_143059.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-No device is connected !!!
-device ID: 1 - Item 1: ǰV851汾: ---> NG
-device ID: 1 - Item 2: ǰMCU汾: ---> NG
-device ID: 1 - Item 3: ǰӲ汾: ---> NG
-device ID: 1 - Item 4: 㷨汾: ---> NG
-device ID: 1 - Item 5: SN: ---> NG
-device ID:-1 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240910_105811.txt b/FactoryTestTool/TestLog/20241028_171608.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_105811.txt
rename to FactoryTestTool/TestLog/20241028_171608.txt
diff --git a/FactoryTestTool/TestLog/20240910_110555.txt b/FactoryTestTool/TestLog/20241029_135401.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_110555.txt
rename to FactoryTestTool/TestLog/20241029_135401.txt
diff --git a/FactoryTestTool/TestLog/20240910_111642.txt b/FactoryTestTool/TestLog/20241029_141318.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_111642.txt
rename to FactoryTestTool/TestLog/20241029_141318.txt
diff --git a/FactoryTestTool/TestLog/20240910_150245.txt b/FactoryTestTool/TestLog/20241029_141414.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_150245.txt
rename to FactoryTestTool/TestLog/20241029_141414.txt
diff --git a/FactoryTestTool/TestLog/20241029_141430.txt b/FactoryTestTool/TestLog/20241029_141430.txt
new file mode 100644
index 0000000..6872b12
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_141430.txt
@@ -0,0 +1,8 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
+device ID: 2 - Item 1: V851汾: ---> NG
+device ID: 2 - Item 2: 806汾: ---> NG
+device ID: 2 - Item 3: Ӳ汾: ---> NG
+device ID:-2 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_141605.txt b/FactoryTestTool/TestLog/20241029_141605.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_141605.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_141801.txt b/FactoryTestTool/TestLog/20241029_141801.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_141801.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_143547.txt b/FactoryTestTool/TestLog/20241029_143547.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_143547.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_150245.txt b/FactoryTestTool/TestLog/20241029_150245.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_150245.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_160741.txt b/FactoryTestTool/TestLog/20241029_160741.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_160741.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_160912.txt b/FactoryTestTool/TestLog/20241029_160912.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_160912.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_161215.txt b/FactoryTestTool/TestLog/20241029_161215.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_161215.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_161747.txt b/FactoryTestTool/TestLog/20241029_161747.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_161747.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_161949.txt b/FactoryTestTool/TestLog/20241029_161949.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_161949.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_162147.txt b/FactoryTestTool/TestLog/20241029_162147.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_162147.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_162403.txt b/FactoryTestTool/TestLog/20241029_162403.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_162403.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_162602.txt b/FactoryTestTool/TestLog/20241029_162602.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_162602.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_162837.txt b/FactoryTestTool/TestLog/20241029_162837.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_162837.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_163056.txt b/FactoryTestTool/TestLog/20241029_163056.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_163056.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_163804.txt b/FactoryTestTool/TestLog/20241029_163804.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_163804.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_164522.txt b/FactoryTestTool/TestLog/20241029_164522.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_164522.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_164746.txt b/FactoryTestTool/TestLog/20241029_164746.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_164746.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_165049.txt b/FactoryTestTool/TestLog/20241029_165049.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_165049.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_165232.txt b/FactoryTestTool/TestLog/20241029_165232.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_165232.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_165551.txt b/FactoryTestTool/TestLog/20241029_165551.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_165551.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_170040.txt b/FactoryTestTool/TestLog/20241029_170040.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_170040.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_170341.txt b/FactoryTestTool/TestLog/20241029_170341.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_170341.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_171955.txt b/FactoryTestTool/TestLog/20241029_171955.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_171955.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_172438.txt b/FactoryTestTool/TestLog/20241029_172438.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_172438.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_172543.txt b/FactoryTestTool/TestLog/20241029_172543.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_172543.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_172945.txt b/FactoryTestTool/TestLog/20241029_172945.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_172945.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_172954.txt b/FactoryTestTool/TestLog/20241029_172954.txt
new file mode 100644
index 0000000..6872b12
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_172954.txt
@@ -0,0 +1,8 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
+device ID: 2 - Item 1: V851汾: ---> NG
+device ID: 2 - Item 2: 806汾: ---> NG
+device ID: 2 - Item 3: Ӳ汾: ---> NG
+device ID:-2 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_173017.txt b/FactoryTestTool/TestLog/20241029_173017.txt
new file mode 100644
index 0000000..8080a39
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_173017.txt
@@ -0,0 +1,12 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
+device ID: 2 - Item 1: V851汾: ---> NG
+device ID: 2 - Item 2: 806汾: ---> NG
+device ID: 2 - Item 3: Ӳ汾: ---> NG
+device ID:-2 ---> All 3 items test completed !!!
+device ID: 3 - Item 1: V851汾: ---> NG
+device ID: 3 - Item 2: 806汾: ---> NG
+device ID: 3 - Item 3: Ӳ汾: ---> NG
+device ID:-3 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_174326.txt b/FactoryTestTool/TestLog/20241029_174326.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_174326.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_174339.txt b/FactoryTestTool/TestLog/20241029_174339.txt
new file mode 100644
index 0000000..6872b12
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_174339.txt
@@ -0,0 +1,8 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
+device ID: 2 - Item 1: V851汾: ---> NG
+device ID: 2 - Item 2: 806汾: ---> NG
+device ID: 2 - Item 3: Ӳ汾: ---> NG
+device ID:-2 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241029_174354.txt b/FactoryTestTool/TestLog/20241029_174354.txt
new file mode 100644
index 0000000..8080a39
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241029_174354.txt
@@ -0,0 +1,12 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
+device ID: 2 - Item 1: V851汾: ---> NG
+device ID: 2 - Item 2: 806汾: ---> NG
+device ID: 2 - Item 3: Ӳ汾: ---> NG
+device ID:-2 ---> All 3 items test completed !!!
+device ID: 3 - Item 1: V851汾: ---> NG
+device ID: 3 - Item 2: 806汾: ---> NG
+device ID: 3 - Item 3: Ӳ汾: ---> NG
+device ID:-3 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_135539.txt b/FactoryTestTool/TestLog/20241113_155139.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_135539.txt
rename to FactoryTestTool/TestLog/20241113_155139.txt
diff --git a/FactoryTestTool/TestLog/20241113_155247.txt b/FactoryTestTool/TestLog/20241113_155247.txt
new file mode 100644
index 0000000..942dc5e
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241113_155247.txt
@@ -0,0 +1,6 @@
+device ID: 2 - Item 1: ǰV851汾: ---> OK
+device ID: 2 - Item 2: ǰMCU汾: ---> OK
+device ID: 2 - Item 3: ǰӲ汾: ---> OK
+device ID: 2 - Item 4: 㷨汾: ---> OK
+device ID: 2 - Item 5: SN: ---> OK
+device ID:-2 ---> All 5 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241118_174349.txt b/FactoryTestTool/TestLog/20241118_174349.txt
new file mode 100644
index 0000000..b7d9434
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241118_174349.txt
@@ -0,0 +1,8 @@
+device ID: 1 - Item 0: ---> NG
+device ID: 1 - Item 1: ģʽ ---> NG
+device ID: 1 - Item 2: ǰV851汾: ---> NG
+device ID: 1 - Item 3: ǰMCU汾: ---> NG
+device ID: 1 - Item 4: ǰӲ汾: ---> NG
+device ID: 1 - Item 5: 㷨汾: ---> NG
+device ID: 1 - Item 6: SN: ---> NG
+device ID:-1 ---> All 6 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241118_174649.txt b/FactoryTestTool/TestLog/20241118_174649.txt
new file mode 100644
index 0000000..682eaf8
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241118_174649.txt
@@ -0,0 +1,7 @@
+device ID: 1 - Item 1: ģʽ ---> OK
+device ID: 1 - Item 2: ǰV851汾: ---> NG
+device ID: 1 - Item 3: ǰMCU汾: ---> NG
+device ID: 1 - Item 4: ǰӲ汾: ---> NG
+device ID: 1 - Item 5: 㷨汾: ---> NG
+device ID: 1 - Item 6: SN: ---> NG
+device ID:-1 ---> All 6 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241121_115205.txt b/FactoryTestTool/TestLog/20241121_115205.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241121_115205.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241121_115351.txt b/FactoryTestTool/TestLog/20241121_115351.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241121_115351.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241121_141824.txt b/FactoryTestTool/TestLog/20241121_141824.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241121_141824.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20240912_141152.txt b/FactoryTestTool/TestLog/20241121_141846.txt
similarity index 57%
rename from FactoryTestTool/TestLog/20240912_141152.txt
rename to FactoryTestTool/TestLog/20241121_141846.txt
index bc66a66..06e98f0 100644
--- a/FactoryTestTool/TestLog/20240912_141152.txt
+++ b/FactoryTestTool/TestLog/20241121_141846.txt
@@ -1,3 +1,7 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
device ID: 1 - Item 1: ǰV851汾: ---> OK
device ID: 1 - Item 2: ǰMCU汾: ---> OK
device ID: 1 - Item 3: ǰӲ汾: ---> OK
diff --git a/FactoryTestTool/TestLog/20240912_135836.txt b/FactoryTestTool/TestLog/20241121_142234.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_135836.txt
rename to FactoryTestTool/TestLog/20241121_142234.txt
diff --git a/FactoryTestTool/TestLog/20240910_105529.txt b/FactoryTestTool/TestLog/20241121_142309.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_105529.txt
rename to FactoryTestTool/TestLog/20241121_142309.txt
diff --git a/FactoryTestTool/TestLog/20240910_111727.txt b/FactoryTestTool/TestLog/20241121_145948.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_111727.txt
rename to FactoryTestTool/TestLog/20241121_145948.txt
diff --git a/FactoryTestTool/TestLog/20240910_112029.txt b/FactoryTestTool/TestLog/20241121_150414.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_112029.txt
rename to FactoryTestTool/TestLog/20241121_150414.txt
diff --git a/FactoryTestTool/TestLog/20240910_112251.txt b/FactoryTestTool/TestLog/20241121_150543.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_112251.txt
rename to FactoryTestTool/TestLog/20241121_150543.txt
diff --git a/FactoryTestTool/TestLog/20240910_175845.txt b/FactoryTestTool/TestLog/20241121_150811.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240910_175845.txt
rename to FactoryTestTool/TestLog/20241121_150811.txt
diff --git a/FactoryTestTool/TestLog/20240912_094338.txt b/FactoryTestTool/TestLog/20241121_151054.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_094338.txt
rename to FactoryTestTool/TestLog/20241121_151054.txt
diff --git a/FactoryTestTool/TestLog/20240912_095203.txt b/FactoryTestTool/TestLog/20241121_151149.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_095203.txt
rename to FactoryTestTool/TestLog/20241121_151149.txt
diff --git a/FactoryTestTool/TestLog/20240912_102548.txt b/FactoryTestTool/TestLog/20241121_151330.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_102548.txt
rename to FactoryTestTool/TestLog/20241121_151330.txt
diff --git a/FactoryTestTool/TestLog/20240912_105026.txt b/FactoryTestTool/TestLog/20241121_151750.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_105026.txt
rename to FactoryTestTool/TestLog/20241121_151750.txt
diff --git a/FactoryTestTool/TestLog/20240912_111447.txt b/FactoryTestTool/TestLog/20241121_152911.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_111447.txt
rename to FactoryTestTool/TestLog/20241121_152911.txt
diff --git a/FactoryTestTool/TestLog/20240912_111912.txt b/FactoryTestTool/TestLog/20241121_154236.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_111912.txt
rename to FactoryTestTool/TestLog/20241121_154236.txt
diff --git a/FactoryTestTool/TestLog/20240912_112126.txt b/FactoryTestTool/TestLog/20241121_155338.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_112126.txt
rename to FactoryTestTool/TestLog/20241121_155338.txt
diff --git a/FactoryTestTool/TestLog/20240912_113709.txt b/FactoryTestTool/TestLog/20241121_160033.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_113709.txt
rename to FactoryTestTool/TestLog/20241121_160033.txt
diff --git a/FactoryTestTool/TestLog/20240912_114351.txt b/FactoryTestTool/TestLog/20241121_160620.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_114351.txt
rename to FactoryTestTool/TestLog/20241121_160620.txt
diff --git a/FactoryTestTool/TestLog/20240912_114819.txt b/FactoryTestTool/TestLog/20241121_161533.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_114819.txt
rename to FactoryTestTool/TestLog/20241121_161533.txt
diff --git a/FactoryTestTool/TestLog/20240912_115049.txt b/FactoryTestTool/TestLog/20241125_102450.txt
similarity index 100%
rename from FactoryTestTool/TestLog/20240912_115049.txt
rename to FactoryTestTool/TestLog/20241125_102450.txt
diff --git a/FactoryTestTool/TestLog/20241210_155714.txt b/FactoryTestTool/TestLog/20241210_155714.txt
new file mode 100644
index 0000000..133fe3c
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241210_155714.txt
@@ -0,0 +1,4 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/TestLog/20241210_155727.txt b/FactoryTestTool/TestLog/20241210_155727.txt
new file mode 100644
index 0000000..5e0bd81
--- /dev/null
+++ b/FactoryTestTool/TestLog/20241210_155727.txt
@@ -0,0 +1,8 @@
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
+device ID: 1 - Item 1: V851汾: ---> NG
+device ID: 1 - Item 2: 806汾: ---> NG
+device ID: 1 - Item 3: Ӳ汾: ---> NG
+device ID:-1 ---> All 3 items test completed !!!
diff --git a/FactoryTestTool/ThirdParty/LicenseGenerate/pix_license.dll b/FactoryTestTool/ThirdParty/LicenseGenerate/pix_license.dll
index 6fdb40a..d65b6c2 100644
Binary files a/FactoryTestTool/ThirdParty/LicenseGenerate/pix_license.dll and b/FactoryTestTool/ThirdParty/LicenseGenerate/pix_license.dll differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared.zip b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared.zip
index 1b1ef05..2f566fa 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared.zip and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared.zip differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavcodec.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavcodec.dll.a
index 4d8fe90..e9ef43b 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavcodec.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavcodec.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavdevice.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavdevice.dll.a
index 432b1c0..753971a 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavdevice.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavdevice.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavfilter.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavfilter.dll.a
index d72631d..05f8eb1 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavfilter.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavfilter.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavformat.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavformat.dll.a
index 13e1eaf..ec1f1ff 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavformat.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavformat.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavutil.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavutil.dll.a
index 1eaf9f6..ed4eb1e 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavutil.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libavutil.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libpostproc.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libpostproc.dll.a
index cd8b9cb..4ab7c9f 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libpostproc.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libpostproc.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswresample.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswresample.dll.a
index 6206b94..66fc22d 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswresample.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswresample.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswscale.dll.a b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswscale.dll.a
index 5db5941..13a9e6f 100644
Binary files a/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswscale.dll.a and b/FactoryTestTool/ThirdParty/ffmpeg-master-latest-win64-gpl-shared/lib/libswscale.dll.a differ
diff --git a/FactoryTestTool/ThirdParty/libqrencode/include/qrencode.h b/FactoryTestTool/ThirdParty/libqrencode/include/qrencode.h
new file mode 100644
index 0000000..1a934cc
--- /dev/null
+++ b/FactoryTestTool/ThirdParty/libqrencode/include/qrencode.h
@@ -0,0 +1,568 @@
+/**
+ * qrencode - QR Code encoder
+ *
+ * Copyright (C) 2006-2017 Kentaro Fukuchi