From 7cd3884c71405fc6b987e950e268ad41614a9667 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Sat, 5 Jul 2025 11:04:14 +0800 Subject: [PATCH 01/41] update:depend library and read me --- README.md | 6 +++--- XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 78a7250..86a8cf4 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,9 @@ macos执行:./XEngine_LINEnv.sh -i 3 git submodule init git submodule update 如果github访问失败,你也可以clone该项目,在主目录下使用命令: -git clone https://gitee.com/xengine/XEngine_OPenSource.git XEngine_Source/XEngine_Depend -git clone https://gitee.com/xengine/XEngine_IPMacData.git XEngine_Source/XEngine_DBDepend/XEngine_IPMacData -git clone https://gitee.com/xengine/XEngine_PhoneData.git XEngine_Source/XEngine_DBDepend/XEngine_PhoneData +git clone https://gitee.com/xengine/XEngine_OPenSource.git XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource +git clone https://gitee.com/xengine/XEngine_IPMacData.git XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData +git clone https://gitee.com/xengine/XEngine_PhoneData.git XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData #### Windows 需要vcpkg配置第三方环境,具体参考vcpkg安装方式,安装好后执行:vcpkg.exe install lua:x86-windows opencv[contrib]:x86-windows libqrencode:x86-windows lua:x64-windows opencv[contrib]:x64-windows libqrencode:x64-windows diff --git a/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource b/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource index 2b47966..91c4b0c 160000 --- a/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource +++ b/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource @@ -1 +1 @@ -Subproject commit 2b4796680134656c5144b3665aac9ec65ea6292a +Subproject commit 91c4b0cdf0d45775e0575f04ae9e13491bd3934a From 2dc0da42beb25fc9167cb4b6d0cb3e43770940f6 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 8 Jul 2025 10:40:41 +0800 Subject: [PATCH 02/41] update:read me --- README.en.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.en.md b/README.en.md index ed6f355..e780ad2 100644 --- a/README.en.md +++ b/README.en.md @@ -88,7 +88,7 @@ use vs open and compile,suport windows 7sp1 and above Just Run it #### sub module -Due to the dependent sub-modules, after you checkout the warehouse, execute the following command in the warehouse directory to pull the sub-modules +Due to the dependent sub-modules, after you checkout the resprepository, execute the following command in the resprepository directory to pull the sub-modules git submodule init git submodule update diff --git a/README.md b/README.md index 86a8cf4..c8cb4ef 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ macos执行:./XEngine_LINEnv.sh -i 3 默认配置没有开启数据库支持,如果需要数据库接口支持,需要自己开启数据库 #### sub module -由于依赖的子模块,在你checkout仓库后,在仓库目录下执行下面的命令拉取子模块 +由于依赖的子模块,在你clone仓库后,在仓库目录下执行下面的命令拉取子模块 git submodule init git submodule update 如果github访问失败,你也可以clone该项目,在主目录下使用命令: From 3b21cd3664db24e9b6f438ae5103a3cf129ec425 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 8 Jul 2025 10:41:32 +0800 Subject: [PATCH 03/41] modify:ntp protocol service extract individually added:dns service --- .../XEngine_Config/XEngine_Config.json | 132 +++++++++--------- .../ModuleConfig_Define.h | 2 + .../ModuleConfigure_Json.cpp | 2 + .../XEngine_HttpApp/XEngine_Hdr.h | 2 + .../XEngine_HttpApp/XEngine_HttpApp.cpp | 40 ++++++ .../XEngine_HttpApp/XEngine_Network.cpp | 12 +- .../XEngine_HttpApp/XEngine_Network.h | 2 + 7 files changed, 123 insertions(+), 69 deletions(-) diff --git a/XEngine_Release/XEngine_Config/XEngine_Config.json b/XEngine_Release/XEngine_Config/XEngine_Config.json index 0d04c3a..483d080 100644 --- a/XEngine_Release/XEngine_Config/XEngine_Config.json +++ b/XEngine_Release/XEngine_Config/XEngine_Config.json @@ -1,82 +1,84 @@ { - "tszIPAddr":"192.168.1.8", - "bDeamon":false, - "bShowWnd":true, - "nHttpPort":5501, - "nRFCPort":5502, - "XMax":{ - "nMaxClient":10000, - "nMaxQueue":10000, - "nIOThread":2, - "nHttpThread":2 + "tszIPAddr": "192.168.1.8", + "bDeamon": false, + "bShowWnd": true, + "nHttpPort": 5501, + "nRFCPort": 5502, + "nNTPPort": 123, + "nDNSPort": 53, + "XMax": { + "nMaxClient": 10000, + "nMaxQueue": 10000, + "nIOThread": 2, + "nHttpThread": 2 }, - "XTime":{ - "nTimeCheck":3, - "nHttpTimeOut":5, - "nP2PTimeOut":60 + "XTime": { + "nTimeCheck": 3, + "nHttpTimeOut": 5, + "nP2PTimeOut": 60 }, - "XLog":{ - "tszAPIFile":"./XEngine_Log/XEngine_HttpApp.Log", - "tszServiceFile":"./XEngine_Log/XEngine_ServiceApp.Log", - "MaxSize":1024000, - "MaxCount":10, - "LogLeave":17, - "LogType":32 + "XLog": { + "tszAPIFile": "./XEngine_Log/XEngine_HttpApp.Log", + "tszServiceFile": "./XEngine_Log/XEngine_ServiceApp.Log", + "MaxSize": 1024000, + "MaxCount": 10, + "LogLeave": 17, + "LogType": 32 }, - "XSql":{ - "bEnable":false, - "SQLAddr":"10.0.2.6", - "SQLPort":3306, - "SQLUser":"root", - "SQLPass":"123123aa" + "XSql": { + "bEnable": false, + "SQLAddr": "10.0.2.6", + "SQLPort": 3306, + "SQLUser": "root", + "SQLPass": "123123aa" }, - "XApi":{ - "tszWeatherUrl":"https://restapi.amap.com/v3/weather/weatherInfo?city=%s&key=3239fc302d6480ce49973f4d1c59e5d8", - "tszBankUrl":"https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?cardNo=%s&cardBinCheck=true", - "tszOilUrl":"https://www.iamwawa.cn/oilprice/api?area=%s", - "st_TranslationInfo":{ - "url":"https://fanyi-api.baidu.com/api/trans/vip/translate", - "appid":"20231228001924304", - "key":"udXGjpmNVeQHml1FjT8E" + "XApi": { + "tszWeatherUrl": "https://restapi.amap.com/v3/weather/weatherInfo?city=%s&key=3239fc302d6480ce49973f4d1c59e5d8", + "tszBankUrl": "https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?cardNo=%s&cardBinCheck=true", + "tszOilUrl": "https://www.iamwawa.cn/oilprice/api?area=%s", + "st_TranslationInfo": { + "url": "https://fanyi-api.baidu.com/api/trans/vip/translate", + "appid": "20231228001924304", + "key": "udXGjpmNVeQHml1FjT8E" } }, - "XPlugin":{ - "bEnable":true, - "tszLibPlugin":"./XEngine_LibPlugin", - "tszLuaPlugin":"./XEngine_LuaPlugin" + "XPlugin": { + "bEnable": true, + "tszLibPlugin": "./XEngine_LibPlugin", + "tszLuaPlugin": "./XEngine_LuaPlugin" }, - "XConfig":{ - "st_ConfigQRCode":{ - "tszModelDetect":"./XEngine_Config/qrmodel/detect.caffemodel", - "tszModelSr":"./XEngine_Config/qrmodel/sr.caffemodel", - "tszProtoDetect":"./XEngine_Config/qrmodel/detect.prototxt", - "tszProtoSr":"./XEngine_Config/qrmodel/sr.prototxt" + "XConfig": { + "st_ConfigQRCode": { + "tszModelDetect": "./XEngine_Config/qrmodel/detect.caffemodel", + "tszModelSr": "./XEngine_Config/qrmodel/sr.caffemodel", + "tszProtoDetect": "./XEngine_Config/qrmodel/detect.prototxt", + "tszProtoSr": "./XEngine_Config/qrmodel/sr.prototxt" }, - "tszConfigDeamon":"./XEngine_Config/XEngine_DeamonConfig.json", - "tszConfigHTTPMime":"./XEngine_Config/HttpMime.types", - "tszConfigHTTPCode":"./XEngine_Config/HttpCode.types" + "tszConfigDeamon": "./XEngine_Config/XEngine_DeamonConfig.json", + "tszConfigHTTPMime": "./XEngine_Config/HttpMime.types", + "tszConfigHTTPCode": "./XEngine_Config/HttpCode.types" }, - "XShortLink":{ - "tszHostUrl":"url.xyry.org", - "nHTTPCode":301 + "XShortLink": { + "tszHostUrl": "url.xyry.org", + "nHTTPCode": 301 }, - "XVerification":{ - "tszUserName":"xyry", - "tszUserPass":"11", - "st_VerSwitch":{ - "bBackService":false, - "bDeamon":false + "XVerification": { + "tszUserName": "xyry", + "tszUserPass": "11", + "st_VerSwitch": { + "bBackService": false, + "bDeamon": false } }, - "XReport":{ - "bEnable":true, - "tszAPIUrl":"http://app.xyry.org:5501/api?function=machine", - "tszServiceName":"XEngine_APIService" + "XReport": { + "bEnable": true, + "tszAPIUrl": "http://app.xyry.org:5501/api?function=machine", + "tszServiceName": "XEngine_APIService" }, - "XImageText":{ - "bEnable":true, - "tszImagePath":"./XEngine_Config/tessdata", - "tszImageLanguage":"chi_sim+eng" + "XImageText": { + "bEnable": true, + "tszImagePath": "./XEngine_Config/tessdata", + "tszImageLanguage": "chi_sim+eng" }, "XAPIModule": { "bEnable": true, diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h index 10ce8de..c6d9128 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h @@ -20,6 +20,8 @@ typedef struct bool bShowWnd; //是否显示窗口启动 int nHttpPort; //HTTP服务端口 int nRFCPort; //RFC标准服务端口 + int nNTPPort; //NTP服务端口 + int nDNSPort; //DNS服务端口 struct { int nMaxClient; //最大客户端个数 diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp index 301ddc3..c3fe3e8 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp @@ -77,6 +77,8 @@ bool CModuleConfigure_Json::ModuleConfigure_Json_File(LPCXSTR lpszConfigFile, XE pSt_ServerConfig->bShowWnd = st_JsonRoot["bShowWnd"].asBool(); pSt_ServerConfig->nHttpPort = st_JsonRoot["nHttpPort"].asInt(); pSt_ServerConfig->nRFCPort = st_JsonRoot["nRFCPort"].asInt(); + pSt_ServerConfig->nNTPPort = st_JsonRoot["nNTPPort"].asInt(); + pSt_ServerConfig->nDNSPort = st_JsonRoot["nDNSPort"].asInt(); if (st_JsonRoot["XMax"].empty() || (4 != st_JsonRoot["XMax"].size())) { diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h index 97422ed..281bbea 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h @@ -132,6 +132,8 @@ extern XHANDLE xhLog; //HTTP服务器 extern XHANDLE xhHTTPSocket; extern XHANDLE xhRFCSocket; +extern XHANDLE xhNTPSocket; +extern XHANDLE xhDNSSocket; extern XHANDLE xhHTTPHeart; extern XHANDLE xhHTTPPacket; extern XHANDLE xhHTTPPool; diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp index c163c9f..16c96df 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp @@ -16,6 +16,8 @@ XHANDLE xhLog = NULL; //HTTP服务器 XHANDLE xhHTTPSocket = NULL; XHANDLE xhRFCSocket = NULL; +XHANDLE xhNTPSocket = NULL; +XHANDLE xhDNSSocket = NULL; XHANDLE xhHTTPHeart = NULL; XHANDLE xhHTTPPacket = NULL; XHANDLE xhHTTPPool = NULL; @@ -35,6 +37,8 @@ void ServiceApp_Stop(int signo) //销毁HTTP资源 NetCore_TCPXCore_DestroyEx(xhHTTPSocket); NetCore_UDPXCore_DestroyEx(xhRFCSocket); + NetCore_UDPXCore_DestroyEx(xhNTPSocket); + NetCore_UDPXCore_DestroyEx(xhDNSSocket); SocketOpt_HeartBeat_DestoryEx(xhHTTPHeart); HttpProtocol_Server_DestroyEx(xhHTTPPacket); ManagePool_Thread_NQDestroy(xhHTTPPool); @@ -365,6 +369,40 @@ int main(int argc, char** argv) { XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_WARN, _X("启动服务中,RFC服务没有被启用")); } + if (st_ServiceConfig.nNTPPort > 0) + { + //网络 + xhNTPSocket = NetCore_UDPXCore_StartEx(st_ServiceConfig.nNTPPort, st_ServiceConfig.st_XMax.nIOThread); + if (NULL == xhNTPSocket) + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,启动NTP网络服务器失败,错误:%lX"), NetCore_GetLastError()); + goto XENGINE_SERVICEAPP_EXIT; + } + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,启动NTP网络服务器成功,NTP端口:%d,IO:%d"), st_ServiceConfig.nNTPPort, st_ServiceConfig.st_XMax.nIOThread); + NetCore_UDPXCore_RegisterCallBackEx(xhNTPSocket, Network_Callback_NTPRecv); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,注册NTP网络事件成功")); + } + else + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_WARN, _X("启动服务中,NTP服务没有被启用")); + } + if (st_ServiceConfig.nDNSPort > 0) + { + //网络 + xhDNSSocket = NetCore_UDPXCore_StartEx(st_ServiceConfig.nDNSPort, st_ServiceConfig.st_XMax.nIOThread); + if (NULL == xhDNSSocket) + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,启动DNS网络服务器失败,错误:%lX"), NetCore_GetLastError()); + goto XENGINE_SERVICEAPP_EXIT; + } + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,启动DNS网络服务器成功,DNS端口:%d,IO:%d"), st_ServiceConfig.nDNSPort, st_ServiceConfig.st_XMax.nIOThread); + NetCore_UDPXCore_RegisterCallBackEx(xhDNSSocket, Network_Callback_DNSRecv); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,注册DNS网络事件成功")); + } + else + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_WARN, _X("启动服务中,DNS服务没有被启用")); + } //初始化P2P if (st_ServiceConfig.st_XTime.nP2PTimeOut > 0) { @@ -552,6 +590,8 @@ int main(int argc, char** argv) //销毁HTTP资源 NetCore_TCPXCore_DestroyEx(xhHTTPSocket); NetCore_UDPXCore_DestroyEx(xhRFCSocket); + NetCore_UDPXCore_DestroyEx(xhNTPSocket); + NetCore_UDPXCore_DestroyEx(xhDNSSocket); SocketOpt_HeartBeat_DestoryEx(xhHTTPHeart); HttpProtocol_Server_DestroyEx(xhHTTPPacket); ManagePool_Thread_NQDestroy(xhHTTPPool); diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp index 129d171..4cc02af 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp @@ -44,10 +44,14 @@ void XCALLBACK Network_Callback_RFCRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, //STUN消息的类型字段(前两位为00)以及魔术cookie字段 RFCTask_Stun_Parse(lpszClientAddr, lpszMSGBuffer, nMSGLen); } - else if (nMSGLen == 48) - { - RFCTask_NTP_Parse(lpszClientAddr, lpszMSGBuffer, nMSGLen); - } +} +void XCALLBACK Network_Callback_NTPRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, LPCXSTR lpszMSGBuffer, int nMSGLen, XPVOID lParam) +{ + RFCTask_NTP_Parse(lpszClientAddr, lpszMSGBuffer, nMSGLen); +} +void XCALLBACK Network_Callback_DNSRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, LPCXSTR lpszMSGBuffer, int nMSGLen, XPVOID lParam) +{ + } //////////////////////////////////////////////////////////////////////////网络IO关闭操作 void XEngine_Network_Close(LPCXSTR lpszClientAddr, bool bHeart) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.h index 4833db6..0eaf830 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.h @@ -17,6 +17,8 @@ void XCALLBACK Network_Callback_HTTPLeave(LPCXSTR lpszClientAddr, XSOCKET hSocke void XCALLBACK Network_Callback_HTTPHeart(LPCXSTR lpszClientAddr, XSOCKET hSocket, int nStatus, XPVOID lParam); //RFC相关 void XCALLBACK Network_Callback_RFCRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, LPCXSTR lpszMSGBuffer, int nMSGLen, XPVOID lParam); +void XCALLBACK Network_Callback_NTPRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, LPCXSTR lpszMSGBuffer, int nMSGLen, XPVOID lParam); +void XCALLBACK Network_Callback_DNSRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, LPCXSTR lpszMSGBuffer, int nMSGLen, XPVOID lParam); //关闭与发送 void XEngine_Network_Close(LPCXSTR lpszClientAddr, bool bHeart); bool XEngine_Network_Send(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer, int nMsgLen); \ No newline at end of file From e206586c91a868e53dd7230acb8a4009aa484081 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 8 Jul 2025 14:36:28 +0800 Subject: [PATCH 04/41] fixed:ntp macro error --- .../XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp index 7897182..9702aa0 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp @@ -2,7 +2,6 @@ bool RFCTask_NTP_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLen) { -#if (XENGINE_VERSION_KERNEL >= 8) && (XENGINE_VERSION_MAIN >= 31) int nSDLen = 0; XCHAR tszSDBuffer[4096] = {}; NTPPROTOCOL_TIMEINFO st_TimeRecv = {}; @@ -13,9 +12,6 @@ bool RFCTask_NTP_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLe NTPProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, NULL, &st_TimeRecv, &st_TimeTras, st_ServiceConfig.tszIPAddr); NetCore_UDPXCore_SendEx(xhRFCSocket, lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("RFC客户端:%s,发送NTP时间同步请求给服务器,处理成功"), lpszClientAddr); -#else - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("RFC客户端:%s,发送NTP时间同步请求给服务器,处理失败,版本不支持"), lpszClientAddr); -#endif return true; } \ No newline at end of file From 3caba961facc638c964c7ef97b5c1f2a69216ec2 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 15 Jul 2025 09:34:02 +0800 Subject: [PATCH 05/41] added:dns protocol parse support --- .../ModuleConfig_Define.h | 41 +++- .../ModuleConfigure_Json.cpp | 80 +++++++ .../ModuleConfigure_Json.h | 1 + .../XEngine_ModuleConfigure.def | 3 +- .../XEngine_ModuleConfigure/pch.cpp | 4 + XEngine_Source/XEngine_ModuleHelp/Makefile | 4 +- .../ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp | 199 ++++++++++++++++++ .../ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.h | 29 +++ .../XEngine_ModuleHelp/ModuleHelp_Define.h | 85 +++++++- .../XEngine_ModuleHelp/ModuleHelp_Error.h | 7 +- .../XEngine_ModuleHelp/XEngine_ModuleHelp.def | 8 +- .../XEngine_ModuleHelp.vcxproj | 2 + .../XEngine_ModuleHelp.vcxproj.filters | 12 ++ XEngine_Source/XEngine_ModuleHelp/pch.cpp | 25 +++ XEngine_Source/XEngine_ModuleHelp/pch.h | 1 + .../XEngine_HttpApp/Makefile | 4 +- .../XEngine_HttpApp/XEngine_Configure.cpp | 6 + .../XEngine_HttpApp/XEngine_Hdr.h | 5 + .../XEngine_HttpApp/XEngine_HttpApp.cpp | 18 +- .../XEngine_HttpApp/XEngine_HttpApp.vcxproj | 2 + .../XEngine_HttpApp.vcxproj.filters | 6 + .../XEngine_HttpApp/XEngine_Network.cpp | 2 +- .../XEngine_TaskRfc/RFCTask_Dns.cpp | 65 ++++++ .../XEngine_TaskRfc/RFCTask_Dns.h | 3 + .../XEngine_TaskRfc/RFCTask_Ntp.cpp | 2 +- 25 files changed, 601 insertions(+), 13 deletions(-) create mode 100644 XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp create mode 100644 XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.h create mode 100644 XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp create mode 100644 XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.h diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h index c6d9128..684f5dd 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h @@ -161,6 +161,26 @@ typedef struct list stl_ListDeamonApp; }XENGINE_DEAMONAPPLIST; ////////////////////////////////////////////////////////////////////////// +//DNS +typedef struct +{ + XCHAR tszDNSName[256]; //域名名称 + XCHAR tszDNSAddr[256]; //域名地址 + int nType; //DNS地址类型,域名,IP + int nTTL; //服务器的TTL +}XENGINE_DNSADDRINFO; +typedef struct +{ + bool bEnable; + XCHAR tszDNSName[256]; + list stl_ListDNSAddr; +}XENGINE_DNSDOMAIN; +typedef struct +{ + list stl_ListDNSServer; + list stl_ListDNSList; +}XENGINE_DNSINFO; +////////////////////////////////////////////////////////////////////////// // 导出函数定义 ////////////////////////////////////////////////////////////////////////// extern "C" XLONG ModuleConfigure_GetLastError(int* pInt_ErrorCode = NULL); @@ -223,4 +243,23 @@ extern "C" bool ModuleConfigure_Json_VersionFile(LPCXSTR lpszConfigFile, XENGINE 意思:是否成功 备注: *********************************************************************/ -extern "C" bool ModuleConfigure_Json_DeamonList(LPCXSTR lpszConfigFile, XENGINE_DEAMONAPPLIST* pSt_AppConfig); \ No newline at end of file +extern "C" bool ModuleConfigure_Json_DeamonList(LPCXSTR lpszConfigFile, XENGINE_DEAMONAPPLIST* pSt_AppConfig); +/******************************************************************** +函数名称:ModuleConfigure_Json_DNSFile +函数功能:读取JSON配置文件 + 参数.一:lpszConfigFile + In/Out:In + 类型:常量字符指针 + 可空:N + 意思:输入要读取的配置文件 + 参数.二:pSt_DNSList + In/Out:Out + 类型:数据结构指针 + 可空:N + 意思:输出DNS服务器列表 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +extern "C" bool ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, XENGINE_DNSINFO* pSt_DNSList); \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp index c3fe3e8..96a5803 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp @@ -374,4 +374,84 @@ bool CModuleConfigure_Json::ModuleConfigure_Json_DeamonList(LPCXSTR lpszConfigFi pSt_AppConfig->stl_ListDeamonApp.push_back(st_APPInfo); } return true; +} +/******************************************************************** +函数名称:ModuleConfigure_Json_DNSFile +函数功能:读取JSON配置文件 + 参数.一:lpszConfigFile + In/Out:In + 类型:常量字符指针 + 可空:N + 意思:输入要读取的配置文件 + 参数.二:pSt_DNSList + In/Out:Out + 类型:数据结构指针 + 可空:N + 意思:输出DNS服务器列表 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +bool CModuleConfigure_Json::ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, XENGINE_DNSINFO* pSt_DNSList) +{ + Config_IsErrorOccur = false; + + if ((NULL == lpszConfigFile) || (NULL == pSt_DNSList)) + { + Config_IsErrorOccur = true; + Config_dwErrorCode = ERROR_MODULE_CONFIGURE_JSON_PARAMENT; + return false; + } + JSONCPP_STRING st_JsonError; + Json::Value st_JsonRoot; + Json::CharReaderBuilder st_JsonBuilder; + + FILE* pSt_File = fopen(lpszConfigFile, "rb"); + if (NULL == pSt_File) + { + Config_IsErrorOccur = true; + Config_dwErrorCode = ERROR_MODULE_CONFIGURE_JSON_OPENFILE; + return false; + } + XCHAR tszMsgBuffer[8192] = {}; + size_t nRet = fread(tszMsgBuffer, 1, sizeof(tszMsgBuffer), pSt_File); + fclose(pSt_File); + + std::unique_ptr const pSt_JsonReader(st_JsonBuilder.newCharReader()); + if (!pSt_JsonReader->parse(tszMsgBuffer, tszMsgBuffer + nRet, &st_JsonRoot, &st_JsonError)) + { + Config_IsErrorOccur = true; + Config_dwErrorCode = ERROR_MODULE_CONFIGURE_JSON_PARSE; + return false; + } + + Json::Value st_JsonServer = st_JsonRoot["DNSServer"]; + for (unsigned int i = 0; i < st_JsonRoot["DNSServer"].size(); i++) + { + pSt_DNSList->stl_ListDNSServer.push_back(st_JsonServer[i].asCString()); + } + + Json::Value st_JsonList = st_JsonRoot["DNSList"]; + for (unsigned int i = 0; i < st_JsonRoot["DNSList"].size(); i++) + { + XENGINE_DNSDOMAIN st_DNSDomain = {}; + + st_DNSDomain.bEnable = st_JsonList["bEnable"].asBool(); + _tcsxcpy(st_DNSDomain.tszDNSName, st_JsonList["DNSName"].asCString()); + + Json::Value st_JsonAddr = st_JsonList["DNSAddr"]; + for (unsigned int j = 0; j < st_JsonList["DNSAddr"].size(); j++) + { + XENGINE_DNSADDRINFO st_DNSAddr = {}; + st_DNSAddr.nType = st_JsonAddr["Type"].asInt(); + st_DNSAddr.nTTL = st_JsonAddr["TTL"].asInt(); + _tcsxcpy(st_DNSAddr.tszDNSName, st_JsonAddr["Name"].asCString()); + _tcsxcpy(st_DNSAddr.tszDNSAddr, st_JsonAddr["Addr"].asCString()); + + st_DNSDomain.stl_ListDNSAddr.push_back(st_DNSAddr); + } + pSt_DNSList->stl_ListDNSList.push_back(st_DNSDomain); + } + return true; } \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.h b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.h index 3a5f847..bf977b6 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.h +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.h @@ -20,6 +20,7 @@ class CModuleConfigure_Json bool ModuleConfigure_Json_File(LPCXSTR lpszConfigFile, XENGINE_SERVICECONFIG* pSt_ServerConfig); bool ModuleConfigure_Json_VersionFile(LPCXSTR lpszConfigFile, XENGINE_SERVICECONFIG* pSt_ServerConfig); bool ModuleConfigure_Json_DeamonList(LPCXSTR lpszConfigFile, XENGINE_DEAMONAPPLIST* pSt_AppConfig); + bool ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, XENGINE_DNSINFO* pSt_DNSList); protected: private: }; \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleConfigure/XEngine_ModuleConfigure.def b/XEngine_Source/XEngine_ModuleConfigure/XEngine_ModuleConfigure.def index 5332cde..1d23465 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/XEngine_ModuleConfigure.def +++ b/XEngine_Source/XEngine_ModuleConfigure/XEngine_ModuleConfigure.def @@ -5,4 +5,5 @@ EXPORTS ModuleConfigure_Json_File ModuleConfigure_Json_VersionFile - ModuleConfigure_Json_DeamonList \ No newline at end of file + ModuleConfigure_Json_DeamonList + ModuleConfigure_Json_DNSFile \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleConfigure/pch.cpp b/XEngine_Source/XEngine_ModuleConfigure/pch.cpp index afb6ec4..3be26e7 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/pch.cpp +++ b/XEngine_Source/XEngine_ModuleConfigure/pch.cpp @@ -40,4 +40,8 @@ extern "C" bool ModuleConfigure_Json_VersionFile(LPCXSTR lpszConfigFile, XENGINE extern "C" bool ModuleConfigure_Json_DeamonList(LPCXSTR lpszConfigFile, XENGINE_DEAMONAPPLIST * pSt_AppConfig) { return m_ConfigJson.ModuleConfigure_Json_DeamonList(lpszConfigFile, pSt_AppConfig); +} +extern "C" bool ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, XENGINE_DNSINFO* pSt_DNSList) +{ + return m_ConfigJson.ModuleConfigure_Json_DNSFile(lpszConfigFile, pSt_DNSList); } \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/Makefile b/XEngine_Source/XEngine_ModuleHelp/Makefile index 25f94c8..24ed96b 100644 --- a/XEngine_Source/XEngine_ModuleHelp/Makefile +++ b/XEngine_Source/XEngine_ModuleHelp/Makefile @@ -6,7 +6,7 @@ LOADHDR = -I ./ -I /usr/include/opencv4 -I /usr/local/include/opencv4 -I /usr/lo LOADSO = LIB = -lXEngine_BaseLib -lXClient_Socket -lNetHelp_APIAddr LIBEX = -OBJECTS = ModuleHelp_IDCard.o ModuleHelp_Language.o ModuleHelp_P2PClient.o ModuleHelp_Locker.o ModuleHelp_QRCode.o ModuleHelp_SocketTest.o ModuleHelp_ImageGet.o ModuleHelp_ImageSet.o pch.o +OBJECTS = ModuleHelp_IDCard.o ModuleHelp_Language.o ModuleHelp_P2PClient.o ModuleHelp_Locker.o ModuleHelp_QRCode.o ModuleHelp_SocketTest.o ModuleHelp_ImageGet.o ModuleHelp_ImageSet.o ModuleHelp_DNSAddr.o pch.o MACRO_QR_SUPPORT := $(shell gcc -E -dM ../XEngine_BuildSwitch.h | grep _XENGINE_BUILD_SWITCH_QRDECODEC | cut -d ' ' -f 3) MACRO_OPENCV_SUPPORT := $(shell gcc -E -dM ../XEngine_BuildSwitch.h | grep _XENGINE_BUILD_SWITCH_OPENCV | cut -d ' ' -f 3) @@ -78,6 +78,8 @@ ModuleHelp_ImageGet.o:./ModuleHelp_Image/ModuleHelp_ImageGet.cpp $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./ModuleHelp_Image/ModuleHelp_ImageGet.cpp ModuleHelp_ImageSet.o:./ModuleHelp_Image/ModuleHelp_ImageSet.cpp $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./ModuleHelp_Image/ModuleHelp_ImageSet.cpp +ModuleHelp_DNSAddr.o:./ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp + $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp pch.o:./pch.cpp $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./pch.cpp diff --git a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp new file mode 100644 index 0000000..bc9c9ce --- /dev/null +++ b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp @@ -0,0 +1,199 @@ +#include "pch.h" +#include "ModuleHelp_DNSAddr.h" +/******************************************************************** +// Created: 2025/07/14 15:47:28 +// File Name: D:\XEngine_APIService\XEngine_Source\XEngine_ModuleHelp\ModuleHelp_DNSAddr\ModuleHelp_DNSAddr.cpp +// File Path: D:\XEngine_APIService\XEngine_Source\XEngine_ModuleHelp\ModuleHelp_DNSAddr +// File Base: ModuleHelp_DNSAddr +// File Ext: cpp +// Project: XEngine +// Author: qyt +// Purpose: DNS解析处理帮助函数 +// History: +*********************************************************************/ +CModuleHelp_DNSAddr::CModuleHelp_DNSAddr() +{ +} +CModuleHelp_DNSAddr::~CModuleHelp_DNSAddr() +{ +} +////////////////////////////////////////////////////////////////////////// +// 公有函数 +////////////////////////////////////////////////////////////////////////// +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_Init +函数功能:初始化DNS数据表 + 参数.一:pSt_DNSInfo + In/Out:In + 类型:数据结构指针 + 可空:N + 意思:输入要转换的列表 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +bool CModuleHelp_DNSAddr::ModuleHelp_DNSAddr_Init(XENGINE_DNSINFO* pSt_DNSInfo) +{ + ModuleHelp_IsErrorOccur = false; + + if (NULL == pSt_DNSInfo) + { + ModuleHelp_IsErrorOccur = true; + ModuleHelp_dwErrorCode = ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_PARAMRT; + return false; + } + + for (auto stl_ListIterator = pSt_DNSInfo->stl_ListDNSServer.begin(); stl_ListIterator != pSt_DNSInfo->stl_ListDNSServer.end(); stl_ListIterator++) + { + stl_ListDNSServer.push_back(stl_ListIterator->c_str()); + } + for (auto stl_ListIterator = pSt_DNSInfo->stl_ListDNSList.begin(); stl_ListIterator != pSt_DNSInfo->stl_ListDNSList.end(); stl_ListIterator++) + { + if (stl_ListIterator->bEnable) + { + stl_MapDNSAddr.insert(make_pair(stl_ListIterator->tszDNSName, stl_ListIterator->stl_ListDNSAddr)); + } + } + return true; +} +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_Destroy +函数功能:销毁DNS帮助函数库 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +bool CModuleHelp_DNSAddr::ModuleHelp_DNSAddr_Destroy() +{ + ModuleHelp_IsErrorOccur = false; + + stl_ListDNSServer.clear(); + stl_MapDNSAddr.clear(); + return true; +} +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_FindA +函数功能:A记录查找 + 参数.一:lpszDNSAddr + In/Out:In + 类型:常量字符指针 + 可空:N + 意思:输入要查找的DNS地址 + 参数.二:pppSt_DNSList + In/Out:Out + 类型:三级指针 + 可空:N + 意思:输出查找到的列表 + 参数.三:pInt_ListCount + In/Out:Out + 类型:整数型指针 + 可空:N + 意思:输出列表个数 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +bool CModuleHelp_DNSAddr::ModuleHelp_DNSAddr_FindA(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO*** pppSt_DNSList, int* pInt_ListCount) +{ + ModuleHelp_IsErrorOccur = false; + + auto stl_MapIterator = stl_MapDNSAddr.find(lpszDNSAddr); + if (stl_MapIterator == stl_MapDNSAddr.end()) + { + ModuleHelp_IsErrorOccur = true; + ModuleHelp_dwErrorCode = ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_NOTFOUND; + return false; + } + + *pInt_ListCount = stl_MapIterator->second.size(); + BaseLib_Memory_Malloc((XPPPMEM)pppSt_DNSList, *pInt_ListCount, sizeof(XENGINE_DNSADDRINFO)); + + auto stl_ListIterator = stl_MapIterator->second.begin(); + for (int i = 0; stl_ListIterator != stl_MapIterator->second.end(); stl_ListIterator++, i++) + { + *(*pppSt_DNSList)[i] = *stl_ListIterator; + } + + return true; +} +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_FindPtr +函数功能:输出IP对应的域名 + 参数.一:lpszDNSAddr + In/Out:In + 类型:常量字符指针 + 可空:N + 意思:输入要查找的IP地址 + 参数.二:pSt_DNSAddr + In/Out:Out + 类型:数据结构指针 + 可空:N + 意思:输出查找到的数据 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +bool CModuleHelp_DNSAddr::ModuleHelp_DNSAddr_FindPtr(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO* pSt_DNSAddr) +{ + ModuleHelp_IsErrorOccur = false; + + auto stl_MapIterator = stl_MapDNSAddr.find(lpszDNSAddr); + if (stl_MapIterator == stl_MapDNSAddr.end()) + { + ModuleHelp_IsErrorOccur = true; + ModuleHelp_dwErrorCode = ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_NOTFOUND; + return false; + } + //查找地址 + bool bIsFound = false; + for (auto stl_ListIterator = stl_MapIterator->second.begin(); stl_ListIterator != stl_MapIterator->second.end(); stl_ListIterator++) + { + if (0 == _tcsxnicmp(stl_ListIterator->tszDNSAddr, lpszDNSAddr, _tcsxlen(stl_ListIterator->tszDNSAddr))) + { + *pSt_DNSAddr = *stl_ListIterator; + bIsFound = true; + break; + } + } + + if (!bIsFound) + { + ModuleHelp_IsErrorOccur = true; + ModuleHelp_dwErrorCode = ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_NOTFOUND; + return false; + } + + return true; +} +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_Select +函数功能:备选地址 + 参数.一:ptszDNSServer + In/Out:Out + 类型:字符指针 + 可空:N + 意思:输出选择的DNS服务器 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +bool CModuleHelp_DNSAddr::ModuleHelp_DNSAddr_Select(XCHAR* ptszDNSServer) +{ + ModuleHelp_IsErrorOccur = false; + + if (stl_ListDNSServer.size() > 1) + { + _tcsxcpy(ptszDNSServer, stl_ListDNSServer.front().c_str()); + } + else + { + _tcsxcpy(ptszDNSServer, stl_ListDNSServer.front().c_str()); + } + + return true; +} \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.h b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.h new file mode 100644 index 0000000..2e3fee5 --- /dev/null +++ b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.h @@ -0,0 +1,29 @@ +#pragma once +/******************************************************************** +// Created: 2025/07/14 15:46:17 +// File Name: D:\XEngine_APIService\XEngine_Source\XEngine_ModuleHelp\ModuleHelp_DNSAddr\ModuleHelp_DNSAddr.h +// File Path: D:\XEngine_APIService\XEngine_Source\XEngine_ModuleHelp\ModuleHelp_DNSAddr +// File Base: ModuleHelp_DNSAddr +// File Ext: h +// Project: XEngine +// Author: qyt +// Purpose: DNS解析处理帮助函数 +// History: +*********************************************************************/ + +class CModuleHelp_DNSAddr +{ +public: + CModuleHelp_DNSAddr(); + ~CModuleHelp_DNSAddr(); +public: + bool ModuleHelp_DNSAddr_Init(XENGINE_DNSINFO* pSt_DNSInfo); + bool ModuleHelp_DNSAddr_Destroy(); + bool ModuleHelp_DNSAddr_FindA(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO*** pppSt_DNSList, int* pInt_ListCount); + bool ModuleHelp_DNSAddr_FindPtr(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO* pSt_DNSAddr); + bool ModuleHelp_DNSAddr_Select(XCHAR* ptszDNSServer); +protected: +private: + std::list stl_ListDNSServer; + std::unordered_map > stl_MapDNSAddr; +}; \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Define.h b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Define.h index 1d8f7ce..098c6d6 100644 --- a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Define.h +++ b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Define.h @@ -1211,4 +1211,87 @@ extern "C" bool ModuleHelp_ImageSet_Ligth(LPCXSTR lpszSrcBuffer, int nSLen, LPCX 意思:是否成功 备注: *********************************************************************/ -extern "C" bool ModuleHelp_ImageSet_Level(LPCXSTR lpszSrcBuffer, int nSLen, LPCXSTR lpszExtFile, XCHAR* ptszDstBuffer, int* pInt_DLen, int nLevel); \ No newline at end of file +extern "C" bool ModuleHelp_ImageSet_Level(LPCXSTR lpszSrcBuffer, int nSLen, LPCXSTR lpszExtFile, XCHAR* ptszDstBuffer, int* pInt_DLen, int nLevel); +/************************************************************************/ +/* DNS处理导出函数 */ +/************************************************************************/ +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_Init +函数功能:初始化DNS数据表 + 参数.一:pSt_DNSInfo + In/Out:In + 类型:数据结构指针 + 可空:N + 意思:输入要转换的列表 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +extern "C" bool ModuleHelp_DNSAddr_Init(XENGINE_DNSINFO* pSt_DNSInfo); +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_Destroy +函数功能:销毁DNS帮助函数库 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +extern "C" bool ModuleHelp_DNSAddr_Destroy(); +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_FindA +函数功能:A记录查找 + 参数.一:lpszDNSAddr + In/Out:In + 类型:常量字符指针 + 可空:N + 意思:输入要查找的DNS地址 + 参数.二:pppSt_DNSList + In/Out:Out + 类型:三级指针 + 可空:N + 意思:输出查找到的列表 + 参数.三:pInt_ListCount + In/Out:Out + 类型:整数型指针 + 可空:N + 意思:输出列表个数 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +extern "C" bool ModuleHelp_DNSAddr_FindA(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO*** pppSt_DNSList, int* pInt_ListCount); +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_FindPtr +函数功能:输出IP对应的域名 + 参数.一:lpszDNSAddr + In/Out:In + 类型:常量字符指针 + 可空:N + 意思:输入要查找的IP地址 + 参数.二:pSt_DNSAddr + In/Out:Out + 类型:数据结构指针 + 可空:N + 意思:输出查找到的数据 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +extern "C" bool ModuleHelp_DNSAddr_FindPtr(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO* pSt_DNSAddr); +/******************************************************************** +函数名称:ModuleHelp_DNSAddr_Select +函数功能:备选地址 + 参数.一:ptszDNSServer + In/Out:Out + 类型:字符指针 + 可空:N + 意思:输出选择的DNS服务器 +返回值 + 类型:逻辑型 + 意思:是否成功 +备注: +*********************************************************************/ +extern "C" bool ModuleHelp_DNSAddr_Select(XCHAR* ptszDNSServer); \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Error.h b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Error.h index 4b75530..3a99efa 100644 --- a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Error.h +++ b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_Error.h @@ -69,4 +69,9 @@ #define ERROR_XENGINE_APISERVICE_MODULE_HELP_IAMGE_CRAETE 0xD6006 //创建句柄失败 #define ERROR_XENGINE_APISERVICE_MODULE_HELP_IAMGE_INIT 0xD6007 //初始化失败 #define ERROR_XENGINE_APISERVICE_MODULE_HELP_IAMGE_READ 0xD6008 //读取数据失败 -#define ERROR_XENGINE_APISERVICE_MODULE_HELP_IAMGE_GET 0xD6009 //获取数据失败 \ No newline at end of file +#define ERROR_XENGINE_APISERVICE_MODULE_HELP_IAMGE_GET 0xD6009 //获取数据失败 +////////////////////////////////////////////////////////////////////////// +// DNS处理错误 +////////////////////////////////////////////////////////////////////////// +#define ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_PARAMRT 0xD7001 //参数错误 +#define ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_NOTFOUND 0xD7002 //没有找到 \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.def b/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.def index 20cfafe..237820b 100644 --- a/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.def +++ b/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.def @@ -46,4 +46,10 @@ EXPORTS ModuleHelp_ImageSet_Flip ModuleHelp_ImageSet_ColorCvt ModuleHelp_ImageSet_Ligth - ModuleHelp_ImageSet_Level \ No newline at end of file + ModuleHelp_ImageSet_Level + + ModuleHelp_DNSAddr_Init + ModuleHelp_DNSAddr_Destroy + ModuleHelp_DNSAddr_FindA + ModuleHelp_DNSAddr_FindPtr + ModuleHelp_DNSAddr_Select \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj b/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj index 6b15a19..7ef3da9 100644 --- a/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj +++ b/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj @@ -247,6 +247,7 @@ + @@ -260,6 +261,7 @@ + diff --git a/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj.filters b/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj.filters index df8a58e..d15dc8e 100644 --- a/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj.filters +++ b/XEngine_Source/XEngine_ModuleHelp/XEngine_ModuleHelp.vcxproj.filters @@ -55,6 +55,12 @@ {660ce380-2906-43e5-a33c-ef5f97f1f585} + + {a5e13955-e617-4202-92b2-236240920728} + + + {80ae4ca3-522b-4ab9-8157-e77fc923ea11} + @@ -93,6 +99,9 @@ 头文件\ModuleHelp_Image + + 头文件\ModuleHelp_DNSAddr + @@ -125,6 +134,9 @@ 源文件\ModuleHelp_Image + + 源文件\ModuleHelp_DNSAddr + diff --git a/XEngine_Source/XEngine_ModuleHelp/pch.cpp b/XEngine_Source/XEngine_ModuleHelp/pch.cpp index 7f13afa..a34567b 100644 --- a/XEngine_Source/XEngine_ModuleHelp/pch.cpp +++ b/XEngine_Source/XEngine_ModuleHelp/pch.cpp @@ -7,6 +7,7 @@ #include "ModuleHelp_SocketTest/ModuleHelp_SocketTest.h" #include "ModuleHelp_Image/ModuleHelp_ImageGet.h" #include "ModuleHelp_Image/ModuleHelp_ImageSet.h" +#include "ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.h" /******************************************************************** // Created: 2022/03/04 13:37:38 // File Name: D:\XEngine_APIService\XEngine_Source\XEngine_ModuleHelp\pch.cpp @@ -29,6 +30,7 @@ CModuleHelp_QRCode m_QRCode; CModuleHelp_SocketTest m_SocketTest; CModuleHelp_ImageGet m_ImageGet; CModuleHelp_ImageSet m_ImageSet; +CModuleHelp_DNSAddr m_DNSAddr; ////////////////////////////////////////////////////////////////////////// /// 导出的函数 ////////////////////////////////////////////////////////////////////////// @@ -212,4 +214,27 @@ extern "C" bool ModuleHelp_ImageSet_Ligth(LPCXSTR lpszSrcBuffer, int nSLen, LPCX extern "C" bool ModuleHelp_ImageSet_Level(LPCXSTR lpszSrcBuffer, int nSLen, LPCXSTR lpszExtFile, XCHAR * ptszDstBuffer, int* pInt_DLen, int nLevel) { return m_ImageSet.ModuleHelp_ImageSet_Level(lpszSrcBuffer, nSLen, lpszExtFile, ptszDstBuffer, pInt_DLen, nLevel); +} +/************************************************************************/ +/* DNS处理导出函数 */ +/************************************************************************/ +extern "C" bool ModuleHelp_DNSAddr_Init(XENGINE_DNSINFO* pSt_DNSInfo) +{ + return m_DNSAddr.ModuleHelp_DNSAddr_Init(pSt_DNSInfo); +} +extern "C" bool ModuleHelp_DNSAddr_Destroy() +{ + return m_DNSAddr.ModuleHelp_DNSAddr_Destroy(); +} +extern "C" bool ModuleHelp_DNSAddr_FindA(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO*** pppSt_DNSList, int* pInt_ListCount) +{ + return m_DNSAddr.ModuleHelp_DNSAddr_FindA(lpszDNSAddr, pppSt_DNSList, pInt_ListCount); +} +extern "C" bool ModuleHelp_DNSAddr_FindPtr(LPCXSTR lpszDNSAddr, XENGINE_DNSADDRINFO* pSt_DNSAddr) +{ + return m_DNSAddr.ModuleHelp_DNSAddr_FindPtr(lpszDNSAddr, pSt_DNSAddr); +} +extern "C" bool ModuleHelp_DNSAddr_Select(XCHAR* ptszDNSServer) +{ + return m_DNSAddr.ModuleHelp_DNSAddr_Select(ptszDNSServer); } \ No newline at end of file diff --git a/XEngine_Source/XEngine_ModuleHelp/pch.h b/XEngine_Source/XEngine_ModuleHelp/pch.h index c90076f..930e2a6 100644 --- a/XEngine_Source/XEngine_ModuleHelp/pch.h +++ b/XEngine_Source/XEngine_ModuleHelp/pch.h @@ -54,6 +54,7 @@ using namespace std; #include #include #include "../XEngine_UserProtocol.h" +#include "../XEngine_ModuleConfigure/ModuleConfig_Define.h" #include "ModuleHelp_Define.h" #include "ModuleHelp_Error.h" /******************************************************************** diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile index 04771ee..beff8be 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile @@ -12,7 +12,7 @@ LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -l -lXEngine_APIModuleIPMac -lXEngine_APIModulePhone LIBEX = OBJECTS = XEngine_Configure.o XEngine_Network.o XEngine_HTTPTask.o XEngine_PluginTask.o XEngine_HttpApp.o \ - RFCTask_Ntp.o RFCTask_Stun.o \ + RFCTask_Ntp.o RFCTask_Stun.o RFCTask_Dns.o \ TaskGet_Bank.o TaskGet_IDCard.o TaskGet_Locker.o TaskGet_Translation.o TaskGet_Reload.o TaskGet_Weather.o TaskGet_IDRegion.o TaskGet_Oil.o TaskGet_APIModule.o \ TaskPost_DTest.o TaskPost_Log.o TaskPost_P2PClient.o TaskPost_PostCode.o TaskPost_QRCode.o TaskPost_ShortLink.o TaskPost_SocketTest.o TaskPost_WordFilter.o TaskPost_Image.o TaskPost_BackService.o TaskPost_Deamon.o TaskPost_Machine.o @@ -71,6 +71,8 @@ RFCTask_Ntp.o:./XEngine_TaskRfc/RFCTask_Ntp.cpp $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./XEngine_TaskRfc/RFCTask_Ntp.cpp RFCTask_Stun.o:./XEngine_TaskRfc/RFCTask_Stun.cpp $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./XEngine_TaskRfc/RFCTask_Stun.cpp +RFCTask_Dns.o:./XEngine_TaskRfc/RFCTask_Dns.cpp + $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./XEngine_TaskRfc/RFCTask_Dns.cpp TaskGet_Bank.o:./XEngine_TaskGet/TaskGet_Bank.cpp $(CC) $(DEBUG) $(FLAGS) $(UNICODE) $(PLATVER) $(LOADHDR) ./XEngine_TaskGet/TaskGet_Bank.cpp diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp index 8e89d04..5b4d4ca 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp @@ -13,6 +13,7 @@ bool XEngine_Configure_Parament(int argc, char** argv) { LPCXSTR lpszConfigFile = _X("./XEngine_Config/XEngine_Config.json"); + LPCXSTR lpszDNSConfig = _X("./XEngine_Config/XEngine_DNSConfig.json"); LPCXSTR lpszVersionFile = _X("./XEngine_Config/XEngine_VersionConfig.json"); if (NULL != st_ServiceConfig.st_XVer.pStl_ListVer) @@ -26,6 +27,11 @@ bool XEngine_Configure_Parament(int argc, char** argv) printf("解析配置文件失败,ModuleConfigure_Json_File:%lX\n", ModuleConfigure_GetLastError()); return false; } + if (!ModuleConfigure_Json_DNSFile(lpszDNSConfig, &st_DNSConfig)) + { + printf("解析配置文件失败,ModuleConfigure_Json_DNSFile:%lX\n", ModuleConfigure_GetLastError()); + return false; + } if (!ModuleConfigure_Json_VersionFile(lpszVersionFile, &st_ServiceConfig)) { printf("解析配置文件失败,ModuleConfigure_Json_VersionFile:%lX\n", ModuleConfigure_GetLastError()); diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h index 281bbea..98c4752 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h @@ -51,6 +51,8 @@ using namespace std; #include #include #include +#include +#include #include #include #include @@ -115,6 +117,7 @@ using namespace std; //rfc #include "XEngine_TaskRfc/RFCTask_Stun.h" #include "XEngine_TaskRfc/RFCTask_Ntp.h" +#include "XEngine_TaskRfc/RFCTask_Dns.h" /******************************************************************** // Created: 2022/01/20 14:42:06 // File Name: D:\XEngine_ServiceApp\XEngine_Source\XEngine_ServiceApp\XEngine_HttpApp\XEngine_Hdr.h @@ -142,6 +145,7 @@ extern XHANDLE xhMemPool; extern unique_ptr pSTDThread_Deamon; //配置文件 extern XENGINE_SERVICECONFIG st_ServiceConfig; +extern XENGINE_DNSINFO st_DNSConfig; extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #include "XEngine_MemoryPool.h" @@ -160,6 +164,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"XEngine_RfcComponents/RfcComponents_HttpProtocol.lib") #pragma comment(lib,"XEngine_RfcComponents/RfcComponents_NatProtocol.lib") #pragma comment(lib,"XEngine_RfcComponents/RfcComponents_NTPProtocol.lib") +#pragma comment(lib,"XEngine_RfcComponents/RfcComponents_DNSProtocol.lib") #pragma comment(lib,"XEngine_SystemSdk/XEngine_SystemApi") #pragma comment(lib,"XEngine_AVCodec/XEngine_AVCollect.lib") #pragma comment(lib,"XEngine_AVCodec/XEngine_VideoCodec.lib") diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp index 16c96df..2ed635b 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp @@ -26,6 +26,7 @@ XHANDLE xhMemPool = NULL; unique_ptr pSTDThread_Deamon = NULL; //配置文件 XENGINE_SERVICECONFIG st_ServiceConfig; +XENGINE_DNSINFO st_DNSConfig; XENGINE_DEAMONAPPLIST st_DeamonAppConfig; void ServiceApp_Stop(int signo) @@ -59,6 +60,7 @@ void ServiceApp_Stop(int signo) ModulePlugin_Loader_Destory(); ModuleHelp_P2PClient_Destory(); ModuleHelp_ImageGet_TextDestory(); + ModuleHelp_DNSAddr_Destroy(); //销毁日志资源 HelpComponents_XLog_Destroy(xhLog); //销毁线程 @@ -220,10 +222,10 @@ int main(int argc, char** argv) xhMemPool = ManagePool_Memory_Create(); if (NULL == xhMemPool) { - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,初始化内存池失败,错误:%lX"), ManagePool_GetLastError()); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,初始化内存池失败,错误:%lX"), ManagePool_GetLastError()); goto XENGINE_SERVICEAPP_EXIT; } - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,初始化内存池成功")); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,初始化内存池成功")); if (st_ServiceConfig.st_XImageText.bEnable) { @@ -375,7 +377,7 @@ int main(int argc, char** argv) xhNTPSocket = NetCore_UDPXCore_StartEx(st_ServiceConfig.nNTPPort, st_ServiceConfig.st_XMax.nIOThread); if (NULL == xhNTPSocket) { - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,启动NTP网络服务器失败,错误:%lX"), NetCore_GetLastError()); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,启动NTP网络服务器失败,端口:%d,错误:%lX"), st_ServiceConfig.nNTPPort, NetCore_GetLastError()); goto XENGINE_SERVICEAPP_EXIT; } XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,启动NTP网络服务器成功,NTP端口:%d,IO:%d"), st_ServiceConfig.nNTPPort, st_ServiceConfig.st_XMax.nIOThread); @@ -392,12 +394,19 @@ int main(int argc, char** argv) xhDNSSocket = NetCore_UDPXCore_StartEx(st_ServiceConfig.nDNSPort, st_ServiceConfig.st_XMax.nIOThread); if (NULL == xhDNSSocket) { - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,启动DNS网络服务器失败,错误:%lX"), NetCore_GetLastError()); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,启动DNS网络服务器失败,端口:%d,错误:%lX"), st_ServiceConfig.nDNSPort, NetCore_GetLastError()); goto XENGINE_SERVICEAPP_EXIT; } XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,启动DNS网络服务器成功,DNS端口:%d,IO:%d"), st_ServiceConfig.nDNSPort, st_ServiceConfig.st_XMax.nIOThread); NetCore_UDPXCore_RegisterCallBackEx(xhDNSSocket, Network_Callback_DNSRecv); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,注册DNS网络事件成功")); + + if (!ModuleHelp_DNSAddr_Init(&st_DNSConfig)) + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("启动服务中,初始化DNS配置帮助函数库失败,错误:%lX"), ModuleHelp_GetLastError()); + goto XENGINE_SERVICEAPP_EXIT; + } + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,初始化DNS配置帮助函数库成功,备用DNS服务个数:%d,配置DNS地址:%d"), st_DNSConfig.stl_ListDNSList.size(), st_DNSConfig.stl_ListDNSServer.size()); } else { @@ -612,6 +621,7 @@ int main(int argc, char** argv) ModulePlugin_Loader_Destory(); ModuleHelp_P2PClient_Destory(); ModuleHelp_ImageGet_TextDestory(); + ModuleHelp_DNSAddr_Destroy(); //销毁日志资源 HelpComponents_XLog_Destroy(xhLog); //销毁线程 diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj index df2b6ac..55e051f 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj @@ -250,6 +250,7 @@ + @@ -281,6 +282,7 @@ + diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj.filters b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj.filters index c19b038..aab67b7 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj.filters +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.vcxproj.filters @@ -117,6 +117,9 @@ 源文件\XEngine_TaskGet + + 源文件\XEngine_TaskRfc + @@ -206,5 +209,8 @@ 头文件 + + 头文件\XEngine_TaskRfc + \ No newline at end of file diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp index 4cc02af..c5526ac 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Network.cpp @@ -51,7 +51,7 @@ void XCALLBACK Network_Callback_NTPRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, } void XCALLBACK Network_Callback_DNSRecv(LPCXSTR lpszClientAddr, XSOCKET hSocket, LPCXSTR lpszMSGBuffer, int nMSGLen, XPVOID lParam) { - + RFCTask_DNS_Parse(lpszClientAddr, lpszMSGBuffer, nMSGLen); } //////////////////////////////////////////////////////////////////////////网络IO关闭操作 void XEngine_Network_Close(LPCXSTR lpszClientAddr, bool bHeart) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp new file mode 100644 index 0000000..54ae972 --- /dev/null +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp @@ -0,0 +1,65 @@ +#include "../XEngine_Hdr.h" + +bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLen) +{ + int nSDLen = 0; + int nRequestID = 0; + XCHAR tszSDBuffer[4096] = {}; + XENGINE_DNSPROTOCOL st_DNSRequest = {}; + + if (!DNSProtocol_Parse_Header(lpszMSGBuffer, nMSGLen, &nRequestID, &st_DNSRequest)) + { + DNSProtocol_Packet_Error(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, XENGINE_DNSPROTOCOL_QUERY_QUESTION_STATUS_FORMAT); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("DNS客户端:%s,发送的DNS协议不正确"), lpszClientAddr); + return false; + } + + if (XENGINE_DNSPROTOCOL_QUERY_QUESTION_TYPE_A == st_DNSRequest.st_QueryInfo.nNameType) + { + int nListCount = 0; + XENGINE_DNSADDRINFO** ppSt_DNSAddr; + if (ModuleHelp_DNSAddr_FindA(st_DNSRequest.tszNameStr, &ppSt_DNSAddr, &nListCount)) + { + //找到A记录 + XENGINE_DNSPROTOCOL** ppSt_DNSAnswer; + BaseLib_Memory_Malloc((XPPPMEM)&ppSt_DNSAnswer, nListCount, sizeof(XENGINE_DNSPROTOCOL)); + for (int i = 0; i < nListCount; i++) + { + ppSt_DNSAnswer[i]->nTTL = ppSt_DNSAddr[i]->nTTL; + ppSt_DNSAnswer[i]->st_QueryInfo.nNameType = ppSt_DNSAddr[i]->nType; + ppSt_DNSAnswer[i]->st_QueryInfo.nNameClass = XENGINE_DNSPROTOCOL_QUERY_QUESTION_CLASS_IN; + _tcsxcpy(ppSt_DNSAnswer[i]->tszNameStr, ppSt_DNSAddr[i]->tszDNSName); + _tcsxcpy(ppSt_DNSAnswer[i]->tszAddrStr, ppSt_DNSAddr[i]->tszDNSAddr); + } + DNSProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, &ppSt_DNSAnswer, nListCount); + BaseLib_Memory_Free((XPPPMEM)&ppSt_DNSAnswer, nListCount); + } + } + else if (XENGINE_DNSPROTOCOL_QUERY_QUESTION_TYPE_PTR == st_DNSRequest.st_QueryInfo.nNameType) + { + int nIPVer = 0; + int nListCount = 1; + XCHAR tszIPStr[256] = {}; + XENGINE_DNSADDRINFO st_DNSAddr = {}; + XENGINE_DNSPROTOCOL** ppSt_DNSAnswer; + + DNSProtocol_Help_PTRStr(st_DNSRequest.tszNameStr, tszIPStr, &nIPVer); + BaseLib_Memory_Malloc((XPPPMEM)&ppSt_DNSAnswer, nListCount, sizeof(XENGINE_DNSPROTOCOL)); + + if (ModuleHelp_DNSAddr_FindPtr(tszIPStr, &st_DNSAddr)) + { + ppSt_DNSAnswer[0]->nTTL = st_DNSAddr.nTTL; + ppSt_DNSAnswer[0]->st_QueryInfo.nNameType = st_DNSAddr.nType; + ppSt_DNSAnswer[0]->st_QueryInfo.nNameClass = XENGINE_DNSPROTOCOL_QUERY_QUESTION_CLASS_IN; + _tcsxcpy(ppSt_DNSAnswer[0]->tszNameStr, st_DNSAddr.tszDNSAddr); + _tcsxcpy(ppSt_DNSAnswer[0]->tszAddrStr, st_DNSAddr.tszDNSName); + } + DNSProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, &ppSt_DNSAnswer, nListCount); + BaseLib_Memory_Free((XPPPMEM)&ppSt_DNSAnswer, nListCount); + } + + NetCore_UDPXCore_SendEx(xhDNSSocket, lpszClientAddr, tszSDBuffer, nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("DNS客户端:%s,发送DNS协议给服务器,处理成功"), lpszClientAddr); + + return true; +} \ No newline at end of file diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.h new file mode 100644 index 0000000..3c2477e --- /dev/null +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.h @@ -0,0 +1,3 @@ +#pragma once + +bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLen); \ No newline at end of file diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp index 9702aa0..795245d 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Ntp.cpp @@ -10,7 +10,7 @@ bool RFCTask_NTP_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLe NTPProtocol_Parse_Header(lpszMSGBuffer, nMSGLen, NULL, NULL, NULL, &st_TimeTras); NTPProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, NULL, &st_TimeRecv, &st_TimeTras, st_ServiceConfig.tszIPAddr); - NetCore_UDPXCore_SendEx(xhRFCSocket, lpszClientAddr, tszSDBuffer, nSDLen); + NetCore_UDPXCore_SendEx(xhNTPSocket, lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("RFC客户端:%s,发送NTP时间同步请求给服务器,处理成功"), lpszClientAddr); return true; From 311189e9c07baa20f916f6d82f2a527b31ec67af Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 15 Jul 2025 09:52:40 +0800 Subject: [PATCH 06/41] fixed:build error --- XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile index beff8be..e9084c4 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile @@ -6,7 +6,7 @@ LOADHDR = -I ./ LOADSO = -L ../../XEngine_ModuleConfigure -L ../../XEngine_ModuleDatabase -L ../../XEngine_ModuleProtocol -L ../../XEngine_ModuleSystem -L ../../XEngine_ModuleHelp -L ../../XEngine_ModulePlugin \ -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport \ -L ../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac -L ../../XEngine_DependLibrary/XEngine_PhoneData/Source/C/XEngine_APIModulePhone -LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lNetHelp_APIAddr -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ +LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lNetHelp_APIAddr -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ -lXEngine_ModuleConfigure -lXEngine_ModuleDatabase -lXEngine_ModuleProtocol -lXEngine_ModuleSystem -lXEngine_ModuleHelp -lXEngine_ModulePlugin \ -ljsoncpp -lXEngine_InfoReport \ -lXEngine_APIModuleIPMac -lXEngine_APIModulePhone From 7099ece51741ca33c8f65d0c71ce46c28e22e47b Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 15 Jul 2025 10:08:06 +0800 Subject: [PATCH 07/41] update:configure file --- .../XEngine_Config/XEngine_Config.json | 4 +- .../XEngine_Config/XEngine_DNSConfig.json | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 XEngine_Release/XEngine_Config/XEngine_DNSConfig.json diff --git a/XEngine_Release/XEngine_Config/XEngine_Config.json b/XEngine_Release/XEngine_Config/XEngine_Config.json index 483d080..a97ad30 100644 --- a/XEngine_Release/XEngine_Config/XEngine_Config.json +++ b/XEngine_Release/XEngine_Config/XEngine_Config.json @@ -4,8 +4,8 @@ "bShowWnd": true, "nHttpPort": 5501, "nRFCPort": 5502, - "nNTPPort": 123, - "nDNSPort": 53, + "nNTPPort": 0, + "nDNSPort": 0, "XMax": { "nMaxClient": 10000, "nMaxQueue": 10000, diff --git a/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json b/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json new file mode 100644 index 0000000..caec63e --- /dev/null +++ b/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json @@ -0,0 +1,44 @@ +{ + "DNSServer": [ + "8.8.8.8", + "8.8.4.4" + ], + "DNSList": [ + { + "bEnable": false, + "DNSName": "www.libxengine.com", + "DNSAddr": [ + { + "Type:": 5, + "TTL": 60, + "Name": "www.libxengine.com", + "Addr": "www.xyry.org" + }, + { + "Type:": 1, + "TTL": 60, + "Name": "www.xyry.org", + "Addr": "118.25.14.242" + }, + { + "Type:": 1, + "TTL": 120, + "Name": "www.libxengine.com", + "Addr": "104.21.4.128" + } + ] + }, + { + "bEnable": true, + "DNSName": "www.xyry.org", + "DNSAddr": [ + { + "Type:": 1, + "TTL": 120, + "Name": "www.xyry.org", + "Addr": "104.21.4.128" + } + ] + } + ] +} \ No newline at end of file From e894bc752a9ca0bce2b6f2dd2dabfeaef36e0271 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 18 Jul 2025 15:32:30 +0800 Subject: [PATCH 08/41] fixed:read dns configure failure --- .../XEngine_Config/XEngine_Config.json | 2 +- .../ModuleConfigure_Json.cpp | 20 ++++++++----------- .../XEngine_HttpApp/XEngine_Configure.cpp | 2 -- .../XEngine_HttpApp/XEngine_HttpApp.cpp | 1 - 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/XEngine_Release/XEngine_Config/XEngine_Config.json b/XEngine_Release/XEngine_Config/XEngine_Config.json index a97ad30..f6eff0f 100644 --- a/XEngine_Release/XEngine_Config/XEngine_Config.json +++ b/XEngine_Release/XEngine_Config/XEngine_Config.json @@ -5,7 +5,7 @@ "nHttpPort": 5501, "nRFCPort": 5502, "nNTPPort": 0, - "nDNSPort": 0, + "nDNSPort": 53, "XMax": { "nMaxClient": 10000, "nMaxQueue": 10000, diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp index 96a5803..c35f8f8 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp @@ -406,7 +406,6 @@ bool CModuleConfigure_Json::ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, JSONCPP_STRING st_JsonError; Json::Value st_JsonRoot; Json::CharReaderBuilder st_JsonBuilder; - FILE* pSt_File = fopen(lpszConfigFile, "rb"); if (NULL == pSt_File) { @@ -417,7 +416,6 @@ bool CModuleConfigure_Json::ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, XCHAR tszMsgBuffer[8192] = {}; size_t nRet = fread(tszMsgBuffer, 1, sizeof(tszMsgBuffer), pSt_File); fclose(pSt_File); - std::unique_ptr const pSt_JsonReader(st_JsonBuilder.newCharReader()); if (!pSt_JsonReader->parse(tszMsgBuffer, tszMsgBuffer + nRet, &st_JsonRoot, &st_JsonError)) { @@ -425,29 +423,27 @@ bool CModuleConfigure_Json::ModuleConfigure_Json_DNSFile(LPCXSTR lpszConfigFile, Config_dwErrorCode = ERROR_MODULE_CONFIGURE_JSON_PARSE; return false; } - Json::Value st_JsonServer = st_JsonRoot["DNSServer"]; for (unsigned int i = 0; i < st_JsonRoot["DNSServer"].size(); i++) { pSt_DNSList->stl_ListDNSServer.push_back(st_JsonServer[i].asCString()); } - Json::Value st_JsonList = st_JsonRoot["DNSList"]; for (unsigned int i = 0; i < st_JsonRoot["DNSList"].size(); i++) { XENGINE_DNSDOMAIN st_DNSDomain = {}; - st_DNSDomain.bEnable = st_JsonList["bEnable"].asBool(); - _tcsxcpy(st_DNSDomain.tszDNSName, st_JsonList["DNSName"].asCString()); + st_DNSDomain.bEnable = st_JsonList[i]["bEnable"].asBool(); + _tcsxcpy(st_DNSDomain.tszDNSName, st_JsonList[i]["DNSName"].asCString()); - Json::Value st_JsonAddr = st_JsonList["DNSAddr"]; - for (unsigned int j = 0; j < st_JsonList["DNSAddr"].size(); j++) + Json::Value st_JsonAddr = st_JsonList[i]["DNSAddr"]; + for (unsigned int j = 0; j < st_JsonList[i]["DNSAddr"].size(); j++) { XENGINE_DNSADDRINFO st_DNSAddr = {}; - st_DNSAddr.nType = st_JsonAddr["Type"].asInt(); - st_DNSAddr.nTTL = st_JsonAddr["TTL"].asInt(); - _tcsxcpy(st_DNSAddr.tszDNSName, st_JsonAddr["Name"].asCString()); - _tcsxcpy(st_DNSAddr.tszDNSAddr, st_JsonAddr["Addr"].asCString()); + st_DNSAddr.nType = st_JsonAddr[j]["Type"].asInt(); + st_DNSAddr.nTTL = st_JsonAddr[j]["TTL"].asInt(); + _tcsxcpy(st_DNSAddr.tszDNSName, st_JsonAddr[j]["Name"].asCString()); + _tcsxcpy(st_DNSAddr.tszDNSAddr, st_JsonAddr[j]["Addr"].asCString()); st_DNSDomain.stl_ListDNSAddr.push_back(st_DNSAddr); } diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp index 5b4d4ca..87aa1b1 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp @@ -37,7 +37,6 @@ bool XEngine_Configure_Parament(int argc, char** argv) printf("解析配置文件失败,ModuleConfigure_Json_VersionFile:%lX\n", ModuleConfigure_GetLastError()); return false; } - for (int i = 0; i < argc; i++) { if ((0 == _tcsxcmp("-h", argv[i])) || (0 == _tcsxcmp("-H", argv[i]))) @@ -75,7 +74,6 @@ bool XEngine_Configure_Parament(int argc, char** argv) bIsTest = true; } } - return true; } diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp index 2ed635b..4a2e29f 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp @@ -153,7 +153,6 @@ int main(int argc, char** argv) THREADPOOL_PARAMENT** ppSt_ListHTTPParam; memset(&st_ServiceConfig, '\0', sizeof(XENGINE_SERVICECONFIG)); - //初始化参数 if (!XEngine_Configure_Parament(argc, argv)) { From 622b85a69d83d2ca290a8efb0a90e897ac5b666b Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 18 Jul 2025 15:35:14 +0800 Subject: [PATCH 09/41] modify:vs copy file --- XEngine_Source/VSCopy_Arm64.bat | 1 + XEngine_Source/VSCopy_Debug.bat | 1 + XEngine_Source/VSCopy_x64.bat | 1 + XEngine_Source/VSCopy_x86.bat | 1 + 4 files changed, 4 insertions(+) diff --git a/XEngine_Source/VSCopy_Arm64.bat b/XEngine_Source/VSCopy_Arm64.bat index ef407e9..e6cbfc9 100644 --- a/XEngine_Source/VSCopy_Arm64.bat +++ b/XEngine_Source/VSCopy_Arm64.bat @@ -20,6 +20,7 @@ copy /y "%XEngine_LibArm64%\XEngine_HelpComponents\HelpComponents_XLog.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_RfcComponents\RfcComponents_HttpProtocol.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_RfcComponents\RfcComponents_NatProtocol.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_RfcComponents\RfcComponents_NTPProtocol.dll" "./" +copy /y "%XEngine_LibArm64%\XEngine_RfcComponents\RfcComponents_DNSProtocol.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_AVHelp.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_VideoCodec.dll" "./" diff --git a/XEngine_Source/VSCopy_Debug.bat b/XEngine_Source/VSCopy_Debug.bat index 46f0513..b4c22c6 100644 --- a/XEngine_Source/VSCopy_Debug.bat +++ b/XEngine_Source/VSCopy_Debug.bat @@ -20,6 +20,7 @@ copy /y "D:\XEngine\XEngine_SourceCode\Debug\HelpComponents_XLog.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\RfcComponents_HttpProtocol.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\RfcComponents_NatProtocol.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\RfcComponents_NTPProtocol.dll" "./" +copy /y "D:\XEngine\XEngine_SourceCode\Debug\RfcComponents_DNSProtocol.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_AVHelp.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_VideoCodec.dll" "./" diff --git a/XEngine_Source/VSCopy_x64.bat b/XEngine_Source/VSCopy_x64.bat index c792bd7..72a7b7c 100644 --- a/XEngine_Source/VSCopy_x64.bat +++ b/XEngine_Source/VSCopy_x64.bat @@ -20,6 +20,7 @@ copy /y "%XEngine_Lib64%\XEngine_HelpComponents\HelpComponents_XLog.dll" "./" copy /y "%XEngine_Lib64%\XEngine_RfcComponents\RfcComponents_HttpProtocol.dll" "./" copy /y "%XEngine_Lib64%\XEngine_RfcComponents\RfcComponents_NatProtocol.dll" "./" copy /y "%XEngine_Lib64%\XEngine_RfcComponents\RfcComponents_NTPProtocol.dll" "./" +copy /y "%XEngine_Lib64%\XEngine_RfcComponents\RfcComponents_DNSProtocol.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_AVHelp.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_VideoCodec.dll" "./" diff --git a/XEngine_Source/VSCopy_x86.bat b/XEngine_Source/VSCopy_x86.bat index 0c05862..240db97 100644 --- a/XEngine_Source/VSCopy_x86.bat +++ b/XEngine_Source/VSCopy_x86.bat @@ -20,6 +20,7 @@ copy /y "%XEngine_Lib32%\XEngine_HelpComponents\HelpComponents_XLog.dll" "./" copy /y "%XEngine_Lib32%\XEngine_RfcComponents\RfcComponents_HttpProtocol.dll" "./" copy /y "%XEngine_Lib32%\XEngine_RfcComponents\RfcComponents_NatProtocol.dll" "./" copy /y "%XEngine_Lib32%\XEngine_RfcComponents\RfcComponents_NTPProtocol.dll" "./" +copy /y "%XEngine_Lib32%\XEngine_RfcComponents\RfcComponents_DNSProtocol.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_AVHelp.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_VideoCodec.dll" "./" From 653aefad0efa4ec27814c84258c5826e03231bab Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 18 Jul 2025 16:06:26 +0800 Subject: [PATCH 10/41] fixed:dns query a and cname --- .../XEngine_Config/XEngine_DNSConfig.json | 12 ++++++------ .../ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp | 8 +------- .../XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json b/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json index caec63e..9f38261 100644 --- a/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json +++ b/XEngine_Release/XEngine_Config/XEngine_DNSConfig.json @@ -5,23 +5,23 @@ ], "DNSList": [ { - "bEnable": false, + "bEnable": true, "DNSName": "www.libxengine.com", "DNSAddr": [ { - "Type:": 5, - "TTL": 60, + "Type": 5, + "TTL": 30, "Name": "www.libxengine.com", "Addr": "www.xyry.org" }, { - "Type:": 1, + "Type": 1, "TTL": 60, "Name": "www.xyry.org", "Addr": "118.25.14.242" }, { - "Type:": 1, + "Type": 1, "TTL": 120, "Name": "www.libxengine.com", "Addr": "104.21.4.128" @@ -33,7 +33,7 @@ "DNSName": "www.xyry.org", "DNSAddr": [ { - "Type:": 1, + "Type": 1, "TTL": 120, "Name": "www.xyry.org", "Addr": "104.21.4.128" diff --git a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp index bc9c9ce..57bb1de 100644 --- a/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp +++ b/XEngine_Source/XEngine_ModuleHelp/ModuleHelp_DNSAddr/ModuleHelp_DNSAddr.cpp @@ -141,13 +141,7 @@ bool CModuleHelp_DNSAddr::ModuleHelp_DNSAddr_FindPtr(LPCXSTR lpszDNSAddr, XENGIN { ModuleHelp_IsErrorOccur = false; - auto stl_MapIterator = stl_MapDNSAddr.find(lpszDNSAddr); - if (stl_MapIterator == stl_MapDNSAddr.end()) - { - ModuleHelp_IsErrorOccur = true; - ModuleHelp_dwErrorCode = ERROR_XENGINE_APISERVICE_MODULE_HELP_DNS_NOTFOUND; - return false; - } + auto stl_MapIterator = stl_MapDNSAddr.begin(); //查找地址 bool bIsFound = false; for (auto stl_ListIterator = stl_MapIterator->second.begin(); stl_ListIterator != stl_MapIterator->second.end(); stl_ListIterator++) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp index 54ae972..7c907ed 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp @@ -49,7 +49,7 @@ bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLe if (ModuleHelp_DNSAddr_FindPtr(tszIPStr, &st_DNSAddr)) { ppSt_DNSAnswer[0]->nTTL = st_DNSAddr.nTTL; - ppSt_DNSAnswer[0]->st_QueryInfo.nNameType = st_DNSAddr.nType; + ppSt_DNSAnswer[0]->st_QueryInfo.nNameType = XENGINE_DNSPROTOCOL_QUERY_QUESTION_TYPE_PTR; ppSt_DNSAnswer[0]->st_QueryInfo.nNameClass = XENGINE_DNSPROTOCOL_QUERY_QUESTION_CLASS_IN; _tcsxcpy(ppSt_DNSAnswer[0]->tszNameStr, st_DNSAddr.tszDNSAddr); _tcsxcpy(ppSt_DNSAnswer[0]->tszAddrStr, st_DNSAddr.tszDNSName); From 4240b83269c8411015886cd4a75ca265b95d07dd Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 18 Jul 2025 16:37:26 +0800 Subject: [PATCH 11/41] modify:dns query support back server query --- .../XEngine_Config/XEngine_Config.json | 2 +- .../XEngine_HttpApp/Makefile | 2 +- .../XEngine_HttpApp/XEngine_Hdr.h | 3 ++ .../XEngine_TaskRfc/RFCTask_Dns.cpp | 42 +++++++++++++++---- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/XEngine_Release/XEngine_Config/XEngine_Config.json b/XEngine_Release/XEngine_Config/XEngine_Config.json index f6eff0f..a97ad30 100644 --- a/XEngine_Release/XEngine_Config/XEngine_Config.json +++ b/XEngine_Release/XEngine_Config/XEngine_Config.json @@ -5,7 +5,7 @@ "nHttpPort": 5501, "nRFCPort": 5502, "nNTPPort": 0, - "nDNSPort": 53, + "nDNSPort": 0, "XMax": { "nMaxClient": 10000, "nMaxQueue": 10000, diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile index e9084c4..ca8a4f6 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile @@ -6,7 +6,7 @@ LOADHDR = -I ./ LOADSO = -L ../../XEngine_ModuleConfigure -L ../../XEngine_ModuleDatabase -L ../../XEngine_ModuleProtocol -L ../../XEngine_ModuleSystem -L ../../XEngine_ModuleHelp -L ../../XEngine_ModulePlugin \ -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport \ -L ../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac -L ../../XEngine_DependLibrary/XEngine_PhoneData/Source/C/XEngine_APIModulePhone -LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lNetHelp_APIAddr -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ +LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lXClient_Socket -lNetHelp_APIAddr -lNetHelp_XSocket -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ -lXEngine_ModuleConfigure -lXEngine_ModuleDatabase -lXEngine_ModuleProtocol -lXEngine_ModuleSystem -lXEngine_ModuleHelp -lXEngine_ModulePlugin \ -ljsoncpp -lXEngine_InfoReport \ -lXEngine_APIModuleIPMac -lXEngine_APIModulePhone diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h index 98c4752..3ac72da 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h @@ -35,6 +35,8 @@ using namespace std; #include #include #include +#include +#include #include #include #include @@ -157,6 +159,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"XEngine_Core/XEngine_Core.lib") #pragma comment(lib,"XEngine_Core/XEngine_ManagePool.lib") #pragma comment(lib,"XEngine_Core/XEngine_Cryption.lib") +#pragma comment(lib,"XEngine_Client/XClient_Socket.lib") #pragma comment(lib,"XEngine_Client/XClient_Stream.lib") #pragma comment(lib,"XEngine_Client/XClient_APIHelp.lib") #pragma comment(lib,"XEngine_NetHelp/NetHelp_APIAddr") diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp index 7c907ed..aab5740 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskRfc/RFCTask_Dns.cpp @@ -2,6 +2,7 @@ bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLen) { + bool bQuery = false; int nSDLen = 0; int nRequestID = 0; XCHAR tszSDBuffer[4096] = {}; @@ -10,6 +11,7 @@ bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLe if (!DNSProtocol_Parse_Header(lpszMSGBuffer, nMSGLen, &nRequestID, &st_DNSRequest)) { DNSProtocol_Packet_Error(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, XENGINE_DNSPROTOCOL_QUERY_QUESTION_STATUS_FORMAT); + NetCore_UDPXCore_SendEx(xhDNSSocket, lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("DNS客户端:%s,发送的DNS协议不正确"), lpszClientAddr); return false; } @@ -33,6 +35,7 @@ bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLe } DNSProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, &ppSt_DNSAnswer, nListCount); BaseLib_Memory_Free((XPPPMEM)&ppSt_DNSAnswer, nListCount); + bQuery = true; } } else if (XENGINE_DNSPROTOCOL_QUERY_QUESTION_TYPE_PTR == st_DNSRequest.st_QueryInfo.nNameType) @@ -41,25 +44,50 @@ bool RFCTask_DNS_Parse(LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLe int nListCount = 1; XCHAR tszIPStr[256] = {}; XENGINE_DNSADDRINFO st_DNSAddr = {}; - XENGINE_DNSPROTOCOL** ppSt_DNSAnswer; - + DNSProtocol_Help_PTRStr(st_DNSRequest.tszNameStr, tszIPStr, &nIPVer); - BaseLib_Memory_Malloc((XPPPMEM)&ppSt_DNSAnswer, nListCount, sizeof(XENGINE_DNSPROTOCOL)); - if (ModuleHelp_DNSAddr_FindPtr(tszIPStr, &st_DNSAddr)) { + XENGINE_DNSPROTOCOL** ppSt_DNSAnswer; + BaseLib_Memory_Malloc((XPPPMEM)&ppSt_DNSAnswer, nListCount, sizeof(XENGINE_DNSPROTOCOL)); + ppSt_DNSAnswer[0]->nTTL = st_DNSAddr.nTTL; ppSt_DNSAnswer[0]->st_QueryInfo.nNameType = XENGINE_DNSPROTOCOL_QUERY_QUESTION_TYPE_PTR; ppSt_DNSAnswer[0]->st_QueryInfo.nNameClass = XENGINE_DNSPROTOCOL_QUERY_QUESTION_CLASS_IN; _tcsxcpy(ppSt_DNSAnswer[0]->tszNameStr, st_DNSAddr.tszDNSAddr); _tcsxcpy(ppSt_DNSAnswer[0]->tszAddrStr, st_DNSAddr.tszDNSName); + + DNSProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, &ppSt_DNSAnswer, nListCount); + BaseLib_Memory_Free((XPPPMEM)&ppSt_DNSAnswer, nListCount); + bQuery = true; } - DNSProtocol_Packet_REPHeader(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, &ppSt_DNSAnswer, nListCount); - BaseLib_Memory_Free((XPPPMEM)&ppSt_DNSAnswer, nListCount); + } + + if (!bQuery) + { + //选择一个备用DNS服务器 + XCHAR tszIPServer[128] = {}; + ModuleHelp_DNSAddr_Select(tszIPServer); + //创建UDP查询连接 + XSOCKET hSocket = XSOCKET_ERROR; + XClient_UDPSelect_Create(&hSocket); + XClient_UDPSelect_Bind(hSocket, 12331); + XClient_UDPSelect_Connect(hSocket, tszIPServer, 53); + XClient_UDPSelect_SendMsg(hSocket, lpszMSGBuffer, nMSGLen); + + if (!BaseLib_IO_Select(hSocket, true, 2000)) + { + DNSProtocol_Packet_Error(tszSDBuffer, &nSDLen, nRequestID, &st_DNSRequest, XENGINE_DNSPROTOCOL_QUERY_QUESTION_STATUS_SERVFAIL); + NetCore_UDPXCore_SendEx(xhDNSSocket, lpszClientAddr, tszSDBuffer, nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("DNS客户端:%s,请求备用服务器数据失败,数据超时"), lpszClientAddr); + return false; + } + nSDLen = 4096; + XClient_UDPSelect_RecvMsg(hSocket, tszSDBuffer, &nSDLen); + XClient_UDPSelect_Close(hSocket); } NetCore_UDPXCore_SendEx(xhDNSSocket, lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("DNS客户端:%s,发送DNS协议给服务器,处理成功"), lpszClientAddr); - return true; } \ No newline at end of file From 167a199109e2a8b46b3df47a9d49af9f8ecca4bb Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Thu, 24 Jul 2025 14:59:19 +0800 Subject: [PATCH 12/41] modify:print message for d-test api --- .../XEngine_HttpApp/XEngine_TaskPost/TaskPost_DTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_DTest.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_DTest.cpp index 85ac83c..75f5e61 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_DTest.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_DTest.cpp @@ -21,6 +21,6 @@ bool HTTPTask_TastPost_DTest(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer, int HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam); } XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("HTTP客户端:%s,请求数据用例测试成功,请求的大小:%d,请求的类型:%d"), lpszClientAddr, nMsgLen, nType); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("HTTP客户端:%s,请求数据用例测试成功,请求的大小:%d,请求的类型:%d,发送的内容:%s"), lpszClientAddr, nMsgLen, nType, lpszMsgBuffer); return true; } \ No newline at end of file From f836322c49ba36064d46486504a96e98021cc1a8 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Thu, 24 Jul 2025 14:59:52 +0800 Subject: [PATCH 13/41] modify:don't limit api key name --- .../XEngine_HttpApp/XEngine_HTTPTask.cpp | 73 ------------------- 1 file changed, 73 deletions(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp index a986127..e01cfc2 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp @@ -104,7 +104,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST XCHAR tszValue[XPATH_MAX]; LPCXSTR lpszFuncName = _X("api"); LPCXSTR lpszParamFuncKey = _X("function"); - LPCXSTR lpszParamName = _X("params1"); //get LPCXSTR lpszParamIDCard = _X("id"); LPCXSTR lpszParamBank = _X("bank"); @@ -169,15 +168,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TastPost_P2PClient(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamZIPCode, tszValue, _tcsxlen(lpszParamZIPCode))) @@ -186,15 +176,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TastPost_PostCode(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamXLog, tszValue, _tcsxlen(lpszParamXLog))) @@ -203,15 +184,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TastPost_LogInfo(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamQRCode, tszValue, _tcsxlen(lpszParamQRCode))) @@ -220,15 +192,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TaskPost_QRCode(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamSocket, tszValue, _tcsxlen(lpszParamSocket))) @@ -237,15 +200,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TastPost_SocketTest(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamDTest, tszValue, _tcsxlen(lpszParamDTest))) @@ -254,15 +208,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TastPost_DTest(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamShortLink, tszValue, _tcsxlen(lpszParamShortLink))) @@ -334,15 +279,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TaskGet_IDCard(lpszClientAddr, tszValue); } else if (0 == _tcsxnicmp(lpszParamBank, tszValue, _tcsxlen(lpszParamBank))) @@ -351,15 +287,6 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - if (0 != _tcsxnicmp(lpszParamName, tszKey, _tcsxlen(lpszParamName))) - { - st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); - return false; - } HTTPTask_TaskGet_BankInfo(lpszClientAddr, tszValue); } else if (0 == _tcsxnicmp(lpszParamTranslation, tszValue, _tcsxlen(lpszParamTranslation))) From 804638753148a3c59cbeed81d8341ebaee057edb Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 22 Aug 2025 10:43:57 +0800 Subject: [PATCH 14/41] update:depend library --- XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource b/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource index 91c4b0c..6a2fd03 160000 --- a/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource +++ b/XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource @@ -1 +1 @@ -Subproject commit 91c4b0cdf0d45775e0575f04ae9e13491bd3934a +Subproject commit 6a2fd030257062f98b2a2751e9d5b6559901a53e From 39b75519357e97ca3e3610c7a48df9d1d0b1b47e Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 22 Aug 2025 10:44:15 +0800 Subject: [PATCH 15/41] update:start parameter are not case sensitive --- .../XEngine_HttpApp/XEngine_Configure.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp index 87aa1b1..fb5fb2f 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Configure.cpp @@ -39,37 +39,37 @@ bool XEngine_Configure_Parament(int argc, char** argv) } for (int i = 0; i < argc; i++) { - if ((0 == _tcsxcmp("-h", argv[i])) || (0 == _tcsxcmp("-H", argv[i]))) + if ((0 == _tcsxicmp("-h", argv[i])) || (0 == _tcsxicmp("-H", argv[i]))) { XEngine_Configure_Help(); return false; } - else if (0 == _tcsxcmp("-d", argv[i])) + else if (0 == _tcsxicmp("-d", argv[i])) { st_ServiceConfig.bDeamon = _ttxoi(argv[++i]); } - else if (0 == _tcsxcmp("-w", argv[i])) + else if (0 == _tcsxicmp("-w", argv[i])) { st_ServiceConfig.bShowWnd = _ttxoi(argv[++i]); } - else if (0 == _tcsxcmp("-hp", argv[i])) + else if (0 == _tcsxicmp("-hp", argv[i])) { st_ServiceConfig.nHttpPort = _ttxoi(argv[++i]); } - else if (0 == _tcsxcmp("-rp", argv[i])) + else if (0 == _tcsxicmp("-rp", argv[i])) { st_ServiceConfig.nRFCPort = _ttxoi(argv[++i]); } - else if (0 == _tcsxcmp("-r", argv[i])) + else if (0 == _tcsxicmp("-r", argv[i])) { st_ServiceConfig.st_XReload.bReload = true; st_ServiceConfig.st_XReload.byCode = _ttxoi(argv[++i]); } - else if (0 == _tcsxcmp("-db", argv[i])) + else if (0 == _tcsxicmp("-db", argv[i])) { st_ServiceConfig.st_XSql.bEnable = _ttxoi(argv[++i]); } - else if (0 == _tcsxcmp("-t", argv[i])) + else if (0 == _tcsxicmp("-t", argv[i])) { bIsTest = true; } From b321ba578dfff59d909896cf9588a03f487cf8e4 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 10:02:15 +0800 Subject: [PATCH 16/41] update:depend library --- XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData | 2 +- XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData b/XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData index a6449e7..4e6e5aa 160000 --- a/XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData +++ b/XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData @@ -1 +1 @@ -Subproject commit a6449e797a2ec10e9e4a3d40c1f9f27487f7dd02 +Subproject commit 4e6e5aabee8b8c42a6f148d8e50feb44fb6f7b5f diff --git a/XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData b/XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData index 2ffa9e3..ce3fd8d 160000 --- a/XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData +++ b/XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData @@ -1 +1 @@ -Subproject commit 2ffa9e3416784d44e07ef77304f4d8cda1570748 +Subproject commit ce3fd8d987f79c89dbbb707771765de95bfd90ea From c447c326ec829d6febcba54b5376c10184093586 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 10:02:42 +0800 Subject: [PATCH 17/41] fixed:build error --- XEngine_Release/copydb.bat | 2 +- XEngine_Release/copydb.sh | 2 +- XEngine_Source/Makefile | 2 +- XEngine_Source/XEngine.sln | 5 +---- XEngine_Source/XEngine_ModuleProtocol/pch.h | 2 +- .../XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h | 6 +++--- 6 files changed, 8 insertions(+), 11 deletions(-) diff --git a/XEngine_Release/copydb.bat b/XEngine_Release/copydb.bat index fb1a38d..ee46329 100644 --- a/XEngine_Release/copydb.bat +++ b/XEngine_Release/copydb.bat @@ -1,4 +1,4 @@ copy /y "..\XEngine_Source\XEngine_DependLibrary\XEngine_IPMacData\XEngine_DBFile\GeoLite2-ASN.mmdb" "./XEngine_DBFile" copy /y "..\XEngine_Source\XEngine_DependLibrary\XEngine_IPMacData\XEngine_DBFile\GeoLite2-City.mmdb" "./XEngine_DBFile" copy /y "..\XEngine_Source\XEngine_DependLibrary\XEngine_IPMacData\XEngine_DBFile\macaddr.xdb" "./XEngine_DBFile" -copy /y "..\XEngine_Source\XEngine_DependLibrary\XEngine_PhoneData\Data\phone_utf.dat" "./XEngine_DBFile/phone.xdb" \ No newline at end of file +copy /y "..\XEngine_Source\XEngine_DependLibrary\XEngine_PhoneData\XEngine_Release\phone_utf.dat" "./XEngine_DBFile/phone.xdb" \ No newline at end of file diff --git a/XEngine_Release/copydb.sh b/XEngine_Release/copydb.sh index 2e0b417..4d03b14 100644 --- a/XEngine_Release/copydb.sh +++ b/XEngine_Release/copydb.sh @@ -3,4 +3,4 @@ cp -f ../XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData/XEngine_DBFile/GeoLite2-ASN.mmdb ./XEngine_DBFile/ cp -f ../XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData/XEngine_DBFile/GeoLite2-City.mmdb ./XEngine_DBFile/ cp -f ../XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData/XEngine_DBFile/macaddr.xdb ./XEngine_DBFile/ -cp -f ../XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData/Data/phone_utf.dat ./XEngine_DBFile/phone.xdb \ No newline at end of file +cp -f ../XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData/XEngine_Release/phone_utf.dat ./XEngine_DBFile/phone.xdb \ No newline at end of file diff --git a/XEngine_Source/Makefile b/XEngine_Source/Makefile index 0b3328c..868b4af 100644 --- a/XEngine_Source/Makefile +++ b/XEngine_Source/Makefile @@ -20,7 +20,7 @@ PLUGIN_MODULE_METER = ./XEngine_PluginModule/ModulePlugin_Meter THIRDPART_MODULE_JSONCPP = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp THIRDPART_MODULE_REPORT = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport -APIMODULE_PHONE_PATH = ./XEngine_DependLibrary/XEngine_PhoneData/Source/C/XEngine_APIModulePhone +APIMODULE_PHONE_PATH = ./XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone APIMODULE_IPMAC_PATH = ./XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac APP_HTTP_PATH = ./XEngine_ServiceApp/XEngine_HttpApp diff --git a/XEngine_Source/XEngine.sln b/XEngine_Source/XEngine.sln index c2166ad..2557300 100644 --- a/XEngine_Source/XEngine.sln +++ b/XEngine_Source/XEngine.sln @@ -109,10 +109,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_APIModuleIPMac", "X {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} = {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_APIModulePhone", "XEngine_DependLibrary\XEngine_PhoneData\Source\C\XEngine_APIModulePhone\XEngine_APIModulePhone.vcxproj", "{A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A}" - ProjectSection(ProjectDependencies) = postProject - {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} = {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} - EndProjectSection +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_APIModulePhone", "XEngine_DependLibrary\XEngine_PhoneData\XEngine_Source\XEngine_APIModulePhone\XEngine_APIModulePhone.vcxproj", "{A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/XEngine_Source/XEngine_ModuleProtocol/pch.h b/XEngine_Source/XEngine_ModuleProtocol/pch.h index 4421c49..fc8543c 100644 --- a/XEngine_Source/XEngine_ModuleProtocol/pch.h +++ b/XEngine_Source/XEngine_ModuleProtocol/pch.h @@ -34,7 +34,7 @@ #include #include #include "../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XIPMac_CommHdr.h" -#include "../XEngine_DependLibrary/XEngine_PhoneData/Source/XPhone_CommHdr.h" +#include "../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XPhone_CommHdr.h" using namespace std; #include "../XEngine_UserProtocol.h" #include "ModuleProtocol_Define.h" diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h index 3ac72da..3420966 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h @@ -70,9 +70,9 @@ using namespace std; #include "../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XIPMac_CommHdr.h" #include "../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac/APIIPMac_Define.h" #include "../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac/APIIPMac_Error.h" -#include "../../XEngine_DependLibrary/XEngine_PhoneData/Source/XPhone_CommHdr.h" -#include "../../XEngine_DependLibrary/XEngine_PhoneData/Source/C/XEngine_APIModulePhone/APIPhone_Define.h" -#include "../../XEngine_DependLibrary/XEngine_PhoneData/Source/C/XEngine_APIModulePhone/APIPhone_Error.h" +#include "../../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XPhone_CommHdr.h" +#include "../../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone/APIPhone_Define.h" +#include "../../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone/APIPhone_Error.h" //加载项目相关头文件 #include "../../XEngine_BuildSwitch.h" #include "../../XEngine_UserProtocol.h" From 6754b9b0f2625903414ecb275eb051678ee63b1f Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 10:50:25 +0800 Subject: [PATCH 18/41] added:http basic and digest authorize support --- XEngine_Source/Makefile | 10 +- XEngine_Source/XEngine.sln | 32 +++-- .../ModuleConfig_Define.h | 3 + .../ModuleConfigure_Json.cpp | 6 +- .../XEngine_HttpApp/Makefile | 6 +- .../XEngine_HttpApp/XEngine_HTTPTask.cpp | 118 ++++++++++++++++-- .../XEngine_HttpApp/XEngine_HTTPTask.h | 2 +- .../XEngine_HttpApp/XEngine_Hdr.h | 8 ++ 8 files changed, 162 insertions(+), 23 deletions(-) diff --git a/XEngine_Source/Makefile b/XEngine_Source/Makefile index 868b4af..6d4025f 100644 --- a/XEngine_Source/Makefile +++ b/XEngine_Source/Makefile @@ -19,7 +19,7 @@ PLUGIN_MODULE_METER = ./XEngine_PluginModule/ModulePlugin_Meter THIRDPART_MODULE_JSONCPP = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp THIRDPART_MODULE_REPORT = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport - +THIRDPART_MODULE_VERIFICATION = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verfication APIMODULE_PHONE_PATH = ./XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone APIMODULE_IPMAC_PATH = ./XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac @@ -31,7 +31,7 @@ else ifeq ($(PLATFORM),mac) FILEEXT = dylib endif -XENGINE_MODULES = libjsoncpp.so libXEngine_InfoReport.so \ +XENGINE_MODULES = libjsoncpp.so libXEngine_InfoReport.so libXEngine_Verfication.so \ libXEngine_ModuleConfigure.so libXEngine_ModuleDatabase.so libXEngine_ModuleProtocol.so libXEngine_ModuleSystem.so libXEngine_ModuleHelp.so libXEngine_ModulePlugin.so \ libModulePlugin_Zodiac.so libModulePlugin_Password.so libModulePlugin_Timezone.so libModulePlugin_BMIndex.so libModulePlugin_Meter.so \ libXEngine_APIModulePhone.so libXEngine_APIModuleIPMac.so \ @@ -52,6 +52,12 @@ ifeq ($(FLAGS), InstallAll) else make -C $(THIRDPART_MODULE_REPORT) PLATFORM=$(PLATFORM) UNICODE=$(UNICODE) RELEASE=$(RELEASE) $(FLAGS) endif +libXEngine_Verfication.so: +ifeq ($(FLAGS), InstallAll) + cp $(THIRDPART_MODULE_VERIFICATION)/libXEngine_Verfication.$(FILEEXT) ../XEngine_Release/ +else + make -C $(THIRDPART_MODULE_VERIFICATION) PLATFORM=$(PLATFORM) UNICODE=$(UNICODE) RELEASE=$(RELEASE) $(FLAGS) +endif libXEngine_APIModulePhone.so: ifeq ($(FLAGS), InstallAll) cp $(APIMODULE_PHONE_PATH)/libXEngine_APIModulePhone.$(FILEEXT) ../XEngine_Release/ diff --git a/XEngine_Source/XEngine.sln b/XEngine_Source/XEngine.sln index 2557300..a4746dd 100644 --- a/XEngine_Source/XEngine.sln +++ b/XEngine_Source/XEngine.sln @@ -19,20 +19,21 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_HttpApp", "XEngine_ServiceApp\XEngine_HttpApp\XEngine_HttpApp.vcxproj", "{E756B7D2-D40D-4106-9C14-1D90F20A712E}" ProjectSection(ProjectDependencies) = postProject {140AD4A9-4918-4345-B352-507C345AEBE0} = {140AD4A9-4918-4345-B352-507C345AEBE0} - {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} = {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} - {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} = {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} {201B6D13-82A7-49E9-9736-D6B3BFE05B30} = {201B6D13-82A7-49E9-9736-D6B3BFE05B30} - {FFAC032D-4F8C-4C70-AF36-D79685A6961F} = {FFAC032D-4F8C-4C70-AF36-D79685A6961F} {32BB166A-3D3D-45EF-8BED-2E0471274159} = {32BB166A-3D3D-45EF-8BED-2E0471274159} {37B8E91F-EC52-41F0-B21D-441D4270C05F} = {37B8E91F-EC52-41F0-B21D-441D4270C05F} {6C935BE1-77E3-4719-A7A6-C76ABAFEE010} = {6C935BE1-77E3-4719-A7A6-C76ABAFEE010} {6D0FCB40-D544-4AB2-A239-2FEBC4B98F6D} = {6D0FCB40-D544-4AB2-A239-2FEBC4B98F6D} {6F111577-DAF8-4294-B516-0077C22D7613} = {6F111577-DAF8-4294-B516-0077C22D7613} - {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} = {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} {92F971AB-CAC9-4D9B-A9CA-AFD9CA17E505} = {92F971AB-CAC9-4D9B-A9CA-AFD9CA17E505} + {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} = {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256} = {A8E43EC0-698A-4807-8A61-B2BE5FAB7256} {BBC4B2B4-1143-45DF-8890-47CE26A61D0E} = {BBC4B2B4-1143-45DF-8890-47CE26A61D0E} {CB443280-E283-44CD-B956-52C404A51DB6} = {CB443280-E283-44CD-B956-52C404A51DB6} + {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} = {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} {F54F152C-594F-4465-A44E-2DB915B39760} = {F54F152C-594F-4465-A44E-2DB915B39760} + {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} = {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} + {FFAC032D-4F8C-4C70-AF36-D79685A6961F} = {FFAC032D-4F8C-4C70-AF36-D79685A6961F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_ModuleDatabase", "XEngine_ModuleDatabase\XEngine_ModuleDatabase.vcxproj", "{140AD4A9-4918-4345-B352-507C345AEBE0}" @@ -78,21 +79,21 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_APIServiceApp", "XEngine_ServiceApp\XEngine_APIServiceApp\XEngine_APIServiceApp.vcxproj", "{096BEF37-4AF6-490D-868B-6306D3E251E7}" ProjectSection(ProjectDependencies) = postProject {140AD4A9-4918-4345-B352-507C345AEBE0} = {140AD4A9-4918-4345-B352-507C345AEBE0} - {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} = {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} - {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} = {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} {201B6D13-82A7-49E9-9736-D6B3BFE05B30} = {201B6D13-82A7-49E9-9736-D6B3BFE05B30} - {FFAC032D-4F8C-4C70-AF36-D79685A6961F} = {FFAC032D-4F8C-4C70-AF36-D79685A6961F} {32BB166A-3D3D-45EF-8BED-2E0471274159} = {32BB166A-3D3D-45EF-8BED-2E0471274159} {37B8E91F-EC52-41F0-B21D-441D4270C05F} = {37B8E91F-EC52-41F0-B21D-441D4270C05F} {6C935BE1-77E3-4719-A7A6-C76ABAFEE010} = {6C935BE1-77E3-4719-A7A6-C76ABAFEE010} {6D0FCB40-D544-4AB2-A239-2FEBC4B98F6D} = {6D0FCB40-D544-4AB2-A239-2FEBC4B98F6D} {6F111577-DAF8-4294-B516-0077C22D7613} = {6F111577-DAF8-4294-B516-0077C22D7613} - {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} = {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} {92F971AB-CAC9-4D9B-A9CA-AFD9CA17E505} = {92F971AB-CAC9-4D9B-A9CA-AFD9CA17E505} + {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} = {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} {BBC4B2B4-1143-45DF-8890-47CE26A61D0E} = {BBC4B2B4-1143-45DF-8890-47CE26A61D0E} {CB443280-E283-44CD-B956-52C404A51DB6} = {CB443280-E283-44CD-B956-52C404A51DB6} {E756B7D2-D40D-4106-9C14-1D90F20A712E} = {E756B7D2-D40D-4106-9C14-1D90F20A712E} + {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} = {F1736B3F-03A2-4FC7-B045-A12BA8D724FB} {F54F152C-594F-4465-A44E-2DB915B39760} = {F54F152C-594F-4465-A44E-2DB915B39760} + {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} = {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} + {FFAC032D-4F8C-4C70-AF36-D79685A6961F} = {FFAC032D-4F8C-4C70-AF36-D79685A6961F} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XEngine_DependLibrary", "XEngine_DependLibrary", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" @@ -111,6 +112,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_APIModuleIPMac", "X EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_APIModulePhone", "XEngine_DependLibrary\XEngine_PhoneData\XEngine_Source\XEngine_APIModulePhone\XEngine_APIModulePhone.vcxproj", "{A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XEngine_Verification", "XEngine_DependLibrary\XEngine_OPenSource\XEngine_Module\XEngine_Verification\XEngine_Verification.vcxproj", "{A8E43EC0-698A-4807-8A61-B2BE5FAB7256}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -325,6 +328,18 @@ Global {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A}.Release|x64.Build.0 = Release|x64 {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A}.Release|x86.ActiveCfg = Release|Win32 {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A}.Release|x86.Build.0 = Release|Win32 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Debug|ARM64.Build.0 = Debug|ARM64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Debug|x64.ActiveCfg = Debug|x64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Debug|x64.Build.0 = Debug|x64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Debug|x86.ActiveCfg = Debug|Win32 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Debug|x86.Build.0 = Debug|Win32 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Release|ARM64.ActiveCfg = Release|ARM64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Release|ARM64.Build.0 = Release|ARM64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Release|x64.ActiveCfg = Release|x64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Release|x64.Build.0 = Release|x64 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Release|x86.ActiveCfg = Release|Win32 + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -341,6 +356,7 @@ Global {F6520D2C-BB8E-45BB-964B-F5D6A4318A89} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {FFAC032D-4F8C-4C70-AF36-D79685A6961F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {A13B72E7-FC40-4A27-81C3-26DF3C8F4C0A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {A8E43EC0-698A-4807-8A61-B2BE5FAB7256} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9B202F91-A601-429E-BB0F-880DDEE096FE} diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h index 684f5dd..124e075 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfig_Define.h @@ -106,6 +106,9 @@ typedef struct { XCHAR tszUserName[XPATH_MAX]; XCHAR tszUserPass[XPATH_MAX]; + XCHAR tszAPIAuth[XPATH_MAX]; + int nVType; + bool bEnable; struct { bool bBackService; diff --git a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp index c35f8f8..8f7d0fb 100644 --- a/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp +++ b/XEngine_Source/XEngine_ModuleConfigure/ModuleConfigure_Json/ModuleConfigure_Json.cpp @@ -197,13 +197,17 @@ bool CModuleConfigure_Json::ModuleConfigure_Json_File(LPCXSTR lpszConfigFile, XE _tcsxcpy(pSt_ServerConfig->st_XImageText.tszImagePath, st_JsonXImageText["tszImagePath"].asCString()); _tcsxcpy(pSt_ServerConfig->st_XImageText.tszImageLanguage, st_JsonXImageText["tszImageLanguage"].asCString()); - if (st_JsonRoot["XVerification"].empty() || (3 != st_JsonRoot["XVerification"].size())) + if (st_JsonRoot["XVerification"].empty() || (6 != st_JsonRoot["XVerification"].size())) { Config_IsErrorOccur = true; Config_dwErrorCode = ERROR_MODULE_CONFIGURE_JSON_XVERICATION; return false; } Json::Value st_JsonXVerifcation = st_JsonRoot["XVerification"]; + + pSt_ServerConfig->st_XVerifcation.bEnable = st_JsonXVerifcation["bEnable"].asBool(); + pSt_ServerConfig->st_XVerifcation.nVType = st_JsonXVerifcation["nVType"].asInt(); + _tcsxcpy(pSt_ServerConfig->st_XVerifcation.tszAPIAuth, st_JsonXVerifcation["tszAPIAuth"].asCString()); _tcsxcpy(pSt_ServerConfig->st_XVerifcation.tszUserName, st_JsonXVerifcation["tszUserName"].asCString()); _tcsxcpy(pSt_ServerConfig->st_XVerifcation.tszUserPass, st_JsonXVerifcation["tszUserPass"].asCString()); diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile index ca8a4f6..9d23a6d 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile @@ -4,11 +4,11 @@ FILEEXT = LIBFLAG = LOADHDR = -I ./ LOADSO = -L ../../XEngine_ModuleConfigure -L ../../XEngine_ModuleDatabase -L ../../XEngine_ModuleProtocol -L ../../XEngine_ModuleSystem -L ../../XEngine_ModuleHelp -L ../../XEngine_ModulePlugin \ - -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport \ - -L ../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac -L ../../XEngine_DependLibrary/XEngine_PhoneData/Source/C/XEngine_APIModulePhone + -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verfication \ + -L ../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac -L ../../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lXClient_Socket -lNetHelp_APIAddr -lNetHelp_XSocket -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ -lXEngine_ModuleConfigure -lXEngine_ModuleDatabase -lXEngine_ModuleProtocol -lXEngine_ModuleSystem -lXEngine_ModuleHelp -lXEngine_ModulePlugin \ - -ljsoncpp -lXEngine_InfoReport \ + -ljsoncpp -lXEngine_InfoReport -lXEngine_Verfication \ -lXEngine_APIModuleIPMac -lXEngine_APIModulePhone LIBEX = OBJECTS = XEngine_Configure.o XEngine_Network.o XEngine_HTTPTask.o XEngine_PluginTask.o XEngine_HttpApp.o \ diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp index e01cfc2..2abe449 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp @@ -44,7 +44,7 @@ XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam) if (HttpProtocol_Server_GetMemoryEx(xhHTTPPacket, ppSst_ListAddr[i]->tszClientAddr, &ptszMsgBuffer, &nMsgLen, &st_HTTPReqparam, &pptszListHdr, &nHDRCount)) { //在另外一个函数里面处理数据 - HTTPTask_TastPost_Handle(&st_HTTPReqparam, ppSst_ListAddr[i]->tszClientAddr, ptszMsgBuffer, nMsgLen, &pptszListHdr, nHDRCount); + HTTPTask_TastPost_Handle(&st_HTTPReqparam, ppSst_ListAddr[i]->tszClientAddr, ptszMsgBuffer, nMsgLen, pptszListHdr, nHDRCount); //释放内存 BaseLib_Memory_FreeCStyle((XPPMEM)&ptszMsgBuffer); BaseLib_Memory_Free((XPPPMEM)&pptszListHdr, nHDRCount); @@ -55,16 +55,13 @@ XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam) } return 0; } -bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszRVBuffer, int nRVLen, XCHAR*** ppptszHDRList, int nHDRCount) +bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszRVBuffer, int nRVLen, XCHAR** pptszHDRList, int nHDRCount) { int nMsgLen = 4096; LPCXSTR lpszMethodPost = _X("POST"); LPCXSTR lpszMethodGet = _X("GET"); - XCHAR tszMsgBuffer[4096]; - RFCCOMPONENTS_HTTP_HDRPARAM st_HDRParam; //发送给客户端的参数 - - memset(tszMsgBuffer, '\0', sizeof(tszMsgBuffer)); - memset(&st_HDRParam, '\0', sizeof(RFCCOMPONENTS_HTTP_HDRPARAM)); + XCHAR tszMsgBuffer[4096] = {}; + RFCCOMPONENTS_HTTP_HDRPARAM st_HDRParam = {}; st_HDRParam.nHttpCode = 200; //HTTP CODE码 st_HDRParam.bIsClose = true; //收到回复后就关闭 @@ -89,7 +86,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST if (nListCount < 1) { //是不是代理转发 - if (HTTPTask_TaskPost_SLProxy(lpszClientAddr, tszGBKBuffer, ppptszHDRList, nHDRCount)) + if (HTTPTask_TaskPost_SLProxy(lpszClientAddr, tszGBKBuffer, &pptszHDRList, nHDRCount)) { return true; } @@ -100,6 +97,111 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); return false; } + //http验证 + if (st_ServiceConfig.st_XVerifcation.bEnable) + { + int nVType = 0; + RFCCOMPONENTS_HTTP_HDRPARAM st_HDRParam = {}; + + st_HDRParam.nHttpCode = 401; + st_HDRParam.bIsClose = true; + st_HDRParam.bAuth = true; + //打包验证信息 + int nHDRLen = 0; + XCHAR tszHDRBuffer[XPATH_MAX] = {}; + if (1 == st_ServiceConfig.st_XVerifcation.nVType) + { + Verification_HTTP_BasicServerPacket(tszHDRBuffer, &nHDRLen); + } + else + { + XCHAR tszNonceStr[64] = {}; + XCHAR tszOpaqueStr[64] = {}; + Verification_HTTP_DigestServerPacket(tszHDRBuffer, &nHDRLen, tszNonceStr, tszOpaqueStr); + } + //后去验证方法 + if (!Verification_HTTP_GetType(pptszHDRList, nHDRCount, &nVType)) + { + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,验证方式:%d,错误:%lX"), lpszClientAddr, st_ServiceConfig.st_XVerifcation.nVType, Verification_GetLastError()); + return false; + } + //验证方式是否一致 + if (st_ServiceConfig.st_XVerifcation.nVType != nVType) + { + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,验证方式错误,请求:%d,需求:%d"), lpszClientAddr, nVType, st_ServiceConfig.st_XVerifcation.nVType); + return false; + } + bool bRet = false; + + if (_tcsxlen(st_ServiceConfig.st_XVerifcation.tszAPIAuth) > 0) + { + int nHTTPCode = 0; + int nMSGLen = 0; + XCLIENT_APIHTTP st_APIHttp = {}; + XCHAR* ptszMSGBuffer = NULL; + if (!APIClient_Http_Request(_X("GET"), st_ServiceConfig.st_XVerifcation.tszAPIAuth, NULL, &nHTTPCode, &ptszMSGBuffer, &nMSGLen, NULL, NULL, &st_APIHttp)) + { + st_HDRParam.nHttpCode = 500; + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,GET请求验证服务:%s 失败,错误码:%lX"), lpszClientAddr, st_ServiceConfig.st_XVerifcation.tszAPIAuth, APIClient_GetLastError()); + return false; + } + if (200 != nHTTPCode) + { + st_HDRParam.nHttpCode = 500; + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,GET请求验证服务:%s 失败,错误:%d"), lpszClientAddr, st_ServiceConfig.st_XVerifcation.tszAPIAuth, nHTTPCode); + return false; + } + XENGINE_PROTOCOL_USERAUTH st_UserAuth = {}; + if (!ModuleProtocol_Parse_Verifcation(ptszMSGBuffer, nMsgLen, st_UserAuth.tszUserName, st_UserAuth.tszUserPass)) + { + st_HDRParam.nHttpCode = 500; + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,返回内容:%s 错误,无法继续"), lpszClientAddr, ptszMSGBuffer); + BaseLib_Memory_FreeCStyle((XPPMEM)&ptszMSGBuffer); + return false; + } + BaseLib_Memory_FreeCStyle((XPPMEM)&ptszMSGBuffer); + + if (1 == nVType) + { + bRet = Verification_HTTP_Basic(st_UserAuth.tszUserName, st_UserAuth.tszUserPass, pptszHDRList, nHDRCount); + } + else if (2 == nVType) + { + bRet = Verification_HTTP_Digest(st_UserAuth.tszUserName, st_UserAuth.tszUserPass, pSt_HTTPParam->tszHttpMethod, pptszHDRList, nHDRCount); + } + } + else + { + if (1 == nVType) + { + bRet = Verification_HTTP_Basic(st_ServiceConfig.st_XVerifcation.tszUserName, st_ServiceConfig.st_XVerifcation.tszUserPass, pptszHDRList, nHDRCount); + } + else if (2 == nVType) + { + bRet = Verification_HTTP_Digest(st_ServiceConfig.st_XVerifcation.tszUserName, st_ServiceConfig.st_XVerifcation.tszUserPass, pSt_HTTPParam->tszHttpMethod, pptszHDRList, nHDRCount); + } + } + + if (!bRet) + { + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,验证处理错误,可能用户密码登信息不匹配,类型:%d"), lpszClientAddr, nVType); + return false; + } + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("HTTP客户端:%s,HTTP验证类型:%d 通过"), lpszClientAddr, nVType); + } + XCHAR tszKey[XPATH_MAX]; XCHAR tszValue[XPATH_MAX]; LPCXSTR lpszFuncName = _X("api"); diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h index b03864e..98f6188 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h @@ -13,4 +13,4 @@ //任务处理池,用来获取一个完整包 XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam); //任务处理相关函数,处理包的内容 -bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszRVBuffer, int nRVLen, XCHAR*** ppptszHDRList, int nHDRCount); \ No newline at end of file +bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszRVBuffer, int nRVLen, XCHAR** pptszHDRList, int nHDRCount); \ No newline at end of file diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h index 3420966..6c0c5e0 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h @@ -67,6 +67,8 @@ using namespace std; #include #include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport/InfoReport_Define.h" #include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport/InfoReport_Error.h" +#include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verification/Verification_Define.h" +#include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verification/Verification_Error.h" #include "../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XIPMac_CommHdr.h" #include "../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac/APIIPMac_Define.h" #include "../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac/APIIPMac_Error.h" @@ -178,6 +180,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #ifdef _DEBUG #ifdef _M_X64 #pragma comment(lib,"../../x64/Debug/XEngine_InfoReport.lib") +#pragma comment(lib,"../../x64/Debug/XEngine_Verification.lib") #pragma comment(lib,"../../x64/Debug/XEngine_APIModuleIPMac.lib") #pragma comment(lib,"../../x64/Debug/XEngine_APIModulePhone.lib") #pragma comment(lib,"../../x64/Debug/XEngine_ModuleConfigure.lib") @@ -188,6 +191,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"../../x64/Debug/XEngine_ModulePlugin.lib") #elif _M_ARM64 #pragma comment(lib,"../../ARM64/Debug/XEngine_InfoReport.lib") +#pragma comment(lib,"../../ARM64/Debug/XEngine_Verification.lib") #pragma comment(lib,"../../ARM64/Debug/XEngine_APIModuleIPMac.lib") #pragma comment(lib,"../../ARM64/Debug/XEngine_APIModulePhone.lib") #pragma comment(lib,"../../ARM64/Debug/XEngine_ModuleConfigure.lib") @@ -198,6 +202,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"../../ARM64/Debug/XEngine_ModulePlugin.lib") #elif _M_IX86 #pragma comment(lib,"../../Debug/XEngine_InfoReport.lib") +#pragma comment(lib,"../../Debug/XEngine_Verification.lib") #pragma comment(lib,"../../Debug/XEngine_APIModuleIPMac.lib") #pragma comment(lib,"../../Debug/XEngine_APIModulePhone.lib") #pragma comment(lib,"../../Debug/XEngine_ModuleConfigure.lib") @@ -210,6 +215,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #else #ifdef _M_X64 #pragma comment(lib,"../../x64/Release/XEngine_InfoReport.lib") +#pragma comment(lib,"../../x64/Release/XEngine_Verification.lib") #pragma comment(lib,"../../x64/Release/XEngine_APIModuleIPMac.lib") #pragma comment(lib,"../../x64/Release/XEngine_APIModulePhone.lib") #pragma comment(lib,"../../x64/Release/XEngine_ModuleConfigure.lib") @@ -220,6 +226,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"../../x64/Release/XEngine_ModulePlugin.lib") #elif _M_ARM64 #pragma comment(lib,"../../ARM64/Release/XEngine_InfoReport.lib") +#pragma comment(lib,"../../ARM64/Release/XEngine_Verification.lib") #pragma comment(lib,"../../ARM64/Release/XEngine_APIModuleIPMac.lib") #pragma comment(lib,"../../ARM64/Release/XEngine_APIModulePhone.lib") #pragma comment(lib,"../../ARM64/Release/XEngine_ModuleConfigure.lib") @@ -230,6 +237,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"../../ARM64/Release/XEngine_ModulePlugin.lib") #elif _M_IX86 #pragma comment(lib,"../../Release/XEngine_InfoReport.lib") +#pragma comment(lib,"../../Release/XEngine_Verification.lib") #pragma comment(lib,"../../Release/XEngine_APIModuleIPMac.lib") #pragma comment(lib,"../../Release/XEngine_APIModulePhone.lib") #pragma comment(lib,"../../Release/XEngine_ModuleConfigure.lib") From b21af6208dab9d3c4ac88fae82d99ed5ad670805 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 11:04:28 +0800 Subject: [PATCH 19/41] modify:deamon and back verification method --- .../XEngine_Config/XEngine_Config.json | 5 +- .../XEngine_HttpApp/XEngine_HTTPTask.cpp | 116 ++++++++++-------- .../XEngine_HttpApp/XEngine_HTTPTask.h | 2 +- .../XEngine_TaskPost/TaskPost_BackService.cpp | 28 ----- .../XEngine_TaskPost/TaskPost_Deamon.cpp | 27 ---- 5 files changed, 73 insertions(+), 105 deletions(-) diff --git a/XEngine_Release/XEngine_Config/XEngine_Config.json b/XEngine_Release/XEngine_Config/XEngine_Config.json index a97ad30..f390a05 100644 --- a/XEngine_Release/XEngine_Config/XEngine_Config.json +++ b/XEngine_Release/XEngine_Config/XEngine_Config.json @@ -5,7 +5,7 @@ "nHttpPort": 5501, "nRFCPort": 5502, "nNTPPort": 0, - "nDNSPort": 0, + "nDNSPort": 53, "XMax": { "nMaxClient": 10000, "nMaxQueue": 10000, @@ -65,6 +65,9 @@ "XVerification": { "tszUserName": "xyry", "tszUserPass": "11", + "tszAPIAuth": "", + "nVType": 1, + "bEnable": false, "st_VerSwitch": { "bBackService": false, "bDeamon": false diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp index 2abe449..96b0d8b 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.cpp @@ -33,7 +33,7 @@ XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam) //再循环客户端拥有的任务个数 for (int j = 0; j < ppSst_ListAddr[i]->nPktCount; j++) { - int nMsgLen = 0; //客户端发送的数据大小,不包括头 + int nSDLen = 0; //客户端发送的数据大小,不包括头 int nHDRCount = 0; XCHAR* ptszMsgBuffer = NULL; //客户端发送的数据 XCHAR** pptszListHdr; @@ -41,10 +41,10 @@ XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam) memset(&st_HTTPReqparam, '\0', sizeof(RFCCOMPONENTS_HTTP_REQPARAM)); //得到一个指定客户端的完整数据包 - if (HttpProtocol_Server_GetMemoryEx(xhHTTPPacket, ppSst_ListAddr[i]->tszClientAddr, &ptszMsgBuffer, &nMsgLen, &st_HTTPReqparam, &pptszListHdr, &nHDRCount)) + if (HttpProtocol_Server_GetMemoryEx(xhHTTPPacket, ppSst_ListAddr[i]->tszClientAddr, &ptszMsgBuffer, &nSDLen, &st_HTTPReqparam, &pptszListHdr, &nHDRCount)) { //在另外一个函数里面处理数据 - HTTPTask_TastPost_Handle(&st_HTTPReqparam, ppSst_ListAddr[i]->tszClientAddr, ptszMsgBuffer, nMsgLen, pptszListHdr, nHDRCount); + HTTPTask_TastPost_Handle(&st_HTTPReqparam, ppSst_ListAddr[i]->tszClientAddr, ptszMsgBuffer, nSDLen, pptszListHdr, nHDRCount); //释放内存 BaseLib_Memory_FreeCStyle((XPPMEM)&ptszMsgBuffer); BaseLib_Memory_Free((XPPPMEM)&pptszListHdr, nHDRCount); @@ -55,12 +55,15 @@ XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam) } return 0; } -bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszRVBuffer, int nRVLen, XCHAR** pptszHDRList, int nHDRCount) +bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLen, XCHAR** pptszHDRList, int nHDRCount) { - int nMsgLen = 4096; + bool bVerification = false; + int nSDLen = 4096; + int nRVLen = 4096; LPCXSTR lpszMethodPost = _X("POST"); LPCXSTR lpszMethodGet = _X("GET"); - XCHAR tszMsgBuffer[4096] = {}; + XCHAR tszSDBuffer[4096] = {}; + XCHAR tszRVBuffer[4096] = {}; RFCCOMPONENTS_HTTP_HDRPARAM st_HDRParam = {}; st_HDRParam.nHttpCode = 200; //HTTP CODE码 @@ -91,8 +94,8 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST return true; } st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); return false; @@ -122,16 +125,16 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST //后去验证方法 if (!Verification_HTTP_GetType(pptszHDRList, nHDRCount, &nVType)) { - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,验证方式:%d,错误:%lX"), lpszClientAddr, st_ServiceConfig.st_XVerifcation.nVType, Verification_GetLastError()); return false; } //验证方式是否一致 if (st_ServiceConfig.st_XVerifcation.nVType != nVType) { - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,验证方式错误,请求:%d,需求:%d"), lpszClientAddr, nVType, st_ServiceConfig.st_XVerifcation.nVType); return false; } @@ -146,25 +149,25 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST if (!APIClient_Http_Request(_X("GET"), st_ServiceConfig.st_XVerifcation.tszAPIAuth, NULL, &nHTTPCode, &ptszMSGBuffer, &nMSGLen, NULL, NULL, &st_APIHttp)) { st_HDRParam.nHttpCode = 500; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,GET请求验证服务:%s 失败,错误码:%lX"), lpszClientAddr, st_ServiceConfig.st_XVerifcation.tszAPIAuth, APIClient_GetLastError()); return false; } if (200 != nHTTPCode) { st_HDRParam.nHttpCode = 500; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,GET请求验证服务:%s 失败,错误:%d"), lpszClientAddr, st_ServiceConfig.st_XVerifcation.tszAPIAuth, nHTTPCode); return false; } XENGINE_PROTOCOL_USERAUTH st_UserAuth = {}; - if (!ModuleProtocol_Parse_Verifcation(ptszMSGBuffer, nMsgLen, st_UserAuth.tszUserName, st_UserAuth.tszUserPass)) + if (!ModuleProtocol_Parse_Verifcation(ptszMSGBuffer, nSDLen, st_UserAuth.tszUserName, st_UserAuth.tszUserPass)) { st_HDRParam.nHttpCode = 500; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,返回内容:%s 错误,无法继续"), lpszClientAddr, ptszMSGBuffer); BaseLib_Memory_FreeCStyle((XPPMEM)&ptszMSGBuffer); return false; @@ -194,11 +197,12 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST if (!bRet) { - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam, NULL, 0, tszHDRBuffer); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, NULL, 0, tszHDRBuffer); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,用户验证失败,验证处理错误,可能用户密码登信息不匹配,类型:%d"), lpszClientAddr, nVType); return false; } + bVerification = true; XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("HTTP客户端:%s,HTTP验证类型:%d 通过"), lpszClientAddr, nVType); } @@ -238,8 +242,8 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST if (0 != _tcsxnicmp(lpszFuncName, tszUrlName, _tcsxlen(lpszFuncName))) { st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); return false; @@ -249,8 +253,8 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST if (0 != _tcsxnicmp(lpszParamFuncKey, tszKey, _tcsxlen(lpszParamFuncKey))) { st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); BaseLib_Memory_Free((XPPPMEM)&pptszList, nListCount); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的URL请求参数不正确:%s"), lpszClientAddr, tszGBKBuffer); return false; @@ -259,7 +263,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST int nPluginType = 0; if (ModulePlugin_Loader_Find(tszValue, &nPluginType)) { - XEngine_PluginTask_Handle(tszValue, lpszClientAddr, lpszRVBuffer, nRVLen, &pptszList, nListCount, nPluginType); + XEngine_PluginTask_Handle(tszValue, lpszClientAddr, lpszMSGBuffer, nMSGLen, &pptszList, nListCount, nPluginType); return true; } if (0 == _tcsxnicmp(lpszMethodPost, pSt_HTTPParam->tszHttpMethod, _tcsxlen(lpszMethodPost))) @@ -270,7 +274,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - HTTPTask_TastPost_P2PClient(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); + HTTPTask_TastPost_P2PClient(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamZIPCode, tszValue, _tcsxlen(lpszParamZIPCode))) { @@ -278,7 +282,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - HTTPTask_TastPost_PostCode(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); + HTTPTask_TastPost_PostCode(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamXLog, tszValue, _tcsxlen(lpszParamXLog))) { @@ -286,7 +290,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - HTTPTask_TastPost_LogInfo(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); + HTTPTask_TastPost_LogInfo(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamQRCode, tszValue, _tcsxlen(lpszParamQRCode))) { @@ -294,7 +298,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - HTTPTask_TaskPost_QRCode(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); + HTTPTask_TaskPost_QRCode(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamSocket, tszValue, _tcsxlen(lpszParamSocket))) { @@ -302,7 +306,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - HTTPTask_TastPost_SocketTest(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); + HTTPTask_TastPost_SocketTest(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamDTest, tszValue, _tcsxlen(lpszParamDTest))) { @@ -310,7 +314,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszKey, '\0', sizeof(tszKey)); memset(tszValue, '\0', sizeof(tszValue)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszValue); - HTTPTask_TastPost_DTest(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszValue)); + HTTPTask_TastPost_DTest(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszValue)); } else if (0 == _tcsxnicmp(lpszParamShortLink, tszValue, _tcsxlen(lpszParamShortLink))) { @@ -319,7 +323,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszType, '\0', sizeof(tszType)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszType); - HTTPTask_TaskPost_ShortLink(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszType)); + HTTPTask_TaskPost_ShortLink(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszType)); } else if (0 == _tcsxnicmp(lpszParamWordFilter, tszValue, _tcsxlen(lpszParamWordFilter))) { @@ -328,7 +332,7 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszType, '\0', sizeof(tszType)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszType); - HTTPTask_TastPost_WordFilter(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszType)); + HTTPTask_TastPost_WordFilter(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszType)); } else if (0 == _tcsxnicmp(lpszParamBack, tszValue, _tcsxlen(lpszParamBack))) { @@ -336,18 +340,34 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST XCHAR tszType[64]; memset(tszType, '\0', sizeof(tszType)); + if (st_ServiceConfig.st_XVerifcation.st_VerSwitch.bBackService && !bVerification) + { + ModuleProtocol_Packet_Common(tszRVBuffer, &nSDLen, 403, _X("User verification required")); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, tszRVBuffer, nRVLen); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求后台协议失败,此模式需要进行验证,但是请求未验证"), lpszClientAddr); + return false; + } BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszType); - HTTPTask_TaskPost_BackService(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszType)); + HTTPTask_TaskPost_BackService(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszType)); } else if (0 == _tcsxnicmp(lpszParamImage, tszValue, _tcsxlen(lpszParamImage))) { //图像处理接口:http://app.xyry.org:5501/api?function=image¶ms1=0 - HTTPTask_TaskPost_Image(lpszClientAddr, lpszRVBuffer, nRVLen, &pptszList, nListCount); + HTTPTask_TaskPost_Image(lpszClientAddr, lpszMSGBuffer, nMSGLen, &pptszList, nListCount); } else if (0 == _tcsxnicmp(lpszParamDeamon, tszValue, _tcsxlen(lpszParamDeamon))) { //守护进程接口:http://app.xyry.org:5501/api?function=deamon¶ms1=0 - HTTPTask_TaskPost_Deamon(lpszClientAddr, lpszRVBuffer, nRVLen); + if (st_ServiceConfig.st_XVerifcation.st_VerSwitch.bDeamon && !bVerification) + { + ModuleProtocol_Packet_Common(tszRVBuffer, &nSDLen, 403, _X("User verification required")); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam, tszRVBuffer, nRVLen); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求守护进程协议失败,此模式需要进行验证,但是请求未验证"), lpszClientAddr); + return false; + } + HTTPTask_TaskPost_Deamon(lpszClientAddr, lpszMSGBuffer, nMSGLen); } else if (0 == _tcsxnicmp(lpszParamMachine, tszValue, _tcsxlen(lpszParamMachine))) { @@ -356,14 +376,14 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST memset(tszType, '\0', sizeof(tszType)); BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszType); - HTTPTask_TastPost_Machine(lpszClientAddr, lpszRVBuffer, nRVLen, _ttxoi(tszType)); + HTTPTask_TastPost_Machine(lpszClientAddr, lpszMSGBuffer, nMSGLen, _ttxoi(tszType)); } else { st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的请求不支持:%s,内容:\r\n%s"), lpszClientAddr, tszGBKBuffer, lpszRVBuffer); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的请求不支持:%s,内容:\r\n%s"), lpszClientAddr, tszGBKBuffer, lpszMSGBuffer); } } else if (0 == _tcsxnicmp(lpszMethodGet, pSt_HTTPParam->tszHttpMethod, _tcsxlen(lpszMethodGet))) @@ -482,26 +502,26 @@ bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXST //phone:http://127.0.0.1:5501/api?function=phone¶m=1369943 //ip:http://127.0.0.1:5501/api?function=ip¶m=117.172.221.14&language=en //mac:http://127.0.0.1:5501/api?function=mac¶m=00:00:0C - memset(tszMsgBuffer, '\0', sizeof(tszMsgBuffer)); + memset(tszSDBuffer, '\0', sizeof(tszSDBuffer)); - BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszMsgBuffer); + BaseLib_String_GetKeyValue(pptszList[1], "=", tszKey, tszSDBuffer); if (nListCount <= 2) { - HTTPTask_TaskGet_APIModule(lpszClientAddr, tszValue, tszMsgBuffer, NULL); + HTTPTask_TaskGet_APIModule(lpszClientAddr, tszValue, tszSDBuffer, NULL); } else { XCHAR tszTPStr[128] = {}; BaseLib_String_GetKeyValue(pptszList[2], "=", tszKey, tszTPStr); - HTTPTask_TaskGet_APIModule(lpszClientAddr, tszValue, tszMsgBuffer, tszTPStr); + HTTPTask_TaskGet_APIModule(lpszClientAddr, tszValue, tszSDBuffer, tszTPStr); } } else { st_HDRParam.nHttpCode = 404; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszMsgBuffer, &nMsgLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, tszMsgBuffer, nMsgLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的请求不支持:%s,内容:\r\n%s"), lpszClientAddr, tszGBKBuffer, lpszRVBuffer); + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, tszSDBuffer, &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, tszSDBuffer, nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,发送的请求不支持:%s,内容:\r\n%s"), lpszClientAddr, tszGBKBuffer, lpszMSGBuffer); } } else diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h index 98f6188..5ace63a 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HTTPTask.h @@ -13,4 +13,4 @@ //任务处理池,用来获取一个完整包 XHTHREAD XCALLBACK HTTPTask_TastPost_Thread(XPVOID lParam); //任务处理相关函数,处理包的内容 -bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszRVBuffer, int nRVLen, XCHAR** pptszHDRList, int nHDRCount); \ No newline at end of file +bool HTTPTask_TastPost_Handle(RFCCOMPONENTS_HTTP_REQPARAM* pSt_HTTPParam, LPCXSTR lpszClientAddr, LPCXSTR lpszMSGBuffer, int nMSGLen, XCHAR** pptszHDRList, int nHDRCount); \ No newline at end of file diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp index a673849..8ed4bbb 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp @@ -47,34 +47,6 @@ bool HTTPTask_TaskPost_BackService(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer st_HDRParam.nHttpCode = 200; //HTTP CODE码 st_HDRParam.bIsClose = true; //收到回复后就关闭 - - if (st_ServiceConfig.st_XVerifcation.st_VerSwitch.bBackService) - { - XCHAR tszUserName[XPATH_MAX]; - XCHAR tszUserPass[XPATH_MAX]; - - memset(tszUserName, '\0', sizeof(tszUserName)); - memset(tszUserPass, '\0', sizeof(tszUserPass)); - - ModuleProtocol_Parse_Verifcation(lpszMsgBuffer, nMsgLen, tszUserName, tszUserPass); - - if (0 != _tcsxnicmp(st_ServiceConfig.st_XVerifcation.tszUserName, tszUserName, _tcsxlen(st_ServiceConfig.st_XVerifcation.tszUserName))) - { - st_HDRParam.nHttpCode = 400; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求后台协议失败,用户验证失败,用户名错误,提供的用户名:%s"), lpszClientAddr, tszUserName); - return false; - } - if (0 != _tcsxnicmp(st_ServiceConfig.st_XVerifcation.tszUserPass, tszUserPass, _tcsxlen(st_ServiceConfig.st_XVerifcation.tszUserPass))) - { - st_HDRParam.nHttpCode = 400; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求后台协议失败,解析协议失败,错误码:%lX"), lpszClientAddr, tszUserPass); - return false; - } - } if (!ModuleProtocol_Parse_BackService(lpszMsgBuffer, nMsgLen, tszSrcBuffer, tszDstBuffer, tszAPIBuffer, &nBSType)) { st_HDRParam.nHttpCode = 400; diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_Deamon.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_Deamon.cpp index ec14838..fee31b0 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_Deamon.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_Deamon.cpp @@ -101,33 +101,6 @@ bool HTTPTask_TaskPost_Deamon(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer, int st_HDRParam.nHttpCode = 200; //HTTP CODE码 st_HDRParam.bIsClose = true; //收到回复后就关闭 - if (st_ServiceConfig.st_XVerifcation.st_VerSwitch.bDeamon) - { - XCHAR tszUserName[XPATH_MAX]; - XCHAR tszUserPass[XPATH_MAX]; - - memset(tszUserName, '\0', sizeof(tszUserName)); - memset(tszUserPass, '\0', sizeof(tszUserPass)); - - ModuleProtocol_Parse_Verifcation(lpszMsgBuffer, nMsgLen, tszUserName, tszUserPass); - if (0 != _tcsxnicmp(st_ServiceConfig.st_XVerifcation.tszUserName, tszUserName, _tcsxlen(st_ServiceConfig.st_XVerifcation.tszUserName))) - { - st_HDRParam.nHttpCode = 400; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求守护协议失败,用户验证失败,用户名错误,提供的用户名:%s"), lpszClientAddr, tszUserName); - return false; - } - if (0 != _tcsxnicmp(st_ServiceConfig.st_XVerifcation.tszUserPass, tszUserPass, _tcsxlen(st_ServiceConfig.st_XVerifcation.tszUserPass))) - { - st_HDRParam.nHttpCode = 400; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求守护协议失败,解析协议失败,错误码:%lX"), lpszClientAddr, tszUserPass); - return false; - } - } - if (!ModuleProtocol_Parse_Deamon(lpszMsgBuffer, nMsgLen, st_DeamonApp.tszAPPName, st_DeamonApp.tszAPPPath, &st_DeamonApp.nReTime, &st_DeamonApp.nReNumber, &st_DeamonApp.bEnable)) { st_HDRParam.nHttpCode = 400; From 9f42dde8d81004354729a97dc999f881c01b8779 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 11:09:43 +0800 Subject: [PATCH 20/41] fixed:build error --- XEngine_Source/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/XEngine_Source/Makefile b/XEngine_Source/Makefile index 6d4025f..57c3811 100644 --- a/XEngine_Source/Makefile +++ b/XEngine_Source/Makefile @@ -19,7 +19,7 @@ PLUGIN_MODULE_METER = ./XEngine_PluginModule/ModulePlugin_Meter THIRDPART_MODULE_JSONCPP = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp THIRDPART_MODULE_REPORT = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport -THIRDPART_MODULE_VERIFICATION = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verfication +THIRDPART_MODULE_VERIFICATION = ./XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verification APIMODULE_PHONE_PATH = ./XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone APIMODULE_IPMAC_PATH = ./XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac @@ -31,7 +31,7 @@ else ifeq ($(PLATFORM),mac) FILEEXT = dylib endif -XENGINE_MODULES = libjsoncpp.so libXEngine_InfoReport.so libXEngine_Verfication.so \ +XENGINE_MODULES = libjsoncpp.so libXEngine_InfoReport.so libXEngine_Verification.so \ libXEngine_ModuleConfigure.so libXEngine_ModuleDatabase.so libXEngine_ModuleProtocol.so libXEngine_ModuleSystem.so libXEngine_ModuleHelp.so libXEngine_ModulePlugin.so \ libModulePlugin_Zodiac.so libModulePlugin_Password.so libModulePlugin_Timezone.so libModulePlugin_BMIndex.so libModulePlugin_Meter.so \ libXEngine_APIModulePhone.so libXEngine_APIModuleIPMac.so \ @@ -52,9 +52,9 @@ ifeq ($(FLAGS), InstallAll) else make -C $(THIRDPART_MODULE_REPORT) PLATFORM=$(PLATFORM) UNICODE=$(UNICODE) RELEASE=$(RELEASE) $(FLAGS) endif -libXEngine_Verfication.so: +libXEngine_Verification.so: ifeq ($(FLAGS), InstallAll) - cp $(THIRDPART_MODULE_VERIFICATION)/libXEngine_Verfication.$(FILEEXT) ../XEngine_Release/ + cp $(THIRDPART_MODULE_VERIFICATION)/libXEngine_Verification.$(FILEEXT) ../XEngine_Release/ else make -C $(THIRDPART_MODULE_VERIFICATION) PLATFORM=$(PLATFORM) UNICODE=$(UNICODE) RELEASE=$(RELEASE) $(FLAGS) endif From a3c7eee5be7589a2781f8af6d5a23c0ee54a666c Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 11:28:10 +0800 Subject: [PATCH 21/41] fixed:build failure --- XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile index 9d23a6d..4a0a132 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile @@ -4,11 +4,11 @@ FILEEXT = LIBFLAG = LOADHDR = -I ./ LOADSO = -L ../../XEngine_ModuleConfigure -L ../../XEngine_ModuleDatabase -L ../../XEngine_ModuleProtocol -L ../../XEngine_ModuleSystem -L ../../XEngine_ModuleHelp -L ../../XEngine_ModulePlugin \ - -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verfication \ + -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verification \ -L ../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac -L ../../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lXClient_Socket -lNetHelp_APIAddr -lNetHelp_XSocket -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ -lXEngine_ModuleConfigure -lXEngine_ModuleDatabase -lXEngine_ModuleProtocol -lXEngine_ModuleSystem -lXEngine_ModuleHelp -lXEngine_ModulePlugin \ - -ljsoncpp -lXEngine_InfoReport -lXEngine_Verfication \ + -ljsoncpp -lXEngine_InfoReport -lXEngine_Verification \ -lXEngine_APIModuleIPMac -lXEngine_APIModulePhone LIBEX = OBJECTS = XEngine_Configure.o XEngine_Network.o XEngine_HTTPTask.o XEngine_PluginTask.o XEngine_HttpApp.o \ From fb459e7310c1b702d8e8c0d9bc09439b1778f710 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Tue, 26 Aug 2025 13:59:27 +0800 Subject: [PATCH 22/41] added:http verification start log --- XEngine_Release/XEngine_Config/XEngine_Config.json | 2 +- .../XEngine_HttpApp/XEngine_HttpApp.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/XEngine_Release/XEngine_Config/XEngine_Config.json b/XEngine_Release/XEngine_Config/XEngine_Config.json index f390a05..2c14e61 100644 --- a/XEngine_Release/XEngine_Config/XEngine_Config.json +++ b/XEngine_Release/XEngine_Config/XEngine_Config.json @@ -5,7 +5,7 @@ "nHttpPort": 5501, "nRFCPort": 5502, "nNTPPort": 0, - "nDNSPort": 53, + "nDNSPort": 0, "XMax": { "nMaxClient": 10000, "nMaxQueue": 10000, diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp index 4a2e29f..21a9dd7 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_HttpApp.cpp @@ -553,6 +553,15 @@ int main(int argc, char** argv) { XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_WARN, _X("启动服务中,数据查询服务没有启用")); } + + if (st_ServiceConfig.st_XVerifcation.bEnable) + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("启动服务中,启用HTTP验证,验证模式为:%d"), st_ServiceConfig.st_XVerifcation.nVType); + } + else + { + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_WARN, _X("启动服务中,数据查询服务没有启用")); + } #ifndef _DEBUG //发送信息报告 if (st_ServiceConfig.st_XReport.bEnable && !bIsTest) From 163d2d68dd8771941e18c9e8ea5d3e385d66fcc3 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 5 Sep 2025 14:21:01 +0800 Subject: [PATCH 23/41] ci:added Centos_build.yml and improved Rocky_build.yml --- .github/workflows/Centos_build.yml | 104 +++++++++++++++++++++++++++++ .github/workflows/Rocky_build.yml | 4 -- 2 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/Centos_build.yml diff --git a/.github/workflows/Centos_build.yml b/.github/workflows/Centos_build.yml new file mode 100644 index 0000000..0756a3f --- /dev/null +++ b/.github/workflows/Centos_build.yml @@ -0,0 +1,104 @@ +name: centos build workflows + +on: + push: + branches: + - 'develop' + paths: + - 'XEngine_Source/**' + - 'XEngine_Release/**' + - '.github/**' + +permissions: + contents: read + +jobs: + build: + runs-on: ${{ matrix.runner }} + container: + image: quay.io/centos/centos:${{ matrix.stream }} + options: --platform ${{ matrix.platform }} + strategy: + matrix: + include: + - arch: amd64 + runner: ubuntu-24.04 + platform: linux/amd64 + artifact: x86-64 + version: 9 + stream: stream9 + - arch: amd64 + runner: ubuntu-24.04 + platform: linux/amd64 + artifact: x86-64 + version: 10 + stream: stream10 + - arch: arm64 + runner: ubuntu-24.04-arm + platform: linux/arm64 + artifact: Arm64 + version: 9 + stream: stream9 + - arch: arm64 + runner: ubuntu-24.04-arm + platform: linux/arm64 + artifact: Arm64 + version: 10 + stream: stream10 + + steps: + - name: Checkout main repository code + uses: actions/checkout@v4 + + - name: Checkout dependency repository (xengine) + uses: actions/checkout@v4 + with: + repository: libxengine/libxengine + path: libxengine + + - name: sub module checkout (opensource) + uses: actions/checkout@v4 + with: + repository: libxengine/XEngine_OPenSource + path: XEngine_Source/XEngine_DependLibrary + + - name: install system package + run: | + dnf update -y + dnf install gcc g++ make git jq unzip wget -y + + - name: Set TERM variable + run: echo "TERM=xterm" >> $GITHUB_ENV + + - name: install xengine library + run: | + latest_tag=$(curl -s https://api.github.com/repos/libxengine/libxengine/releases/latest | jq -r .tag_name) + wget https://github.com/libxengine/libxengine/releases/download/$latest_tag/XEngine_RockyLinux_${{ matrix.version }}_${{ matrix.artifact }}.zip + unzip ./XEngine_RockyLinux_${{ matrix.version }}_${{ matrix.artifact }}.zip -d ./XEngine_RockyLinux_${{ matrix.version }}_${{ matrix.artifact }} + cd XEngine_RockyLinux_${{ matrix.version }}_${{ matrix.artifact }} + + chmod 777 * + ./XEngine_LINEnv.sh -i 3 + - name: make + run: | + cd XEngine_Source + make + make FLAGS=InstallAll + make FLAGS=CleanAll + + make RELEASE=1 + make FLAGS=InstallAll + make FLAGS=CleanAll + - name: test + run: | + cd XEngine_Release + chmod 777 copydb.sh + ./copydb.sh + ./XEngine_APIServiceApp -t + + - name: Upload folder as artifact with CentOS + uses: actions/upload-artifact@v4 + with: + name: XEngine_MQServiceApp-CentOS_${{ matrix.version }}_${{ matrix.artifact }} + path: XEngine_Release/ + retention-days: 1 \ No newline at end of file diff --git a/.github/workflows/Rocky_build.yml b/.github/workflows/Rocky_build.yml index c316b02..e0cc5ae 100644 --- a/.github/workflows/Rocky_build.yml +++ b/.github/workflows/Rocky_build.yml @@ -75,9 +75,6 @@ jobs: - name: install system package run: | - dnf clean all - dnf makecache - dnf distro-sync -y dnf update -y dnf install gcc g++ make git jq unzip wget -y @@ -90,7 +87,6 @@ jobs: chmod 777 * ./XEngine_LINEnv.sh -i 3 - dnf install libavdevice -y - name: install build package run: | dnf install lua-devel opencv-devel qrencode-devel leptonica-devel tesseract-devel -y From a6d83fc462555fa047b4b94b591332d24acf5886 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 5 Sep 2025 14:24:51 +0800 Subject: [PATCH 24/41] delete:not use return --- .../XEngine_ServiceApp/XEngine_HttpApp/XEngine_MemoryPool.h | 1 - 1 file changed, 1 deletion(-) diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_MemoryPool.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_MemoryPool.h index ab2f7b5..55f3799 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_MemoryPool.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_MemoryPool.h @@ -19,7 +19,6 @@ class CXEngine_MemoryPoolEx if (NULL == lPtr) { XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ALERT, _X("内存池分配失败,系统面临崩溃!")); - return; } } ~CXEngine_MemoryPoolEx() From 871f480a7cf91f6b4c945049c9a8c19369f182d0 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 5 Sep 2025 14:25:21 +0800 Subject: [PATCH 25/41] ci:fixed build --- .github/workflows/Centos_build.yml | 20 +++++++++++++++----- .github/workflows/release.yml | 9 +++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Centos_build.yml b/.github/workflows/Centos_build.yml index 0756a3f..1e2f9cf 100644 --- a/.github/workflows/Centos_build.yml +++ b/.github/workflows/Centos_build.yml @@ -56,20 +56,30 @@ jobs: repository: libxengine/libxengine path: libxengine - - name: sub module checkout (opensource) + - name: sub module checkout (XEngine_OPenSource) uses: actions/checkout@v4 with: repository: libxengine/XEngine_OPenSource - path: XEngine_Source/XEngine_DependLibrary + path: XEngine_Source/XEngine_DependLibrary/XEngine_OPenSource + - name: sub module checkout (XEngine_PhoneData) + uses: actions/checkout@v4 + with: + repository: libxengine/XEngine_PhoneData + path: XEngine_Source/XEngine_DependLibrary/XEngine_PhoneData + - name: sub module checkout (XEngine_IPMacData) + uses: actions/checkout@v4 + with: + repository: libxengine/XEngine_IPMacData + path: XEngine_Source/XEngine_DependLibrary/XEngine_IPMacData + - name: Set TERM variable + run: echo "TERM=xterm" >> $GITHUB_ENV + - name: install system package run: | dnf update -y dnf install gcc g++ make git jq unzip wget -y - - name: Set TERM variable - run: echo "TERM=xterm" >> $GITHUB_ENV - - name: install xengine library run: | latest_tag=$(curl -s https://api.github.com/repos/libxengine/libxengine/releases/latest | jq -r .tag_name) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6df2191..edc412a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,6 +52,15 @@ jobs: skip_unpack: true if_no_artifact_found: fail path: ./XRelease/ + - name: Download CentOS build + uses: dawidd6/action-download-artifact@v11 + with: + workflow: Centos_build.yml + workflow_conclusion: success + check_artifacts: false + skip_unpack: true + if_no_artifact_found: fail + path: ./XRelease/ - name: Download macbuild uses: dawidd6/action-download-artifact@v11 with: From e0d703452000cd19d1eae2fefa47bde7e83fc8a5 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 5 Sep 2025 15:06:51 +0800 Subject: [PATCH 26/41] modify:avformat instead xstream --- XEngine_Source/VSCopy_Arm64.bat | 1 - XEngine_Source/VSCopy_Debug.bat | 1 - XEngine_Source/VSCopy_x64.bat | 1 - XEngine_Source/VSCopy_x86.bat | 1 - .../XEngine_HttpApp/Makefile | 2 +- .../XEngine_HttpApp/XEngine_Hdr.h | 6 +- .../XEngine_TaskPost/TaskPost_BackService.cpp | 113 ++++++++---------- 7 files changed, 56 insertions(+), 69 deletions(-) diff --git a/XEngine_Source/VSCopy_Arm64.bat b/XEngine_Source/VSCopy_Arm64.bat index e6cbfc9..fc80a1d 100644 --- a/XEngine_Source/VSCopy_Arm64.bat +++ b/XEngine_Source/VSCopy_Arm64.bat @@ -6,7 +6,6 @@ copy /y "%XEngine_LibArm64%\XEngine_Core\XEngine_ManagePool.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_Core\XEngine_Cryption.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_Client\XClient_APIHelp.dll" "./" -copy /y "%XEngine_LibArm64%\XEngine_Client\XClient_Stream.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_Client\XClient_Socket.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_NetHelp\NetHelp_XSocket.dll" "./" diff --git a/XEngine_Source/VSCopy_Debug.bat b/XEngine_Source/VSCopy_Debug.bat index b4c22c6..f04881c 100644 --- a/XEngine_Source/VSCopy_Debug.bat +++ b/XEngine_Source/VSCopy_Debug.bat @@ -6,7 +6,6 @@ copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_ManagePool.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_Cryption.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XClient_APIHelp.dll" "./" -copy /y "D:\XEngine\XEngine_SourceCode\Debug\XClient_Stream.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XClient_Socket.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\NetHelp_XSocket.dll" "./" diff --git a/XEngine_Source/VSCopy_x64.bat b/XEngine_Source/VSCopy_x64.bat index 72a7b7c..17353f2 100644 --- a/XEngine_Source/VSCopy_x64.bat +++ b/XEngine_Source/VSCopy_x64.bat @@ -6,7 +6,6 @@ copy /y "%XEngine_Lib64%\XEngine_Core\XEngine_ManagePool.dll" "./" copy /y "%XEngine_Lib64%\XEngine_Core\XEngine_Cryption.dll" "./" copy /y "%XEngine_Lib64%\XEngine_Client\XClient_APIHelp.dll" "./" -copy /y "%XEngine_Lib64%\XEngine_Client\XClient_Stream.dll" "./" copy /y "%XEngine_Lib64%\XEngine_Client\XClient_Socket.dll" "./" copy /y "%XEngine_Lib64%\XEngine_NetHelp\NetHelp_XSocket.dll" "./" diff --git a/XEngine_Source/VSCopy_x86.bat b/XEngine_Source/VSCopy_x86.bat index 240db97..62dd8b9 100644 --- a/XEngine_Source/VSCopy_x86.bat +++ b/XEngine_Source/VSCopy_x86.bat @@ -6,7 +6,6 @@ copy /y "%XEngine_Lib32%\XEngine_Core\XEngine_ManagePool.dll" "./" copy /y "%XEngine_Lib32%\XEngine_Core\XEngine_Cryption.dll" "./" copy /y "%XEngine_Lib32%\XEngine_Client\XClient_APIHelp.dll" "./" -copy /y "%XEngine_Lib32%\XEngine_Client\XClient_Stream.dll" "./" copy /y "%XEngine_Lib32%\XEngine_Client\XClient_Socket.dll" "./" copy /y "%XEngine_Lib32%\XEngine_NetHelp\NetHelp_XSocket.dll" "./" diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile index 4a0a132..bea0458 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/Makefile @@ -6,7 +6,7 @@ LOADHDR = -I ./ LOADSO = -L ../../XEngine_ModuleConfigure -L ../../XEngine_ModuleDatabase -L ../../XEngine_ModuleProtocol -L ../../XEngine_ModuleSystem -L ../../XEngine_ModuleHelp -L ../../XEngine_ModulePlugin \ -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/jsoncpp -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport -L ../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verification \ -L ../../XEngine_DependLibrary/XEngine_IPMacData/XEngine_Source/XEngine_APIModuleIPMac -L ../../XEngine_DependLibrary/XEngine_PhoneData/XEngine_Source/XEngine_APIModulePhone -LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_Stream -lXClient_APIHelp -lXClient_Socket -lNetHelp_APIAddr -lNetHelp_XSocket -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect \ +LIB = -lXEngine_BaseSafe -lXEngine_BaseLib -lXEngine_Algorithm -lXEngine_Core -lXEngine_ManagePool -lXEngine_Cryption -lXClient_APIHelp -lXClient_Socket -lNetHelp_APIAddr -lNetHelp_XSocket -lHelpComponents_XLog -lRfcComponents_HttpProtocol -lRfcComponents_NatProtocol -lRfcComponents_NTPProtocol -lRfcComponents_DNSProtocol -lXEngine_ProcFile -lXEngine_SystemApi -lXEngine_AVHelp -lXEngine_VideoCodec -lXEngine_AudioCodec -lXEngine_AVCollect -lXEngine_AVFormat \ -lXEngine_ModuleConfigure -lXEngine_ModuleDatabase -lXEngine_ModuleProtocol -lXEngine_ModuleSystem -lXEngine_ModuleHelp -lXEngine_ModulePlugin \ -ljsoncpp -lXEngine_InfoReport -lXEngine_Verification \ -lXEngine_APIModuleIPMac -lXEngine_APIModulePhone diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h index 6c0c5e0..378b9ce 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_Hdr.h @@ -39,8 +39,6 @@ using namespace std; #include #include #include -#include -#include #include #include #include @@ -65,6 +63,8 @@ using namespace std; #include #include #include +#include +#include #include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport/InfoReport_Define.h" #include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_InfoReport/InfoReport_Error.h" #include "../../XEngine_DependLibrary/XEngine_OPenSource/XEngine_Module/XEngine_Verification/Verification_Define.h" @@ -162,7 +162,6 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"XEngine_Core/XEngine_ManagePool.lib") #pragma comment(lib,"XEngine_Core/XEngine_Cryption.lib") #pragma comment(lib,"XEngine_Client/XClient_Socket.lib") -#pragma comment(lib,"XEngine_Client/XClient_Stream.lib") #pragma comment(lib,"XEngine_Client/XClient_APIHelp.lib") #pragma comment(lib,"XEngine_NetHelp/NetHelp_APIAddr") #pragma comment(lib,"XEngine_HelpComponents/HelpComponents_XLog.lib") @@ -175,6 +174,7 @@ extern XENGINE_DEAMONAPPLIST st_DeamonAppConfig; #pragma comment(lib,"XEngine_AVCodec/XEngine_VideoCodec.lib") #pragma comment(lib,"XEngine_AVCodec/XEngine_AudioCodec.lib") #pragma comment(lib,"XEngine_AVCodec/XEngine_AVHelp.lib") +#pragma comment(lib,"XEngine_AVCodec/XEngine_AVFormat.lib") #pragma comment(lib,"Ws2_32.lib") #pragma comment(lib,"Dbghelp.lib") #ifdef _DEBUG diff --git a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp index 8ed4bbb..1e80206 100644 --- a/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp +++ b/XEngine_Source/XEngine_ServiceApp/XEngine_HttpApp/XEngine_TaskPost/TaskPost_BackService.cpp @@ -3,15 +3,11 @@ static bool bRecord = false; static XHANDLE xhSound = NULL; static XHANDLE xhScreen = NULL; -static XHANDLE xhStream = NULL; +static XHANDLE xhPacket = NULL; static XHANDLE xhAudioFifo = NULL; void XCALLBACK HTTPTask_TaskPost_CBVideo(uint8_t* ptszAVBuffer, int nAVLen, AVCOLLECT_TIMEINFO* pSt_TimeInfo, XPVOID lParam) { - if (!XClient_StreamPush_LiveVideo(xhStream, ptszAVBuffer, nAVLen)) - { - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("屏幕采集器,推流编码失败,需要关闭推流服务,错误码:%lX"), StreamClient_GetLastError()); - } } void XCALLBACK HTTPTask_TaskPost_CBAudio(uint8_t* ptszAVBuffer, int nAVLen, AVCOLLECT_TIMEINFO* pSt_TimeInfo, XPVOID lParam) { @@ -24,10 +20,6 @@ void XCALLBACK HTTPTask_TaskPost_CBAudio(uint8_t* ptszAVBuffer, int nAVLen, AVCO { break; } - if (!XClient_StreamPush_LiveAudio(xhStream, tszAVBuffer, nAVLen)) - { - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("音频采集器,推流编码失败,需要关闭推流服务,错误码:%lX"), StreamClient_GetLastError()); - } } } } @@ -298,8 +290,45 @@ bool HTTPTask_TaskPost_BackService(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求屏幕录制失败,因为已经在录制中了"), lpszClientAddr); return false; } - XENGINE_PROTOCOL_AVINFO st_AVInfo; - memset(&st_AVInfo, '\0', sizeof(XENGINE_PROTOCOL_AVINFO)); + AVCODEC_TIMEBASE st_VideoTime = {}; + AVCODEC_TIMEBASE st_AudioTime = {}; + xhPacket = AVFormat_Packet_Init(); + if (!AVFormat_Packet_Output(xhPacket, tszAPIBuffer, _X("flv"))) + { + st_HDRParam.nHttpCode = 400; + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,请求屏幕录制失败,推流服务端:%s 连接失败,错误码:%lX"), lpszClientAddr, tszAPIBuffer, AVFormat_GetLastError()); + return false; + } + //屏幕采集 + AVCOLLECT_SCREENINFO st_AVScreen; + memset(&st_AVScreen, '\0', sizeof(AVCOLLECT_SCREENINFO)); + + st_AVScreen.nFrameRate = 24; + st_AVScreen.nPosX = 0; + st_AVScreen.nPosY = 0; + _xstprintf(st_AVScreen.tszVideoSize, _X("%s"), _X("1920x1080")); +#ifdef _MSC_BUILD + xhScreen = AVCollect_Video_Init("gdigrab", tszDstBuffer, &st_AVScreen, HTTPTask_TaskPost_CBVideo); +#elif __linux__ + xhScreen = AVCollect_Video_Init("x11grab", tszDstBuffer, &st_AVScreen, HTTPTask_TaskPost_CBVideo); +#else + xhScreen = AVCollect_Video_Init("avfoundation", tszDstBuffer, &st_AVScreen, HTTPTask_TaskPost_CBVideo); +#endif + if (NULL == xhScreen) + { + st_HDRParam.nHttpCode = 400; + HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); + XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); + XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,屏幕采集器请求失败,错误码:%lX"), lpszClientAddr, AVCollect_GetLastError()); + return false; + } + XHANDLE xhVideoCodec = NULL; + AVCollect_Video_GetAVCodec(xhScreen, &xhVideoCodec); + AVCollect_Video_GetTimeBase(xhScreen, &st_VideoTime); + AVFormat_Packet_StreamCreate(xhPacket, xhVideoCodec); + AVFormat_Packet_TimeBase(xhPacket, 0, &st_VideoTime); //启用音频 if (1 == nBSType) { @@ -318,7 +347,11 @@ bool HTTPTask_TaskPost_BackService(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,初始化音频采集器请求失败,错误码:%lX"), lpszClientAddr, AVCollect_GetLastError()); return false; } +#ifdef _MSC_BUILD xhAudioFifo = AudioCodec_Help_FifoInit(ENUM_AVCODEC_AUDIO_SAMPLEFMT_S16, 2); +#else + xhAudioFifo = AudioCodec_Help_FifoInit(ENUM_AVCODEC_AUDIO_SAMPLEFMT_S16, 2); +#endif if (NULL == xhAudioFifo) { st_HDRParam.nHttpCode = 400; @@ -327,59 +360,17 @@ bool HTTPTask_TaskPost_BackService(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,初始化音频采集器请求失败,错误码:%lX"), lpszClientAddr, AudioCodec_GetLastError()); return false; } - st_AVInfo.st_AudioInfo.bEnable = true; - AVCollect_Audio_GetInfo(xhSound, &st_AVInfo); - //音频编码参数 - st_AVInfo.st_AudioInfo.enAVCodec = ENUM_XENGINE_AVCODEC_AUDIO_TYPE_AAC; - st_AVInfo.st_AudioInfo.nSampleFmt = ENUM_AVCODEC_AUDIO_SAMPLEFMT_S16; - } - //屏幕采集 - AVCOLLECT_SCREENINFO st_AVScreen; - memset(&st_AVScreen, '\0', sizeof(AVCOLLECT_SCREENINFO)); - - st_AVScreen.nFrameRate = 24; - st_AVScreen.nPosX = 0; - st_AVScreen.nPosY = 0; - _xstprintf(st_AVScreen.tszVideoSize, _X("%s"), _X("1920x1080")); -#ifdef _MSC_BUILD - xhScreen = AVCollect_Video_Init("gdigrab", tszDstBuffer, &st_AVScreen, HTTPTask_TaskPost_CBVideo); -#elif __linux__ - xhScreen = AVCollect_Video_Init("x11grab", tszDstBuffer, &st_AVScreen, HTTPTask_TaskPost_CBVideo); -#else - xhScreen = AVCollect_Video_Init("avfoundation", tszDstBuffer, &st_AVScreen, HTTPTask_TaskPost_CBVideo); -#endif - if (NULL == xhScreen) - { - st_HDRParam.nHttpCode = 400; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,屏幕采集器请求失败,错误码:%lX"), lpszClientAddr, AVCollect_GetLastError()); - return false; - } - AVCollect_Video_GetInfo(xhScreen, &st_AVInfo); - st_AVInfo.st_VideoInfo.enAVCodec = ENUM_XENGINE_AVCODEC_VIDEO_TYPE_H264; - xhStream = XClient_StreamPush_LiveInit(); - if (NULL == xhStream) - { - st_HDRParam.nHttpCode = 400; - HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); - XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); - XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_ERROR, _X("HTTP客户端:%s,推流:%s 请求失败,错误码:%lX"), lpszClientAddr, tszDstBuffer, StreamClient_GetLastError()); - return false; + XHANDLE xhAudioCodec = NULL; + AVCollect_Audio_GetAVCodec(xhSound, &xhAudioCodec); + AVCollect_Audio_GetTimeBase(xhSound, &st_AudioTime); + AVFormat_Packet_StreamCreate(xhPacket, xhAudioCodec); + AVFormat_Packet_TimeBase(xhPacket, 1, &st_AudioTime); } bRecord = true; - XClient_StreamPush_LiveOutput(xhStream, tszAPIBuffer, _X("flv")); - XClient_StreamPush_LiveCreate(xhStream, &st_AVInfo); - - AVCODEC_TIMEBASE st_VideoTime = {}; - AVCODEC_TIMEBASE st_AudioTime = {}; - AVCollect_Audio_GetTimeBase(xhSound, &st_AudioTime); - AVCollect_Video_GetTimeBase(xhScreen, &st_VideoTime); - XClient_StreamPush_LiveTime(xhStream, &st_VideoTime, &st_AudioTime); + AVFormat_Packet_Start(xhPacket); AVCollect_Audio_Start(xhSound); AVCollect_Video_Start(xhScreen); - XClient_StreamPush_LiveWriteHdr(xhStream); HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); XEngine_Network_Send(lpszClientAddr, m_MemorySend.get(), nSDLen); XLOG_PRINT(xhLog, XENGINE_HELPCOMPONENTS_XLOG_IN_LOGLEVEL_INFO, _X("HTTP客户端:%s,开始屏幕录制,音频:%s,视频:%s 推流:%s 请求成功"), lpszClientAddr, tszSrcBuffer, tszDstBuffer, tszAPIBuffer); @@ -391,10 +382,10 @@ bool HTTPTask_TaskPost_BackService(LPCXSTR lpszClientAddr, LPCXSTR lpszMsgBuffer { AVCollect_Video_Destory(xhScreen); AVCollect_Audio_Destory(xhSound); - XClient_StreamPush_LiveClose(xhStream); + AVFormat_Packet_Stop(xhPacket); xhScreen = NULL; xhSound = NULL; - xhStream = NULL; + xhPacket = NULL; bRecord = false; } HttpProtocol_Server_SendMsgEx(xhHTTPPacket, m_MemorySend.get(), &nSDLen, &st_HDRParam); From 4dbb517a71b11d87d1e4cb38c9a91909bb425cb9 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 5 Sep 2025 15:08:17 +0800 Subject: [PATCH 27/41] update:vs copy --- XEngine_Source/VSCopy_Arm64.bat | 1 + XEngine_Source/VSCopy_Debug.bat | 1 + XEngine_Source/VSCopy_x64.bat | 1 + XEngine_Source/VSCopy_x86.bat | 1 + 4 files changed, 4 insertions(+) diff --git a/XEngine_Source/VSCopy_Arm64.bat b/XEngine_Source/VSCopy_Arm64.bat index fc80a1d..a36b1c1 100644 --- a/XEngine_Source/VSCopy_Arm64.bat +++ b/XEngine_Source/VSCopy_Arm64.bat @@ -25,6 +25,7 @@ copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_AVHelp.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_VideoCodec.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_AudioCodec.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_AVCollect.dll" "./" +copy /y "%XEngine_LibArm64%\XEngine_AVCodec\XEngine_AVFormat.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\avcodec-61.dll" "./" copy /y "%XEngine_LibArm64%\XEngine_AVCodec\avdevice-61.dll" "./" diff --git a/XEngine_Source/VSCopy_Debug.bat b/XEngine_Source/VSCopy_Debug.bat index f04881c..c05ca12 100644 --- a/XEngine_Source/VSCopy_Debug.bat +++ b/XEngine_Source/VSCopy_Debug.bat @@ -25,6 +25,7 @@ copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_AVHelp.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_VideoCodec.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_AudioCodec.dll" "./" copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_AVCollect.dll" "./" +copy /y "D:\XEngine\XEngine_SourceCode\Debug\XEngine_AVFormat.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\avcodec-61.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\avdevice-61.dll" "./" diff --git a/XEngine_Source/VSCopy_x64.bat b/XEngine_Source/VSCopy_x64.bat index 17353f2..37e3f97 100644 --- a/XEngine_Source/VSCopy_x64.bat +++ b/XEngine_Source/VSCopy_x64.bat @@ -25,6 +25,7 @@ copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_AVHelp.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_VideoCodec.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_AudioCodec.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_AVCollect.dll" "./" +copy /y "%XEngine_Lib64%\XEngine_AVCodec\XEngine_AVFormat.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\avcodec-61.dll" "./" copy /y "%XEngine_Lib64%\XEngine_AVCodec\avdevice-61.dll" "./" diff --git a/XEngine_Source/VSCopy_x86.bat b/XEngine_Source/VSCopy_x86.bat index 62dd8b9..0b06c96 100644 --- a/XEngine_Source/VSCopy_x86.bat +++ b/XEngine_Source/VSCopy_x86.bat @@ -25,6 +25,7 @@ copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_AVHelp.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_VideoCodec.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_AudioCodec.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_AVCollect.dll" "./" +copy /y "%XEngine_Lib32%\XEngine_AVCodec\XEngine_AVFormat.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\avcodec-61.dll" "./" copy /y "%XEngine_Lib32%\XEngine_AVCodec\avdevice-61.dll" "./" From 3d5e02f708c2702ba0956b06b53e8cbd7bc533f8 Mon Sep 17 00:00:00 2001 From: qyt <486179@qq.com> Date: Fri, 5 Sep 2025 16:26:20 +0800 Subject: [PATCH 28/41] fixed:centos build lost packet --- .github/workflows/Centos_build.yml | 5 +++++ .github/workflows/Rocky_build.yml | 2 ++ XEngine_Docment/Docment_en.docx | Bin 161327 -> 156972 bytes XEngine_Docment/Docment_zh.docx | Bin 171090 -> 172063 bytes 4 files changed, 7 insertions(+) diff --git a/.github/workflows/Centos_build.yml b/.github/workflows/Centos_build.yml index 1e2f9cf..aa23541 100644 --- a/.github/workflows/Centos_build.yml +++ b/.github/workflows/Centos_build.yml @@ -89,6 +89,11 @@ jobs: chmod 777 * ./XEngine_LINEnv.sh -i 3 + + - name: install build package + run: | + dnf install lua-devel opencv-devel qrencode-devel leptonica-devel tesseract-devel -y + - name: make run: | cd XEngine_Source diff --git a/.github/workflows/Rocky_build.yml b/.github/workflows/Rocky_build.yml index e0cc5ae..0b97129 100644 --- a/.github/workflows/Rocky_build.yml +++ b/.github/workflows/Rocky_build.yml @@ -87,9 +87,11 @@ jobs: chmod 777 * ./XEngine_LINEnv.sh -i 3 + - name: install build package run: | dnf install lua-devel opencv-devel qrencode-devel leptonica-devel tesseract-devel -y + - name: make run: | cd XEngine_Source diff --git a/XEngine_Docment/Docment_en.docx b/XEngine_Docment/Docment_en.docx index 712e0a64cd177455c3ea7daf9a5379a9894482d0..7c1191454568b9d0a3da0748af0cf856f157972d 100644 GIT binary patch delta 120729 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∋kgD9a_8qA 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 delta 125119 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