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 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** \mainpage + * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D + * symbology. + * + * \section encoding Encoding + * + * There are two methods to encode data: encoding a string/data or + * encoding a structured data. + * + * \subsection encoding-string Encoding a string/data + * You can encode a string by calling QRcode_encodeString(). + * The given string is parsed automatically and encoded. If you want to encode + * data that can be represented as a C string style (NUL terminated), you can + * simply use this way. + * + * If the input data contains Kanji (Shift-JIS) characters and you want to + * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint. + * Otherwise, all of non-alphanumeric characters are encoded as 8-bit data. + * If you want to encode a whole string in 8-bit mode, you can use + * QRcode_encodeString8bit() instead. + * + * Please note that a C string can not contain NUL characters. If your data + * contains NUL, you must use QRcode_encodeData(). + * + * \subsection encoding-input Encoding a structured data + * You can construct a structured input data manually. If the structure of the + * input data is known, you can use this method. + * At first, create a ::QRinput object by QRinput_new(). Then add input data + * to the QRinput object by QRinput_append(). Finally call QRcode_encodeInput() + * to encode the QRinput data. + * You can reuse the QRinput object again to encode it in other symbols with + * different parameters. + * + * \section result Result + * The encoded symbol is generated as a ::QRcode object. It will contain its + * version number, the width of the symbol, and an array represents the symbol. + * See ::QRcode for the details. You can free the object by QRcode_free(). + * + * Please note that the version of the result may be larger than specified. + * In such cases, the input data would be too large to be encoded in a + * symbol of the specified version. + * + * \section structured Structured append + * Libqrencode can generate "Structured-appended" symbols that enables to split + * a large data set into mulitple QR codes. A QR code reader concatenates + * multiple QR code symbols into a string. + * Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured() + * to generate structured-appended symbols. This functions returns an instance + * of ::QRcode_List. The returned list is a singly-linked list of QRcode: you + * can retrieve each QR code in this way: + * + * \code + * QRcode_List *qrcodes; + * QRcode_List *entry; + * QRcode *qrcode; + * + * qrcodes = QRcode_encodeStringStructured(...); + * entry = qrcodes; + * while(entry != NULL) { + * qrcode = entry->code; + * // do something + * entry = entry->next; + * } + * QRcode_List_free(entry); + * \endcode + * + * Instead of using auto-parsing functions, you can construct your own + * structured input. At first, instantiate an object of ::QRinput_Struct + * by calling QRinput_Struct_new(). This object can hold multiple ::QRinput, + * and one QR code is generated for a ::QRinput. + * QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct + * object. In order to generate structured-appended symbols, it is required to + * embed headers to each symbol. You can use + * QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate + * headers to each symbol. You should call this function just once before + * encoding symbols. + */ + +#ifndef QRENCODE_H +#define QRENCODE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encoding mode. + */ +typedef enum { + QR_MODE_NUL = -1, ///< Terminator (NUL character). Internal use only + QR_MODE_NUM = 0, ///< Numeric mode + QR_MODE_AN, ///< Alphabet-numeric mode + QR_MODE_8, ///< 8-bit data mode + QR_MODE_KANJI, ///< Kanji (shift-jis) mode + QR_MODE_STRUCTURE, ///< Internal use only + QR_MODE_ECI, ///< ECI mode + QR_MODE_FNC1FIRST, ///< FNC1, first position + QR_MODE_FNC1SECOND, ///< FNC1, second position +} QRencodeMode; + +/** + * Level of error correction. + */ +typedef enum { + QR_ECLEVEL_L = 0, ///< lowest + QR_ECLEVEL_M, + QR_ECLEVEL_Q, + QR_ECLEVEL_H ///< highest +} QRecLevel; + +/** + * Maximum version (size) of QR-code symbol. + */ +#define QRSPEC_VERSION_MAX 40 + +/** + * Maximum version (size) of QR-code symbol. + */ +#define MQRSPEC_VERSION_MAX 4 + + +/****************************************************************************** + * Input data (qrinput.c) + *****************************************************************************/ + +/** + * Singly linked list to contain input strings. An instance of this class + * contains its version and error correction level too. It is required to + * set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(), + * or use QRinput_new2() to instantiate an object. + */ +typedef struct _QRinput QRinput; + +/** + * Instantiate an input data object. The version is set to 0 (auto-select) + * and the error correction level is set to QR_ECLEVEL_L. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput *QRinput_new(void); + +/** + * Instantiate an input data object. + * @param version version number. + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_new2(int version, QRecLevel level); + +/** + * Instantiate an input data object. Object's Micro QR Code flag is set. + * Unlike with full-sized QR Code, version number must be specified (>0). + * @param version version number (1--4). + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_newMQR(int version, QRecLevel level); + +/** + * Append data to an input object. + * The data is copied and appended to the input object. + * @param input input object. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data); + +/** + * Append ECI header. + * @param input input object. + * @param ecinum ECI indicator number (0 - 999999) + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_appendECIheader(QRinput *input, unsigned int ecinum); + +/** + * Get current version. + * @param input input object. + * @return current version. + */ +extern int QRinput_getVersion(QRinput *input); + +/** + * Set version of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersion(QRinput *input, int version); + +/** + * Get current error correction level. + * @param input input object. + * @return Current error correcntion level. + */ +extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input); + +/** + * Set error correction level of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level); + +/** + * Set version and error correction level of the QR code at once. + * This function is recommened for Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level); + +/** + * Free the input object. + * All of data chunks in the input object are freed too. + * @param input input object. + */ +extern void QRinput_free(QRinput *input); + +/** + * Validate the input data. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 invalid arguments. + */ +extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data); + +/** + * Set of QRinput for structured symbols. + */ +typedef struct _QRinput_Struct QRinput_Struct; + +/** + * Instantiate a set of input data object. + * @return an instance of QRinput_Struct. On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_Struct_new(void); + +/** + * Set parity of structured symbols. + * @param s structured input object. + * @param parity parity of s. + */ +extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity); + +/** + * Append a QRinput object to the set. QRinput created by QRinput_newMQR() + * will be rejected. + * @warning never append the same QRinput object twice or more. + * @param s structured input object. + * @param input an input object. + * @retval >0 number of input objects in the structure. + * @retval -1 an error occurred. See Exceptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid arguments. + */ +extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input); + +/** + * Free all of QRinput in the set. + * @param s a structured input object. + */ +extern void QRinput_Struct_free(QRinput_Struct *s); + +/** + * Split a QRinput to QRinput_Struct. It calculates a parity, set it, then + * insert structured-append headers. QRinput created by QRinput_newMQR() will + * be rejected. + * @param input input object. Version number and error correction level must be + * set. + * @return a set of input data. On error, NULL is returned, and errno is set + * to indicate the error. See Exceptions for the details. + * @throw ERANGE input data is too large. + * @throw EINVAL invalid input data. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input); + +/** + * Insert structured-append headers to the input structure. It calculates + * a parity and set it if the parity is not set yet. + * @param s input structure + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory. + */ +extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s); + +/** + * Set FNC1-1st position flag. + */ +extern int QRinput_setFNC1First(QRinput *input); + +/** + * Set FNC1-2nd position flag and application identifier. + */ +extern int QRinput_setFNC1Second(QRinput *input, unsigned char appid); + +/****************************************************************************** + * QRcode output (qrencode.c) + *****************************************************************************/ + +/** + * QRcode class. + * Symbol data is represented as an array contains width*width uchars. + * Each uchar represents a module (dot). If the less significant bit of + * the uchar is 1, the corresponding module is black. The other bits are + * meaningless for usual applications, but here its specification is described. + * + * @verbatim + MSB 76543210 LSB + |||||||`- 1=black/0=white + ||||||`-- 1=ecc/0=data code area + |||||`--- format information + ||||`---- version information + |||`----- timing pattern + ||`------ alignment pattern + |`------- finder pattern and separator + `-------- non-data modules (format, timing, etc.) + @endverbatim + */ +typedef struct { + int version; ///< version of the symbol + int width; ///< width of the symbol + unsigned char *data; ///< symbol data +} QRcode; + +/** + * Singly-linked list of QRcode. Used to represent a structured symbols. + * A list is terminated with NULL. + */ +typedef struct _QRcode_List { + QRcode *code; + struct _QRcode_List *next; +} QRcode_List; + +/** + * Create a symbol from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param input input data. + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode *QRcode_encodeInput(QRinput *input); + +/** + * Create a symbol from the string. The library automatically parses the input + * string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeString(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeString(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Micro QR Code version of QRcode_encodeString8bit(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level); + +/** + * Encode byte stream (may include '\0') in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input data. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeData(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Free the instance of QRcode class. + * @param qrcode an instance of QRcode class. + */ +extern void QRcode_free(QRcode *qrcode); + +/** + * Create structured symbols from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param s input data, structured. + * @return a singly-linked list of QRcode. + */ +extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s); + +/** + * Create structured symbols from the string. The library automatically parses + * the input string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeStringStructured(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level); + +/** + * Create structured symbols from byte stream (may include '\0'). Wholde data + * are encoded in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input dat. + * @param version version of the symbol. + * @param level error correction level. + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Return the number of symbols included in a QRcode_List. + * @param qrlist a head entry of a QRcode_List. + * @return number of symbols in the list. + */ +extern int QRcode_List_size(QRcode_List *qrlist); + +/** + * Free the QRcode_List. + * @param qrlist a head entry of a QRcode_List. + */ +extern void QRcode_List_free(QRcode_List *qrlist); + + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +/** + * Return a string that identifies the library version. + * @param major_version major version number + * @param minor_version minor version number + * @param micro_version micro version number + */ +extern void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version); + +/** + * Return a string that identifies the library version. + * @return a string identifies the library version. The string is held by the + * library. Do NOT free it. + */ +extern char *QRcode_APIVersionString(void); + +/** + * @deprecated + */ +#ifndef _MSC_VER +extern void QRcode_clearCache(void) __attribute__ ((deprecated)); +#else +extern void QRcode_clearCache(void); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* QRENCODE_H */ diff --git a/FactoryTestTool/ThirdParty/libqrencode/lib/ErWeiMaLib.lib b/FactoryTestTool/ThirdParty/libqrencode/lib/ErWeiMaLib.lib new file mode 100644 index 0000000..b151ed6 Binary files /dev/null and b/FactoryTestTool/ThirdParty/libqrencode/lib/ErWeiMaLib.lib differ diff --git a/FactoryTestTool/ThirdParty/qmdnsengine-master/examples/provider.zip b/FactoryTestTool/ThirdParty/qmdnsengine-master/examples/provider.zip index cf7198b..36edb00 100644 Binary files a/FactoryTestTool/ThirdParty/qmdnsengine-master/examples/provider.zip and b/FactoryTestTool/ThirdParty/qmdnsengine-master/examples/provider.zip differ diff --git a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll index 3d2727c..32f6469 100644 Binary files a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll and b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll differ diff --git a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll.a b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll.a index 92fd2ce..bcd8bf9 100644 Binary files a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll.a and b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx32/libYTDoorLockAuthTool.dll.a differ diff --git a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll index 2818e90..d485e24 100644 Binary files a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll and b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll differ diff --git a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll.a b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll.a index e99a13a..4fc7f0f 100644 Binary files a/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll.a and b/FactoryTestTool/ThirdParty/youtu_auth_tool/libs/windowsx64/libYTDoorLockAuthTool.dll.a differ diff --git a/FactoryTestTool/UI_config.ini b/FactoryTestTool/UI_config.ini index 55e9766..7ee4f97 100644 --- a/FactoryTestTool/UI_config.ini +++ b/FactoryTestTool/UI_config.ini @@ -10,7 +10,7 @@ Width = 1340 Height = 900 [Labels] -tool_version = SL100 工厂产测工具 - V0.0.7 +;tool_version = SL100 工厂产测工具 - V0.0.7 start_listening = 开始监听\n(Start Listening...) one_clicked_test = 一键功能测试 front_board_name = 前 板 diff --git a/misc/avcodec-61.dll b/misc/avcodec-61.dll index f3b5da2..1ce820b 100644 Binary files a/misc/avcodec-61.dll and b/misc/avcodec-61.dll differ diff --git a/misc/avdevice-61.dll b/misc/avdevice-61.dll index b4baebf..e715fab 100644 Binary files a/misc/avdevice-61.dll and b/misc/avdevice-61.dll differ diff --git a/misc/avfilter-10.dll b/misc/avfilter-10.dll index a246566..8bfeba9 100644 Binary files a/misc/avfilter-10.dll and b/misc/avfilter-10.dll differ diff --git a/misc/avformat-61.dll b/misc/avformat-61.dll index b70959f..f4d6bfe 100644 Binary files a/misc/avformat-61.dll and b/misc/avformat-61.dll differ diff --git a/misc/avutil-59.dll b/misc/avutil-59.dll index 713f715..5e472b4 100644 Binary files a/misc/avutil-59.dll and b/misc/avutil-59.dll differ diff --git a/misc/libYTDoorLockAuthTool.dll b/misc/libYTDoorLockAuthTool.dll index 3d2727c..32f6469 100644 Binary files a/misc/libYTDoorLockAuthTool.dll and b/misc/libYTDoorLockAuthTool.dll differ diff --git a/misc/postproc-58.dll b/misc/postproc-58.dll index adcf6f1..e5a578e 100644 Binary files a/misc/postproc-58.dll and b/misc/postproc-58.dll differ diff --git a/misc/swresample-5.dll b/misc/swresample-5.dll index 3ed2c7f..f2b2f10 100644 Binary files a/misc/swresample-5.dll and b/misc/swresample-5.dll differ diff --git a/misc/swscale-8.dll b/misc/swscale-8.dll index 9bb263e..de2f210 100644 Binary files a/misc/swscale-8.dll and b/misc/swscale-8.dll differ