1.添加图片注册和前后板主题图片上传;2.修改mdns连接方式

This commit is contained in:
钟富强 2024-12-10 16:15:55 +08:00
parent 9d506e1cfc
commit d2bccd9c49
177 changed files with 4381 additions and 5709 deletions

View File

@ -42,22 +42,7 @@
<ClCompile Include="SourceCode\Media\VideoDecoder\RingBuffer.cpp" />
<ClCompile Include="SourceCode\Network\ClientHandler.cpp" />
<ClCompile Include="SourceCode\Network\httpClient.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\abstractserver.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\bitmap.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\browser.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\cache.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\dns.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\hostname.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\mdns.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\message.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\prober.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\provider.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\query.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\record.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\resolver.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\server.cpp" />
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\service.cpp" />
<ClCompile Include="SourceCode\Network\mdns\servicemodel.cpp" />
<ClCompile Include="SourceCode\Network\mdns\mdns.c" />
<ClCompile Include="SourceCode\RecvDataHandler\RecvDataHandler.cpp" />
<ClCompile Include="SourceCode\Widget\MainWidget.cpp">
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">input</DynamicSource>
@ -77,12 +62,14 @@
<None Include="SourceCode\Json\JsonFile\backBoardOneClickTest.json" />
<None Include="SourceCode\Json\JsonFile\backBoardTest.json" />
<None Include="SourceCode\Json\JsonFile\backBoardUuid.json" />
<None Include="SourceCode\Json\JsonFile\backCmd_config.json" />
<None Include="SourceCode\Json\JsonFile\backDevInfo.json" />
<None Include="SourceCode\Json\JsonFile\factoryProductInfo.json" />
<None Include="SourceCode\Json\JsonFile\frontBoardFuncConfig.json" />
<None Include="SourceCode\Json\JsonFile\frontBoardLicense.json" />
<None Include="SourceCode\Json\JsonFile\frontBoardOneClickTest.json" />
<None Include="SourceCode\Json\JsonFile\frontBoardTest.json" />
<None Include="SourceCode\Json\JsonFile\frontCmd_config.json" />
<None Include="SourceCode\Json\JsonFile\frontDevInfo.json" />
<None Include="SourceCode\Json\JsonFile\funcConfig.json" />
<None Include="SourceCode\Json\JsonFile\getPic.json" />
@ -98,6 +85,8 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceCode\Json\readJsonFile.h" />
<ClInclude Include="SourceCode\Network\mdns\mdns.h" />
<QtMoc Include="SourceCode\Network\mdns\MdnsServiceThread.h" />
<ClInclude Include="SourceCode\Widget\UI_Widget\UI_Name.h" />
<QtMoc Include="SourceCode\LicenseGenerate\LicenseConfirmWindow.h" />
<ClInclude Include="SourceCode\LicenseGenerate\LicenseGenerate.h" />
@ -105,37 +94,8 @@
<ClInclude Include="SourceCode\Media\Media.h" />
<QtMoc Include="SourceCode\Network\ImageEnrollWindow.h" />
<QtMoc Include="SourceCode\Network\PasswordEnrollWindow.h" />
<QtMoc Include="SourceCode\Network\mdns\servicemodel.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\abstractserver.h" />
<QtMoc Include="SourceCode\Network\httpClient.h" />
<QtMoc Include="SourceCode\Media\VideoDecoder\FocusWindow.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\bitmap.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\browser.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\cache.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\dns.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\hostname.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\mdns.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\message.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\prober.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\provider.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\qmdnsengine_export.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\query.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\record.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\resolver.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\server.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\service.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\bitmap_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\browser_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\cache_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\hostname_p.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\message_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\prober_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\provider_p.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\query_p.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\record_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\resolver_p.h" />
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\server_p.h" />
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\service_p.h" />
<ClInclude Include="SourceCode\RecvDataHandler\MsgTpye.h" />
<QtMoc Include="SourceCode\Media\VideoDecoder\FFmpegDecoder.h" />
<ClInclude Include="SourceCode\Media\VideoDecoder\RingBuffer.h" />
@ -231,22 +191,22 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalOptions>/utf-8</AdditionalOptions>
<AdditionalIncludeDirectories>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</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>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</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;ErWeiMaLib.lib;Iphlpapi.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;E:\facttest\new_factest\FactoryTestTool\ThirdParty\libqrencode\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalOptions>/utf-8</AdditionalOptions>
<PreprocessorDefinitions>DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>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</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>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</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libYTDoorLockAuthTool.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;ErWeiMaLib.lib;Iphlpapi.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\QT\qt\5.15.2\msvc2019_64\lib;.\ThirdParty\youtu_auth_tool\libs\windowsx64;E:\facttest\new_factest\FactoryTestTool\ThirdParty\libqrencode\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

View File

@ -26,60 +26,15 @@
<ClCompile Include="SourceCode\LicenseGenerate\LicenseGenerate.cpp">
<Filter>LicenseGenerate</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\servicemodel.cpp">
<Filter>Network\mdns</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\abstractserver.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\bitmap.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\browser.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\cache.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\dns.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\hostname.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\mdns.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\message.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\prober.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\provider.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\query.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\record.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\resolver.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\server.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\qmdnsengine\src\service.cpp">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Widget\UI_Widget\UI_Widget.cpp">
<Filter>Widget\UI_Widget</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\httpClient.cpp">
<Filter>Network</Filter>
</ClCompile>
<ClCompile Include="SourceCode\Network\mdns\mdns.c">
<Filter>Network\mdns</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<QtMoc Include="SourceCode\Widget\MainWidget.h">
@ -106,60 +61,15 @@
<QtMoc Include="SourceCode\Network\PasswordEnrollWindow.h">
<Filter>Network</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\servicemodel.h">
<Filter>Network\mdns</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\abstractserver.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\browser.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\cache.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\hostname.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\prober.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\provider.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\resolver.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\include\server.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\browser_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\cache_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\hostname_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\prober_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\provider_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\resolver_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\qmdnsengine\src\server_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\httpClient.h">
<Filter>Network</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Media\VideoDecoder\FocusWindow.h">
<Filter>Media\VideoDecoder</Filter>
</QtMoc>
<QtMoc Include="SourceCode\Network\mdns\MdnsServiceThread.h">
<Filter>Network\mdns</Filter>
</QtMoc>
</ItemGroup>
<ItemGroup>
<None Include=".editorconfig" />
@ -212,6 +122,12 @@
<Filter>Json\JsonFile</Filter>
</None>
<None Include="UI_config.ini" />
<None Include="SourceCode\Json\JsonFile\backCmd_config.json">
<Filter>Json\JsonFile</Filter>
</None>
<None Include="SourceCode\Json\JsonFile\frontCmd_config.json">
<Filter>Json\JsonFile</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Filter Include="Widget">
@ -241,15 +157,6 @@
<Filter Include="Network\mdns">
<UniqueIdentifier>{3570ab1e-6ede-402b-8dd0-1c53afff0bd8}</UniqueIdentifier>
</Filter>
<Filter Include="Network\mdns\qmdnsengine">
<UniqueIdentifier>{d437b89e-76f2-495a-9434-e6ab8479c960}</UniqueIdentifier>
</Filter>
<Filter Include="Network\mdns\qmdnsengine\include">
<UniqueIdentifier>{7f4c4097-0c9f-4b37-967c-5efae6108a91}</UniqueIdentifier>
</Filter>
<Filter Include="Network\mdns\qmdnsengine\src">
<UniqueIdentifier>{e8857e15-2519-4a60-9fd5-eff901a76ba6}</UniqueIdentifier>
</Filter>
<Filter Include="Widget\UI_Widget">
<UniqueIdentifier>{ca263230-ea2f-4140-82aa-19b06eca1b1e}</UniqueIdentifier>
</Filter>
@ -273,48 +180,12 @@
<ClInclude Include="SourceCode\LicenseGenerate\LicenseGenerate.h">
<Filter>LicenseGenerate</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\bitmap.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\dns.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\mdns.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\message.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\query.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\record.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\service.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\bitmap_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\message_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\query_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\record_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\src\service_p.h">
<Filter>Network\mdns\qmdnsengine\src</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\qmdnsengine\include\qmdnsengine_export.h">
<Filter>Network\mdns\qmdnsengine\include</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Widget\UI_Widget\UI_Name.h">
<Filter>Widget\UI_Widget</Filter>
</ClInclude>
<ClInclude Include="SourceCode\Network\mdns\mdns.h">
<Filter>Network\mdns</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="icon.rc" />

View File

View File

@ -0,0 +1,7 @@
{
"cmds": {
"GET_FRONT_V851_VERSION": "0x0400",
"GET_REAR_V851_VERSION": "0x0401",
"START_PROCESS": "0x0500"
}
}

View File

@ -61,7 +61,7 @@
},
{
"cmd": "IMG_ENROLL",
"val": 0,
"val": "",
"lable": "图片注册",
"timeout": 2000
},

View File

@ -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"
}
}

View File

@ -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");
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -21,11 +21,16 @@
#include <QElapsedTimer>
#include <QStorageInfo>
#include <QMessageBox>
#include <QEventLoop>
#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<void(QString)> 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;

View File

@ -0,0 +1,44 @@
#include <QThread>
#include <QDebug>
#include <signal.h>
#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; // 默认运行状态
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class Message;
/**
* @brief Base class for sending and receiving DNS messages
*
* Many of the other classes in this library require the ability to send and
* receive DNS messages. By having them use this base class, they become far
* easier to test. Any class derived from this one that implements the pure
* virtual methods can be used for sending and receiving DNS messages.
*/
class QMDNSENGINE_EXPORT AbstractServer : public QObject
{
Q_OBJECT
public:
/**
* @brief Abstract constructor
*/
explicit AbstractServer(QObject *parent = 0);
/**
* @brief Send a message to its provided destination
*
* The message should be sent over the IP protocol specified in the
* message and to the target address and port specified in the message.
*/
virtual void sendMessage(const Message &message) = 0;
/**
* @brief Send a message to the multicast address on each interface
*
* The message should be sent over both IPv4 and IPv6 on all interfaces.
*/
virtual void sendMessageToAll(const Message &message) = 0;
Q_SIGNALS:
/**
* @brief Indicate that a DNS message was received
* @param message newly received message
*/
void messageReceived(const Message &message);
/**
* @brief Indicate that an error has occurred
* @param message brief description of the error
*/
void error(const QString &message);
};
}
#endif // QMDNSENGINE_ABSTRACTSERVER_H

View File

@ -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

View File

@ -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 <QByteArray>
#include <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class AbstractServer;
class Cache;
class Service;
class QMDNSENGINE_EXPORT BrowserPrivate;
/**
* @brief %Browser for local services
*
* This class provides a simple way to discover services on the local network.
* A cache may be provided in the constructor to store records for future
* queries.
*
* To browse for services of any type:
*
* @code
* QMdnsEngine::Browser browser(&server, QMdnsEngine::MdnsBrowseType);
* @endcode
*
* To browse for services of a specific type:
*
* @code
* QMdnsEngine::Browser browser(&server, "_http._tcp.local.");
* @endcode
*
* When a service is found, the serviceAdded() signal is emitted:
*
* @code
* connect(&browser, &QMdnsEngine::Browser::serviceAdded, [](const QMdnsEngine::Service &service) {
* qDebug() << "Service added:" << service.name();
* });
* @endcode
*
* The serviceUpdated() and serviceRemoved() signals are emitted when services
* are updated (their properties change) or are removed, respectively.
*/
class QMDNSENGINE_EXPORT Browser : public QObject
{
Q_OBJECT
public:
/**
* @brief Create a new browser instance
* @param server server to use for receiving and sending mDNS messages
* @param type service type to browse for
* @param cache DNS cache to use or null to create one
* @param parent QObject
*/
Browser(AbstractServer *server, const QByteArray &type, Cache *cache = 0, QObject *parent = 0);
Q_SIGNALS:
/**
* @brief Indicate that a new service has been added
*
* This signal is emitted when the PTR and SRV records for a service are
* received. If TXT records are received later, the serviceUpdated()
* signal will be emitted.
*/
void serviceAdded(const Service &service);
/**
* @brief Indicate that the specified service was updated
*
* This signal is emitted when the SRV record for a service (identified by
* its name and type) or a TXT record has changed.
*/
void serviceUpdated(const Service &service);
/**
* @brief Indicate that the specified service was removed
*
* This signal is emitted when an essential record (PTR or SRV) is
* expiring from the cache. This will also occur when an updated PTR or
* SRV record is received with a TTL of 0.
*/
void serviceRemoved(const Service &service);
private:
BrowserPrivate *const d;
};
}
#endif // QMDNSENGINE_BROWSER_H

View File

@ -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 <QList>
#include <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class Record;
class QMDNSENGINE_EXPORT CachePrivate;
/**
* @brief %Cache for DNS records
*
* Records are added to the cache using the addRecord() method which are then
* stored in the cache until they are considered to have expired, at which
* point they are purged. The shouldQuery() signal is used to indicate when a
* record is approaching expiry and the recordExpired() signal indicates when
* a record has expired (at which point it is removed).
*
* The cache can be queried to retrieve one or more records matching a given
* type. For example, to retrieve all TXT records that match a given name:
*
* @code
* Cache cache;
*
* QList<QMdnsEngine::Record> records;
* cache.lookupRecords("My Service._http._tcp.local.", QMdnsEngine::TXT, records);
*
* for (const QMdnsEngine::Record &record : records) {
* qDebug() << "Record:" << record.name();
* }
* @endcode
*
* Alternatively, lookupRecord() can be used to find a single record.
*/
class QMDNSENGINE_EXPORT Cache : public QObject
{
Q_OBJECT
public:
/**
* @brief Create an empty cache.
*/
explicit Cache(QObject *parent = 0);
/**
* @brief Add a record to the cache
* @param record add this record to the cache
*
* The TTL for the record will be added to the current time to calculate
* when the record expires. Existing records of the same name and type
* will be replaced, resetting their expiration.
*/
void addRecord(const Record &record);
/**
* @brief Retrieve a single record from the cache
* @param name name of record to retrieve or null for any
* @param type type of record to retrieve or ANY for all types
* @param record storage for the record retrieved
* @return true if a record was retrieved
*
* Some record types allow multiple records to be stored with identical
* names and types. This method will only retrieve the first matching
* record. Use lookupRecords() to obtain all of the records.
*/
bool lookupRecord(const QByteArray &name, quint16 type, Record &record) const;
/**
* @brief Retrieve multiple records from the cache
* @param name name of records to retrieve or null for any
* @param type type of records to retrieve or ANY for all types
* @param records storage for the records retrieved
* @return true if records were retrieved
*/
bool lookupRecords(const QByteArray &name, quint16 type, QList<Record> &records) const;
Q_SIGNALS:
/**
* @brief Indicate that a record will expire soon and a new query should be issued
* @param record reference to the record that will soon expire
*
* This signal is emitted when a record reaches approximately 50%, 85%,
* 90%, and 95% of its lifetime.
*/
void shouldQuery(const Record &record);
/**
* @brief Indicate that the specified record expired
* @param record reference to the record that has expired
*/
void recordExpired(const Record &record);
private:
CachePrivate *const d;
};
}
#endif // QMDNSENGINE_CACHE_H

View File

@ -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 <QByteArray>
#include <QMap>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class Message;
class Record;
enum {
/// IPv4 address record
A = 1,
/// IPv6 address record
AAAA = 28,
/// Wildcard for cache lookups
ANY = 255,
/// List of records
NSEC = 47,
/// Pointer to hostname
PTR = 12,
/// %Service information
SRV = 33,
/// Arbitrary metadata
TXT = 16
};
/**
* @brief Parse a name from a raw DNS packet
* @param packet raw DNS packet data
* @param offset offset into the packet where the name begins
* @param name reference to QByteArray to store the name in
* @return true if no errors occurred
*
* The offset will be incremented by the number of bytes read. Name
* compression requires access to the contents of the packet.
*/
QMDNSENGINE_EXPORT bool parseName(const QByteArray &packet, quint16 &offset, QByteArray &name);
/**
* @brief Write a name to a raw DNS packet
* @param packet raw DNS packet to write to
* @param offset offset to update with the number of bytes written
* @param name name to write to the packet
* @param nameMap map of names already written to their offsets
*
* The offset will be incremented by the number of bytes read. The name map
* will be updated with offsets of any names written so that it can be passed
* to future invocations of this function.
*/
QMDNSENGINE_EXPORT void writeName(QByteArray &packet, quint16 &offset, const QByteArray &name, QMap<QByteArray, quint16> &nameMap);
/**
* @brief Parse a record from a raw DNS packet
* @param packet raw DNS packet data
* @param offset offset into the packet where the record begins
* @param record reference to Record to populate
* @return true if no errors occurred
*/
QMDNSENGINE_EXPORT bool parseRecord(const QByteArray &packet, quint16 &offset, Record &record);
/**
* @brief Write a record to a raw DNS packet
* @param packet raw DNS packet to write to
* @param offset offset to update with the number of bytes written
* @param record record to write to the packet
* @param nameMap map of names already written to their offsets
*/
QMDNSENGINE_EXPORT void writeRecord(QByteArray &packet, quint16 &offset, Record &record, QMap<QByteArray, quint16> &nameMap);
/**
* @brief Populate a Message with data from a raw DNS packet
* @param packet raw DNS packet data
* @param message reference to Message to populate
* @return true if no errors occurred
*/
QMDNSENGINE_EXPORT bool fromPacket(const QByteArray &packet, Message &message);
/**
* @brief Create a raw DNS packet from a Message
* @param message Message to create the packet from
* @param packet storage for raw DNS packet
*/
QMDNSENGINE_EXPORT void toPacket(const Message &message, QByteArray &packet);
/**
* @brief Retrieve the string representation of a DNS type
* @param type integer type
* @return human-readable name for the type
*/
QMDNSENGINE_EXPORT QString typeName(quint16 type);
}
#endif // QMDNSENGINE_DNS_H

View File

@ -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 <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class AbstractServer;
class QMDNSENGINE_EXPORT HostnamePrivate;
/**
* @brief %Hostname reserved for exclusive use
*
* In order to provide services on the local network, a unique hostname must
* be used. This class asserts a hostname (by first confirming that it is not
* in use) and then responds to A and AAAA queries for the hostname.
*
* @code
* QMdnsEngine::Hostname hostname(&server);
*
* connect(&hostname, &QMdnsEngine::Hostname::hostnameChanged, [](const QByteArray &hostname) {
* qDebug() << "New hostname:" << hostname;
* });
* @endcode
*/
class QMDNSENGINE_EXPORT Hostname : public QObject
{
Q_OBJECT
public:
/**
* @brief Create a new hostname
*/
Hostname(AbstractServer *server, QObject *parent = 0);
/**
* @brief 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

View File

@ -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 <QByteArray>
#include <QHostAddress>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
/**
* @brief Standard port for mDNS
*/
QMDNSENGINE_EXPORT extern const quint16 MdnsPort;
/**
* @brief Standard IPv4 address for mDNS
*/
QMDNSENGINE_EXPORT extern const QHostAddress MdnsIpv4Address;
/**
* @brief Standard IPv6 address for mDNS
*/
QMDNSENGINE_EXPORT extern const QHostAddress MdnsIpv6Address;
/**
* @brief Service type for browsing service types
*/
QMDNSENGINE_EXPORT extern const QByteArray MdnsBrowseType;
}
#endif // QMDNSENGINE_MDNS_H

View File

@ -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 <QHostAddress>
#include <QList>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class Query;
class Record;
class QMDNSENGINE_EXPORT MessagePrivate;
/**
* @brief DNS message
*
* A DNS message consists of a header and zero or more queries and records.
* Instances of this class are created and initialized by
* [AbstractServer](@ref QMdnsEngine::AbstractServer) when messages are
* received from the network.
*
* If a message is being constructed in reply to one received from the
* network, the reply() method can be used to simplify initialization:
*
* @code
* connect(&server, &QMdnsEngine::Server::messageReceived, [](const QMdnsEngine::Message &message) {
* QMdnsEngine::Message reply;
* reply.reply(message);
* server.sendMessage(reply);
* });
* @endcode
*/
class QMDNSENGINE_EXPORT Message
{
public:
/**
* @brief Create an empty message
*/
Message();
/**
* @brief Create a copy of an existing message
*/
Message(const Message &other);
/**
* @brief Assignment operator
*/
Message &operator=(const Message &other);
/**
* @brief Destroy the message
*/
virtual ~Message();
/**
* @brief Retrieve the address for the message
*
* When receiving messages, this is the address that the message was
* received from.
*/
QHostAddress address() const;
/**
* @brief Set the address for the message
*
* When sending messages, this is the address that the message will be
* sent to. QMdnsEngine::MdnsIpv4Address and QMdnsEngine::MdnsIpv6Address
* can be used for mDNS messages.
*/
void setAddress(const QHostAddress &address);
/**
* @brief Retrieve the port for the message
*
* When receiving messages, this is the port that the message was received
* from. For traditional queries, this will be an ephemeral port. For mDNS
* queries, this will always equal QMdnsEngine::MdnsPort.
*/
quint16 port() const;
/**
* @brief Set the port for the message
*
* When sending messages, this is the port that the message will be sent
* to. This should be set to QMdnsEngine::MdnsPort unless the message is a
* reply to a traditional DNS query.
*/
void setPort(quint16 port);
/**
* @brief Retrieve the transaction ID for the message
*
* This is always set to 1 for mDNS messages. Traditional DNS queries may
* set this to an arbitrary integer.
*/
quint16 transactionId() const;
/**
* @brief Set the transaction ID for the message
*
* The default transaction ID is 0. This value should not be changed
* unless responding to a traditional DNS query.
*/
void setTransactionId(quint16 transactionId);
/**
* @brief Determine if the message is a response
*/
bool isResponse() const;
/**
* @brief Set whether the message is a response
*/
void setResponse(bool isResponse);
/**
* @brief Determine if the message is truncated
*/
bool isTruncated() const;
/**
* @brief Set whether the message is truncated
*/
void setTruncated(bool isTruncated);
/**
* @brief Retrieve a list of queries in the message
*/
QList<Query> queries() const;
/**
* @brief Add a query to the message
*/
void addQuery(const Query &query);
/**
* @brief Retrieve a list of records in the message
*/
QList<Record> records() const;
/**
* @brief Add a record to the message
*/
void addRecord(const Record &record);
/**
* @brief Reply to another message
*
* The message will be correctly initialized to respond to the other
* message. This includes setting the target address, port, and
* transaction ID.
*/
void reply(const Message &other);
private:
MessagePrivate *const d;
};
}
#endif // QMDNSENGINE_MESSAGE_H

View File

@ -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 <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class AbstractServer;
class Record;
class QMDNSENGINE_EXPORT ProberPrivate;
/**
* @brief %Prober to confirm that a record is unique
*
* Before responding to queries for a record, its uniqueness on the network
* must be confirmed. This class takes care of probing for existing records
* that match and adjusts the record's name until a unique one is found.
*
* For example, to probe for a SRV record:
*
* @code
* QMdnsEngine::Record record;
* record.setName("My Service._http._tcp.local.");
* record.setType(QMdnsEngine::SRV);
* record.setPort(1234);
* record.setTarget(hostname.hostname());
*
* QMdnsEngine::Prober prober(&server, record);
* connect(&prober, &QMdnsEngine::Prober::nameConfirmed, [](const QByteArray &name) {
* qDebug() << "Name confirmed:" << name;
* });
* @endcode
*/
class QMDNSENGINE_EXPORT Prober : public QObject
{
Q_OBJECT
public:
/**
* @brief Create a new prober
*/
Prober(AbstractServer *server, const Record &record, QObject *parent = 0);
Q_SIGNALS:
/**
* @brief Indicate that the name has been confirmed unique
* @param name that was confirmed to be unique
*/
void nameConfirmed(const QByteArray &name);
private:
ProberPrivate *const d;
};
}
#endif // QMDNSENGINE_PROBER_H

View File

@ -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 <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class AbstractServer;
class Hostname;
class Service;
class QMDNSENGINE_EXPORT ProviderPrivate;
/**
* @brief %Provider for a single mDNS service
*
* This class provide a [Service](@ref QMdnsEngine::Service) on the local
* network by responding to the appropriate DNS queries. A hostname is
* required for creating the SRV record.
*
* The provider needs to be given a reference to the service through the
* update() method so that it can construct DNS records:
*
* @code
* QMdnsEngine::Service service;
* service.setType("_http._tcp.local.");
* service.setName("My Service");
* service.setPort(1234);
*
* QMdnsEngine::Provider provider;
* provider.update(service);
* @endcode
*
* This method can also be used to update the provider's records.
*/
class QMDNSENGINE_EXPORT Provider : public QObject
{
Q_OBJECT
public:
/**
* @brief Create a new service provider
*/
Provider(AbstractServer *server, Hostname *hostname, QObject *parent = 0);
/**
* @brief Update the service with the provided information
* @param service updated service description
*
* This class will not respond to any DNS queries until the hostname is
* confirmed and this method is called.
*/
void update(const Service &service);
private:
ProviderPrivate *const d;
};
}
#endif // QMDNSENGINE_PROVIDER_H

View File

@ -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 <QtCore/qglobal.h>
#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

View File

@ -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 <QByteArray>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class QMDNSENGINE_EXPORT QueryPrivate;
/**
* @brief DNS query
*
* This class represents a query for a DNS record. For example, to query for
* the IPv4 address of a local host:
*
* @code
* QMdnsEngine::Query query;
* query.setName("myserver.local.");
* query.setType(QMdnsEngine::A);
*
* message.addQuery(query);
* @endcode
*/
class QMDNSENGINE_EXPORT Query
{
public:
/**
* @brief Create an empty query
*/
Query();
/**
* @brief Create a copy of an existing query
*/
Query(const Query &other);
/**
* @brief Assignment operator
*/
Query &operator=(const Query &other);
/**
* @brief Destroy the query
*/
virtual ~Query();
/**
* @brief Retrieve the name being queried
*/
QByteArray name() const;
/**
* @brief Set the name to query
*/
void setName(const QByteArray &name);
/**
* @brief Retrieve the type of record being queried
*/
quint16 type() const;
/**
* @brief Set the type of record to query
*
* Constants, such as QMdnsEngine::SRV are provided for convenience.
*/
void setType(quint16 type);
/**
* @brief Determine if a unicast response is desired
*/
bool unicastResponse() const;
/**
* @brief Set whether a unicast response is desired
*/
void setUnicastResponse(bool unicastResponse);
private:
QueryPrivate *const d;
};
QMDNSENGINE_EXPORT QDebug operator<<(QDebug dbg, const Query &query);
}
#endif // QMDNSENGINE_QUERY_H

View File

@ -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 <QByteArray>
#include <QHostAddress>
#include <QMap>
#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<QByteArray, QByteArray> attributes() const;
/**
* @brief Set attributes for the record
*/
void setAttributes(const QMap<QByteArray, QByteArray> &attributes);
/**
* @brief Add an attribute to the record
*/
void addAttribute(const QByteArray &key, const QByteArray &value);
/**
* @brief Retrieve the bitmap for the record
*
* This field is used by QMdnsEngine::NSEC records.
*/
Bitmap bitmap() const;
/**
* @brief Set the bitmap for the record
*/
void setBitmap(const Bitmap &bitmap);
private:
RecordPrivate *const d;
};
QMDNSENGINE_EXPORT QDebug operator<<(QDebug dbg, const Record &record);
}
#endif // QMDNSENGINE_RECORD_H

View File

@ -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 <QHostAddress>
#include <QObject>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class AbstractServer;
class Cache;
class QMDNSENGINE_EXPORT ResolverPrivate;
/**
* @brief %Resolver for services
*
* When [Browser](@ref QMdnsEngine::Browser) indicates that a new service has
* been found, it becomes necessary to resolve the service in order to connect
* to it. This class serves that role. A [Cache](@ref QMdnsEngine::Cache) can
* optionally be provided to speed up the resolving process.
*
* For example, assuming that `record` is a SRV record:
*
* @code
* QMdnsEngine::Resolver resolver(&server, record.target());
* connect(&resolver, &QMdnsEngine::Resolver::resolved, [](const QHostAddress &address) {
* qDebug() << "Address:" << address;
* });
* @endcode
*/
class QMDNSENGINE_EXPORT Resolver : public QObject
{
Q_OBJECT
public:
/**
* @brief Create a new resolver
*/
Resolver(AbstractServer *server, const QByteArray &name, Cache *cache = 0, QObject *parent = 0);
Q_SIGNALS:
/**
* @brief Indicate that the host resolved to an address
* @param address service address
*
* This signal will be emitted once for each resolved address. For
* example, if a host provides both A and AAAA records, this signal will
* be emitted twice.
*/
void resolved(const QHostAddress &address);
private:
ResolverPrivate *const d;
};
}
#endif // QMDNSENGINE_RESOLVER_H

View File

@ -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

View File

@ -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 <QByteArray>
#include <QHostAddress>
#include <QList>
#include <QMap>
#include "qmdnsengine_export.h"
namespace QMdnsEngine
{
class QMDNSENGINE_EXPORT ServicePrivate;
/**
* @brief %Service available on the local network
*
* This class contains the descriptive information necessary to represent an
* individual service made available to the local network. Instances are
* provided by [Browser](@ref QMdnsEngine::Browser) as services are
* discovered. Instances must be created and passed to
* [Provider::update()](@ref QMdnsEngine::Provider::update) to provide a
* service.
*/
class QMDNSENGINE_EXPORT Service
{
public:
/**
* @brief Create an uninitialized service
*/
Service();
/**
* @brief Create a copy of an existing service
*/
Service(const Service &other);
/**
* @brief Assignment operator
*/
Service &operator=(const Service &other);
/**
* @brief Equality operator
*/
bool operator==(const Service &other) const;
/**
* @brief Inequality operator
*/
bool operator!=(const Service &other) const;
/**
* @brief Destroy the service
*/
virtual ~Service();
/**
* @brief Retrieve the service type
*/
QByteArray type() const;
/**
* @brief Set the service type
*
* For example, an HTTP service might use "_http._tcp".
*/
void setType(const QByteArray &type);
/**
* @brief Retrieve the service name
*/
QByteArray name() const;
/**
* @brief Set the service name
*
* This is combined with the service type and domain to form the FQDN for
* the service.
*/
void setName(const QByteArray &name);
/**
* @brief Retrieve the hostname of the device providing the service
*/
QByteArray hostname() const;
/**
* @brief Set the hostname of the device providing the service
*/
void setHostname(const QByteArray &hostname);
/**
* @brief Retrieve the service port
*/
quint16 port() const;
/**
* @brief Set the service port
*/
void setPort(quint16 port);
/**
* @brief Retrieve the attributes for the service
*
* Boolean attributes will have null values (invoking QByteArray::isNull()
* on the value will return true).
*/
QMap<QByteArray, QByteArray> attributes() const;
/**
* @brief Set the attributes for the service
*/
void setAttributes(const QMap<QByteArray, QByteArray> &attributes);
/**
* @brief Add an attribute to the service
*/
void addAttribute(const QByteArray &key, const QByteArray &value);
private:
ServicePrivate *const d;
};
QMDNSENGINE_EXPORT QDebug operator<<(QDebug debug, const Service &service);
}
#endif // QMDNSENGINE_SERVICE_H

View File

@ -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 <QtCore/qglobal.h>
#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

View File

@ -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)
{
}

View File

@ -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);
}

View File

@ -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 <QtGlobal>
namespace QMdnsEngine
{
class BitmapPrivate
{
public:
BitmapPrivate();
virtual ~BitmapPrivate();
void free();
void fromData(quint8 newLength, const quint8 *newData);
quint8 length;
quint8 *data;
};
}
#endif // QMDNSENGINE_BITMAP_P_H

View File

@ -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<Record> txtRecords;
if (cache->lookupRecords(fqName, TXT, txtRecords)) {
QMap<QByteArray, QByteArray> attributes;
for (const Record &record : qAsConst(txtRecords)) {
for (auto i = record.attributes().constBegin();
i != record.attributes().constEnd(); ++i) {
attributes.insert(i.key(), i.value());
}
}
service.setAttributes(attributes);
}
// If the service existed, this is an update; otherwise it is a new
// addition; emit the appropriate signal
if (!services.contains(fqName)) {
emit q->serviceAdded(service);
} else if(services.value(fqName) != service) {
emit q->serviceUpdated(service);
}
services.insert(fqName, service);
hostnames.insert(service.hostname());
return false;
}
void BrowserPrivate::onMessageReceived(const Message &message)
{
if (!message.isResponse()) {
return;
}
const bool any = type == MdnsBrowseType;
// Use a set to track all services that are updated in the message to
// prevent unnecessary queries for SRV and TXT records
QSet<QByteArray> updateNames;
const auto records = message.records();
for (const Record &record : records) {
bool cacheRecord = false;
switch (record.type()) {
case PTR:
if (any && record.name() == MdnsBrowseType) {
ptrTargets.insert(record.target());
serviceTimer.start();
cacheRecord = true;
} else if (any || record.name() == type) {
updateNames.insert(record.target());
cacheRecord = true;
}
break;
case SRV:
case TXT:
if (any || record.name().endsWith("." + type)) {
updateNames.insert(record.name());
cacheRecord = true;
}
break;
}
if (cacheRecord) {
cache->addRecord(record);
}
}
// For each of the services marked to be updated, perform the update and
// make a list of all missing SRV records
QSet<QByteArray> queryNames;
for (const QByteArray &name : qAsConst(updateNames)) {
if (updateService(name)) {
queryNames.insert(name);
}
}
// Cache A / AAAA records after services are processed to ensure hostnames are known
for (const Record &record : records) {
bool cacheRecord = false;
switch (record.type()) {
case A:
case AAAA:
cacheRecord = hostnames.contains(record.name());
break;
}
if (cacheRecord) {
cache->addRecord(record);
}
}
// Build and send a query for all of the SRV and TXT records
if (queryNames.count()) {
Message queryMessage;
for (const QByteArray &name : qAsConst(queryNames)) {
Query query;
query.setName(name);
query.setType(SRV);
queryMessage.addQuery(query);
query.setType(TXT);
queryMessage.addQuery(query);
}
server->sendMessageToAll(queryMessage);
}
}
void BrowserPrivate::onShouldQuery(const Record &record)
{
// Assume that all messages in the cache are still in use (by the browser)
// and attempt to renew them immediately
Query query;
query.setName(record.name());
query.setType(record.type());
Message message;
message.addQuery(query);
server->sendMessageToAll(message);
}
void BrowserPrivate::onRecordExpired(const Record &record)
{
// If the SRV record has expired for a service, then it must be
// removed - TXT records on the other hand, cause an update
QByteArray serviceName;
switch (record.type()) {
case SRV:
serviceName = record.name();
break;
case TXT:
updateService(record.name());
return;
default:
return;
}
Service service = services.value(serviceName);
if (!service.name().isNull()) {
emit q->serviceRemoved(service);
services.remove(serviceName);
updateHostnames();
}
}
void BrowserPrivate::onQueryTimeout()
{
Query query;
query.setName(type);
query.setType(PTR);
Message message;
message.addQuery(query);
// TODO: including too many records could cause problems
// Include PTR records for the target that are already known
QList<Record> records;
if (cache->lookupRecords(query.name(), PTR, records)) {
for (const Record &record : qAsConst(records)) {
message.addRecord(record);
}
}
server->sendMessageToAll(message);
queryTimer.start();
}
void BrowserPrivate::onServiceTimeout()
{
if (ptrTargets.count()) {
Message message;
for (const QByteArray &target : qAsConst(ptrTargets)) {
// Add a query for PTR records
Query query;
query.setName(target);
query.setType(PTR);
message.addQuery(query);
// Include PTR records for the target that are already known
QList<Record> records;
if (cache->lookupRecords(target, PTR, records)) {
for (const Record &record : qAsConst(records)) {
message.addRecord(record);
}
}
}
server->sendMessageToAll(message);
ptrTargets.clear();
}
}
void BrowserPrivate::updateHostnames()
{
hostnames.clear();
for (const auto& service : services) {
hostnames.insert(service.hostname());
}
}
Browser::Browser(AbstractServer *server, const QByteArray &type, Cache *cache, QObject *parent)
: QObject(parent),
d(new BrowserPrivate(this, server, type, cache))
{
}

View File

@ -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 <QByteArray>
#include <QMap>
#include <QObject>
#include <QSet>
#include <QTimer>
#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<QByteArray> ptrTargets;
QMap<QByteArray, Service> services;
QSet<QByteArray> hostnames;
QTimer queryTimer;
QTimer serviceTimer;
private Q_SLOTS:
void onMessageReceived(const Message &message);
void onShouldQuery(const Record &record);
void onRecordExpired(const Record &record);
void onQueryTimeout();
void onServiceTimeout();
private:
void updateHostnames();
Browser *const q;
};
}
#endif // QMDNSENGINE_BROWSER_P_H

View File

@ -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 <QtGlobal>
#if(QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
#include <QRandomGenerator>
#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<QDateTime> triggers{
now.addMSecs(record.ttl() * 500 + random), // 50%
now.addMSecs(record.ttl() * 850 + random), // 85%
now.addMSecs(record.ttl() * 900 + random), // 90%
now.addMSecs(record.ttl() * 950 + random), // 95%
now.addSecs(record.ttl())
};
// Append the record and its triggers
d->entries.append({record, triggers});
// Check if the new record's first trigger is earlier than the next
// scheduled trigger; if so, restart the timer
if (d->nextTrigger.isNull() || triggers.at(0) < d->nextTrigger) {
d->nextTrigger = triggers.at(0);
d->timer.start(now.msecsTo(d->nextTrigger));
}
}
bool Cache::lookupRecord(const QByteArray &name, quint16 type, Record &record) const
{
QList<Record> records;
if (lookupRecords(name, type, records)) {
record = records.at(0);
return true;
}
return false;
}
bool Cache::lookupRecords(const QByteArray &name, quint16 type, QList<Record> &records) const
{
bool recordsAdded = false;
for (const CachePrivate::Entry &entry : d->entries) {
if ((name.isNull() || entry.record.name() == name) &&
(type == ANY || entry.record.type() == type)) {
records.append(entry.record);
recordsAdded = true;
}
}
return recordsAdded;
}

View File

@ -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 <QDateTime>
#include <QList>
#include <QObject>
#include <QTimer>
#include "../include/record.h"
namespace QMdnsEngine
{
class Cache;
class CachePrivate : public QObject
{
Q_OBJECT
public:
struct Entry
{
Record record;
QList<QDateTime> triggers;
};
CachePrivate(Cache *cache);
QTimer timer;
QList<Entry> entries;
QDateTime nextTrigger;
private Q_SLOTS:
void onTimeout();
private:
Cache *const q;
};
}
#endif // QMDNSENGINE_CACHE_P_H

View File

@ -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 <QHostAddress>
#include <QtEndian>
#include "../include/bitmap.h"
#include "../include/dns.h"
#include "../include/message.h"
#include "../include/query.h"
#include "../include/record.h"
namespace QMdnsEngine
{
template<class T>
bool parseInteger(const QByteArray &packet, quint16 &offset, T &value)
{
if (offset + sizeof(T) > static_cast<unsigned int>(packet.length())) {
return false; // out-of-bounds
}
value = qFromBigEndian<T>(reinterpret_cast<const uchar*>(packet.constData() + offset));
offset += sizeof(T);
return true;
}
template<class T>
void writeInteger(QByteArray &packet, quint16 &offset, T value)
{
value = qToBigEndian<T>(value);
packet.append(reinterpret_cast<const char*>(&value), sizeof(T));
offset += sizeof(T);
}
bool parseName(const QByteArray &packet, quint16 &offset, QByteArray &name)
{
quint16 offsetEnd = 0;
quint16 offsetPtr = offset;
forever {
quint8 nBytes;
if (!parseInteger<quint8>(packet, offset, nBytes)) {
return false;
}
if (!nBytes) {
break;
}
switch (nBytes & 0xc0) {
case 0x00:
if (offset + nBytes > packet.length()) {
return false; // length exceeds message
}
name.append(packet.mid(offset, nBytes));
name.append('.');
offset += nBytes;
break;
case 0xc0:
{
quint8 nBytes2;
quint16 newOffset;
if (!parseInteger<quint8>(packet, offset, nBytes2)) {
return false;
}
newOffset = ((nBytes & ~0xc0) << 8) | nBytes2;
if (newOffset >= offsetPtr) {
return false; // prevent infinite loop
}
offsetPtr = newOffset;
if (!offsetEnd) {
offsetEnd = offset;
}
offset = newOffset;
break;
}
default:
return false; // no other types supported
}
}
if (offsetEnd) {
offset = offsetEnd;
}
return true;
}
void writeName(QByteArray &packet, quint16 &offset, const QByteArray &name, QMap<QByteArray, quint16> &nameMap)
{
QByteArray fragment = name;
if (fragment.endsWith('.')) {
fragment.chop(1);
}
while (fragment.length()) {
if (nameMap.contains(fragment)) {
writeInteger<quint16>(packet, offset, nameMap.value(fragment) | 0xc000);
return;
}
nameMap.insert(fragment, offset);
int index = fragment.indexOf('.');
if (index == -1) {
index = fragment.length();
}
writeInteger<quint8>(packet, offset, index);
packet.append(fragment.left(index));
offset += index;
fragment.remove(0, index + 1);
}
writeInteger<quint8>(packet, offset, 0);
}
bool parseRecord(const QByteArray &packet, quint16 &offset, Record &record)
{
QByteArray name;
quint16 type, class_, dataLen;
quint32 ttl;
if (!parseName(packet, offset, name) ||
!parseInteger<quint16>(packet, offset, type) ||
!parseInteger<quint16>(packet, offset, class_) ||
!parseInteger<quint32>(packet, offset, ttl) ||
!parseInteger<quint16>(packet, offset, dataLen)) {
return false;
}
record.setName(name);
record.setType(type);
record.setFlushCache(class_ & 0x8000);
record.setTtl(ttl);
switch (type) {
case A:
{
quint32 ipv4Addr;
if (!parseInteger<quint32>(packet, offset, ipv4Addr)) {
return false;
}
record.setAddress(QHostAddress(ipv4Addr));
break;
}
case AAAA:
{
if (offset + 16 > packet.length()) {
return false;
}
record.setAddress(QHostAddress(
reinterpret_cast<const quint8*>(packet.constData() + offset)
));
offset += 16;
break;
}
case NSEC:
{
QByteArray nextDomainName;
quint8 number;
quint8 length;
if (!parseName(packet, offset, nextDomainName) ||
!parseInteger<quint8>(packet, offset, number) ||
!parseInteger<quint8>(packet, offset, length) ||
number != 0 ||
offset + length > packet.length()) {
return false;
}
Bitmap bitmap;
bitmap.setData(length, reinterpret_cast<const quint8*>(packet.constData() + offset));
record.setNextDomainName(nextDomainName);
record.setBitmap(bitmap);
offset += length;
break;
}
case PTR:
{
QByteArray target;
if (!parseName(packet, offset, target)) {
return false;
}
record.setTarget(target);
break;
}
case SRV:
{
quint16 priority, weight, port;
QByteArray target;
if (!parseInteger<quint16>(packet, offset, priority) ||
!parseInteger<quint16>(packet, offset, weight) ||
!parseInteger<quint16>(packet, offset, port) ||
!parseName(packet, offset, target)) {
return false;
}
record.setPriority(priority);
record.setWeight(weight);
record.setPort(port);
record.setTarget(target);
break;
}
case TXT:
{
quint16 start = offset;
while (offset < start + dataLen) {
quint8 nBytes;
if (!parseInteger<quint8>(packet, offset, nBytes) ||
offset + nBytes > packet.length()) {
return false;
}
if (nBytes == 0) {
break;
}
QByteArray attr(packet.constData() + offset, nBytes);
offset += nBytes;
int splitIndex = attr.indexOf('=');
if (splitIndex == -1) {
record.addAttribute(attr, QByteArray());
} else {
record.addAttribute(attr.left(splitIndex), attr.mid(splitIndex + 1));
}
}
break;
}
default:
offset += dataLen;
break;
}
return true;
}
void writeRecord(QByteArray &packet, quint16 &offset, Record &record, QMap<QByteArray, quint16> &nameMap)
{
writeName(packet, offset, record.name(), nameMap);
writeInteger<quint16>(packet, offset, record.type());
writeInteger<quint16>(packet, offset, record.flushCache() ? 0x8001 : 1);
writeInteger<quint32>(packet, offset, record.ttl());
offset += 2;
QByteArray data;
switch (record.type()) {
case A:
writeInteger<quint32>(data, offset, record.address().toIPv4Address());
break;
case AAAA:
{
Q_IPV6ADDR ipv6Addr = record.address().toIPv6Address();
data.append(reinterpret_cast<const char*>(&ipv6Addr), sizeof(Q_IPV6ADDR));
offset += data.length();
break;
}
case NSEC:
{
quint8 length = record.bitmap().length();
writeName(data, offset, record.nextDomainName(), nameMap);
writeInteger<quint8>(data, offset, 0);
writeInteger<quint8>(data, offset, length);
data.append(reinterpret_cast<const char*>(record.bitmap().data()), length);
offset += length;
break;
}
case PTR:
writeName(data, offset, record.target(), nameMap);
break;
case SRV:
writeInteger<quint16>(data, offset, record.priority());
writeInteger<quint16>(data, offset, record.weight());
writeInteger<quint16>(data, offset, record.port());
writeName(data, offset, record.target(), nameMap);
break;
case TXT:
if (!record.attributes().count()) {
writeInteger<quint8>(data, offset, 0);
break;
}
for (auto i = record.attributes().constBegin(); i != record.attributes().constEnd(); ++i) {
QByteArray entry = i.value().isNull() ? i.key() : i.key() + "=" + i.value();
writeInteger<quint8>(data, offset, entry.length());
data.append(entry);
offset += entry.length();
}
break;
default:
break;
}
offset -= 2;
writeInteger<quint16>(packet, offset, data.length());
packet.append(data);
}
bool fromPacket(const QByteArray &packet, Message &message)
{
quint16 offset = 0;
quint16 transactionId, flags, nQuestion, nAnswer, nAuthority, nAdditional;
if (!parseInteger<quint16>(packet, offset, transactionId) ||
!parseInteger<quint16>(packet, offset, flags) ||
!parseInteger<quint16>(packet, offset, nQuestion) ||
!parseInteger<quint16>(packet, offset, nAnswer) ||
!parseInteger<quint16>(packet, offset, nAuthority) ||
!parseInteger<quint16>(packet, offset, nAdditional)) {
return false;
}
message.setTransactionId(transactionId);
message.setResponse(flags & 0x8400);
message.setTruncated(flags & 0x0200);
for (int i = 0; i < nQuestion; ++i) {
QByteArray name;
quint16 type, class_;
if (!parseName(packet, offset, name) ||
!parseInteger<quint16>(packet, offset, type) ||
!parseInteger<quint16>(packet, offset, class_)) {
return false;
}
Query query;
query.setName(name);
query.setType(type);
query.setUnicastResponse(class_ & 0x8000);
message.addQuery(query);
}
quint16 nRecord = nAnswer + nAuthority + nAdditional;
for (int i = 0; i < nRecord; ++i) {
Record record;
if (!parseRecord(packet, offset, record)) {
return false;
}
message.addRecord(record);
}
return true;
}
void toPacket(const Message &message, QByteArray &packet)
{
quint16 offset = 0;
quint16 flags = (message.isResponse() ? 0x8400 : 0) |
(message.isTruncated() ? 0x200 : 0);
qDebug() << "Flags set in toPacket:" << QString::number(flags, 16);
writeInteger<quint16>(packet, offset, message.transactionId());
writeInteger<quint16>(packet, offset, flags);
writeInteger<quint16>(packet, offset, message.queries().length());
writeInteger<quint16>(packet, offset, message.records().length());
writeInteger<quint16>(packet, offset, 0);
writeInteger<quint16>(packet, offset, 0);
QMap<QByteArray, quint16> nameMap;
const auto queries = message.queries();
for (const Query &query : queries) {
writeName(packet, offset, query.name(), nameMap);
writeInteger<quint16>(packet, offset, query.type());
writeInteger<quint16>(packet, offset, query.unicastResponse() ? 0x8001 : 1);
}
const auto records = message.records();
for (Record record : records) {
writeRecord(packet, offset, record, nameMap);
}
}
QString typeName(quint16 type)
{
switch (type) {
case A: return "A";
case AAAA: return "AAAA";
case ANY: return "ANY";
case NSEC: return "NSEC";
case PTR: return "PTR";
case SRV: return "SRV";
case TXT: return "TXT";
default: return "?";
}
}
}

View File

@ -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 <QHostAddress>
#include <QHostInfo>
#include <QNetworkAddressEntry>
#include <QNetworkInterface>
#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(&registrationTimer, &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;
}

View File

@ -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 <QObject>
#include <QTimer>
class QHostAddress;
namespace QMdnsEngine
{
class AbstractServer;
class Hostname;
class Message;
class Record;
class HostnamePrivate : public QObject
{
Q_OBJECT
public:
HostnamePrivate(Hostname *hostname, AbstractServer *server);
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

View File

@ -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.");
}

View File

@ -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<Query> Message::queries() const
{
return d->queries;
}
void Message::addQuery(const Query &query)
{
d->queries.append(query);
}
QList<Record> Message::records() const
{
return d->records;
}
void Message::addRecord(const Record &record)
{
d->records.append(record);
}
void Message::reply(const Message &other)
{
if (other.port() == MdnsPort) {
if (other.address().protocol() == QAbstractSocket::IPv4Protocol) {
setAddress(MdnsIpv4Address);
} else {
setAddress(MdnsIpv6Address);
}
} else {
setAddress(other.address());
}
setPort(other.port());
setTransactionId(other.transactionId());
setResponse(true);
}

View File

@ -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 <QHostAddress>
#include <QList>
namespace QMdnsEngine
{
class Query;
class Record;
class MessagePrivate
{
public:
MessagePrivate();
QHostAddress address;
quint16 port;
quint16 transactionId;
bool isResponse;
bool isTruncated;
QList<Query> queries;
QList<Record> records;
};
}
#endif // QMDNSENGINE_MESSAGE_P_H

View File

@ -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))
{
}

View File

@ -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 <QObject>
#include <QTimer>
#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

View File

@ -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();
}*/
}
}

View File

@ -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 <QObject>
#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

View File

@ -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 <QDebug>
#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;
}

View File

@ -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 <QByteArray>
namespace QMdnsEngine
{
class QueryPrivate
{
public:
QueryPrivate();
QByteArray name;
quint16 type;
bool unicastResponse;
};
}
#endif // QMDNSENGINE_QUERY_P_H

View File

@ -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 <QDebug>
#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<QByteArray, QByteArray> Record::attributes() const
{
return d->attributes;
}
void Record::setAttributes(const QMap<QByteArray, QByteArray> &attributes)
{
d->attributes = attributes;
}
void Record::addAttribute(const QByteArray &key, const QByteArray &value)
{
d->attributes.insert(key, value);
}
Bitmap Record::bitmap() const
{
return d->bitmap;
}
void Record::setBitmap(const Bitmap &bitmap)
{
d->bitmap = bitmap;
}
QDebug QMdnsEngine::operator<<(QDebug dbg, const Record &record)
{
QDebugStateSaver saver(dbg);
Q_UNUSED(saver);
dbg.noquote().nospace() << "Record(" << typeName(record.type()) << " " << record.name() << ")";
return dbg;
}

View File

@ -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 <QByteArray>
#include <QHostAddress>
#include <QMap>
#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<QByteArray, QByteArray> attributes;
Bitmap bitmap;
};
}
#endif // QMDNSENGINE_RECORD_P_H

View File

@ -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 <QTimer>
#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<Record> ResolverPrivate::existing() const
{
QList<Record> records;
cache->lookupRecords(name, A, records);
cache->lookupRecords(name, AAAA, records);
return records;
}
void ResolverPrivate::query() const
{
Message message;
// Add a query for A and AAAA records
Query query;
query.setName(name);
query.setType(A);
message.addQuery(query);
query.setType(AAAA);
message.addQuery(query);
// Add existing (known) records to the query
const auto records = existing();
for (const Record &record : records) {
message.addRecord(record);
}
// Send the query
server->sendMessageToAll(message);
}
void ResolverPrivate::onMessageReceived(const Message &message)
{
if (!message.isResponse()) {
return;
}
const auto records = message.records();
for (const Record &record : records) {
if (record.name() == name && (record.type() == A || record.type() == AAAA)) {
cache->addRecord(record);
if (!addresses.contains(record.address())) {
emit q->resolved(record.address());
addresses.insert(record.address());
}
}
}
}
void ResolverPrivate::onTimeout()
{
const auto records = existing();
for (const Record &record : records) {
emit q->resolved(record.address());
}
}
Resolver::Resolver(AbstractServer *server, const QByteArray &name, Cache *cache, QObject *parent)
: QObject(parent),
d(new ResolverPrivate(this, server, name, cache))
{
}

View File

@ -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 <QHostAddress>
#include <QObject>
#include <QSet>
#include <QTimer>
namespace QMdnsEngine
{
class AbstractServer;
class Cache;
class Message;
class Record;
class Resolver;
class ResolverPrivate : public QObject
{
Q_OBJECT
public:
explicit ResolverPrivate(Resolver *resolver, AbstractServer *server, const QByteArray &name, Cache *cache);
QList<Record> existing() const;
void query() const;
AbstractServer *server;
QByteArray name;
Cache *cache;
QSet<QHostAddress> addresses;
QTimer timer;
private Q_SLOTS:
void onMessageReceived(const Message &message);
void onTimeout();
private:
Resolver *const q;
};
}
#endif // QMDNSENGINE_RESOLVER_P_H

View File

@ -1,137 +0,0 @@
#include <QtGlobal>
#ifdef Q_OS_UNIX
# include <cerrno>
# include <cstring>
# include <sys/socket.h>
#endif
#include <QHostAddress>
#include <QNetworkInterface>
#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<char*>(&arg), sizeof(int))) {
emit q->error(strerror(errno));
return false;
}
#endif
if (!socket.bind(address, MdnsPort, QAbstractSocket::ReuseAddressHint)) {
emit q->error(socket.errorString());
return false;
}
#ifdef Q_OS_UNIX
}
#endif
return true;
}
void ServerPrivate::onTimeout()
{
// A timer is used to run a set of operations once per minute; first, the
// two sockets are bound - if this fails, another attempt is made once per
// timeout; secondly, all network interfaces are enumerated; if the
// interface supports multicast, the socket will join the mDNS multicast
// groups
bool ipv4Bound = bindSocket(ipv4Socket, QHostAddress::AnyIPv4);
bool ipv6Bound = bindSocket(ipv6Socket, QHostAddress::AnyIPv6);
if (ipv4Bound || ipv6Bound) {
const auto interfaces = QNetworkInterface::allInterfaces();
for (const QNetworkInterface &networkInterface : interfaces) {
if (networkInterface.flags() & QNetworkInterface::CanMulticast) {
if (ipv4Bound) {
ipv4Socket.joinMulticastGroup(MdnsIpv4Address, networkInterface);
}
if (ipv6Bound) {
ipv6Socket.joinMulticastGroup(MdnsIpv6Address, networkInterface);
}
}
}
}
timer.start();
}
void ServerPrivate::onReadyRead()
{
// Read the packet from the socket
QUdpSocket *socket = qobject_cast<QUdpSocket*>(sender());
QByteArray packet;
packet.resize(socket->pendingDatagramSize());
QHostAddress address;
quint16 port;
socket->readDatagram(packet.data(), packet.size(), &address, &port);
// Attempt to decode the packet
Message message;
if (fromPacket(packet, message)) {
message.setAddress(address);
message.setPort(port);
emit q->messageReceived(message);
}
}
Server::Server(QObject *parent)
: AbstractServer(parent),
d(new ServerPrivate(this))
{
}
void Server::sendMessage(const Message &message)
{
QByteArray packet;
toPacket(message, packet);
if (message.address().protocol() == QAbstractSocket::IPv4Protocol) {
d->ipv4Socket.writeDatagram(packet, message.address(), message.port());
} else {
d->ipv6Socket.writeDatagram(packet, message.address(), message.port());
}
}
void Server::sendMessageToAll(const Message &message)
{
QByteArray packet;
toPacket(message, packet);
//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;
}

View File

@ -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 <QObject>
#include <QTimer>
#include <QUdpSocket>
class QHostAddress;
namespace QMdnsEngine
{
class Server;
class ServerPrivate : public QObject
{
Q_OBJECT
public:
explicit ServerPrivate(Server *server);
bool bindSocket(QUdpSocket &socket, const QHostAddress &address);
QTimer timer;
QUdpSocket ipv4Socket{ this };
QUdpSocket ipv6Socket{ this };
private Q_SLOTS:
void onTimeout();
void onReadyRead();
private:
Server *const q;
};
}
#endif // QMDNSENGINE_SERVER_P_H

View File

@ -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<QByteArray, QByteArray> Service::attributes() const
{
return d->attributes;
}
void Service::setAttributes(const QMap<QByteArray, QByteArray> &attributes)
{
d->attributes = attributes;
}
void Service::addAttribute(const QByteArray &key, const QByteArray &value)
{
d->attributes.insert(key, value);
}
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;
}

View File

@ -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 <QByteArray>
#include <QMap>
namespace QMdnsEngine
{
class ServicePrivate
{
public:
ServicePrivate();
QByteArray type;
QByteArray name;
QByteArray hostname;
quint16 port;
QMap<QByteArray, QByteArray> attributes;
};
}
#endif // QMDNSENGINE_SERVICE_P_H

View File

@ -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.";
}
}

View File

@ -1,31 +0,0 @@
// servicemodel.h
#ifndef SERVICEMODEL_H
#define SERVICEMODEL_H
#include <QObject>
#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

View File

@ -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

View File

@ -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<unsigned char>(buffer->at(7)) << 8) |
(static_cast<unsigned char>(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<unsigned char>(buffer->at(10)) == 0x00);
bool success = (static_cast<unsigned char>(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<QString, int> 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";

View File

@ -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<int, QString> 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();

View File

@ -1,6 +1,6 @@
// MainWidget.cpp
#include "MainWidget.h"
#include <qrencode.h>
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<void(QString)> 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<QHostAddress> 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<void(QString)> 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<QHostAddress> 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<QString, QString>& 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<QString, QString>& 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<QPushButton*>(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<QPushButton*>(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<QPushButton*>(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<QPushButton*>(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) {

View File

@ -44,22 +44,29 @@
#include <QMessageAuthenticationCode>
#include <QCoreApplication>
#include <QSettings>
#include <QImage>
#include <QPainter>
#include <winsock2.h>
#include <iphlpapi.h>
#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<void(QString)> 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<int, QTimer*> clientReadTimers;
QMap<int, ClientHandler*> 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

View File

@ -41,10 +41,12 @@ UI_config loadConfig(const QString& filePath)
{
UI_config config;
QMap<QString, QString> 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", "前 板");

View File

@ -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 !!!

View File

@ -1,18 +0,0 @@
device ID: 1 - Item 1: V851测试SPK ---> NG
device ID: 1 - Item 2: 806测试SPK ---> 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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

View File

@ -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 !!!

Some files were not shown because too many files have changed in this diff Show More