diff --git a/acl_cpp_vc2003.sln b/acl_cpp_vc2003.sln index 16d2218bb..56ecc2a27 100644 --- a/acl_cpp_vc2003.sln +++ b/acl_cpp_vc2003.sln @@ -536,6 +536,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disque_pool", "lib_acl_cpp\ {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redis_geo", "lib_acl_cpp\samples\redis\redis_geo\redis_geo_vc2003.vcproj", "{2DABFAD1-114B-4F96-9185-DC0C56A3662D}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -1226,6 +1233,14 @@ Global {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release.Build.0 = Release|Win32 {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll.ActiveCfg = Releasedll|Win32 {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll.Build.0 = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug.ActiveCfg = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug.Build.0 = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll.ActiveCfg = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll.Build.0 = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release.ActiveCfg = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release.Build.0 = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll.ActiveCfg = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll.Build.0 = Releasedll|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/acl_cpp_vc2008.sln b/acl_cpp_vc2008.sln index 69ed8e562..24dc8a19a 100644 --- a/acl_cpp_vc2008.sln +++ b/acl_cpp_vc2008.sln @@ -612,6 +612,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disque_cluster", "lib_acl_c {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redis_geo", "lib_acl_cpp\samples\redis\redis_geo\redis_geo_vc2008.vcproj", "{2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}" + ProjectSection(ProjectDependencies) = postProject + {64BF4D83-53BB-4045-8522-9FF9F73B14D4} = {64BF4D83-53BB-4045-8522-9FF9F73B14D4} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -1298,6 +1305,14 @@ Global {1D480138-D65E-4B4E-A2B6-372927EFD61A}.Release|Win32.Build.0 = Release|Win32 {1D480138-D65E-4B4E-A2B6-372927EFD61A}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 {1D480138-D65E-4B4E-A2B6-372927EFD61A}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.Debug|Win32.ActiveCfg = Debug|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.Debug|Win32.Build.0 = Debug|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.Release|Win32.ActiveCfg = Release|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.Release|Win32.Build.0 = Release|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA}.Releasedll|Win32.Build.0 = Releasedll|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1393,6 +1408,7 @@ Global {9A0B9C5B-484E-4C8B-9793-DDA4A33B07FA} = {4887D780-3316-4603-9A77-7AD9A4F8E1DE} {34E75CAA-8883-4808-AC8A-FED139A49F11} = {4887D780-3316-4603-9A77-7AD9A4F8E1DE} {0C44CD71-0A6C-4132-B59A-8BB49F0C44F8} = {4887D780-3316-4603-9A77-7AD9A4F8E1DE} + {2147D0CD-57C8-4C50-BBA8-71EF03B7C2AA} = {4887D780-3316-4603-9A77-7AD9A4F8E1DE} {60E02ECD-9FF5-4ED0-B991-49D2548FE193} = {C4D183AB-3E2D-4664-8C63-EFB05FCF3A82} {71A55E11-A1AD-44A2-8D7E-B717B8EDF76B} = {C4D183AB-3E2D-4664-8C63-EFB05FCF3A82} {D4FB2F8D-F9C4-4B84-8677-0D2205F5EC16} = {C4D183AB-3E2D-4664-8C63-EFB05FCF3A82} diff --git a/acl_cpp_vc2010.sln b/acl_cpp_vc2010.sln index b1b3db91a..1d7ca0445 100644 --- a/acl_cpp_vc2010.sln +++ b/acl_cpp_vc2010.sln @@ -324,6 +324,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disque_cluster_vc2010", "li {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redis_geo_vc2010", "lib_acl_cpp\samples\redis\redis_geo\redis_geo_vc2010.vcxproj", "{50A37701-CDC8-477E-8B7F-711FB0A90844}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -883,6 +890,16 @@ Global {65ADEA28-65B4-4930-B9BB-D338848F0841}.Releasedll|Win32.Build.0 = Releasedll|Win32 {65ADEA28-65B4-4930-B9BB-D338848F0841}.Template|Win32.ActiveCfg = Release|Win32 {65ADEA28-65B4-4930-B9BB-D338848F0841}.Template|Win32.Build.0 = Release|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Debug|Win32.ActiveCfg = Debug|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Debug|Win32.Build.0 = Debug|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Release|Win32.ActiveCfg = Release|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Release|Win32.Build.0 = Release|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Template|Win32.ActiveCfg = Release|Win32 + {50A37701-CDC8-477E-8B7F-711FB0A90844}.Template|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -942,6 +959,7 @@ Global {560AD9F1-FDD5-4C89-9CCC-F4CF68FED05F} = {7B001BDA-0EFF-4EE0-89E7-C0EECE8955A9} {AD4762CE-510B-4D2C-9075-CCE7689286C4} = {7B001BDA-0EFF-4EE0-89E7-C0EECE8955A9} {3DF1326C-0D04-45D8-AD8A-1285A62EE652} = {7B001BDA-0EFF-4EE0-89E7-C0EECE8955A9} + {50A37701-CDC8-477E-8B7F-711FB0A90844} = {7B001BDA-0EFF-4EE0-89E7-C0EECE8955A9} {84376B60-FF20-4FD0-967E-C568FC2FBC53} = {DC80E4B1-1DC2-49D8-9FC3-BD3E60337968} {56583E9A-B66F-4EF5-92DA-31CF24D33AB9} = {9C7533AA-D559-49ED-BE0F-7E52369A6FAD} {C80B0853-6D1C-4E5F-8C31-F4D77770C63D} = {9C7533AA-D559-49ED-BE0F-7E52369A6FAD} diff --git a/acl_cpp_vc2012.sln b/acl_cpp_vc2012.sln index 9e3069728..b5bf0cf03 100644 --- a/acl_cpp_vc2012.sln +++ b/acl_cpp_vc2012.sln @@ -528,6 +528,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wizard_demo", "wizard_demo" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpd_download", "app\wizard_demo\httpd_download\httpd_download_vc2012.vcxproj", "{1A38C49B-F712-4115-980B-6DBD632D25CF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "https_proxy", "lib_acl_cpp\samples\ssl\https_proxy\https_proxy_vc2012.vcxproj", "{5F75216D-8263-4F6F-9390-76E7AC129AEE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dgate", "lib_acl\samples\dgate\dgate_vc2012.vcxproj", "{9073FA9F-26A1-482C-91D0-876434C3E4EB}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redis_geo", "lib_acl_cpp\samples\redis\redis_geo\redis_geo_vc2012.vcxproj", "{AE10B13D-774D-49A5-9066-E90F124BA99C}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Mixed Platforms = Debug|Mixed Platforms @@ -2527,6 +2541,96 @@ Global {1A38C49B-F712-4115-980B-6DBD632D25CF}.Template|Win32.Build.0 = DebugDll|Win32 {1A38C49B-F712-4115-980B-6DBD632D25CF}.Template|x64.ActiveCfg = DebugDll|x64 {1A38C49B-F712-4115-980B-6DBD632D25CF}.Template|x64.Build.0 = DebugDll|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Debug|Win32.Build.0 = Debug|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Debug|x64.ActiveCfg = Debug|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Debug|x64.Build.0 = Debug|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.DebugDll|Mixed Platforms.ActiveCfg = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.DebugDll|Mixed Platforms.Build.0 = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.DebugDll|x64.ActiveCfg = DebugDll|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.DebugDll|x64.Build.0 = DebugDll|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Release|Win32.ActiveCfg = Release|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Release|Win32.Build.0 = Release|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Release|x64.ActiveCfg = Release|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Release|x64.Build.0 = Release|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Releasedll|Mixed Platforms.ActiveCfg = ReleaseDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Releasedll|Mixed Platforms.Build.0 = ReleaseDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Releasedll|x64.ActiveCfg = ReleaseDll|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Releasedll|x64.Build.0 = ReleaseDll|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Template|Mixed Platforms.ActiveCfg = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Template|Mixed Platforms.Build.0 = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Template|Win32.ActiveCfg = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Template|Win32.Build.0 = DebugDll|Win32 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Template|x64.ActiveCfg = DebugDll|x64 + {5F75216D-8263-4F6F-9390-76E7AC129AEE}.Template|x64.Build.0 = DebugDll|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Debug|Win32.ActiveCfg = Debug|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Debug|Win32.Build.0 = Debug|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Debug|x64.ActiveCfg = Debug|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Debug|x64.Build.0 = Debug|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.DebugDll|Mixed Platforms.ActiveCfg = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.DebugDll|Mixed Platforms.Build.0 = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.DebugDll|x64.ActiveCfg = DebugDll|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.DebugDll|x64.Build.0 = DebugDll|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Release|Mixed Platforms.Build.0 = Release|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Release|Win32.ActiveCfg = Release|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Release|Win32.Build.0 = Release|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Release|x64.ActiveCfg = Release|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Release|x64.Build.0 = Release|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Releasedll|Mixed Platforms.ActiveCfg = ReleaseDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Releasedll|Mixed Platforms.Build.0 = ReleaseDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Releasedll|x64.ActiveCfg = ReleaseDll|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Releasedll|x64.Build.0 = ReleaseDll|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Template|Mixed Platforms.ActiveCfg = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Template|Mixed Platforms.Build.0 = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Template|Win32.ActiveCfg = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Template|Win32.Build.0 = DebugDll|Win32 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Template|x64.ActiveCfg = DebugDll|x64 + {9073FA9F-26A1-482C-91D0-876434C3E4EB}.Template|x64.Build.0 = DebugDll|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Debug|Win32.ActiveCfg = Debug|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Debug|Win32.Build.0 = Debug|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Debug|x64.ActiveCfg = Debug|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Debug|x64.Build.0 = Debug|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.DebugDll|Mixed Platforms.ActiveCfg = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.DebugDll|Mixed Platforms.Build.0 = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.DebugDll|x64.ActiveCfg = DebugDll|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.DebugDll|x64.Build.0 = DebugDll|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Release|Mixed Platforms.Build.0 = Release|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Release|Win32.ActiveCfg = Release|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Release|Win32.Build.0 = Release|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Release|x64.ActiveCfg = Release|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Release|x64.Build.0 = Release|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Releasedll|Mixed Platforms.ActiveCfg = Releasedll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Releasedll|Mixed Platforms.Build.0 = Releasedll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Releasedll|x64.ActiveCfg = Releasedll|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Releasedll|x64.Build.0 = Releasedll|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Template|Mixed Platforms.ActiveCfg = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Template|Mixed Platforms.Build.0 = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Template|Win32.ActiveCfg = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Template|Win32.Build.0 = DebugDll|Win32 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Template|x64.ActiveCfg = DebugDll|x64 + {AE10B13D-774D-49A5-9066-E90F124BA99C}.Template|x64.Build.0 = DebugDll|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2589,10 +2693,12 @@ Global {DEDE0B8A-35C5-4674-A10A-BF6544F6A885} = {06493E1B-DA69-4471-AF4C-6890A6D0F6EE} {B8ADBED2-0FFC-49F7-A8AE-A42CE262166D} = {3A25DC67-2832-4912-8FD5-66E499E38F11} {B14C93A6-DABE-48F9-A78C-C94049B69984} = {3A25DC67-2832-4912-8FD5-66E499E38F11} + {5F75216D-8263-4F6F-9390-76E7AC129AEE} = {3A25DC67-2832-4912-8FD5-66E499E38F11} {D1F030D1-36F7-4440-9801-42E31E767A52} = {FB676B5A-D82C-45CB-9E1F-F3793419DDA9} {2495A6D4-777F-48BF-99C0-702E4A11FD23} = {FB676B5A-D82C-45CB-9E1F-F3793419DDA9} {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34} = {267F658E-44AF-4080-8577-EFCE99A5E030} {4B58485B-D846-4485-9C5E-7F2304D71701} = {267F658E-44AF-4080-8577-EFCE99A5E030} + {9073FA9F-26A1-482C-91D0-876434C3E4EB} = {267F658E-44AF-4080-8577-EFCE99A5E030} {D232833B-57A9-4167-B37C-A4594953F93D} = {3CC8D45A-8E3F-4F5C-A7DF-4D8027E4EA9C} {84376B60-FF20-4FD0-967E-C568FC2FBC53} = {3CC8D45A-8E3F-4F5C-A7DF-4D8027E4EA9C} {C8535C82-3DCB-472E-9E8F-DA769D9375B1} = {3CC8D45A-8E3F-4F5C-A7DF-4D8027E4EA9C} @@ -2618,6 +2724,7 @@ Global {97BC2502-5B1C-44B4-8809-83A268306FA1} = {14531A45-383C-4CCF-870B-B5C867A314F2} {5EA23ADB-6481-4CA1-9C31-7D92036DFD47} = {14531A45-383C-4CCF-870B-B5C867A314F2} {E3280617-6D0D-4639-9014-31BCD4ADFADC} = {14531A45-383C-4CCF-870B-B5C867A314F2} + {AE10B13D-774D-49A5-9066-E90F124BA99C} = {14531A45-383C-4CCF-870B-B5C867A314F2} {D90DCF51-E219-4BD8-A032-076335675F58} = {C8535C82-3DCB-472E-9E8F-DA769D9375B1} {8945DE73-78D8-4C1E-B828-2558AA33448E} = {B6BE4E77-F69D-43B0-BE8A-77A8AA61A89E} {067E9700-A518-4747-AE70-0C6F433AE478} = {B6BE4E77-F69D-43B0-BE8A-77A8AA61A89E} diff --git a/app/wizard_demo/httpd_download/http_servlet.cpp b/app/wizard_demo/httpd_download/http_servlet.cpp index 16de7c605..4800350e9 100644 --- a/app/wizard_demo/httpd_download/http_servlet.cpp +++ b/app/wizard_demo/httpd_download/http_servlet.cpp @@ -20,12 +20,11 @@ bool http_servlet::reply(acl::HttpServletRequest& req, acl::string buf; buf.vformat(fmt, ap); va_end(ap); - bool keep_alive = req.isKeepAlive(); res.setStatus(status) - .setKeepAlive(keep_alive) + .setKeepAlive(req.isKeepAlive()) .setContentType("text/html; charset=utf-8") .setContentLength(buf.length()); - return res.write(buf) && keep_alive; + return res.write(buf); } bool http_servlet::doError(acl::HttpServletRequest& req, @@ -100,8 +99,6 @@ bool http_servlet::transfer_file(acl::HttpServletRequest& req, if (fsize <= 0) return reply(req, res, 500, "invalid file size: %lld", fsize); - bool keep_alive = req.isKeepAlive(); - acl::string hdr_entry; acl::string filename; filename.basename(in.file_path()); // 从文件全路径中提取文件名 @@ -109,7 +106,7 @@ bool http_servlet::transfer_file(acl::HttpServletRequest& req, // 设置 HTTP 响应头中的字段 res.setStatus(200) - .setKeepAlive(keep_alive) + .setKeepAlive(req.isKeepAlive()) .setContentLength(fsize) .setContentType("application/octet-stream") // 设置 HTTP 头中的文件名 @@ -184,8 +181,6 @@ bool http_servlet::transfer_file(acl::HttpServletRequest& req, return reply(req, res, 500, "fseek(%lld) error %s", range_from, acl::last_serror()); - bool keep_alive = req.isKeepAlive(); - acl::string hdr_entry; acl::string filename; filename.basename(in.file_path()); // 从文件全路径中提取文件名 @@ -193,7 +188,7 @@ bool http_servlet::transfer_file(acl::HttpServletRequest& req, // 设置 HTTP 响应头中的字段 res.setStatus(206) // 响应状态 206 表示部分数据 - .setKeepAlive(keep_alive) // 是否保持长连接 + .setKeepAlive(req.isKeepAlive())// 是否保持长连接 .setContentLength(length) // 实际要传输的数据长度 .setContentType("application/octet-stream") // 数据类型 // 设置 HTTP 头中的文件名 @@ -236,5 +231,5 @@ bool http_servlet::transfer_file(acl::HttpServletRequest& req, return false; } - return true && keep_alive; + return true; } diff --git a/lib_acl/changes.txt b/lib_acl/changes.txt index 1fed0b011..2652ed721 100644 --- a/lib_acl/changes.txt +++ b/lib_acl/changes.txt @@ -1,6 +1,10 @@ 修改历史列表: ------------------------------------------------------------------------ +494) 2015.7.7 +494.1) bugfix: acl_urlcode.c 中函数 acl_url_decode 当输入串非法时有可能造成内存溢出 +494.2) samples/dgate: 将之前写过的一个 DNS 查询代理的例子加入 + 493) 2015.6.28 493.1) compile: 支持在 VC x64 环境下编译使用 493.2) workaroud: 为了防止因在 acl_define_win32.h 中将 FD_SETSIZE 设置的过大 diff --git a/lib_acl/samples/dgate/Makefile b/lib_acl/samples/dgate/Makefile new file mode 100644 index 000000000..a47dfef17 --- /dev/null +++ b/lib_acl/samples/dgate/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = dgate diff --git a/lib_acl/samples/dgate/bench/Makefile b/lib_acl/samples/dgate/bench/Makefile new file mode 100644 index 000000000..1ff2bce3e --- /dev/null +++ b/lib_acl/samples/dgate/bench/Makefile @@ -0,0 +1,109 @@ +SHELL = /bin/sh +#CC = gcc +CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes -Wmissing-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../lib_all/lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +ALL_LIBS = -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./Debug + +#Project's objs +SOURCES = $(wildcard *.cpp) +OBJS = $(patsubst %.cpp, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +PROG_NAME = dbench + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)/%.o: %.cpp + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/lib_acl/samples/dgate/bench/main.cpp b/lib_acl/samples/dgate/bench/main.cpp new file mode 100644 index 000000000..b54204cb2 --- /dev/null +++ b/lib_acl/samples/dgate/bench/main.cpp @@ -0,0 +1,158 @@ +#include "lib_acl.h" +#include +#ifdef ACL_UNIX +#include +#endif + +typedef struct THREAD_CTX +{ + int count; + char ip[64]; + unsigned short port; + char domain[256]; + time_t tmspec; +} THREAD_CTX; + +static char *var_server_ip = "127.0.0.1"; +static int var_server_port = 53; +static char *var_domain = "mailz.hexun.com"; +static acl_pthread_mutex_t __lock; + +static int __total_cnt = 0, __count = 0; + +static void bench_info(int count, time_t tmspec) +{ + printf("total_cnt=%d, count=%d, tmspec=%ld\r\n", + __total_cnt, count, tmspec); +} + +static void bench_stat(int cnt) +{ + static time_t last; + time_t now, inter; + + return; + + acl_pthread_mutex_lock(&__lock); + __total_cnt += cnt; + __count += cnt; + time(&now); + inter = now - last; + if (inter >= 1) { + bench_info(__count, inter); + __count = 0; + last = now; + } + acl_pthread_mutex_unlock(&__lock); +} + +static void init(void) +{ + acl_socket_init(); + acl_pthread_mutex_init(&__lock, NULL); +} + +static void *thread_run(void *arg) +{ + THREAD_CTX *ctx = (THREAD_CTX*) arg; + ACL_RES *res; + ACL_DNS_DB *dns_db; + time_t begin, last; + int i, cnt; + + res = acl_res_new(ctx->ip, ctx->port); + + last = begin = time(NULL); + cnt = 0; + for (i = 0; i < ctx->count; i++) + { + dns_db = acl_res_lookup(res, ctx->domain); + acl_netdb_free(dns_db); + cnt++; + if (i % 4000 == 0) { + bench_stat(cnt); + cnt = 0; + last = time(NULL); + } + } + + bench_stat(cnt); + bench_info(cnt, time(NULL) - last); + acl_res_free(res); + ctx->tmspec = time(NULL) - begin; + return (ctx); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -t {thread_count} -n {total_count} -i {server_ip} -p {server_port}\r\n", + procname); +} + +int main(int argc, char *argv[]) +{ + char ch; + int nthread = 50, count = 1000000, i, n; + time_t tmspec; + acl_pthread_t *ptid; + acl_pthread_attr_t attr; + THREAD_CTX *ctx; + time_t begin; + void *ptr; + + while ((ch = getopt(argc, argv, "ht:n:i:p:")) > 0) + { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 't': + nthread = atol(optarg); + break; + case 'n': + count = atol(optarg); + break; + case 'i': + var_server_ip = acl_mystrdup(optarg); + break; + case 'p': + var_server_port = atoi(optarg); + break; + default: + break; + } + } + + init(); + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 0); + + begin = time(NULL); + n = count / nthread; + ptid = (acl_pthread_t*) acl_mycalloc(nthread, sizeof(acl_pthread_t)); + for (i = 0; i < nthread; i++) + { + ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX)); + ctx->count = n; + ACL_SAFE_STRNCPY(ctx->ip, var_server_ip, sizeof(ctx->ip)); + ctx->port = var_server_port; + ACL_SAFE_STRNCPY(ctx->domain, var_domain, sizeof(ctx->domain)); + acl_pthread_create(&ptid[i], &attr, thread_run, (void*) ctx); + } + + tmspec = 0; + for (i = 0; i < nthread; i++) + { + acl_pthread_join(ptid[i], &ptr); + ctx = (THREAD_CTX*) ptr; + tmspec += ctx->tmspec; + acl_myfree(ctx); + } + acl_myfree(ptid); + printf("total time spent: %ld, inter spent time: %ld secconds\r\n", + tmspec, time(NULL) - begin); + printf("Enter any key to exit\r\n"); + getchar(); + return (0); +} diff --git a/lib_acl/samples/dgate/cache.cpp b/lib_acl/samples/dgate/cache.cpp new file mode 100644 index 000000000..b441f6cbf --- /dev/null +++ b/lib_acl/samples/dgate/cache.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "service_main.h" + +static ACL_AIO *__aio = NULL; +static ACL_HTABLE *__cache = NULL; + +void ns_cache_init(ACL_AIO *aio) +{ + const char *myname = "ns_cache_init"; + + if (__cache != NULL) + acl_msg_fatal("%s(%d): __cache != NULL", myname, __LINE__); + + __aio = aio; + __cache = acl_htable_create(10000, 0); +} + +static void ns_cache_timeout_fn(int event_type acl_unused, + ACL_EVENT *event acl_unused, void *context) +{ + NS_CACHE_ENTRY *entry = (NS_CACHE_ENTRY*) context; + + acl_htable_delete(__cache, entry->domain, NULL); + ns_cache_entry_free(entry); +} + +void ns_cache_add(NS_CACHE_ENTRY *entry) +{ + const char *myname = "ns_cache_add"; + NS_CACHE_ENTRY *old_entry; + + if (__cache == NULL) + acl_msg_fatal("%s(%d): ns_cache_init not called", + myname, __LINE__); + + old_entry = (NS_CACHE_ENTRY*) acl_htable_find(__cache, entry->domain); + if (old_entry == NULL) { + acl_htable_enter(__cache, entry->domain, (char*) entry); + if (entry->ttl > 0) + acl_aio_request_timer(__aio, ns_cache_timeout_fn, + entry, entry->ttl, 0); + return; + } + + if (entry->ttl > 0) { + acl_aio_cancel_timer(__aio, ns_cache_timeout_fn, old_entry); + acl_aio_request_timer(__aio, ns_cache_timeout_fn, + entry, entry->ttl, 0); + } + if (entry == old_entry) + return; + acl_htable_delete(__cache, old_entry->domain, NULL); + ns_cache_entry_free(old_entry); + acl_htable_enter(__cache, entry->domain, (char*) entry); +} + +NS_CACHE_ENTRY *ns_cache_find(const char *domain) +{ + const char *myname = "ns_cache_find"; + NS_CACHE_ENTRY *entry; + char key[MAX_DOMAIN_LEN]; + + if (__cache == NULL) + acl_msg_fatal("%s(%d): ns_cache_init not called", + myname, __LINE__); + + ACL_SAFE_STRNCPY(key, domain, sizeof(key)); + acl_lowercase(key); + + entry = (NS_CACHE_ENTRY*) acl_htable_find(__cache, key); + return (entry); +} + +int ns_cache_delete(const char *domain) +{ + const char *myname = "ns_cache_delete"; + char key[MAX_DOMAIN_LEN]; + + if (__cache == NULL) + acl_msg_fatal("%s(%d): ns_cache_init not called", + myname, __LINE__); + + ACL_SAFE_STRNCPY(key, domain, sizeof(key)); + acl_lowercase(key); + + return (acl_htable_delete(__cache, key, + (void (*)(void*))ns_cache_entry_free)); +} + +void ns_cache_entry_free(NS_CACHE_ENTRY *entry) +{ + if (entry->ip_list) + acl_argv_free(entry->ip_list); + acl_myfree(entry); +} + +NS_CACHE_ENTRY *ns_cache_entry_new(const char *domain, const ACL_ARGV *ip_list, + const char *cache_buf, int dlen, int ttl) +{ + const char *myname = "ns_cache_entry_new"; + NS_CACHE_ENTRY *entry; + int i; + + if (ip_list == NULL && (cache_buf == NULL || dlen <= 0)) { + acl_msg_error("%s(%d): invalid input args", myname, __LINE__); + return (NULL); + } + if (ip_list != NULL && (cache_buf != NULL && dlen > 0)) { + acl_msg_error("%s(%d): ip_list != NULL and cache_buf != NULL", + myname, __LINE__); + return (NULL); + } + + entry = (NS_CACHE_ENTRY*) acl_mycalloc(1, sizeof(NS_CACHE_ENTRY)); + entry->idx = 0; + entry->ttl = ttl; + ACL_SAFE_STRNCPY(entry->domain, domain, sizeof(entry->domain)); + acl_lowercase(entry->domain); + + if (ip_list) { + entry->ip_list = acl_argv_alloc(10); + for (i = 0; i < ip_list->argc; i++) { + acl_argv_add(entry->ip_list, ip_list->argv[i], NULL); + } + entry->cache_dlen = 0; + } else if (cache_buf) { + memcpy(entry->cache_buf, cache_buf, dlen); + entry->cache_dlen = dlen; + } + + return (entry); +} + +static char __unknown_domain[MAX_DOMAIN_LEN]; +static NS_CACHE_ENTRY *__unknown_cache_entry; + +void ns_cache_add_unknown(const char *domain, const ACL_ARGV *ip_list) +{ + __unknown_cache_entry = ns_cache_entry_new(domain, ip_list, NULL, 0, 0); + ACL_SAFE_STRNCPY(__unknown_domain, domain, sizeof(__unknown_domain)); +} + +NS_CACHE_ENTRY *ns_cache_unknown(void) +{ + const char *myname = "ns_cache_unknown"; + + if (__unknown_cache_entry == NULL) + acl_msg_fatal("%s(%d): __unknown_cache_entry null", + myname, __LINE__); + return (__unknown_cache_entry); +} + +ACL_ARGV *ns_cache_ip_list(NS_CACHE_ENTRY *cache_entry) +{ + ACL_ARGV *argv = acl_argv_alloc(10); + ACL_ARGV *ip_list = cache_entry->ip_list; + int i, n; + + n = ip_list->argc; + if (cache_entry->idx >= n) + cache_entry->idx = 0; + i = cache_entry->idx++; + while (n-- > 0) { + acl_argv_add(argv, ip_list->argv[i++], NULL); + if (i >= ip_list->argc) + i = 0; + } + + return (argv); +} diff --git a/lib_acl/samples/dgate/configure.cpp b/lib_acl/samples/dgate/configure.cpp new file mode 100644 index 000000000..0ca771b2e --- /dev/null +++ b/lib_acl/samples/dgate/configure.cpp @@ -0,0 +1,187 @@ +#include "stdafx.h" +#include +#include "configure.h" + +char *var_cfg_allow_ip; // 允许访问的 IP 地址范围 +char *var_cfg_domains; // 本地域名映射关系 +char *var_cfg_domain_unknown; // 当域名不存在时返回给客户端的其它替换地址 +char *var_cfg_dns_name; // 本域名服务器的名称 +char *var_cfg_dns_ip; // 本域名服务器的 IP +char *var_cfg_dns_neighbor_ip; // 上游 DNS 服务器 IP + +static ACL_CFG_STR_TABLE __conf_str_tab[] = { + { "allow_ip", "0.0.0.0:255.255.255.254", &var_cfg_allow_ip }, + { "domain_map", "", &var_cfg_domains }, + { "domain_unknown", "211.157.110.179:211.157.110.185", &var_cfg_domain_unknown }, + { "dns_name", "mytest.com.cn", &var_cfg_dns_name }, + { "dns_ip", "211.157.110.179", &var_cfg_dns_ip }, + { "dns_neighbor_ip", "8.8.8.8", &var_cfg_dns_neighbor_ip }, + { 0, 0, 0 }, +}; + +int var_cfg_hijack_unknown; // 是否需要对不存在域名进行劫持 +int var_cfg_dns_neighbor_port;// 上游 DNS 服务器 PORT + +static ACL_CFG_BOOL_TABLE __conf_bool_tab[] = { + { "hijack_unknown", 0, &var_cfg_hijack_unknown }, + { 0, 0, 0 }, +}; + +static ACL_CFG_INT_TABLE __conf_int_tab[] = { + { "dns_neighbor_port", 53, &var_cfg_dns_neighbor_port, 0, 0 }, + { 0, 0, 0, 0, 0 } +}; + +static ACL_IPLINK *__allow_ip = NULL; +static ACL_HTABLE *__domain_map_table = NULL; +static DOMAIN_MAP *__domain_unknown = NULL; +static int __all_to_one_ip = 0; + +static void conf_allow_ip(const char *ip_list) +{ + const char *myname = "conf_allow_ip"; + ACL_ARGV *argv; + char *ipfrom, *ipto; + int i; + + __allow_ip = acl_iplink_create(10); + argv = acl_argv_split(ip_list, ",; \t"); + for (i = 0; i < argv->argc; i++) { + ipfrom = argv->argv[i]; + ipto = strchr(ipfrom, ':'); + if (ipto == NULL) { + acl_msg_warn("%s(%d): ip_list(%s) invalid", + myname, __LINE__, ip_list); + continue; + } + *ipto++ = 0; + acl_iplink_insert(__allow_ip, ipfrom, ipto); + } + acl_argv_free(argv); +} + +static void domain_map_add_unknown(void) +{ + const char *myname = "domain_map_add_unknown"; + + __domain_unknown = (DOMAIN_MAP*) acl_mycalloc(1, sizeof(DOMAIN_MAP)); + __domain_unknown->idx = 0; + ACL_SAFE_STRNCPY(__domain_unknown->domain, "unknown", + sizeof(__domain_unknown->domain)); + __domain_unknown->ip_list = acl_argv_split(var_cfg_domain_unknown, ":"); + if (__domain_unknown->ip_list == NULL) + acl_msg_fatal("%s(%d): domain_unknown(%s) invalid", + myname, __LINE__, var_cfg_domain_unknown); +} + +static void domain_map_add(const ACL_ARGV *ip_list) +{ + const char *myname = "domain_map_add"; + DOMAIN_MAP *domain_map; + int i; + + if (ip_list->argc < 2) + acl_msg_fatal("%s(%d): ip_list->argc(%d) < 2", + myname, __LINE__, ip_list->argc); + + domain_map = (DOMAIN_MAP*) acl_mycalloc(1, sizeof(DOMAIN_MAP)); + domain_map->idx = 0; + ACL_SAFE_STRNCPY(domain_map->domain, ip_list->argv[0], + sizeof(domain_map->domain)); + acl_lowercase(domain_map->domain); + + domain_map->ip_list = acl_argv_alloc(10); + for (i = 1; i < ip_list->argc; i++) + acl_argv_add(domain_map->ip_list, ip_list->argv[i], NULL); + + acl_htable_enter(__domain_map_table, domain_map->domain, domain_map); + if (strcasecmp(domain_map->domain, "all") == 0) + __all_to_one_ip = 1; +} + +static void conf_domains_map(const char *domains) +{ + const char *myname = "conf_domains_map"; + ACL_ARGV *argv, *ip_list; + int i; + + if (domains == NULL || *domains == 0) + return; + argv = acl_argv_split(domains, ",; \t"); + + for (i = 0; i < argv->argc; i++) { + ip_list = acl_argv_split(argv->argv[i], ":"); + if (ip_list->argc < 2) { + acl_msg_warn("%s(%d): invalid data(%s)", + myname, __LINE__, argv->argv[i]); + acl_argv_free(ip_list); + } else { + domain_map_add(ip_list); + acl_argv_free(ip_list); + } + } + + acl_argv_free(argv); +} + +void conf_load(const char *filepath) +{ + const char *myname = "conf_load"; + ACL_XINETD_CFG_PARSER *cfg; + + __domain_map_table = acl_htable_create(100, 0); + + cfg = acl_xinetd_cfg_load(filepath); + if (cfg == NULL) { + acl_msg_error("%s(%d): load confiugre(%s) error", + myname, __LINE__, filepath); + return; + } + + acl_xinetd_params_bool_table(cfg, __conf_bool_tab); + acl_xinetd_params_int_table(cfg, __conf_int_tab); + acl_xinetd_params_str_table(cfg, __conf_str_tab); + + conf_allow_ip(var_cfg_allow_ip); + domain_map_add_unknown(); + conf_domains_map(var_cfg_domains); + + acl_xinetd_cfg_free(cfg); +} + +int host_allow(const char *ip) +{ + if (__allow_ip == NULL) + return (1); + if (acl_iplink_lookup_str(__allow_ip, ip) != NULL) + return (1); + return (0); +} + +DOMAIN_MAP *domain_map_find(const char *domain) +{ + char domain_buf[256]; + DOMAIN_MAP *domain_map; + + if (__all_to_one_ip) + ACL_SAFE_STRNCPY(domain_buf, "all", sizeof(domain_buf)); + else + ACL_SAFE_STRNCPY(domain_buf, domain, sizeof(domain_buf)); + + acl_lowercase(domain_buf); + + domain_map = (DOMAIN_MAP*) acl_htable_find( + __domain_map_table, domain_buf); + return (domain_map); +} + +DOMAIN_MAP *domain_map_unknown(void) +{ + const char *myname = "domain_map_unknown"; + + if (__domain_unknown == NULL) + acl_msg_fatal("%s(%d): __domain_unknown null", + myname, __LINE__); + + return (__domain_unknown); +} diff --git a/lib_acl/samples/dgate/configure.h b/lib_acl/samples/dgate/configure.h new file mode 100644 index 000000000..0ecf1a828 --- /dev/null +++ b/lib_acl/samples/dgate/configure.h @@ -0,0 +1,32 @@ +#ifndef __CONFIGURE_INCLUDE_H__ +#define __CONFIGURE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DOMAIN_MAP { + char domain[256]; + ACL_ARGV *ip_list; + int idx; +} DOMAIN_MAP; + +extern char *var_cfg_allow_ip; +extern char *var_cfg_domains; +extern char *var_cfg_domain_unknown; +extern char *var_cfg_dns_name; +extern char *var_cfg_dns_ip; +extern char *var_cfg_dns_neighbor_ip; +extern int var_cfg_hijack_unknown; +extern int var_cfg_dns_neighbor_port; + +void conf_load(const char *filepath); +int host_allow(const char *ip); +DOMAIN_MAP *domain_map_find(const char *domain); +DOMAIN_MAP *domain_map_unknown(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/samples/dgate/dgate.cf b/lib_acl/samples/dgate/dgate.cf new file mode 100644 index 000000000..f67b6e911 --- /dev/null +++ b/lib_acl/samples/dgate/dgate.cf @@ -0,0 +1,31 @@ + +service server { +# 本地域名映射关系表,格式:域名1:ip11:ip12..., 域名2:ip21:ip22... +# domain_map = mailz.hexun.com:127.0.0.1:211.157.110.179:211.157.110.185, \ +# www1.sina.com:192.168.0.1:192.168.0.2:192.168.0.3, \ +# a.b.c:193.168.0.1:193.168.0.2:193.168.0.3 +# domain_map = all:192.168.1.1:192.168.1.2:192.168.1.3 + domain_map = m.hotmail.com:192.168.188.173, \ + blu405-m.hotmail.com:192.168.188.173, \ + 263esCom1.263es.com:192.168.198.47, \ + 263es.com:192.168.198.47, \ + i.163.com:127.0.0.1, \ + ex.qq.com:127.0.0.1, \ + #all:192.168.198.47 + +# 未知域名返回的缺省地址列表 +# domain_unknown = 211.157.110.179:211.157.110.185 + domain_unknown = 127.0.0.1 + +# 本 DNS 服务器的名称标识 + dns_name = acl_dgate + +# 本 DNS 服务器的 IP 地址 + dns_ip = 192.168.198.41 + +# 上游 DNS 服务器的 IP +# dns_neighbor_ip = 211.157.131.7 + dns_neighbor_ip = 192.168.198.47 +# 上游 DNS 服务器的 PORT + dns_neighbor_port = 53 +} diff --git a/lib_acl/samples/dgate/dgate_vc2012.vcxproj b/lib_acl/samples/dgate/dgate_vc2012.vcxproj new file mode 100644 index 000000000..fddfc65a7 --- /dev/null +++ b/lib_acl/samples/dgate/dgate_vc2012.vcxproj @@ -0,0 +1,384 @@ +锘 + + + + DebugDll + Win32 + + + DebugDll + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDll + Win32 + + + ReleaseDll + x64 + + + Release + Win32 + + + Release + x64 + + + + dgate + {9073FA9F-26A1-482C-91D0-876434C3E4EB} + dgate + Win32Proj + + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + .\ + Debug\ + true + + + true + .\ + .\Debug\ + + + .\ + Release\ + false + + + false + + + .\ + ReleaseDll\ + false + + + false + + + .\ + DebugDll\ + true + + + true + + + + Disabled + ..\..\include; ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)dgate.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)dgate.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)dgate.exe + ..\..\..\lib\win64;..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)dgate.pdb + Console + false + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012.lib;%(AdditionalDependencies) + $(OutDir)dgate.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + false + + MachineX86 + + + + + ..\..\include; ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012.lib;lib_protocol_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)dgate.exe + ..\..\..\lib\win64;..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + false + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)dgate.exe + true + Console + + + false + + MachineX86 + lib_acl.lib;%(AdditionalDependencies) + ..\..\..\dist\lib\win32 + + + + + ..\..\include; ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;VC2003;ACL_DLL;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)dgate.exe + true + Console + + + + + false + + + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\..\dist\lib\win64 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)dgate.exe + libc;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)dgate.pdb + Console + false + + MachineX86 + lib_acl_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32; + + + + + Disabled + ..\..\include; ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;VC2003;ACL_CPP_DLL;ACL_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)dgate.exe + libc;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)dgate.pdb + Console + false + + + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\dist\lib\win64 + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl/samples/dgate/dgate_vc2012.vcxproj.filters b/lib_acl/samples/dgate/dgate_vc2012.vcxproj.filters new file mode 100644 index 000000000..96d997382 --- /dev/null +++ b/lib_acl/samples/dgate/dgate_vc2012.vcxproj.filters @@ -0,0 +1,68 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl/samples/dgate/gateway_tcp.cpp b/lib_acl/samples/dgate/gateway_tcp.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/lib_acl/samples/dgate/main.cpp b/lib_acl/samples/dgate/main.cpp new file mode 100644 index 000000000..cb9eaa94b --- /dev/null +++ b/lib_acl/samples/dgate/main.cpp @@ -0,0 +1,54 @@ +// DnsGateway.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "configure.h" +#include "service_main.h" + +static SERVICE *__service; + +static char *__conf_file = "dgate.cf"; + +static void init(void) +{ + acl_socket_init(); + conf_load(__conf_file); + //acl_msg_open("dgate.log", "dgate"); + acl_msg_stdout_enable(1); + __service = service_create("0.0.0.0", 53, var_cfg_dns_neighbor_ip, + var_cfg_dns_neighbor_port); + printf("neighbor dns_ip: %s, dns_port: %d\r\n", + var_cfg_dns_neighbor_ip, var_cfg_dns_neighbor_port); +} + +static void run(void) +{ + service_start(__service); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -f conf_file\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + char ch; + + while ((ch = getopt(argc, argv, "hf:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'f': + __conf_file = acl_mystrdup(optarg); + break; + default: + break; + } + } + + init(); + run(); + return 0; +} diff --git a/lib_acl/samples/dgate/res_util.cpp b/lib_acl/samples/dgate/res_util.cpp new file mode 100644 index 000000000..c1363ab78 --- /dev/null +++ b/lib_acl/samples/dgate/res_util.cpp @@ -0,0 +1,26 @@ +#include "stdafx.h" +#include "rfc1035.h" +#include "util.h" + +ACL_ARGV *res_a_create(const rfc1035_rr *answer, int n) +{ + int i; + struct in_addr sin_addr; + ACL_ARGV *a; + char ip[32]; + + if (n <= 0) + return (NULL); + + a = acl_argv_alloc(n); + + for (i = 0; i < n; i++) { + if (answer[i].type == RFC1035_TYPE_A) { + memcpy(&sin_addr, answer[i].rdata, 4); + ACL_SAFE_STRNCPY(ip, inet_ntoa(sin_addr), sizeof(ip)); + acl_argv_add(a, ip, NULL); + } + } + + return (a); +} diff --git a/lib_acl/samples/dgate/rfc1035.cpp b/lib_acl/samples/dgate/rfc1035.cpp new file mode 100644 index 000000000..987798078 --- /dev/null +++ b/lib_acl/samples/dgate/rfc1035.cpp @@ -0,0 +1,838 @@ + +#include "stdafx.h" +#include /* for snprintf */ + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "rfc1035.h" + +#define RFC1035_MAXLABELSZ 63 +#define rfc1035_unpack_error 15 + +int rfc1035_errno; +const char *rfc1035_error_message; + +#if 0 +#define RFC1035_UNPACK_DEBUG acl_msg_error("unpack error at %s:%d", __FILE__,__LINE__) +#else +#define RFC1035_UNPACK_DEBUG (void)0 +#endif + +/* +* rfc1035HeaderPack() +* +* Packs a rfc1035_header structure into a buffer. +* Returns number of octets packed (should always be 12) +*/ +static int rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr) +{ + const char *myname = "rfc1035HeaderPack"; + int off = 0; + unsigned short s; + unsigned short t; + + if (sz < 12) + acl_msg_fatal("%s: sz(%d) < 12", myname, sz); + + s = htons(hdr->id); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + t = 0; + t |= hdr->qr << 15; + t |= (hdr->opcode << 11); + t |= (hdr->aa << 10); + t |= (hdr->tc << 9); + t |= (hdr->rd << 8); + t |= (hdr->ra << 7); + t |= hdr->rcode; + s = htons(t); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->qdcount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->ancount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->nscount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->arcount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + if (off != 12) + acl_msg_fatal("%s: off(%d) != 12", myname, off); + return off; +} + +/* +* rfc1035LabelPack() +* +* Packs a label into a buffer. The format of +* a label is one octet specifying the number of character +* bytes to follow. Labels must be smaller than 64 octets. +* Returns number of octets packed. +*/ +static int rfc1035LabelPack(char *buf, size_t sz, const char *label) +{ + const char *myname = "rfc1035LabelPack"; + int off = 0; + size_t len = label ? strlen(label) : 0; + + if (label) { + if (strchr(label, '.') != NULL) + acl_msg_fatal("%s: '.' exist in label(%s)", myname, label); + } + + if (len > RFC1035_MAXLABELSZ) + len = RFC1035_MAXLABELSZ; + if (sz < len + 1) + acl_msg_fatal("%s: sz(%d) < len(%d) + 1", myname, sz, len); + *(buf + off) = (char) len; + off++; + memcpy(buf + off, label, len); + off += (int) len; + return off; +} + +/* +* rfc1035NamePack() +* +* Packs a name into a buffer. Names are packed as a +* sequence of labels, terminated with NULL label. +* Note message compression is not supported here. +* Returns number of octets packed. +*/ +static int rfc1035NamePack(char *buf, size_t sz, const char *name) +{ + const char *myname = "rfc1035NamePack"; + int off = 0; + char *copy, *ptr; + char *t; + + copy = acl_mystrdup(name); + /* + * NOTE: use of strtok here makes names like foo....com valid. + */ + ptr = copy; + for (t = acl_mystrtok(&ptr, "."); t; t = acl_mystrtok(&ptr, ".")) + off += rfc1035LabelPack(buf + off, sz - off, t); + acl_myfree(copy); + off += rfc1035LabelPack(buf + off, sz - off, NULL); + if (off > (int) sz) + acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, sz); + return off; +} + +/* +* rfc1035QuestionPack() +* +* Packs a QUESTION section of a message. +* Returns number of octets packed. +*/ +static int rfc1035QuestionPack(char *buf, size_t sz, const char *name, + unsigned short type, unsigned short tclass) +{ + const char *myname = "rfc1035QuestionPack"; + int off = 0; + unsigned short s; + + off += rfc1035NamePack(buf + off, sz - off, name); + s = htons(type); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(tclass); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + if (off > (int) sz) + acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, sz); + + return off; +} + +/* +* rfc1035HeaderUnpack() +* +* Unpacks a RFC1035 message header buffer into the header fields +* of the rfc1035_message structure. +* +* Updates the buffer offset, which is the same as number of +* octects unpacked since the header starts at offset 0. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035HeaderUnpack(const char *buf, size_t sz, int *off, + rfc1035_message * h) +{ + const char *myname = "rfc1035HeaderUnpack"; + unsigned short s; + unsigned short t; + + if (*off != 0) + acl_msg_fatal("%s: *off(%d) != 0", myname, *off); + + /* + * The header is 12 octets. This is a bogus message if the size + * is less than that. + */ + if (sz < 12) + return 1; + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->id = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + t = ntohs(s); + h->qr = (t >> 15) & 0x01; + h->opcode = (t >> 11) & 0x0F; + h->aa = (t >> 10) & 0x01; + h->tc = (t >> 9) & 0x01; + h->rd = (t >> 8) & 0x01; + h->ra = (t >> 7) & 0x01; + /* + * We might want to check that the reserved 'Z' bits (6-4) are + * all zero as per RFC 1035. If not the message should be + * rejected. + */ + h->rcode = t & 0x0F; + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->qdcount = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->ancount = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->nscount = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->arcount = ntohs(s); + + if (*off != 12) + acl_msg_fatal("%s: *off(%d) != 12", myname, *off); + return 0; +} + +/* +* rfc1035NameUnpack() +* +* Unpacks a Name in a message buffer into a char*. +* Note 'buf' points to the beginning of the whole message, +* 'off' points to the spot where the Name begins, and 'sz' +* is the size of the whole message. 'name' must be allocated +* by the caller. +* +* Supports the RFC1035 message compression through recursion. +* +* Updates the new buffer offset. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035NameUnpack(const char *buf, size_t sz, int *off, + unsigned short *rdlength, char *name, size_t ns, int rdepth) +{ + const char *myname = "rfc1035NameUnpack"; + int no = 0; + unsigned char c; + size_t len; + + if (ns <= 0) + acl_msg_fatal("%s: ns(%d) <= 0", myname, ns); + do { + if (*off >= (int) sz) + acl_msg_fatal("%s: *off(%d) >= sz(%d)", myname, *off, sz); + c = *(buf + (*off)); + if (c > 191) { + /* blasted compression */ + unsigned short s; + int ptr; + if (rdepth > 64) /* infinite pointer loop */ + return 1; + memcpy(&s, buf + (*off), sizeof(s)); + s = ntohs(s); + (*off) += sizeof(s); + /* Sanity check */ + if ((*off) >= (int) sz) + return 1; + ptr = s & 0x3FFF; + /* Make sure the pointer is inside this message */ + if (ptr >= (int) sz) + return 1; + return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, + ns - no, rdepth + 1); + } else if (c > RFC1035_MAXLABELSZ) { + /* + * "(The 10 and 01 combinations are reserved for future use.)" + */ + return 1; + } else { + (*off)++; + len = (size_t) c; + if (len == 0) + break; + if (len > (ns - no - 1)) /* label won't fit */ + return 1; + if ((*off) + len >= sz) /* message is too short */ + return 1; + memcpy(name + no, buf + (*off), len); + (*off) += (int) len; + no += (int) len; + *(name + (no++)) = '.'; + if (rdlength) + *rdlength += (unsigned short) len + 1; + } + } while (c > 0 && no < (int) ns); + if (no) + *(name + no - 1) = '\0'; + else + *name = '\0'; + /* make sure we didn't allow someone to overflow the name buffer */ + if (no > (int) ns) + acl_msg_fatal("%s: no(%d) > ns(%d)", myname, no, ns); + return 0; +} + +/* +* rfc1035RRUnpack() +* +* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. +* The caller must free RR->rdata! +* +* Updates the new message buffer offset. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035RRUnpack(const char *buf, size_t sz, int *off, rfc1035_rr * RR) +{ + const char *myname = "rfc1035RRUnpack"; + unsigned short s; + unsigned int i; + unsigned short rdlength; + int rdata_off; + + if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) { + RFC1035_UNPACK_DEBUG; + memset(RR, '\0', sizeof(*RR)); + return 1; + } + /* + * Make sure the remaining message has enough octets for the + * rest of the RR fields. + */ + if ((*off) + 10 > (int) sz) { + RFC1035_UNPACK_DEBUG; + memset(RR, '\0', sizeof(*RR)); + return 1; + } + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + RR->type = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + RR->tclass = ntohs(s); + memcpy(&i, buf + (*off), sizeof(i)); + (*off) += sizeof(i); + RR->ttl = ntohl(i); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + rdlength = ntohs(s); + if ((*off) + rdlength > (int) sz) { + /* + * We got a truncated packet. 'dnscache' truncates UDP + * replies at 512 octets, as per RFC 1035. + */ + RFC1035_UNPACK_DEBUG; + memset(RR, '\0', sizeof(*RR)); + return 1; + } + RR->rdlength = rdlength; + switch (RR->type) { + case RFC1035_TYPE_PTR: + RR->rdata = (char*) acl_mymalloc(RFC1035_MAXHOSTNAMESZ); + rdata_off = *off; + RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */ + if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, + RR->rdata, RFC1035_MAXHOSTNAMESZ, 0)) + return 1; + if (rdata_off > ((*off) + rdlength)) { + /* + * This probably doesn't happen for valid packets, but + * I want to make sure that NameUnpack doesn't go beyond + * the RDATA area. + */ + RFC1035_UNPACK_DEBUG; + acl_myfree(RR->rdata); + memset(RR, '\0', sizeof(*RR)); + return 1; + } + break; + case RFC1035_TYPE_A: + default: + RR->rdata = (char*) acl_mymalloc(rdlength); + memcpy(RR->rdata, buf + (*off), rdlength); + break; + } + (*off) += rdlength; + if (*off > (int) sz) + acl_msg_fatal("%s: *off(%d) > sz(%d)", myname, *off, sz); + return 0; +} + +const char *rfc1035Strerror(int errnum) +{ + struct __ERRMSG{ + int errnum; + const char *msg; + }; + static const struct __ERRMSG errmsg[] = { + { 0, "No error condition" }, + { 1, "Format Error: The name server was unable to " + "interpret the query." }, + { 2, "Server Failure: The name server was " + "unable to process this query." }, + { 3, "Name Error: The domain name does not exist." }, + { 4, "Not Implemented: The name server does " + "not support the requested kind of query." }, + { 5, "Refused: The name server refuses to " + "perform the specified operation." }, + { rfc1035_unpack_error, "The DNS reply message is corrupt or could " + "not be safely parsed." }, + { -1, NULL }, + }; + const char *unknown = "Unknown Error"; + int i; + + for (i = 0; errmsg[i].msg != NULL; i++) { + if (errmsg[i].errnum == -errnum) + return (errmsg[i].msg); + } + + return (unknown); +} + +static void rfc1035SetErrno(int n) +{ + switch (rfc1035_errno = n) { + case 0: + rfc1035_error_message = "No error condition"; + break; + case 1: + rfc1035_error_message = "Format Error: The name server was " + "unable to interpret the query."; + break; + case 2: + rfc1035_error_message = "Server Failure: The name server was " + "unable to process this query."; + break; + case 3: + rfc1035_error_message = "Name Error: The domain name does " + "not exist."; + break; + case 4: + rfc1035_error_message = "Not Implemented: The name server does " + "not support the requested kind of query."; + break; + case 5: + rfc1035_error_message = "Refused: The name server refuses to " + "perform the specified operation."; + break; + case rfc1035_unpack_error: + rfc1035_error_message = "The DNS reply message is corrupt or could " + "not be safely parsed."; + break; + default: + rfc1035_error_message = "Unknown Error"; + break; + } +} + +static void rfc1035RRDestroy(rfc1035_rr * rr, int n) +{ + const char *myname = "rfc1035RRDestroy"; + + if (rr == NULL) + return; + if (n <= 0) + acl_msg_fatal("%s: n(%d) <= 0", myname, n); + while (n--) { + if (rr[n].rdata) + acl_myfree(rr[n].rdata); + } + acl_myfree(rr); +} + +/* +* rfc1035QueryUnpack() +* +* Unpacks a RFC1035 Query Record into 'query' from a message buffer. +* +* Updates the new message buffer offset. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035QueryUnpack(const char *buf, size_t sz, int *off, + rfc1035_query * query) +{ + unsigned short s; + + if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) { + RFC1035_UNPACK_DEBUG; + memset(query, '\0', sizeof(*query)); + return 1; + } + if (*off + 4 > (int) sz) { + RFC1035_UNPACK_DEBUG; + memset(query, '\0', sizeof(*query)); + return 1; + } + memcpy(&s, buf + *off, 2); + *off += 2; + query->qtype = ntohs(s); + memcpy(&s, buf + *off, 2); + *off += 2; + query->qclass = ntohs(s); + return 0; +} + +void rfc1035MessageDestroy(rfc1035_message * msg) +{ + if (!msg) + return; + if (msg->query) + acl_myfree(msg->query); + if (msg->answer) + rfc1035RRDestroy(msg->answer, msg->ancount); + acl_myfree(msg); +} + +/* +* rfc1035QueryCompare() +* +* Compares two rfc1035_query entries +* +* Returns 0 (equal) or !=0 (different) +*/ +int rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b) +{ + size_t la, lb; + + if (a->qtype != b->qtype) + return 1; + if (a->qclass != b->qclass) + return 1; + la = strlen(a->name); + lb = strlen(b->name); + if (la != lb) { + /* Trim root label(s) */ + while (la > 0 && a->name[la - 1] == '.') + la--; + while (lb > 0 && b->name[lb - 1] == '.') + lb--; + } + if (la != lb) + return 1; + + return strncasecmp(a->name, b->name, la); +} + +/* +* rfc1035MessageUnpack() +* +* Takes the contents of a DNS reply and fills in an array +* of resource record structures. The records array is allocated +* here, and should be freed by calling rfc1035RRDestroy(). +* +* Returns number of records unpacked, zero if DNS reply indicates +* zero answers, or an error number < 0. +*/ + +int rfc1035MessageUnpack(const char *buf, size_t sz, rfc1035_message ** answer) +{ + int off = 0; + int i; + int nr = 0; + rfc1035_message *msg; + rfc1035_rr *recs; + rfc1035_query *querys; + + msg = (rfc1035_message*) acl_mycalloc(1, sizeof(*msg)); + if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) { + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno(rfc1035_unpack_error); + acl_myfree(msg); + return -rfc1035_unpack_error; + } + rfc1035_errno = 0; + rfc1035_error_message = NULL; + i = (int) msg->qdcount; + if (i != 1) { + /* This can not be an answer to our queries.. */ + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno(rfc1035_unpack_error); + acl_myfree(msg); + return -rfc1035_unpack_error; + } + querys = msg->query = (rfc1035_query*) acl_mycalloc((int) msg->qdcount, sizeof(*querys)); + for (i = 0; i < (int) msg->qdcount; i++) { + if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) { + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno(rfc1035_unpack_error); + rfc1035MessageDestroy(msg); + return -rfc1035_unpack_error; + } + } + *answer = msg; + if (msg->rcode) { + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno((int) msg->rcode); + return -((int) msg->rcode); + } + if (msg->ancount == 0) + return 0; + recs = msg->answer = (rfc1035_rr*) acl_mycalloc((int) msg->ancount, sizeof(*recs)); + for (i = 0; i < (int) msg->ancount; i++) { + if (off >= (int) sz) { /* corrupt packet */ + RFC1035_UNPACK_DEBUG; + break; + } + if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */ + RFC1035_UNPACK_DEBUG; + break; + } + nr++; + } + if (nr == 0) { + /* + * we expected to unpack some answers (ancount != 0), but + * didn't actually get any. + */ + rfc1035MessageDestroy(msg); + *answer = NULL; + rfc1035SetErrno(rfc1035_unpack_error); + return -rfc1035_unpack_error; + } + + if (msg->nscount > 0) { + //rfc1035NSUnpack(buf, sz, &off); + } + + if (msg->arcount > 0) { + //rfc1035ARUnpack(buf, sz, &off); + } + return nr; +} + +/* +* rfc1035RRPack() +* +* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. +* The caller must free RR->rdata! +* +* Updates the new message buffer offset. +* +* Returns > 0 (success) or 0 (error) +*/ +static int rfc1035RRPack(const rfc1035_rr *RR, char *buf, size_t sz) +{ + const char *myname = "rfc1035RRPack"; + unsigned short s; + unsigned int i; + int off = 0, off_saved; + + off = rfc1035NamePack(buf + off, sz, RR->name); + s = htons(RR->type); + memcpy(buf + off, &s,sizeof(s)); + off += sizeof(s); + + s = htons(RR->tclass); + memcpy(buf + off, &s ,sizeof(s)); + off += sizeof(s); + + i = htonl(RR->ttl); + memcpy(buf + off, &i ,sizeof(i)); + off += sizeof(i); + + switch (RR->type) { + case RFC1035_TYPE_PTR: + case RFC1035_TYPE_NS: + if (strlen(RR->rdata) > RFC1035_MAXHOSTNAMESZ) + return (0); + off_saved = off; + off += sizeof(s); + off += rfc1035NamePack(buf + off, sz, RR->rdata); + s = off - off_saved - (unsigned short) sizeof(s); + s = htons(s); + memcpy(buf + off_saved, &s ,sizeof(s)); + break; + default: + s = htons(RR->rdlength); + memcpy(buf + off, &s ,sizeof(s)); + off += sizeof(s); + memcpy(buf + off, RR->rdata, RR->rdlength); + off += RR->rdlength; + break; + } + + if ((unsigned) off > sz) + acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, sz); + + return (off); +} + +ssize_t rfc1035BuildAReply(const char *hostname, const ACL_ARGV *ip_argv, + const char *dnsname, const char *dns_ip, + unsigned short qid, char *buf, size_t sz) +{ + rfc1035_message h; + rfc1035_rr rr; + size_t offset = 0; + unsigned int nip; + int i; + + memset(&h, '\0', sizeof(h)); + h.id = qid; + h.qr = 1; + h.opcode = 0; /* QUERY */ + h.aa = 0; + h.tc = 0; + h.rd = 1; + h.ra = 0; + h.rcode = 0; + h.qdcount = 1; + h.ancount = ip_argv->argc; + h.nscount = (dnsname && *dnsname) ? 1 : 0; + h.arcount = (h.nscount && dns_ip && *dns_ip) ? 1 : 0; + offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); + offset += rfc1035QuestionPack(buf + offset, sz - offset, hostname, + RFC1035_TYPE_A, RFC1035_CLASS_IN); + + for (i = 0; i < ip_argv->argc; i++) { + memset(&rr, 0, sizeof(rr)); + snprintf(rr.name, sizeof(rr.name), "%s", hostname); + rr.type = RFC1035_TYPE_A; + rr.tclass = RFC1035_CLASS_IN; + rr.ttl = 5; + rr.rdlength = 4; + nip = inet_addr(ip_argv->argv[i]); + rr.rdata = (char*) acl_mycalloc(1, rr.rdlength); + memcpy(rr.rdata, &nip, rr.rdlength); + offset += rfc1035RRPack(&rr, buf + offset, sz - offset); + acl_myfree(rr.rdata); + } + + if (h.nscount) { + memset(&rr, 0, sizeof(rr)); + snprintf(rr.name, sizeof(rr.name), "%s", dnsname); + rr.type = RFC1035_TYPE_NS; + rr.tclass = RFC1035_CLASS_IN; + rr.ttl = 5; + rr.rdlength = (unsigned short) strlen(dnsname); + rr.rdata = acl_mystrdup(dnsname); + offset += rfc1035RRPack(&rr, buf + offset, sz - offset); + acl_myfree(rr.rdata); + } + + if (h.arcount) { + memset(&rr, 0, sizeof(rr)); + snprintf(rr.name, sizeof(rr.name), "%s", dnsname); + rr.type = RFC1035_TYPE_NS; + rr.tclass = RFC1035_CLASS_IN; + rr.ttl = 5; + rr.rdlength = (unsigned short) strlen(dns_ip); + rr.rdata = acl_mystrdup(dns_ip); + offset += rfc1035RRPack(&rr, buf + offset, sz - offset); + acl_myfree(rr.rdata); + } + + return ((int) offset); +} +/* +* rfc1035BuildAQuery() +* +* Builds a message buffer with a QUESTION to lookup A records +* for a hostname. Caller must allocate 'buf' which should +* probably be at least 512 octets. The 'szp' initially +* specifies the size of the buffer, on return it contains +* the size of the message (i.e. how much to write). +* Returns the size of the query +*/ +ssize_t rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, + unsigned short qid, rfc1035_query * query) +{ + const char *myname = "rfc1035BuildAQuery"; + rfc1035_message h; + size_t offset = 0; + + memset(&h, '\0', sizeof(h)); + h.id = qid; + h.qr = 0; + h.rd = 1; + h.opcode = 0; /* QUERY */ + h.qdcount = (unsigned int) 1; + offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); + offset += rfc1035QuestionPack(buf + offset, sz - offset, hostname, + RFC1035_TYPE_A, RFC1035_CLASS_IN); + if (query) { + query->qtype = RFC1035_TYPE_A; + query->qclass = RFC1035_CLASS_IN; + ACL_SAFE_STRNCPY(query->name, hostname, sizeof(query->name)); + } + + if (offset > sz) + acl_msg_fatal("%s: offset(%d) > sz(%d)", myname, offset, sz); + return (ssize_t) offset; +} + +/* +* rfc1035BuildPTRQuery() +* +* Builds a message buffer with a QUESTION to lookup PTR records +* for an address. Caller must allocate 'buf' which should +* probably be at least 512 octets. The 'szp' initially +* specifies the size of the buffer, on return it contains +* the size of the message (i.e. how much to write). +* Returns the size of the query +*/ +ssize_t rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, + size_t sz, unsigned short qid, rfc1035_query * query) +{ + const char *myname = "rfc1035BuildPTRQuery"; + rfc1035_message h; + size_t offset = 0; + static char rev[32]; + unsigned int i; + + memset(&h, '\0', sizeof(h)); + i = (unsigned int) ntohl(addr.s_addr); + snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.", + i & 255, (i >> 8) & 255, (i >> 16) & 255, (i >> 24) & 255); + h.id = qid; + h.qr = 0; + h.rd = 1; + h.opcode = 0; /* QUERY */ + h.qdcount = (unsigned int) 1; + offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); + offset += rfc1035QuestionPack(buf + offset, sz - offset, rev, + RFC1035_TYPE_PTR, RFC1035_CLASS_IN); + if (query) { + query->qtype = RFC1035_TYPE_PTR; + query->qclass = RFC1035_CLASS_IN; + ACL_SAFE_STRNCPY(query->name, rev, sizeof(query->name)); + } + if (offset > sz) + acl_msg_fatal("%s: offset(%d) > sz(%d)", myname, offset, sz); + return (ssize_t) offset; +} + +/* +* We're going to retry a former query, but we +* just need a new ID for it. Lucky for us ID +* is the first field in the message buffer. +*/ +void rfc1035SetQueryID(char *buf, unsigned short qid) +{ + unsigned short s = htons(qid); + memcpy(buf, &s, sizeof(s)); +} diff --git a/lib_acl/samples/dgate/rfc1035.h b/lib_acl/samples/dgate/rfc1035.h new file mode 100644 index 000000000..85ba63e7a --- /dev/null +++ b/lib_acl/samples/dgate/rfc1035.h @@ -0,0 +1,77 @@ +#ifndef __MY_RFC1035_INCLUDE_H__ +#define __MY_RFC1035_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#endif + +/* rfc1035 - DNS */ +#define RFC1035_MAXHOSTNAMESZ 256 + +typedef struct rfc1035_rr { + char name[RFC1035_MAXHOSTNAMESZ]; + unsigned short type; + unsigned short tclass; /* class */ + unsigned int ttl; + unsigned short rdlength; + char *rdata; +} rfc1035_rr; + +typedef struct rfc1035_query { + char name[RFC1035_MAXHOSTNAMESZ]; + unsigned short qtype; + unsigned short qclass; +} rfc1035_query; + +typedef struct rfc1035_message { + unsigned short id; + unsigned int qr:1; + unsigned int opcode:4; + unsigned int aa:1; + unsigned int tc:1; + unsigned int rd:1; + unsigned int ra:1; + unsigned int rcode:4; + unsigned short qdcount; + unsigned short ancount; + unsigned short nscount; + unsigned short arcount; + rfc1035_query *query; + rfc1035_rr *answer; +} rfc1035_message; + +const char *rfc1035Strerror(int errnum); +ssize_t rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, + unsigned short qid, rfc1035_query * query); +ssize_t rfc1035BuildPTRQuery(const struct in_addr, char *buf, size_t sz, + unsigned short qid, rfc1035_query * query); +void rfc1035SetQueryID(char *, unsigned short qid); +int rfc1035MessageUnpack(const char *buf, size_t sz, + rfc1035_message ** answer); +int rfc1035QueryCompare(const rfc1035_query *, const rfc1035_query *); +void rfc1035MessageDestroy(rfc1035_message * message); +ssize_t rfc1035BuildAReply(const char *hostname, const ACL_ARGV *ip_argv, + const char *dnsname, const char *dns_ip, + unsigned short qid, char *buf, size_t sz); + +extern int rfc1035_errno; +extern const char *rfc1035_error_message; + +#define RFC1035_TYPE_A 1 +#define RFC1035_TYPE_NS 2 +#define RFC1035_TYPE_CNAME 5 +#define RFC1035_TYPE_PTR 12 +#define RFC1035_TYPE_AAAA 28 +#define RFC1035_CLASS_IN 1 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/samples/dgate/service_main.cpp b/lib_acl/samples/dgate/service_main.cpp new file mode 100644 index 000000000..bb52bc028 --- /dev/null +++ b/lib_acl/samples/dgate/service_main.cpp @@ -0,0 +1,112 @@ +#include "stdafx.h" +#include "service_main.h" + +void create_key(char *key, size_t size, char type, unsigned short id) +{ + const char *myname = "create_key"; + + if (type == SERVICE_CTX_TCP_REQUEST) + snprintf(key, size, "TCP:REQUEST:%d", id); + else if (type == SERVICE_CTX_TCP_RESPOND) + snprintf(key, size, "TCP:RESPOND:%d", id); + else if (type == SERVICE_CTX_UDP_REQUEST) + snprintf(key, size, "UDP:REQUEST:%d", id); + else if (type == SERVICE_CTX_UDP_RESPOND) + snprintf(key, size, "UDP:RESPOND:%d", id); + else + acl_msg_fatal("%s(%d): type(%d) invalid", + myname, __LINE__, type); +} + +SERVICE_CTX *service_ctx_new(SERVICE *service, ACL_ASTREAM *stream, + char type, unsigned short id) +{ + const char *myname = "service_ctx_new"; + SERVICE_CTX *ctx = (SERVICE_CTX*) acl_mycalloc(1, sizeof(SERVICE_CTX)); + + ctx->service = service; + ctx->stream = stream; + ctx->type = type; + ctx->id = id; + + create_key(ctx->key, sizeof(ctx->key), type, id); + + if (acl_htable_enter(service->table, ctx->key, ctx) == NULL) + acl_msg_fatal("%s(%d): enter to table error, key(%s)", + myname, __LINE__, ctx->key); + return (ctx); +} + +void service_ctx_free(SERVICE_CTX *ctx) +{ + acl_htable_delete(ctx->service->table, ctx->key, NULL); + acl_myfree(ctx); +} + +SERVICE_CTX *service_ctx_find(SERVICE *service, char type, unsigned int id) +{ + SERVICE_CTX *ctx; + char key[KEY_LEN]; + + create_key(key, sizeof(key), type, id); + ctx = (SERVICE_CTX*) acl_htable_find(service->table, key); + return (ctx); +} + +static int accept_callback(ACL_ASTREAM *client, void *context) +{ + SERVICE *service = (SERVICE*) context; + + service_tcp_main(client, service); + return (0); +} + +void service_start(SERVICE *service) +{ + while (1) + acl_aio_loop(service->aio); +} + +SERVICE *service_create(const char *local_ip, short local_port, + const char *dns_ip, short dns_port) +{ + const char *myname = "service_create"; + SERVICE *service; + ACL_VSTREAM *sstream; + char addr[64]; + + // 创建提供 TCP 方式查询时的监听流 + snprintf(addr, sizeof(addr), "%s:%d", local_ip, local_port); + sstream = acl_vstream_listen_ex(addr, 128, ACL_NON_BLOCKING, 1024, 10); + if (sstream == NULL) { + acl_msg_error("%s(%d): can't listen on addr(%s)", + myname, __LINE__, addr); + return (NULL); + } + + service = (SERVICE*) acl_mycalloc(1, sizeof(SERVICE)); + ACL_SAFE_STRNCPY(service->listen_addr, + addr, sizeof(service->listen_addr)); + ACL_SAFE_STRNCPY(service->dns_ip, dns_ip, sizeof(service->dns_ip)); + service->dns_port = dns_port; + snprintf(service->dns_addr, sizeof(service->dns_addr), + "%s:%d", dns_ip, dns_port); + service->conn_timeout = 10; + service->rw_timeout = 10; + + service->table = acl_htable_create(100, 0); + service->aio = acl_aio_create(ACL_EVENT_SELECT); + service->sstream = acl_aio_open(service->aio, sstream); + acl_aio_ctl(service->sstream, ACL_AIO_CTL_ACCEPT_FN, accept_callback, + ACL_AIO_CTL_CTX, service, ACL_AIO_CTL_END); + + acl_aio_accept(service->sstream); + service_udp_init(service, local_ip, local_port, dns_ip, dns_port); + return (service); +} + +void service_free(SERVICE *service) +{ + // XXX: aio have no free function + acl_myfree(service); +} diff --git a/lib_acl/samples/dgate/service_main.h b/lib_acl/samples/dgate/service_main.h new file mode 100644 index 000000000..1d9e030a6 --- /dev/null +++ b/lib_acl/samples/dgate/service_main.h @@ -0,0 +1,80 @@ +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SERVICE SERVICE; + +#define MAX_DOMAIN_LEN 256 + +struct SERVICE +{ + unsigned short curr_id; + ACL_HTABLE *table; + ACL_AIO *aio; + ACL_ASTREAM *sstream; + char listen_addr[256]; + char dns_addr[256]; + char dns_ip[32]; + short dns_port; + char type; +#define SERVICE_TYPE_UDP 0 +#define SERVICE_TYPE_TCP 1 + + int conn_timeout; + int rw_timeout; +}; + +#define KEY_LEN 64 +#define MAX_BUF 4096 + +typedef struct SERVICE_CTX +{ + ACL_ASTREAM *stream; + SERVICE *service; + char domain[256]; + char domain_root[256]; + char request_buf[MAX_BUF]; + int request_len; + char respond_buf[MAX_BUF]; + int respond_len; + unsigned short id; + unsigned short id_original; + unsigned short qtype; + char type; +#define SERVICE_CTX_TCP_REQUEST 0 +#define SERVICE_CTX_TCP_RESPOND 1 +#define SERVICE_CTX_UDP_REQUEST 2 +#define SERVICE_CTX_UDP_RESPOND 3 + char key[KEY_LEN]; + + struct sockaddr_in client_addr; + int client_addr_len; +} SERVICE_CTX; + +/* in service_main.cpp */ +void create_key(char *key, size_t size, char type, unsigned short id); +SERVICE_CTX *service_ctx_new(SERVICE *service, ACL_ASTREAM *stream, + char type, unsigned short id); +void service_ctx_free(SERVICE_CTX *ctx); +SERVICE_CTX *service_ctx_find(SERVICE *service, char type, unsigned int id); +void service_start(SERVICE *service); +SERVICE *service_create(const char *local_ip, short local_port, + const char *dns_ip, short dns_port); +void service_free(SERVICE *service); + +/* in service_tcp.cpp */ +void service_tcp_main(ACL_ASTREAM *client, SERVICE *service); + +/* in service_udp.cpp */ +void service_udp_init(SERVICE *service, const char *local_ip, int local_port, + const char *remote_ip, int remote_port); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/samples/dgate/service_tcp.cpp b/lib_acl/samples/dgate/service_tcp.cpp new file mode 100644 index 000000000..37fb9b9e9 --- /dev/null +++ b/lib_acl/samples/dgate/service_tcp.cpp @@ -0,0 +1,162 @@ +#include "stdafx.h" +#include "service_main.h" + +static int respond_data_callback(ACL_ASTREAM *astream acl_unused, + void *context, const char *data, int len) +{ + const char *myname = "respond_data_callback"; + SERVICE_CTX *respond_ctx = (SERVICE_CTX*) context; + SERVICE_CTX *request_ctx; + struct iovec chunks[2]; + unsigned short n; + int dlen; + char buf[MAX_BUF]; + + request_ctx = service_ctx_find(respond_ctx->service, + SERVICE_CTX_TCP_REQUEST, respond_ctx->id); + if (request_ctx == NULL) { + acl_msg_error("%s(%d): request client(%d) exit now", + myname, __LINE__, respond_ctx->id); + return (-1); + } + + n = htons(len); + dlen = len > MAX_BUF ? MAX_BUF : len; + memcpy(buf, data, dlen); + chunks[0].iov_base = &n; + chunks[0].iov_len = 2; + chunks[1].iov_base = buf; + chunks[1].iov_len = dlen; + acl_aio_writev(request_ctx->stream, chunks, 2); + acl_aio_iocp_close(request_ctx->stream); + return (-1); +} + +static int respond_len_callback(ACL_ASTREAM *astream, void *context, + char *data, int len acl_unused) +{ + const char *myname = "respond_len_callback"; + unsigned short n; + + n = ntohs(*(const unsigned short *) data); + if (n <= 0) { + acl_msg_error("%s(%d): n(%d) invalid", myname, __LINE__, n); + return (-1); + } + if (n > MAX_BUF) { + acl_msg_error("%s(%d): n(%d) too long", myname, __LINE__, n); + return (-1); + } + acl_aio_ctl(astream, + ACL_AIO_CTL_READ_HOOK_ADD, respond_data_callback, context, + ACL_AIO_CTL_END); + acl_aio_readn(astream, n); + return (0); +} + +static int write_request_callback(ACL_ASTREAM *astream, void *context) +{ + //SERVICE_CTX *ctx = (SERVICE_CTX*) context; + acl_aio_ctl(astream, + ACL_AIO_CTL_READ_HOOK_ADD, respond_len_callback, context, + ACL_AIO_CTL_END); + acl_aio_readn(astream, 2); + return (0); +} + +static int respond_connect_callback(ACL_ASTREAM *astream, void *context) +{ + SERVICE_CTX *ctx = (SERVICE_CTX*) context; + unsigned short len; + struct iovec chunks[2]; + + acl_aio_ctl(astream, + ACL_AIO_CTL_WRITE_HOOK_ADD, write_request_callback, context, + ACL_AIO_CTL_END); + len = htons(ctx->request_len); + chunks[0].iov_base = &len; + chunks[0].iov_len = 2; + chunks[1].iov_base = ctx->request_buf; + chunks[1].iov_len = ctx->request_len; + acl_aio_writev(astream, chunks, 2); + return (0); +} + +static int respond_close_callback(ACL_ASTREAM *astream acl_unused, void *context) +{ + SERVICE_CTX *ctx = (SERVICE_CTX*) context; + + service_ctx_free(ctx); + return (-1); +} + +static int request_data_callback(ACL_ASTREAM *astream acl_unused, void *context, + char *data, int len) +{ + const char *myname = "request_data_callback"; + SERVICE_CTX *request_ctx = (SERVICE_CTX*) context, *respond_ctx; + SERVICE *service = request_ctx->service; + ACL_ASTREAM *server; + + server = acl_aio_connect(service->aio, service->dns_addr, + service->conn_timeout); + if (server == NULL) { + acl_msg_error("%s(%d): connect dns(%s) error", + myname, __LINE__, service->dns_addr); + return (-1); + } + + respond_ctx = service_ctx_new(service, server, + SERVICE_CTX_TCP_RESPOND, request_ctx->id); // 与请求端共享同一ID + memcpy(respond_ctx->request_buf, data, len); + respond_ctx->request_len = len; + acl_aio_ctl(server, + ACL_AIO_CTL_CONNECT_HOOK_ADD, respond_connect_callback, respond_ctx, + ACL_AIO_CTL_CLOSE_HOOK_ADD, respond_close_callback, respond_ctx, + ACL_AIO_CTL_CTX, respond_ctx, + ACL_AIO_CTL_END); + return (0); +} + +static int request_len_callback(ACL_ASTREAM *astream, void *context, + char *data, int len acl_unused) +{ + const char *myname = "request_len_callback"; + //SERVICE_CTX *ctx = (SERVICE_CTX*) context; + unsigned short n; + + n = ntohs(*(const unsigned short *) data); + if (n <= 0) { + acl_msg_error("%s(%d): n(%d) invalid", myname, __LINE__, n); + return (-1); + } + acl_aio_ctl(astream, + ACL_AIO_CTL_READ_HOOK_ADD, request_data_callback, context, + ACL_AIO_CTL_END); + acl_aio_readn(astream, n); + return (0); +} + +static int request_close_callback(ACL_ASTREAM *astream acl_unused, void *context) +{ + SERVICE_CTX *ctx = (SERVICE_CTX*) context; + + service_ctx_free(ctx); + return (-1); +} + +void service_tcp_main(ACL_ASTREAM *client, SERVICE *service) +{ + //const char *myname = "service_tcp_main"; + SERVICE_CTX *ctx; + + ctx = service_ctx_new(service, client, SERVICE_CTX_TCP_REQUEST, + service->curr_id++); + acl_aio_ctl(client, + ACL_AIO_CTL_READ_HOOK_ADD, request_len_callback, ctx, + ACL_AIO_CTL_CLOSE_HOOK_ADD, request_close_callback, ctx, + ACL_AIO_CTL_TIMEOUT, service->rw_timeout, + ACL_AIO_CTL_CTX, ctx, + ACL_AIO_CTL_END); + acl_aio_readn(client, 2); // 读取两个字节 +} diff --git a/lib_acl/samples/dgate/service_udp.cpp b/lib_acl/samples/dgate/service_udp.cpp new file mode 100644 index 000000000..567e0c49b --- /dev/null +++ b/lib_acl/samples/dgate/service_udp.cpp @@ -0,0 +1,501 @@ +#include "stdafx.h" +#include "rfc1035.h" +#include "configure.h" +#include "service_main.h" + +#define UDP_READ_NONE 1 + +typedef struct UDP_CTX +{ + SERVICE *service; + char remote_ip[32]; + short remote_port; + char local_ip[32]; + short local_port; + + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + + // 临时变量用于传递参数 + struct sockaddr_in client_addr; + int client_addr_len; + + ACL_ASTREAM *stream_request; + ACL_ASTREAM *stream_respond; +} UDP_CTX; + +static int udp_read(ACL_SOCKET fd, void *buf, size_t size, + struct sockaddr_in *from_addr, int *from_addr_len) +{ + int ret; + +#ifdef ACL_UNIX + ret = recvfrom(fd, buf, size, 0, (struct sockaddr*) from_addr, + (socklen_t*) from_addr_len); +#else + ret = recvfrom(fd, (char*) buf, (int) size, 0, + (struct sockaddr*) from_addr, from_addr_len); +#endif + + return (ret); +} + +static int udp_write(ACL_SOCKET fd, const void *buf, size_t size, + struct sockaddr_in *to_addr, int to_addr_len) +{ + int ret; + +#ifdef ACL_UNIX + ret = sendto(fd, buf, size, 0, + (struct sockaddr*) to_addr, to_addr_len); +#else + ret = sendto(fd, (const char*) buf, (int) size, 0, + (struct sockaddr*) to_addr, to_addr_len); +#endif + + return (ret); +} + +static int request_read_fn(ACL_SOCKET fd, void *buf, size_t size, + int timeout acl_unused, ACL_VSTREAM *fp acl_unused, void *arg) +{ + const char *myname = "request_read_fn"; + UDP_CTX *ctx = (UDP_CTX*) arg; + int ret; + + ctx->client_addr_len = sizeof(ctx->client_addr); + ret = udp_read(fd, buf, size, &ctx->client_addr, + &ctx->client_addr_len); + if (ret < 0) { + acl_msg_error("%s(%d): recvfrom error(%s)", + myname, __LINE__, acl_last_serror()); + return (UDP_READ_NONE); + } + return (ret); +} + +static int respond_read_fn(ACL_SOCKET fd, void *buf, size_t size, + int timeout acl_unused, ACL_VSTREAM *fp acl_unused, void *arg) +{ + const char *myname = "respond_read_fn"; + UDP_CTX *ctx = (UDP_CTX*) arg; + struct sockaddr_in server_addr; + int ret, addr_len = sizeof(server_addr); + + ret = udp_read(fd, buf, size, &server_addr, &addr_len); + if (ret < 0) { + acl_msg_error("%s(%d): recvfrom error(%s)", + myname, __LINE__, acl_last_serror()); + } + if (server_addr.sin_addr.s_addr != ctx->remote_addr.sin_addr.s_addr) { + char ip[32]; + + acl_inet_ntoa(server_addr.sin_addr, ip, sizeof(ip)); + acl_msg_warn("%s(%d): invalid addr(%s) from server", + myname, __LINE__, ip); + return (UDP_READ_NONE); + } + return (ret); +} + +static int udp_write_fn(ACL_SOCKET fd acl_unused, const void *buf acl_unused, + size_t size acl_unused, int timeout acl_unused, + ACL_VSTREAM *fp acl_unused, void *arg acl_unused) +{ + const char *myname = "udp_write_fn"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (-1); +} + +#if 0 +static UDP_CTX *udp_ctx_new(const char *remote_ip, short remote_port, + const char *local_ip, short local_port) +{ + UDP_CTX *ctx = (UDP_CTX*) acl_mycalloc(1, sizeof(UDP_CTX)); + + ACL_SAFE_STRNCPY(ctx->remote_ip, remote_ip, sizeof(ctx->remote_ip)); + ctx->remote_port = remote_port; + ACL_SAFE_STRNCPY(ctx->local_ip, local_ip, sizeof(ctx->local_ip)); + ctx->local_port = local_port; + return (ctx); +} +#endif + +static ACL_VSTREAM *stream_udp_open(void) +{ + const char *myname = "stream_udp_open"; + ACL_VSTREAM *stream; + ACL_SOCKET fd; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d): socket create error", myname, __LINE__); + + stream = acl_vstream_fdopen(fd, O_RDWR, 1024, 0, ACL_VSTREAM_TYPE_SOCK); + return (stream); +} + +static ACL_VSTREAM *stream_udp_bind(struct sockaddr_in addr) +{ + const char *myname = "stream_udp_bind"; + ACL_VSTREAM *stream; + ACL_SOCKET fd; + + stream = stream_udp_open(); + fd = ACL_VSTREAM_SOCK(stream); + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) + acl_msg_fatal("%s(%d): can't bind", myname, __LINE__); + + return (stream); +} + +static ACL_ARGV *build_ip_list(DOMAIN_MAP *domain_map) +{ + ACL_ARGV *argv = acl_argv_alloc(10); + ACL_ARGV *ip_list = domain_map->ip_list; + int i, n; + + n = ip_list->argc; + if (domain_map->idx >= n) + domain_map->idx = 0; + i = domain_map->idx++; + + while (n-- > 0) { + acl_msg_info("\t%s", ip_list->argv[i]); + acl_argv_add(argv, ip_list->argv[i++], NULL); + if (i >= ip_list->argc) + i = 0; + } + + return (argv); +} + +static void reply_client_local(ACL_SOCKET fd, DOMAIN_MAP *domain_map, + SERVICE_CTX *service_ctx) +{ + char respond_buf[MAX_BUF]; + ACL_ARGV *ip_list; + int dlen; + + ip_list = build_ip_list(domain_map); + dlen = rfc1035BuildAReply(service_ctx->domain, + ip_list, + service_ctx->domain_root, + var_cfg_dns_ip, + service_ctx->id_original, + respond_buf, + sizeof(respond_buf)); + + acl_argv_free(ip_list); + + (void) udp_write(fd, respond_buf, dlen, &service_ctx->client_addr, + service_ctx->client_addr_len); +} + +static void debug_msg(const rfc1035_message* msg, int n) +{ + int i; + char ip[64]; + struct sockaddr_in saddr; + + for (i = 0; i < n; i++) { + if (msg->answer[i].type == RFC1035_TYPE_A) { + memcpy(&saddr.sin_addr, msg->answer[i].rdata, 4); + acl_inet_ntoa(saddr.sin_addr, ip, sizeof(ip)); + acl_msg_info("\t%s", ip); + } + } +} + +static void reply_client(ACL_SOCKET fd, char *buf, int dlen, + SERVICE_CTX *service_ctx) +{ + const char *myname = "reply_client"; + rfc1035_message *msg; + char respond_buf[MAX_BUF]; + int ret; + + // 先备份源数据 + memcpy(respond_buf, buf, dlen); + + ret = rfc1035MessageUnpack(buf, dlen, &msg); + + // 当上游 DNS 服务器返回域名不存在或出现错误时,若允许进行域名替换,则返回缺省地址 + if (var_cfg_hijack_unknown + && service_ctx->qtype == RFC1035_TYPE_A && ret == -3) + { + const char *domain_query = service_ctx->domain[0] + ? service_ctx->domain : NULL; + DOMAIN_MAP *domain_map= domain_map_unknown(); + ACL_ARGV *ip_list; + + acl_msg_error("%s(%d): rfc1035MessageUnpack error(%d)", + myname, __LINE__, ret); + + // 当解包失败时返回本地配置好的 IP 列表 + ip_list = build_ip_list(domain_map); + dlen = rfc1035BuildAReply( + domain_query ? domain_query : "unknown", + ip_list, + service_ctx->domain_root, + var_cfg_dns_ip, + service_ctx->id_original, + respond_buf, + sizeof(respond_buf)); + acl_argv_free(ip_list); + + acl_msg_info("%s(%d): respond my pkt: restore id=%d", + myname, __LINE__, service_ctx->id_original); + (void) udp_write(fd, respond_buf, dlen, + &service_ctx->client_addr, + service_ctx->client_addr_len); + } else { + // 恢复原ID, 需要转换成网络字节序 + unsigned short id_original; + + id_original = htons(service_ctx->id_original); + memcpy(respond_buf, &id_original, 2); + + debug_msg(msg, ret); + + acl_msg_info("%s(%d): reply to client, dlen=%d, id=%d, " + "ret=%d, domain(%s)", + myname, __LINE__, dlen, id_original, ret, + msg->query ? msg->query->name : "unknown"); + + rfc1035MessageDestroy(msg); + + (void) udp_write(fd, respond_buf, dlen, + &service_ctx->client_addr, + service_ctx->client_addr_len); + } +} + +static int read_respond_callback(ACL_ASTREAM *astream, void *context, + char *data, int len) +{ + const char *myname = "read_respond_callback"; + UDP_CTX *ctx = (UDP_CTX*) context; + SERVICE *service = ctx->service; + ACL_ASTREAM *client = ctx->stream_request; + ACL_VSTREAM *client_stream = acl_aio_vstream(client); + SERVICE_CTX *service_ctx; + unsigned short id; + char respond_buf[MAX_BUF]; + + if (len == UDP_READ_NONE) { + acl_aio_read(astream); + return (0); + } + + memcpy(&id, data, 2); + id = ntohs(id); + + service_ctx = service_ctx_find(service, SERVICE_CTX_UDP_REQUEST, id); + if (service_ctx == NULL) { + char key[KEY_LEN]; + + create_key(key, sizeof(key), SERVICE_CTX_UDP_REQUEST, id); + acl_msg_warn("%s(%d): not found id(%s)", + myname, __LINE__, key); + acl_aio_read(astream); + return (0); + } + + len = len > MAX_BUF ? MAX_BUF : len; + memcpy(respond_buf, data, len); + + reply_client(ACL_VSTREAM_SOCK(client_stream), respond_buf, + len, service_ctx); + + service_ctx_free(service_ctx); + acl_aio_read(astream); + return (0); +} + +static const char* get_query_type(int n) +{ + if (n == RFC1035_TYPE_A) + return "A"; + else if (n == RFC1035_TYPE_NS) + return "NS"; + else if (n == RFC1035_TYPE_CNAME) + return "CNAME"; + else if (n == RFC1035_TYPE_PTR) + return "PTR"; + else if (n == RFC1035_TYPE_AAAA) + return "AAA"; + else + return "UNKNOWN"; +} + +static void parse_query(const rfc1035_query *query, SERVICE_CTX *service_ctx) +{ + ACL_ARGV *argv; + + snprintf(service_ctx->domain, sizeof(service_ctx->domain), + "%s", query->name); + argv = acl_argv_split(service_ctx->domain, "."); + if (argv->argc >= 2) { + int i, k, size = sizeof(service_ctx->domain_root), n; + char *ptr = service_ctx->domain_root; + + k = argv->argc - 2; + for (i = k; i < argv->argc; i++) { + if (i > k) { + *ptr++ = '.'; + size--; + if (size <= 0) + break; + } + n = (int) strlen(argv->argv[i]); + ACL_SAFE_STRNCPY(ptr, argv->argv[i], size); + size -= n; + if (size <= 0) + break; + ptr += n; + } + } else { + ACL_SAFE_STRNCPY(service_ctx->domain_root, + var_cfg_dns_name, sizeof(service_ctx->domain_root)); + } + acl_argv_free(argv); + + service_ctx->qtype = query->qtype; + + acl_msg_info("type=%s(%d), class=%d", get_query_type(query->qtype), + query->qtype, query->qclass); +} + +static int read_request_callback(ACL_ASTREAM *astream, void *context, + char *data, int len) +{ + UDP_CTX *ctx = (UDP_CTX*) context; + SERVICE *service = ctx->service; + ACL_ASTREAM *server = ctx->stream_respond; + ACL_VSTREAM *server_stream = acl_aio_vstream(server); + ACL_VSTREAM *client_stream = acl_aio_vstream(astream); + SERVICE_CTX *service_ctx; + rfc1035_message *msg; + unsigned short id; + int ret; + + if (len == UDP_READ_NONE) { + acl_aio_read(astream); + return (0); + } + + service_ctx = service_ctx_new(ctx->service, astream, + SERVICE_CTX_UDP_REQUEST, service->curr_id++); + + if (service->curr_id == (unsigned short) -1) + service->curr_id = 0; + + ret = rfc1035MessageUnpack(data, len, &msg); + if (ret >= 0) { + if (msg->query) + parse_query(msg->query, service_ctx); + + rfc1035MessageDestroy(msg); + } + + memcpy(&service_ctx->client_addr, &ctx->client_addr, + ctx->client_addr_len); + service_ctx->client_addr_len = ctx->client_addr_len; + // 备份原ID , 且以主机字节序存储 + memcpy(&service_ctx->id_original, data, 2); + service_ctx->id_original = ntohs(service_ctx->id_original); + acl_msg_info("id_original=%d", service_ctx->id_original); + + acl_msg_info(">>> query %s, type(%d) %s: ", service_ctx->domain, + service_ctx->qtype, get_query_type(service_ctx->qtype)); + + // 仅处理 A 记录 + if (service_ctx->qtype == RFC1035_TYPE_A) { + DOMAIN_MAP *domain_map; + + // 先查询本地域名映射中是否存在对应域名 + domain_map = domain_map_find(service_ctx->domain); + if (domain_map) { + reply_client_local( + ACL_VSTREAM_SOCK(client_stream), + domain_map, + service_ctx); + return (0); + } + } + + // 如果非 A 记录且本地域名映射表中不存在该域名,则需要转发请求给上游 DNS 服务器 + + service_ctx->request_len = len > MAX_BUF ? MAX_BUF : len; + memcpy(service_ctx->request_buf, data, len); + id = htons(service_ctx->id); + memcpy(service_ctx->request_buf, &id, 2); + + acl_msg_info("request one key=%s, request_len=%d, len=%d", + service_ctx->key, service_ctx->request_len, len); + + // 向上游 DNS 服务器转发请求包,收到响应后 read_respond_callback 将被回调 + (void) udp_write(ACL_VSTREAM_SOCK(server_stream), + service_ctx->request_buf, service_ctx->request_len, + &ctx->remote_addr, sizeof(ctx->remote_addr)); + + acl_aio_read(astream); + return (0); +} + +void service_udp_init(SERVICE *service, const char *local_ip, + int local_port, const char *remote_ip, int remote_port) +{ + UDP_CTX *ctx = (UDP_CTX*) acl_mycalloc(1, sizeof(UDP_CTX)); + struct sockaddr_in addr; + ACL_VSTREAM *stream; + + ctx->service = service; + + ACL_SAFE_STRNCPY(ctx->local_ip, local_ip, sizeof(ctx->local_ip)); + ctx->local_port = local_port; + ctx->local_addr.sin_addr.s_addr = inet_addr(local_ip); + ctx->local_addr.sin_port = htons(local_port); + ctx->local_addr.sin_family = AF_INET; + + ACL_SAFE_STRNCPY(ctx->remote_ip, remote_ip, sizeof(ctx->remote_ip)); + ctx->remote_port = remote_port; + ctx->remote_addr.sin_addr.s_addr = inet_addr(remote_ip); + ctx->remote_addr.sin_port = htons(remote_port); + ctx->remote_addr.sin_family = AF_INET; + + // 创建接收客户端请求的流 + stream = stream_udp_bind(ctx->local_addr); + acl_vstream_ctl(stream, + ACL_VSTREAM_CTL_READ_FN, request_read_fn, + ACL_VSTREAM_CTL_WRITE_FN, udp_write_fn, + ACL_VSTREAM_CTL_CONTEXT, ctx, + ACL_VSTREAM_CTL_END); + + ctx->stream_request = acl_aio_open(service->aio, stream); + acl_aio_ctl(ctx->stream_request, + ACL_AIO_CTL_READ_HOOK_ADD, read_request_callback, ctx, + ACL_AIO_CTL_CTX, ctx, + ACL_AIO_CTL_END); + acl_aio_read(ctx->stream_request); + + // 创建接收服务端响应的流 + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + + stream = stream_udp_bind(addr); + acl_vstream_ctl(stream, + ACL_VSTREAM_CTL_READ_FN, respond_read_fn, + ACL_VSTREAM_CTL_WRITE_FN, udp_write_fn, + ACL_VSTREAM_CTL_CONTEXT, ctx, + ACL_VSTREAM_CTL_END); + + ctx->stream_respond = acl_aio_open(service->aio, stream); + acl_aio_ctl(ctx->stream_respond, + ACL_AIO_CTL_READ_HOOK_ADD, read_respond_callback, ctx, + ACL_AIO_CTL_CTX, ctx, + ACL_AIO_CTL_END); + acl_aio_read(ctx->stream_respond); +} diff --git a/lib_acl/samples/dgate/start.sh b/lib_acl/samples/dgate/start.sh new file mode 100644 index 000000000..7df4b433d --- /dev/null +++ b/lib_acl/samples/dgate/start.sh @@ -0,0 +1,2 @@ +#!/bin/sh +nohup ./dgate -i 59.151.31.137 & diff --git a/lib_acl/samples/dgate/stdafx.cpp b/lib_acl/samples/dgate/stdafx.cpp new file mode 100644 index 000000000..348bb1940 --- /dev/null +++ b/lib_acl/samples/dgate/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// cgi_upload.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl/samples/dgate/stdafx.h b/lib_acl/samples/dgate/stdafx.h new file mode 100644 index 000000000..6abc595ea --- /dev/null +++ b/lib_acl/samples/dgate/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 +#include "lib_acl.h" +#if defined(_WIN32) || defined(_WIN64) +#define snprintf _snprintf +#endif diff --git a/lib_acl/samples/dgate/stop.sh b/lib_acl/samples/dgate/stop.sh new file mode 100644 index 000000000..6e137dfb4 --- /dev/null +++ b/lib_acl/samples/dgate/stop.sh @@ -0,0 +1,3 @@ +#!/bin/sh +killall -9 dgate + diff --git a/lib_acl/samples/dgate/util.h b/lib_acl/samples/dgate/util.h new file mode 100644 index 000000000..0ce24da37 --- /dev/null +++ b/lib_acl/samples/dgate/util.h @@ -0,0 +1,15 @@ +#ifndef __DGATE_UTIL_INCLUDE_H__ +#define __DGATE_UTIL_INCLUDE_H__ + +#include "lib_acl.h" +#ifdef __cplusplus +extern "C" { +#endif + +ACL_ARGV *res_a_create(const rfc1035_rr *answer, int n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/code/acl_urlcode.c b/lib_acl/src/code/acl_urlcode.c index 6cdd31565..83fbf2e0e 100644 --- a/lib_acl/src/code/acl_urlcode.c +++ b/lib_acl/src/code/acl_urlcode.c @@ -11,42 +11,36 @@ #endif -static unsigned char hex_enc_table[] = "0123456789ABCDEF"; +static unsigned char enc_tab[] = "0123456789ABCDEF"; char *acl_url_encode(const char *str) { - const char *myname = "acl_url_encode"; register int i, j, len, tmp_len; unsigned char *tmp; len = (int) strlen(str); tmp_len = len; - tmp = (unsigned char*) acl_mymalloc(len+1); - if (tmp == NULL) - acl_msg_fatal("%s(%d): malloc error", myname, __LINE__); + tmp = (unsigned char*) acl_mymalloc(len + 1); for (i = 0, j = 0; i < len; i++, j++) { - tmp[j] = (unsigned char)str[i]; + tmp[j] = (unsigned char) str[i]; if (tmp[j] == ' ') tmp[j] = '+'; else if (!isalnum(tmp[j]) && strchr("_-.", tmp[j]) == NULL) { tmp_len += 3; tmp = acl_myrealloc(tmp, tmp_len); - if (!tmp) - acl_msg_fatal("%s(%d): realloc error", myname, __LINE__); tmp[j++] = '%'; - tmp[j++] = hex_enc_table[(unsigned char)str[i] >> 4]; - tmp[j] = hex_enc_table[(unsigned char)str[i] & 0x0F]; + tmp[j++] = enc_tab[(unsigned char)str[i] >> 4]; + tmp[j] = enc_tab[(unsigned char)str[i] & 0x0F]; } } tmp[j] = '\0'; - - return ((char*) tmp); + return (char*) tmp; } -static unsigned char hex_dec_table[256] = { +static unsigned char dec_tab[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -67,34 +61,39 @@ static unsigned char hex_dec_table[256] = { char *acl_url_decode(const char *str) { - const char *myname = "acl_url_decode"; char *tmp; register int i, len, pos = 0; len = (int) strlen(str); tmp = (char *) acl_mymalloc(len + 1); - if (tmp == NULL) - acl_msg_fatal("%s(%d): malloc error", myname, __LINE__); for (i = 0; i < len; i++) { - /* If we found a '%' character, then the next two are the character - * hexa code. Converting a hexadecimal code to their decimal is easy: - * The first character needs to be multiplied by 16 ( << 4 ), and the + /* If we found a '%' character, then the next two are + * the character hexa code. Converting a hexadecimal + * code to their decimal is easy: The first character + * needs to be multiplied by 16 ( << 4 ), and the * another one we just get the value from hextable variable */ - if ((str[i] == '%') && isalnum(str[i+1]) && isalnum(str[i+2])) { - tmp[pos] = (hex_dec_table[(unsigned char) str[i+1]] << 4) - + hex_dec_table[(unsigned char) str[i+2]]; - i += 2; - } else if (str[i] == '+') + if (str[i] == '+') tmp[pos] = ' '; - else + else if (str[i] != '%') + tmp[pos] = str[i]; + else if (i + 2 >= len) { /* check boundary */ + tmp[pos++] = '%'; /* keep it */ + if (++i >= len) + break; + tmp[pos] = str[i]; + break; + } else if (isalnum(str[i + 1]) && isalnum(str[i + 2])) { + tmp[pos] = (dec_tab[(unsigned char) str[i + 1]] << 4) + + dec_tab[(unsigned char) str[i + 2]]; + i += 2; + } else tmp[pos] = str[i]; pos++; } tmp[pos] = '\0'; - - return (tmp); + return tmp; } diff --git a/lib_acl_cpp/changes.txt b/lib_acl_cpp/changes.txt index ac35fd45e..b80573c3b 100644 --- a/lib_acl_cpp/changes.txt +++ b/lib_acl_cpp/changes.txt @@ -1,6 +1,15 @@ 修改历史列表: ------------------------------------------------------------------------ +325) 2015.7.13 +325.1) sample: 增加示例 samples/redis/redis_geo 用来测试地理信息模块类 redis_geo + +324) 2015.7.11-12 +324.1) feature: 增加了 redis_geo 类,用于支持 redis 地理位置信息处理功能 + +323) 2015.7.6 +323.1) feature: HttpServlet 类增加了自动判断是否需要与客户端保持长连接的方法 + 322) 2015.7.4 322.1) feature: http_client 类增加了 get_range 方法,用于数据断点续传过程中 322.2) feature: HttpServletRequest 类增加了 getRange 方法用于数据断点续传过程中 diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp index 7b135724d..f7ec96064 100644 --- a/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp +++ b/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp @@ -140,7 +140,7 @@ public: /** * 当 HTTP 请求为 OPTION 方式时的虚函数 */ - virtual bool doOption(HttpServletRequest&, HttpServletResponse&) + virtual bool doOptions(HttpServletRequest&, HttpServletResponse&) { logger_error("child not implement doPurge yet!"); return false; diff --git a/lib_acl_cpp/include/acl_cpp/http/http_header.hpp b/lib_acl_cpp/include/acl_cpp/http/http_header.hpp index e788a57db..75019a4bd 100644 --- a/lib_acl_cpp/include/acl_cpp/http/http_header.hpp +++ b/lib_acl_cpp/include/acl_cpp/http/http_header.hpp @@ -143,6 +143,14 @@ public: */ http_header& set_keep_alive(bool on); + /** + * 检查当前头是否设置了保持长连接选项 + */ + bool get_keep_alive() const + { + return keep_alive_; + } + /** * 向 HTTP 头中添加 cookie * @param name {const char*} cookie 名 @@ -346,7 +354,6 @@ public: */ http_header& set_cgi_mode(bool on); -protected: private: //char* domain_; // HTTP 服务器域名 //unsigned short port_; // HTTP 服务器端口 diff --git a/lib_acl_cpp/include/acl_cpp/lib_acl.hpp b/lib_acl_cpp/include/acl_cpp/lib_acl.hpp index 865553f0c..89b45f3cf 100644 --- a/lib_acl_cpp/include/acl_cpp/lib_acl.hpp +++ b/lib_acl_cpp/include/acl_cpp/lib_acl.hpp @@ -154,6 +154,7 @@ #include "acl_cpp/redis/redis_cluster.hpp" #include "acl_cpp/redis/redis_slot.hpp" #include "acl_cpp/redis/redis_node.hpp" +#include "acl_cpp/redis/redis_geo.hpp" #include "acl_cpp/redis/redis.hpp" #include "acl_cpp/disque/disque.hpp" diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis.hpp index a65e1b1e6..368c59e31 100644 --- a/lib_acl_cpp/include/acl_cpp/redis/redis.hpp +++ b/lib_acl_cpp/include/acl_cpp/redis/redis.hpp @@ -13,6 +13,7 @@ #include "acl_cpp/redis/redis_transaction.hpp" #include "acl_cpp/redis/redis_zset.hpp" #include "acl_cpp/redis/redis_cluster.hpp" +#include "acl_cpp/redis/redis_geo.hpp" namespace acl { @@ -37,6 +38,7 @@ class ACL_CPP_API redis , public redis_transaction , public redis_zset , public redis_cluster + , public redis_geo { public: redis(redis_client* conn = NULL); diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_geo.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_geo.hpp new file mode 100644 index 000000000..98697d25c --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_geo.hpp @@ -0,0 +1,330 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/redis/redis_command.hpp" + +namespace acl +{ + +#define GEO_INVALID 360 +#define GEO_LONGITUDE_MIN -180 +#define GEO_LONGITUDE_MAX 180 +#define GEO_LATITUDE_MIN -85.05112878 +#define GEO_LATITUDE_MAX 85.05112878 + +enum +{ + GEO_UNIT_FT, + GEO_UNIT_M, + GEO_UNIT_MI, + GEO_UNIT_KM, +}; + +enum +{ + GEO_WITH_COORD = 1 << 0, + GEO_WITH_DIST = 1 << 1, + GEO_WITH_HASH = 1 << 2, +}; + +enum +{ + GEO_SORT_NONE, + GEO_SORT_ASC, + GEO_SORT_DESC, +}; + +class ACL_CPP_API geo_member +{ +public: + geo_member(const char* name); + geo_member(const geo_member& member); + ~geo_member(); + + void set_name(const char* name); + const char* get_name() const + { + return name_.c_str(); + } + + void set_dist(double dist); + double get_dist() const + { + return dist_; + } + +#if defined(_WIN32) || defined(_WIN64) + void set_hash(__int64 hash); + __int64 get_hash() const +#else + void set_hash(long long int hash); + long long int get_hash() const +#endif // defined(_WIN32) || defined(_WIN64) + { + return hash_; + } + + void set_coordinate(double longitude, double latitude); + double get_longitude() const + { + return longitude_; + } + + double get_latitude() const + { + return latitude_; + } + +private: + string name_; + double dist_; +#if defined(_WIN32) || defined(_WIN64) + __int64 hash_; +#else + long long int hash_; +#endif // defined(_WIN32) || defined(_WIN64) + + double longitude_; + double latitude_; +}; + +class redis_client; + +class ACL_CPP_API redis_geo : virtual public redis_command +{ +public: + /** + * see redis_command::redis_command() + */ + redis_geo(); + + /** + * see redis_command::redis_command(redis_client*) + */ + redis_geo(redis_client* conn); + + /** + * see redis_command::redis_command(redis_client_cluster*, size_t) + */ + redis_geo(redis_client_cluster* cluster, size_t max_conns); + virtual ~redis_geo(); + + ///////////////////////////////////////////////////////////////////// + + /** + * 添加一个指定的地理位置坐标至指定的 key 中 + * Add the specified geospatial item (latitude, logitude, name) + * to the specified key. + * @param key {const char*} 对应的键值 + * the specified key + * @param member {const char*} 该地理坐标的标识符 + * the geospatial's identifier + * @param loginitude {double} 经度 + * the geospatial's loginitude + * @param latitude {double} 纬度 + * the geospatial's latitude + * @return {int} 1:添加成功,0:该地理坐标标识符已存在,即使对其值进行了修改, + * 也将返回 0,-1:表示出错。 + * the return value as below: + * 1: add one new member successfully + * 0: the member already existed, and the geospatial may be changed + * -1: some erro happened + */ + int geoadd(const char* key, const char* member, + double longitude, double latitude); + + /** + * 给指定 key 添加一组地址位置坐标数据 + * Add the specified geospatial items (latitude, logitude, name) + * to the specified key. + * @param key {const char*} 对应的键值 + * the specified key + * @param size {size_t} 数组的长度 + * the array's size + * @param memebers {const char* []} 成员数组,其长度由 size 指定 + * the members array, which's length was specified by size parameter + * @param longitudes {const double[]} 经度数据数组,其长度由 size 指定 + * the logintitudes array, which's length was specifed by size parameter + * @param latitudes {const double[]} 纬度数据数组,其长度由 size 指定 + * the lattitudes array, which's length was specifed by size parameter + * @return {int} 添加成功的成员数量,返回值含义如下: + * return the successfully added members's count: + * > 0: 表示成功添加的成员数量; + * represent the successfully added memebers's count + * 0: 这些成员都已经存在 + * the members's belong the key already existing + * -1: 表示出错,可以通过 result_error 函数查看出错原因 + * some error happened, the result_error function can be used + * to find the error's reason + */ + int geoadd(const char* key, size_t size, const char* memebers[], + const double longitudes[], const double latitudes[]); + + /** + * 给指定 key 添加一组地址位置坐标数据 + * Add the specified geospatial items (latitude, logitude, name) + * to the specified key. + * @param key {const char*} 对应的键值 + * the specified key + * @param memebers {const std::vector&} 成员数组 + * the members array + * @param longitudes {const std::vector&} 经度数据数组 + * the logintitudes array + * @param latitudes {const std::vector&} 纬度数据数组 + * the lattitudes array + * @return {int} 添加成功的成员数量,返回值含义如下: + * return the successfully added members's count: + * > 0: 表示成功添加的成员数量; + * represent the successfully added memebers's count + * 0: 这些成员都已经存在 + * the members's belong the key already existing + * -1: 表示出错,可以通过 result_error 函数查看出错原因 + * some error happened, the result_error function can be used + * to find the error's reason + * 注意:三个数组(members, longitudes, latitudes)的数组长度必须相等 + * Notice: the three array's length must be equal between members, + * longitudes and latitudes + */ + int geoadd(const char* key, const std::vector& members, + const std::vector& longitudes, + const std::vector& latitudes); + + /** + * 以字符串方式返回指定成员的 GEOHASH 值 + * Returns members of a geospatial index as standard geohash strings. + * @param key {const char*} 对应的键值 + * the specified key + * @param memebers {const std::vector&} 成员数组 + * the members array + * @param results {std::vector&} 存储结果集合 + * store the result + * @return {bool} 操作是否成功 + * if the operation was successful. + */ + bool geohash(const char* key, const std::vector& members, + std::vector& results); + + /** + * 以字符串方式返回指定成员的 GEOHASH 值 + * Returns members of a geospatial index as standard geohash strings. + * @param key {const char*} 对应的键值 + * the specified key + * @param memeber {const char*} 成员名 + * the member of a geospatial index + * @param result {std::vector&} 存储结果 + * store the result + * @return {bool} 操作是否成功 + * if the operation was successful. + */ + bool geohash(const char* key, const char* member, string& result); + + /** + * 获得指定成员的地理位置坐标 + * Returns longitude and latitude of members of a geospatial index + * @param key {const char*} 对应的键值 + * the specified key + * @param memebers {const std::vector&} 成员数组 + * the members array + * @param results {std::vector >&} 存储结果集 + * store the results + * @return {bool} 操作是否成功 + * if the operation was successful. + */ + bool geopos(const char* key, const std::vector& members, + std::vector >& results); + + /** + * 获得某个指定成员的地理位置坐标 + * Returns longitude and latitude of the one member of + * a geospatial index + * @param key {const char*} 指定键值 + * the specifed key + * @param member {const char*} 指定成员名 + * the specified member + * @param result {std::pair&} 存储坐标点结果 + * store the result of longitude and latitude of the member + * @return {bool} 操作是否成功 + * if the operation was successful. + */ + bool geopos(const char* key, const char* member, + std::pair& result); + + /** + * 获得两个地理位置坐标之间的距离 + * Returns the distance between two members of a geospatial index + * @param key {const char*} 对应的键值 + * the specified key + * @param member1 {const char*} 地理坐标成员 + * one member of a geospatial index + * @param member2 {const char*} 地理坐标成员 + * another member of a geospatial index + * @param unit {int} 返回的距离的单位值 + * @return {double} 两个坐标之间的长度,返回值 < 0 表示出错 + * returns the distance between two members, which was less than 0 + * if some error happened. + */ + double geodist(const char* key, const char* member1, + const char* member2, int unit = GEO_UNIT_M); + + /** + * 获得距离某指定坐标位置在给定距离范围内的所有坐标点 + * Query a sorted set representing a geospatial index to fetch + * members matching a given maximum distance from a point + * @param key {const char*} 对应的键值 + * the specified key + * @param longitude {double} 指定坐标点的经度值 + * the longitude of the specified geospatial coordinate + * @param latitude {double} 指定坐标点的纬度值 + * the latitude of the specified geospatial coordinate + * @param radius {double} 限定的距离范围大小 + * the distance from the specified coordinate + * @param unit {int} radius 距离的单位类型 + * the unit type of the raidus + * @param with {int} 查询条件选项,参见上面的定义:GEO_WITH_XXX + * the serach operations, defined as GEO_WITH_XXX above + * @param sort {int} 查询结果的排序方式,定义参见:GEO_SORT_XXX + * the sorted type of the results, defined as GEO_SORT_XXX above + * @return {const std::vector&} 符合条件的坐标点的结果集 + * Returns the results according the searching conditions. + */ + const std::vector& georadius(const char* key, + double longitude, double latitude, double radius, + int unit = GEO_UNIT_M, + int with = GEO_WITH_COORD | GEO_WITH_DIST, + int sort = GEO_SORT_ASC); + + /** + * 获得距离某指定坐标位置在给定距离范围内的所有坐标点 + * Query a sorted set representing a geospatial index to fetch + * members matching a given maximum distance from a member + * @param key {const char*} 对应的键值 + * the specified key + * @param member {const char*} 某个指定的坐标点成员 + * the specified member of a geospatial index + * @param radius {double} 限定的距离范围大小 + * the distance from the specified coordinate + * @param unit {int} radius 距离的单位类型 + * the unit type of the raidus + * @param with {int} 查询条件选项,参见上面的定义:GEO_WITH_XXX + * the serach operations, defined as GEO_WITH_XXX above + * @param sort {int} 查询结果的排序方式,定义参见:GEO_SORT_XXX + * the sorted type of the results, defined as GEO_SORT_XXX above + * @return {const std::vector&} 符合条件的坐标点的结果集 + * Returns the results according the searching conditions. + */ + const std::vector& georadiusbymember(const char* key, + const char* member, double radius, + int unit = GEO_UNIT_M, + int with = GEO_WITH_COORD | GEO_WITH_DIST, + int sort = GEO_SORT_ASC); + +private: + std::vector positions_; + + void add_one_pos(const redis_result& rr); + static const char* get_unit(int unit); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp index ba1a0c2b3..ba1e3ea70 100644 --- a/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_result.hpp @@ -81,6 +81,15 @@ public: */ long long int get_integer64(bool* success = NULL) const; + /** + * 当返回值为 REDIS_RESULT_STRING 类型时,本方法返回对应的 double 类型值 + * get the double value for REDIS_RESULT_STRING result + * @param success {bool*} 本指针非 NULL 时记录操作过程是否成功 + * when not NULL, storing the status of success + * @return {double} + */ + double get_double(bool* success = NULL) const; + /** * 当返回值为 REDIS_RESULT_STATUS 类型时,本方法返回状态信息 * get operation status for REDIS_RESULT_STATUS result diff --git a/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj b/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj index 2f6a28017..b5b945c27 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj @@ -745,6 +745,9 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + @@ -1270,6 +1273,9 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj b/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj index 912b67c5f..01beaf22c 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj @@ -825,6 +825,10 @@ RelativePath=".\src\redis\redis_connection.cpp" > + + @@ -1487,6 +1491,10 @@ RelativePath=".\include\acl_cpp\redis\redis_connection.hpp" > + + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj index e791f9a32..e73b92538 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj @@ -297,6 +297,7 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + @@ -443,6 +444,7 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + @@ -532,4 +534,4 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y - + \ No newline at end of file diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters index 1785c4cda..a0b56a38a 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters @@ -469,6 +469,9 @@ src\disque + + src\redis + @@ -963,6 +966,9 @@ include\disque + + include\redis + @@ -1081,4 +1087,4 @@ {8cd1597f-0491-4bb1-81d1-4a8e9f30edf5} - + \ No newline at end of file diff --git a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj index 31a532f0c..7d9fae572 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj @@ -174,7 +174,7 @@ Disabled .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) - _DEBUG;_LIB;_MT;USE_WIN_ICONV;%(PreprocessorDefinitions) + _DEBUG;_LIB;_MT;USE_WIN_ICONV;HAS_POLARSSL;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -491,6 +491,7 @@ copy $(TargetName).pdb ..\dist\lib\win64\$(TargetName).pdb /Y + @@ -640,6 +641,7 @@ copy $(TargetName).pdb ..\dist\lib\win64\$(TargetName).pdb /Y + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters index ffff7e94c..2c5db2a1f 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters +++ b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters @@ -472,6 +472,9 @@ Source Files\stdlib + + Source Files\redis + @@ -975,6 +978,9 @@ Header Files\stdlib + + Header Files\redis + diff --git a/lib_acl_cpp/samples/redis/Makefile b/lib_acl_cpp/samples/redis/Makefile index 8510317db..c8798c8be 100644 --- a/lib_acl_cpp/samples/redis/Makefile +++ b/lib_acl_cpp/samples/redis/Makefile @@ -16,6 +16,7 @@ all: @(cd redis_client_cluster; make) @(cd redis_client_cluster2; make) @(cd redis; make) + @(cd redis_geo; make) # @(cd redis_server; make) clean: @@ -36,4 +37,5 @@ clean: @(cd redis_client_cluster; make clean) @(cd redis_client_cluster2; make clean) @(cd redis; make clean) + @(cd redis_geo; make clean) # @(cd redis_server; make) diff --git a/lib_acl_cpp/samples/redis/redis_geo/Makefile b/lib_acl_cpp/samples/redis/redis_geo/Makefile new file mode 100644 index 000000000..0cce54611 --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/Makefile @@ -0,0 +1,3 @@ +base_path = ../../.. +PROG = redis_geo +include ../../Makefile.in diff --git a/lib_acl_cpp/samples/redis/redis_geo/redis_geo.cpp b/lib_acl_cpp/samples/redis/redis_geo/redis_geo.cpp new file mode 100644 index 000000000..5aab7a47d --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/redis_geo.cpp @@ -0,0 +1,302 @@ +#include "stdafx.h" + +#define MAX_MEMBER 2 + +static acl::string __keypre("geo_key"); + +static bool test_geoadd(acl::redis& redis, int n) +{ + acl::string key; + acl::string member; + std::vector members; + std::vector longitudes; + std::vector latitudes; + + members.reserve(MAX_MEMBER); + + for (int i = 0; i < MAX_MEMBER; i++) + { + member.format("member_%d", i); + members.push_back(member); + longitudes.push_back(48 + 0.01 * i); + latitudes.push_back(45 + 0.01 * i); + } + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + + redis.clear(); + int ret = redis.geoadd(key, members, longitudes, latitudes); + if (ret < 0) + { + printf("geoadd key: %s error: %s\r\n", + key.c_str(), redis.result_error()); + return false; + } + else if (i >= 10) + continue; + + printf("geoadd ok, key: %s, ret: %d\r\n", key.c_str(), ret); + } + + return true; +} + +static bool test_geohash(acl::redis& redis, int n) +{ + acl::string key; + acl::string member; + std::vector members; + std::vector results; + + members.reserve(MAX_MEMBER); + + for (int i = 0; i < MAX_MEMBER; i++) + { + member.format("member_%d", i); + members.push_back(member); + } + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + redis.clear(); + bool ret = redis.geohash(key.c_str(), members, results); + if (!ret) + { + printf("geohash key: %s error\r\n", key.c_str()); + return false; + } + else if (i >= 10) + continue; + + printf("geohash ok, key: %s, count: %d\r\n", key.c_str(), ret); + + for (size_t j = 0; j < members.size(); j ++) + { + //printf(">> %s: %s\r\n", members[j].c_str(), + // results[j].c_str()); + printf(">>member: %s\r\n", members[j].c_str()); + printf(">>size: %d\r\n", (int) results[j].length()); + printf(">>result: %s\r\n", results[j].c_str()); + } + } + + return true; +} + +static bool test_geopos(acl::redis& redis, int n) +{ + acl::string key; + acl::string member; + std::vector members; + std::vector > results; + + members.reserve(MAX_MEMBER); + + for (int i = 0; i < MAX_MEMBER; i++) + { + member.format("member_%d", i); + members.push_back(member); + } + + for (int i = 0; i < n; i++) + { + redis.clear(); + results.clear(); + + key.format("%s_%d", __keypre.c_str(), i); + bool ret = redis.geopos(key.c_str(), members, results); + if (!ret) + { + printf("geopos error\r\n"); + return false; + } + else if (i >= 10) + continue; + + printf("key: %s\r\n", key.c_str()); + for (size_t j = 0; j < members.size(); j++) + { + printf(">>%s: longitude = %.8f, latitude = %.8f\r\n", + members[j].c_str(), results[j].first, + results[j].second); + } + } + + return true; +} + +static bool test_geodist(acl::redis& redis, int n) +{ + acl::string key; + acl::string member1("member_0"), member2("member_1"); + + for (int i = 0; i < n; i++) + { + redis.clear(); + key.format("%s_%d", __keypre.c_str(), i); + double ret = redis.geodist(key.c_str(), member1.c_str(), + member2.c_str()); + if (ret < 0) + { + printf("geodist error, key: %s\r\n", key.c_str()); + return false; + } + else if (i >= 10) + continue; + + printf("ok, key: %s, dist: %.8f between %s and %s\r\n", + key.c_str(), ret, member1.c_str(), member2.c_str()); + } + + return true; +} + +static bool test_georadius(acl::redis& redis, int n) +{ + acl::string key; + double longitude = 48, latitude = 45, radius = 10; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + const std::vector& members = redis.georadius( + key.c_str(), longitude, latitude, radius); + if (members.empty()) + continue; + if (i >= 10) + continue; + + std::vector::const_iterator cit; + for (cit = members.begin(); cit != members.end(); ++cit) + { + printf(">>%s: longitude: %.8f, latitude: %.8f, dist: %.8f\r\n", + (*cit).get_name(), (*cit).get_longitude(), + (*cit).get_latitude(), (*cit).get_dist()); + } + } + + return true; +} + +static bool test_georadiusbymember(acl::redis& redis, int n) +{ + acl::string key; + double radius = 10; + const char* member = "member_10"; + + for (int i = 0; i < n; i++) + { + key.format("%s_%d", __keypre.c_str(), i); + const std::vector& members = + redis.georadiusbymember(key.c_str(), member, radius); + if (members.empty()) + continue; + if (i >= 10) + continue; + + std::vector::const_iterator cit; + for (cit = members.begin(); cit != members.end(); ++cit) + { + printf(">>%s: longitude: %.8f, latitude: %.8f, dist: %.8f\r\n", + (*cit).get_name(), (*cit).get_longitude(), + (*cit).get_latitude(), (*cit).get_dist()); + } + } + + return true; +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help]\r\n" + "-s redis_addr[127.0.0.1:6379]\r\n" + "-n count\r\n" + "-C connect_timeout[default: 10]\r\n" + "-T rw_timeout[default: 10]\r\n" + "-a cmd[geoadd|geohash|geopos|geodist|georadius|georadiusbymember\r\n", + procname); +} + +int main(int argc, char* argv[]) +{ + int ch, n = 1, conn_timeout = 10, rw_timeout = 10; + acl::string addr("127.0.0.1:6379"), cmd; + + while ((ch = getopt(argc, argv, "hs:n:C:T:a:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'n': + n = atoi(optarg); + break; + case 'C': + conn_timeout = atoi(optarg); + break; + case 'T': + rw_timeout = atoi(optarg); + break; + case 'a': + cmd = optarg; + break; + default: + break; + } + } + + acl::acl_cpp_init(); + + acl::redis_client_cluster cluster(conn_timeout, rw_timeout); + cluster.set(addr.c_str(), 100); + + acl::redis redis; + redis.set_cluster(&cluster, 100); + + bool ret; + + if (cmd == "geoadd") + ret = test_geoadd(redis, n); + else if (cmd == "geohash") + ret = test_geohash(redis, n); + else if (cmd == "geopos") + ret = test_geopos(redis, n); + else if (cmd == "geodist") + ret = test_geodist(redis, n); + else if (cmd == "georadius") + ret = test_georadius(redis, n); + else if (cmd == "georadiusbymember") + ret = test_georadiusbymember(redis, n); + else if (cmd == "all") + { + ret = test_geoadd(redis, n) + && test_geohash(redis, n) + && test_geopos(redis, n) + && test_geodist(redis, n) + && test_georadius(redis, n) + && test_georadiusbymember(redis, n); + } + else + { + ret = false; + printf("unknown cmd: %s\r\n", cmd.c_str()); + } + + if (ret == true) + printf("test OK!\r\n"); + else + printf("test failed!\r\n"); + +#ifdef WIN32 + printf("enter any key to exit\r\n"); + getchar(); +#endif + return 0; +} diff --git a/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2003.vcproj b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2003.vcproj new file mode 100644 index 000000000..511769aa5 --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2003.vcproj @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2008.vcproj b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2008.vcproj new file mode 100644 index 000000000..e176c85ab --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2008.vcproj @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2010.vcxproj b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2010.vcxproj new file mode 100644 index 000000000..9ec288895 --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2010.vcxproj @@ -0,0 +1,197 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {50A37701-CDC8-477E-8B7F-711FB0A90844} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\..\lib\win32;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + MachineX86 + + + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + MachineX86 + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + MachineX86 + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2012.vcxproj b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2012.vcxproj new file mode 100644 index 000000000..ecf08f105 --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/redis_geo_vc2012.vcxproj @@ -0,0 +1,357 @@ +锘 + + + + DebugDll + Win32 + + + DebugDll + x64 + + + Debug + Win32 + + + Debug + x64 + + + Releasedll + Win32 + + + Releasedll + x64 + + + Release + Win32 + + + Release + x64 + + + + {AE10B13D-774D-49A5-9066-E90F124BA99C} + Win32Proj + redis_geo + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + true + Release\ + Release\ + false + false + $(Configuration)\ + $(Configuration)\ + true + true + $(Configuration)\ + $(Configuration)\ + true + true + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\..\lib\win32;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + MachineX86 + + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\..\lib\win64;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + + + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + MachineX86 + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + MachineX86 + + + + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)redis_geo.exe + ..\..\..\lib;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + $(OutDir)redis_geo.pdb + Console + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/redis/redis_geo/stdafx.cpp b/lib_acl_cpp/samples/redis/redis_geo/stdafx.cpp new file mode 100644 index 000000000..c69804ef5 --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// xml.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/redis/redis_geo/stdafx.h b/lib_acl_cpp/samples/redis/redis_geo/stdafx.h new file mode 100644 index 000000000..425c6c84b --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 +#include "acl_cpp/lib_acl.hpp" +#include "lib_acl.h" + diff --git a/lib_acl_cpp/samples/redis/redis_geo/valgrind.sh b/lib_acl_cpp/samples/redis/redis_geo/valgrind.sh new file mode 100644 index 000000000..ddaedec6e --- /dev/null +++ b/lib_acl_cpp/samples/redis/redis_geo/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./redis_geo -s 127.0.0.1:6379 -a all -n 10 diff --git a/lib_acl_cpp/samples/session/stdafx.h b/lib_acl_cpp/samples/session/stdafx.h index ce8c0e681..ab1fa7dae 100644 --- a/lib_acl_cpp/samples/session/stdafx.h +++ b/lib_acl_cpp/samples/session/stdafx.h @@ -5,5 +5,6 @@ #pragma once // TODO: 在此处引用程序要求的附加头文件 +#include "lib_acl.h" #include "acl_cpp/lib_acl.hpp" #include "lib_acl.h" diff --git a/lib_acl_cpp/samples/ssl/https_proxy/Makefile b/lib_acl_cpp/samples/ssl/https_proxy/Makefile new file mode 100644 index 000000000..ede26cdf2 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/Makefile @@ -0,0 +1,4 @@ +base_path = ../../.. +include ../../Makefile.in +PROG = https_proxy +EXTLIBS += -lpolarssl -lz diff --git a/lib_acl_cpp/samples/ssl/https_proxy/http_servlet.cpp b/lib_acl_cpp/samples/ssl/https_proxy/http_servlet.cpp new file mode 100644 index 000000000..e5ed1b232 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/http_servlet.cpp @@ -0,0 +1,130 @@ +#include "stdafx.h" +#include "https_client.h" +#include "http_servlet.h" + +http_servlet::http_servlet(acl::ostream& out, acl::polarssl_conf* conf) + : handled_(false) + , out_(out) + , client_ssl_conf_(conf) +{ + +} + +http_servlet::~http_servlet(void) +{ + +} + +void http_servlet::logger_request(acl::HttpServletRequest& req) +{ + acl::string req_hdr; + acl::http_client* client = req.getClient(); + client->sprint_header(req_hdr, NULL); + out_.format("\r\n>>>request header<<<\r\n"); + out_.write(req_hdr); + out_.format("\r\n"); +} + +bool http_servlet::doError(acl::HttpServletRequest& req, + acl::HttpServletResponse& res) +{ +// if (handled_) + return false; + + out_.format(">>> request method: doError <<<\r\n"); + logger_request(req); + + res.setStatus(400); + res.setContentType("text/html; charset="); + // 发送 http 响应体 + acl::string buf("\r\n"); + (void) res.getOutputStream().write(buf); + return false; +} + +bool http_servlet::doUnknown(acl::HttpServletRequest& req, + acl::HttpServletResponse& res) +{ + out_.format(">>> request method: doUnknown <<<\r\n"); + logger_request(req); + + res.setStatus(400); + res.setContentType("text/html; charset="); + // 发送 http 响应体 + acl::string buf("\r\n"); + (void) res.getOutputStream().write(buf); + return false; +} + +bool http_servlet::doPut(acl::HttpServletRequest& req, + acl::HttpServletResponse&) +{ + handled_ = true; + out_.format(">>> request method: PUT <<<\r\n"); + logger_request(req); + return true; +} + +bool http_servlet::doConnect(acl::HttpServletRequest& req, + acl::HttpServletResponse&) +{ + handled_ = true; + out_.format(">>> request method: CONNECT <<<\r\n"); + logger_request(req); + return true; +} + +bool http_servlet::doDelete(acl::HttpServletRequest& req, + acl::HttpServletResponse&) +{ + handled_ = true; + out_.format(">>> request method: DELETE <<<\r\n"); + logger_request(req); + return true; +} + +bool http_servlet::doHead(acl::HttpServletRequest& req, + acl::HttpServletResponse&) +{ + handled_ = true; + out_.format(">>> request method: HEAD <<<\r\n"); + logger_request(req); + return true; +} + +bool http_servlet::doOptions(acl::HttpServletRequest& req, + acl::HttpServletResponse& res) +{ + handled_ = true; + out_.format(">>> request method: OPTIONS <<<\r\n"); + return doPost(req, res); +} + +bool http_servlet::doGet(acl::HttpServletRequest& req, + acl::HttpServletResponse& res) +{ + handled_ = true; + out_.format(">>> request method: GET <<<\r\n"); + return doPost(req, res); +} + +bool http_servlet::doPost(acl::HttpServletRequest& req, + acl::HttpServletResponse& res) +{ + handled_ = true; + acl::http_client* conn = req.getClient(); + conn->header_disable("Accept-Encoding"); + logger_request(req); + + // 生成完整的 url,以备下面使用 + const char* host = req.getRemoteHost(); + const char* uri = req.getRequestUri(); + if (host == NULL || *host == 0) + host = req.getLocalAddr(); + + url_.format("http://%s%s", host, uri ? uri : "/"); + out_.format(">>> request url: %s\r\n", url_.c_str()); + + https_client client(out_, client_ssl_conf_); + return client.http_request(req, res); +} diff --git a/lib_acl_cpp/samples/ssl/https_proxy/http_servlet.h b/lib_acl_cpp/samples/ssl/https_proxy/http_servlet.h new file mode 100644 index 000000000..aef266d42 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/http_servlet.h @@ -0,0 +1,36 @@ +#pragma once + +class http_servlet : public acl::HttpServlet +{ +public: + http_servlet(acl::ostream& out, acl::polarssl_conf* conf); + ~http_servlet(); + +protected: + bool doGet(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + bool doPost(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + bool doUnknown(acl::HttpServletRequest&, + acl::HttpServletResponse& res); + bool doError(acl::HttpServletRequest&, + acl::HttpServletResponse& res); + bool doConnect(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + bool doPut(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + bool doDelete(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + bool doHead(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + bool doOptions(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + +private: + bool handled_; + acl::string url_; + acl::ostream& out_; + acl::polarssl_conf* client_ssl_conf_; + + void logger_request(acl::HttpServletRequest& req); +}; diff --git a/lib_acl_cpp/samples/ssl/https_proxy/https_client.cpp b/lib_acl_cpp/samples/ssl/https_proxy/https_client.cpp new file mode 100644 index 000000000..cc8034dd0 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/https_client.cpp @@ -0,0 +1,177 @@ +#include "stdafx.h" +#include +#include +#include "master_service.h" +#include "https_client.h" + +#define DEBUG 100 + +https_client::https_client(acl::ostream& out, acl::polarssl_conf* conf) +: out_(out) +, ssl_conf_(conf) +{ +} + +https_client::~https_client() +{ +} + +bool https_client::connect_server(const acl::string& server_addr, + acl::http_client& client) +{ + // 先查本地映射表中有没有映射项 + master_service& ms = acl::singleton2::get_instance(); + const char* addr = ms.get_addr(server_addr.c_str()); + if (addr == NULL) + addr = server_addr.c_str(); + + if (client.open(addr, 60, 60, true) == false) + { + out_.format("connect server %s error", addr); + return false; + } + else + logger_debug(DEBUG, 1, "connect server ok"); + + if (ssl_conf_) + { + logger_debug(DEBUG, 1, "begin open ssl"); + + acl::polarssl_io* ssl = new acl::polarssl_io(*ssl_conf_, false); + if (client.get_stream().setup_hook(ssl) == ssl) + { + out_.puts("open ssl client error"); + ssl->destroy(); + return false; + } + else + logger_debug(DEBUG, 1, "open ssl ok"); + } + + return true; +} + +bool https_client::http_request(acl::HttpServletRequest& req, + acl::HttpServletResponse& res) +{ + const char* host = req.getRemoteHost(); + if (host == NULL || *host == 0) + host = req.getLocalAddr(); + + acl::string server_addr; + if (ssl_conf_ == NULL) + server_addr.format("%s:80", host); + else + server_addr.format("%s:443", host); + + std::auto_ptr backend(new acl::http_client); + + // 连接服务器 + if (connect_server(server_addr, *backend) == false) + return false; + + acl::http_client* front = req.getClient(); + + // 取得 HTTP 请求头数据 + acl::string req_hdr; + front->sprint_header(req_hdr, NULL); + + // 转发 HTTP 请求头至服务器 + if (backend->get_ostream().write(req_hdr) == -1) + { + out_.puts(">>>>write header error"); + return false; + } + if (backend->get_ostream().write("\r\n") == -1) + { + out_.puts(">>>>write CRLF error"); + return false; + } + + // 如果还有数据体,则转发请求的数据体给服务器 + long long int len = req.getContentLength(); + + if (len > 0) + { + char req_body[8192]; + int ret; + + while (true) + { + ret = front->read_body(req_body, sizeof(req_body) - 1); + if (ret < 0) + { + out_.puts(">>> read req body error"); + return false; + } + if (ret == 0) + break; + + req_body[ret] = 0; + out_.write(req_body, ret); + if (backend->get_ostream().write(req_body, ret) == -1) + { + out_.puts(">>> write body to server error"); + return false; + } + } + } + out_.puts(""); + + // 开始从后端服务器读取响应头和响应体数据 + + out_.puts(">>>> begin read res header<<<<<"); + if (backend->read_head() == false) + { + out_.puts(">>>>>>>>read header error<<<<<<<<<<"); + return false; + } + + acl::string res_hdr; + backend->sprint_header(res_hdr, NULL); + if (res.getOutputStream().write(res_hdr) == -1) + { + out_.puts(">>>>>write res hdr error<<<<<<"); + return false; + } + + if (res.getOutputStream().write("\r\n") == -1) + { + out_.puts(">>>write CRLF error"); + return false; + } + + out_.puts("------------------res hdr----------------"); + out_.write(res_hdr); + out_.puts("------------------res hdr end------------"); + + char buf[8192]; + + while (true) + { + int ret = backend->read_body(buf, sizeof(buf) - 1); + if (ret < 0) + { + logger_error(">>> read body error"); + return false; + } + else if (ret == 0) + break; + + buf[ret] = 0; + out_.write(buf, ret); + if (res.getOutputStream().write(buf, ret) == -1) + { + out_.puts(">>> write res body error"); + return false; + } + } + + const char* ptr = backend->header_value("Transfer-Encoding"); + if (ptr == NULL || *ptr == 0 || strcasecmp(ptr, "chunked") != 0) + return backend->keep_alive(); + + // 发送 http 响应体,因为设置了 chunk 传输模式,所以需要多调用一次 + // res.write 且两个参数均为 0 以表示 chunk 传输数据结束 + return res.write(NULL, 0); +} diff --git a/lib_acl_cpp/samples/ssl/https_proxy/https_client.h b/lib_acl_cpp/samples/ssl/https_proxy/https_client.h new file mode 100644 index 000000000..8481118d4 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/https_client.h @@ -0,0 +1,18 @@ +#pragma once + +class https_client +{ +public: + https_client(acl::ostream& out, acl::polarssl_conf* conf); + ~https_client(); + + bool http_request(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); + +private: + acl::ostream& out_; + acl::polarssl_conf* ssl_conf_; + + bool connect_server(const acl::string& server_addr, + acl::http_client& client); +}; diff --git a/lib_acl_cpp/samples/ssl/https_proxy/https_proxy.cf b/lib_acl_cpp/samples/ssl/https_proxy/https_proxy.cf new file mode 100644 index 000000000..e29a1b356 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/https_proxy.cf @@ -0,0 +1,125 @@ + +service http_server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 +# for master_type = inet +# master_service = 127.0.0.1:5001 +# for master_type = unix +# master_service = echo.sock +# for master_type = sock + master_service = 1443 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 +# master_type = inet +# master_type = unix + master_type = sock + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 预启动进程数,该值不得大于 master_maxproc + master_prefork = 1 +# 进程程序名 + master_command = https_server +# 进程日志记录文件 + master_log = {install_path}/var/log/https_server +# 调试日志方式,格式:tag:level; tag:level; tab:level, 如:all:1; 101:2 +# master_debug = +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 当启动多个子进程实例时,该开关控制多个子进程在接收连接时是否向 acl_master 发送消息报告自己的状态 +# master_status_notify = 1 +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1), +# 以加速事件循环过程, 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 1 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 1 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = kernel +# 事件引擎检查所有空闲描述符的时间间隔(毫秒) +# ioctl_check_inter = 100 +# 当启用 master_dispatch 连接分开服务后,该配置指定 master_dispatch 所监听的 +# 域套接口的全路径,这样本子进程就可以从 master_dispatch 获得客户端连接 +# ioctl_dispatch_addr = {install_path}/var/private/dispatch.sock +# 当 ioctl_dispatch_addr 开启后,下面参数控制本服务进程发给前端 master_dispatch 的服务标识信息 +# ioctl_dispatch_type = default + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程池中工作线程等待任务时间间隔(毫秒) +# ioctl_schedule_wait = 50 +# 线程任务调度的时间间隔大于此值(毫秒)后记警告日志 +# ioctl_schedule_warn = 100 +# 线程处理任务拥堵数超过此阀值后记警告日志,设为 0 则内部只有当拥堵任务数超过总线程数的 10 倍时才报警 +# ioctl_qlen_warn = 0 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = all + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +############################################################################ +# 应用自己的配置选项 + +# crt_file = {install_path}/conf/ssl/mm263com1.crt +# key_file = {install_path}/conf/ssl/mm263com.key + crt_file = ssl_crt.pem + key_file = ssl_key.pem + client_ssl = 1 + addrs_map = 263esComp1.263es.com:443|192.168.198.47:443, \ + 263es.com:443|192.168.198.47:443, \ + m.hotmail.com:443|65.54.225.167:443, \ + blu405-m.hotmail.com:443|134.170.0.216:443, \ + i.163.com:443|61.135.251.139:443, \ + ex.qq.com:443|183.60.15.145:443 +} + diff --git a/lib_acl_cpp/samples/ssl/https_proxy/https_proxy_vc2012.vcxproj b/lib_acl_cpp/samples/ssl/https_proxy/https_proxy_vc2012.vcxproj new file mode 100644 index 000000000..9375ed144 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/https_proxy_vc2012.vcxproj @@ -0,0 +1,373 @@ +锘 + + + + DebugDll + Win32 + + + DebugDll + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDll + Win32 + + + ReleaseDll + x64 + + + Release + Win32 + + + Release + x64 + + + + https_proxy + {5F75216D-8263-4F6F-9390-76E7AC129AEE} + Win32Proj + + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + .\ + Debug\ + true + + + true + + + Release\ + Release\ + false + + + false + + + $(Configuration)\ + $(Configuration)\ + true + + + true + + + $(Configuration)\ + $(Configuration)\ + false + + + false + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAS_POLARSSL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;lib_acl_cpp_vc2012d.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win32;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmt;libc;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)https_proxy.pdb + Console + false + + MachineX86 + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;HAS_POLARSSL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;lib_acl_cpp_vc2012d.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win64;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + libcmt;libc;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)https_proxy.pdb + Console + false + + + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012.lib;lib_protocol_vc2012.lib;lib_acl_cpp_vc2012.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win32;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + false + + MachineX86 + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012.lib;lib_protocol_vc2012.lib;lib_acl_cpp_vc2012.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win64;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + false + + + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;VC2003;ACL_DLL;ACL_CPP_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win32;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)https_proxy.pdb + Console + false + + MachineX86 + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;polarssl.lib;%(AdditionalDependencies) + + + + + Disabled + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;VC2003;ACL_DLL;ACL_CPP_DLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win64;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)https_proxy.pdb + Console + false + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;polarssl.lib;%(AdditionalDependencies) + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;VC2003;ACL_DLL;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win32;..\..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + false + + MachineX86 + lib_acl.lib;lib_acl_cpp.lib;lib_protocol.lib;polarssl.lib;%(AdditionalDependencies) + + + + + ..\..\..\include;..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;VC2003;ACL_DLL;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)https_proxy.exe + ..\..\..\..\lib\win64;..\..\..\..\dist\lib\win64;%(AdditionalLibraryDirectories) + true + Console + true + true + false + + + lib_acl.lib;lib_acl_cpp.lib;lib_protocol.lib;polarssl.lib;%(AdditionalDependencies) + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/ssl/https_proxy/https_proxy_vc2012.vcxproj.filters b/lib_acl_cpp/samples/ssl/https_proxy/https_proxy_vc2012.vcxproj.filters new file mode 100644 index 000000000..53fa43292 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/https_proxy_vc2012.vcxproj.filters @@ -0,0 +1,54 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/ssl/https_proxy/main.cpp b/lib_acl_cpp/samples/ssl/https_proxy/main.cpp new file mode 100644 index 000000000..6e4085a69 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/main.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "help") == 0) + printf("usage: %s alone addr conf_file\r\n", argv[0]); + else if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + acl::log::stdout_open(true); // 日志输出至标准输出 + + const char* addr = "0.0.0.0:443"; + if (argc >= 3) + addr = argv[2]; + printf("listen on: %s\r\n", addr); + + if (argc >= 4) + ms.run_alone(addr, argv[3], 0, 100); // 单独运行方式 + else + ms.run_alone(addr, NULL, 0, 100); // 单独运行方式 + + printf("Enter any key to exit now\r\n"); + getchar(); + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/lib_acl_cpp/samples/ssl/https_proxy/master_service.cpp b/lib_acl_cpp/samples/ssl/https_proxy/master_service.cpp new file mode 100644 index 000000000..d576fa173 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/master_service.cpp @@ -0,0 +1,244 @@ +#include "stdafx.h" +#include "http_servlet.h" +#include "master_service.h" + +////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_crt_file; +char *var_cfg_key_file; +char *var_cfg_log_file; +char *var_cfg_addrs_map; +acl::master_str_tbl var_conf_str_tab[] = { + { "crt_file", "", &var_cfg_crt_file }, + { "key_file", "", &var_cfg_key_file }, + { "log_file", "./log.txt", &var_cfg_log_file }, + { "addrs_map", "", &var_cfg_addrs_map }, + + { 0, 0, 0 } +}; + +int var_cfg_session_cache; +int var_cfg_client_ssl; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "session_cache", 1, &var_cfg_session_cache }, + { "client_ssl", 1, &var_cfg_client_ssl }, + + { 0, 0, 0 } +}; + +int var_cfg_io_timeout; +acl::master_int_tbl var_conf_int_tab[] = { + { "io_timeout", 60, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +acl::master_int64_tbl var_conf_int64_tab[] = { + + { 0, 0 , 0 , 0, 0 } +}; + +////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +: server_ssl_conf_(NULL) +, client_ssl_conf_(NULL) +{ +} + +master_service::~master_service() +{ + if (server_ssl_conf_) + delete server_ssl_conf_; + if (client_ssl_conf_) + delete client_ssl_conf_; +} + +acl::polarssl_io* master_service::setup_ssl(acl::socket_stream& conn, + acl::polarssl_conf& conf) +{ + acl::polarssl_io* hook = (acl::polarssl_io*) conn.get_hook(); + if (hook != NULL) + return hook; + + // 对于使用 SSL 方式的流对象,需要将 SSL IO 流对象注册至网络 + // 连接流对象中,即用 ssl io 替换 stream 中默认的底层 IO 过程 + + out_.puts("begin setup ssl hook..."); + + // 采用阻塞 SSL 握手方式 + acl::polarssl_io* ssl = new acl::polarssl_io(conf, true, false); + if (conn.setup_hook(ssl) == ssl) + { + logger_error("setup_hook error!"); + ssl->destroy(); + return NULL; + } + + out_.format("setup hook ok, tid: %lu", acl::thread::thread_self()); + return ssl; +} + +bool master_service::thread_on_read(acl::socket_stream* conn) +{ + http_servlet* servlet = (http_servlet*) conn->get_ctx(); + if (servlet == NULL) + logger_fatal("servlet null!"); + + if (server_ssl_conf_ == NULL) + return servlet->doRun("127.0.0.1:11211", conn); + + acl::polarssl_io* ssl = setup_ssl(*conn, *server_ssl_conf_); + if (ssl == NULL) + return false; + + if (ssl->handshake() == false) + { + out_.puts("ssl handshake failed"); + return false; + } + + if (ssl->handshake_ok() == false) + { + out_.puts("handshake trying ..."); + return true; + } + + return servlet->doRun("127.0.0.1:11211", conn); +} + +bool master_service::thread_on_accept(acl::socket_stream* conn) +{ +// logger("connect from %s, fd: %d", conn->get_peer(true), +// conn->sock_handle()); + + conn->set_rw_timeout(var_cfg_io_timeout); + + http_servlet* servlet = new http_servlet(out_, client_ssl_conf_); + servlet->setParseBody(false); + conn->set_ctx(servlet); + + return true; +} + +bool master_service::thread_on_timeout(acl::socket_stream* conn acl_unused) +{ +// logger("read timeout from %s, fd: %d", conn->get_peer(), +// conn->sock_handle()); + return false; +} + +void master_service::thread_on_close(acl::socket_stream* conn) +{ +// logger("disconnect from %s, fd: %d", conn->get_peer(), +// conn->sock_handle()); + + http_servlet* servlet = (http_servlet*) conn->get_ctx(); + if (servlet) + delete servlet; +} + +void master_service::thread_on_init() +{ +} + +void master_service::thread_on_exit() +{ +} + +const char* master_service::get_addr(const char* from) const +{ + if (from == NULL || *from == 0) + return NULL; + acl::string key(from); + key.lower(); + std::map::const_iterator cit = + addrs_map_.find(key); + if (cit != addrs_map_.end()) + return cit->second.c_str(); + else + { + logger("Local not exist from: %s\r\n", from); + return NULL; + } +} + +void master_service::create_addrs_map() +{ + if (var_cfg_addrs_map == NULL || *var_cfg_addrs_map == 0) + return; + + // 数据格式:domain11:port11|domain12:port12, ... + acl::string buf(var_cfg_addrs_map); + std::vector& addrs = buf.split2(" \t,;"); + for (std::vector::iterator it = addrs.begin(); + it != addrs.end(); ++it) + { + std::vector pair = (*it).split2("|"); + if (pair.size() == 2) + { + addrs_map_[pair[0].lower()] = pair[1].lower(); + logger("add addr map: %s->%s", pair[0].c_str(), + pair[1].c_str()); + } + } +} + +void master_service::proc_on_init() +{ + create_addrs_map(); + + if (var_cfg_log_file != NULL && *var_cfg_log_file != 0) + { + if (out_.open_write(var_cfg_log_file) == false) + logger_error("open %s error %s", var_cfg_log_file, + acl::last_serror()); + else + logger("open %s ok", var_cfg_log_file); + } + else + logger("no log file open"); + + if (var_cfg_client_ssl) + client_ssl_conf_ = new acl::polarssl_conf; + else + client_ssl_conf_ = NULL; + + if (var_cfg_crt_file == NULL || *var_cfg_crt_file == 0 + || var_cfg_key_file == NULL || *var_cfg_key_file == 0) + { + return; + } + + // 加载服务端 SSL 证书 + server_ssl_conf_ = new acl::polarssl_conf(); + + // 允许服务端的 SSL 会话缓存功能 + server_ssl_conf_->enable_cache(var_cfg_session_cache ? true : false); + + // 添加本地服务的证书 + if (server_ssl_conf_->add_cert(var_cfg_crt_file) == false) + { + logger_error("add cert failed, crt: %s, key: %s", + var_cfg_crt_file, var_cfg_key_file); + delete server_ssl_conf_; + server_ssl_conf_ = NULL; + return; + } + logger("load cert ok, crt: %s, key: %s", + var_cfg_crt_file, var_cfg_key_file); + + // 添加本地服务密钥 + if (server_ssl_conf_->set_key(var_cfg_key_file) == false) + { + logger_error("add key failed, crt: %s, key: %s", + var_cfg_crt_file, var_cfg_key_file); + delete server_ssl_conf_; + server_ssl_conf_ = NULL; + } +} + +void master_service::proc_on_exit() +{ +} diff --git a/lib_acl_cpp/samples/ssl/https_proxy/master_service.h b/lib_acl_cpp/samples/ssl/https_proxy/master_service.h new file mode 100644 index 000000000..005591e25 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/master_service.h @@ -0,0 +1,94 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern char *var_cfg_str; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_bool; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_int; +extern acl::master_int_tbl var_conf_int_tab[]; + +extern long long int var_cfg_int64; +extern acl::master_int64_tbl var_conf_int64_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +//class acl::socket_stream; + +class master_service : public acl::master_threads +{ +public: + master_service(); + ~master_service(); + + const char* get_addr(const char* from) const; + +protected: + /** + * 纯虚函数:当某个客户端连接有数据可读或关闭或出错时调用此函数 + * @param stream {socket_stream*} + * @return {bool} 返回 false 则表示当函数返回后需要关闭连接, + * 否则表示需要保持长连接,如果该流出错,则应用应该返回 false + */ + virtual bool thread_on_read(acl::socket_stream* stream); + + /** + * 当线程池中的某个线程获得一个连接时的回调函数, + * 子类可以做一些初始化工作 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + */ + virtual bool thread_on_accept(acl::socket_stream* stream); + + /** + * 当某个网络连接的 IO 读写超时时的回调函数,如果该函数返回 true 则表示继续等待下一次 + * 读写,否则则希望关闭该连接 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + */ + virtual bool thread_on_timeout(acl::socket_stream* stream); + + /** + * 当与某个线程绑定的连接关闭时的回调函数 + * @param stream {socket_stream*} + */ + virtual void thread_on_close(acl::socket_stream* stream); + + /** + * 当线程池中一个新线程被创建时的回调函数 + */ + virtual void thread_on_init(); + + /** + * 当线程池中一个线程退出时的回调函数 + */ + virtual void thread_on_exit(); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); + +private: + acl::polarssl_conf* server_ssl_conf_; + acl::polarssl_conf* client_ssl_conf_; + std::map addrs_map_; + acl::ofstream out_; + + acl::polarssl_io* setup_ssl(acl::socket_stream& conn, + acl::polarssl_conf& conf); + + void create_addrs_map(); +}; diff --git a/lib_acl_cpp/samples/ssl/https_proxy/stdafx.cpp b/lib_acl_cpp/samples/ssl/https_proxy/stdafx.cpp new file mode 100644 index 000000000..f01a2ff42 --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/ssl/https_proxy/stdafx.h b/lib_acl_cpp/samples/ssl/https_proxy/stdafx.h new file mode 100644 index 000000000..88376f8ad --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/stdafx.h @@ -0,0 +1,19 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "acl_cpp/lib_acl.hpp" +#include "lib_acl.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/lib_acl_cpp/samples/ssl/https_proxy/valgrind.sh b/lib_acl_cpp/samples/ssl/https_proxy/valgrind.sh new file mode 100644 index 000000000..e1c4cfe3c --- /dev/null +++ b/lib_acl_cpp/samples/ssl/https_proxy/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./https_proxy alone diff --git a/lib_acl_cpp/src/http/HttpServlet.cpp b/lib_acl_cpp/src/http/HttpServlet.cpp index 1d72ef0dd..b1c9c066c 100644 --- a/lib_acl_cpp/src/http/HttpServlet.cpp +++ b/lib_acl_cpp/src/http/HttpServlet.cpp @@ -116,7 +116,7 @@ bool HttpServlet::doRun(session& session, socket_stream* stream /* = NULL */) ret = doHead(req, res); break; case HTTP_METHOD_OPTION: - ret = doOption(req, res); + ret = doOptions(req, res); break; default: ret = false; // 有可能是IO失败或未知方法 @@ -138,7 +138,9 @@ bool HttpServlet::doRun(session& session, socket_stream* stream /* = NULL */) delete out; } - return ret; + // 返回给上层调用者:true 表示继续保持长连接,否则表示需断开连接 + return ret && req.isKeepAlive() + && res.getHttpHeader().get_keep_alive(); } bool HttpServlet::doRun(const char* memcached_addr /* = "127.0.0.1:11211" */, diff --git a/lib_acl_cpp/src/redis/redis_command.cpp b/lib_acl_cpp/src/redis/redis_command.cpp index 8f9612678..bb1abcb95 100644 --- a/lib_acl_cpp/src/redis/redis_command.cpp +++ b/lib_acl_cpp/src/redis/redis_command.cpp @@ -1153,7 +1153,7 @@ void redis_command::build_request1(size_t argc, const char* argv[], size_t lens[ request_buf_->append(argv[i], lens[i]); request_buf_->append("\r\n"); } - //printf("%s: %s", __FUNCTION__, request_buf_->c_str()); + printf("%s:\r\n%s\r\n", __FUNCTION__, request_buf_->c_str()); } void redis_command::build_request2(size_t argc, const char* argv[], size_t lens[]) diff --git a/lib_acl_cpp/src/redis/redis_geo.cpp b/lib_acl_cpp/src/redis/redis_geo.cpp new file mode 100644 index 000000000..0b3dc8af9 --- /dev/null +++ b/lib_acl_cpp/src/redis/redis_geo.cpp @@ -0,0 +1,614 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/snprintf.hpp" +#include "acl_cpp/stdlib/dbuf_pool.hpp" +#include "acl_cpp/redis/redis_geo.hpp" + +namespace acl +{ + +#define BUFLEN 32 + +///////////////////////////////////////////////////////////////////////////// + +geo_member::geo_member(const char* name) +: name_(name) +{ + dist_ = -1; + hash_ = -1; + longitude_ = GEO_INVALID; + latitude_ = GEO_INVALID; +} + +geo_member::geo_member(const geo_member& member) +{ + name_ = member.name_.c_str(); + dist_ = member.dist_; + hash_ = member.hash_; + longitude_ = member.longitude_; + latitude_ = member.latitude_; +} + +geo_member::~geo_member() +{ +} + +void geo_member::set_dist(double dist) +{ + dist_ = dist; +} + +void geo_member::set_hash(acl_int64 hash) +{ + hash_ = hash; +} + +void geo_member::set_coordinate(double longitude, double latitude) +{ + if (longitude >= GEO_LONGITUDE_MIN + && longitude <= GEO_LONGITUDE_MAX + && latitude >= GEO_LATITUDE_MIN + && latitude <= GEO_LATITUDE_MAX) + { + longitude_ = longitude; + latitude_ = longitude; + } +} + +///////////////////////////////////////////////////////////////////////////// + +redis_geo::redis_geo() +: redis_command(NULL) +{ +} + +redis_geo::redis_geo(redis_client* conn) +: redis_command(conn) +{ +} + +redis_geo::redis_geo(redis_client_cluster* cluster, size_t max_conns) +: redis_command(cluster, max_conns) +{ +} + +redis_geo::~redis_geo() +{ +} + +int redis_geo::geoadd(const char* key, const char* member, + double longitude, double latitude) +{ + size_t argc = 5; + const char* argv[5]; + size_t lens[5]; + + argv[0] = "GEOADD"; + lens[0] = sizeof("GEOADD") - 1; + + argv[1] = key; + lens[1] = strlen(key); + + char* buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", longitude); + argv[2] = buf; + lens[2] = strlen(buf); + + buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", latitude); + argv[3] = buf; + lens[3] = strlen(buf); + + argv[4] = member; + lens[4] = strlen(member); + + hash_slot(key); + build_request(argc, argv, lens); + return get_number(); +} + +int redis_geo::geoadd(const char* key, size_t size, const char* members[], + const double longitudes[], const double latitudes[]) +{ + size_t argc = 2 + 3 * size; + const char** argv = (const char**) + pool_->dbuf_alloc(argc * sizeof(char*)); + size_t *lens = (size_t*) pool_->dbuf_alloc(argc * sizeof(size_t)); + + argv[0] = "GEOADD"; + lens[0] = sizeof("GEOADD") - 1; + + argv[1] = key; + lens[1] = strlen(key); + + for (size_t i = 0, n = 2; i < size; i++) + { + char* buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", longitudes[i]); + argv[n] = buf; + lens[n] = strlen(argv[n]); + n++; + + buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", latitudes[i]); + argv[n] = buf; + lens[n] = strlen(argv[n]); + n++; + + argv[n] = members[i]; + lens[n] = strlen(argv[n]); + n++; + } + + hash_slot(key); + build_request(argc, argv, lens); + return get_number(); +} + +int redis_geo::geoadd(const char* key, const std::vector& members, + const std::vector& longitudes, + const std::vector& latitudes) +{ + if (members.empty()) + { + logger_error("members empty"); + return -1; + } + if (members.size() != longitudes.size()) + { + logger_error("longitudes's size(%d) != members's size(%d)", + (int) longitudes.size(), (int) members.size()); + return -1; + } + if (latitudes.size() != longitudes.size()) + { + logger_error("latitudes's size(%d) != longitudes's size(%d)", + (int) latitudes.size(), (int) longitudes.size()); + return -1; + } + + size_t argc = 2 + 3 * members.size(); + const char** argv = (const char**) + pool_->dbuf_alloc(argc * sizeof(char*)); + size_t *lens = (size_t*) pool_->dbuf_alloc(argc * sizeof(size_t)); + + argv[0] = "GEOADD"; + lens[0] = sizeof("GEOADD") - 1; + + argv[1] = key; + lens[1] = strlen(key); + + size_t size = members.size(); + for (size_t i = 0, n = 2; i < size; i++) + { + char* buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", longitudes[i]); + argv[n] = buf; + lens[n] = strlen(argv[n]); + n++; + + buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", latitudes[i]); + argv[n] = buf; + lens[n] = strlen(argv[n]); + n++; + + argv[n] = members[i].c_str(); + lens[n] = members[i].size(); + n++; + } + + hash_slot(key); + build_request(argc, argv, lens); + return get_number(); +} + +bool redis_geo::geohash(const char* key, const std::vector& members, + std::vector& results) +{ + hash_slot(key); + build("GEOHASH", key, members); + if (get_strings(results) < 0) + return false; + return results.size() == members.size() ? true : false; +} + +bool redis_geo::geohash(const char* key, const char* member, string& result) +{ + const char* names[1]; + names[0] = member; + + hash_slot(key); + build("GEOHASH", key, names, 1); + return get_string(result) < 0 ? false : true; +} + +bool redis_geo::geopos(const char* key, const std::vector& members, + std::vector >& results) +{ + hash_slot(key); + build("GEOPOS", key, members); + const redis_result* result = run(); + if (result == NULL || result->get_type() != REDIS_RESULT_ARRAY) + return false; + + size_t size; + const redis_result** children = result->get_children(&size); + if (children == NULL) + return false; + + string buf; + + for (size_t i = 0; i < size; i++) + { + const redis_result* child = children[i]; + if (child->get_type() != REDIS_RESULT_ARRAY) + { + results.push_back(std::make_pair(GEO_INVALID, + GEO_INVALID)); + continue; + } + + size_t n; + const redis_result** xy = child->get_children(&n); + if (xy == NULL || n != 2) + { + results.push_back(std::make_pair(GEO_INVALID, + GEO_INVALID)); + continue; + } + const redis_result* rr_lo = xy[0], *rr_la = xy[1]; + if (rr_lo->get_type() != REDIS_RESULT_STRING + || rr_la->get_type() != REDIS_RESULT_STRING) + { + results.push_back(std::make_pair(GEO_INVALID, + GEO_INVALID)); + continue; + } + + double lo = rr_lo->get_double(); + if (lo < GEO_LONGITUDE_MIN || lo > GEO_LONGITUDE_MAX) + { + results.push_back(std::make_pair(GEO_INVALID, + GEO_INVALID)); + continue; + } + + double la = rr_la->get_double(); + if (la < GEO_LATITUDE_MIN || la > GEO_LATITUDE_MAX) + { + results.push_back(std::make_pair(GEO_INVALID, + GEO_INVALID)); + continue; + } + + results.push_back(std::make_pair(lo, la)); + } + + return true; +} + +bool redis_geo::geopos(const char* key, const char* member, + std::pair& result) +{ + result.first = GEO_INVALID; + result.second = GEO_INVALID; + + const char* names[1]; + names[0] = member; + + hash_slot(key); + build("GEOHASH", key, names, 1); + const redis_result* rr = run(); + if (rr == NULL || rr->get_type() != REDIS_RESULT_ARRAY) + return false; + + size_t size; + const redis_result** children = rr->get_children(&size); + if (children == NULL || size != 1) + return false; + + string buf; + const redis_result* child = children[0]; + if (child->get_type() != REDIS_RESULT_ARRAY) + return false; + + size_t n; + const redis_result** xy = child->get_children(&n); + if (xy == NULL || n != 2) + return false; + + const redis_result* rr_lo = xy[0], *rr_la = xy[1]; + double lo = rr_lo->get_double(); + if (lo < GEO_LONGITUDE_MIN || lo > GEO_LONGITUDE_MAX) + return false; + + double la = rr_la->get_double(); + if (la < GEO_LATITUDE_MIN || la > GEO_LATITUDE_MAX) + return false; + + result.first = lo; + result.second = la; + return true; +} + +double redis_geo::geodist(const char* key, const char* member1, + const char* member2, int unit /* = GEO_UNIT_M */) +{ + const char* names[3]; + names[0] = member1; + names[1] = member2; + + size_t argc = 2; + + const char* unit_s = get_unit(unit); + if (unit_s != NULL) + { + names[2] = unit_s; + argc++; + } + + hash_slot(key); + build("GEODIST", key, names, argc); + + string buf; + if (get_string(buf) == 0) + return -1; + return atof(buf.c_str()); +} + +const std::vector& redis_geo::georadius(const char* key, + double longitude, double latitude, double radius, + int unit /* = GEO_UNIT_M */, + int with /* = GEO_WITH_COORD | GEO_WITH_DIST */, + int sort /* = GEO_SORT_ASC */) +{ + positions_.clear(); + + const char* argv[10]; + size_t lens[10]; + size_t argc = 0; + + argv[argc] = "GEORADIUS"; + lens[argc] = sizeof("GEORADIUS") - 1; + argc++; + + argv[argc] = key; + lens[argc] = strlen(key); + argc++; + + char* buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", longitude); + argv[argc] = buf; + lens[argc] = strlen(buf); + argc++; + + buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", latitude); + argv[argc] = buf; + lens[argc] = strlen(buf); + argc++; + + buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", radius); + argv[argc] = buf; + lens[argc] = strlen(buf); + argc++; + + const char* unit_s = get_unit(unit); + if (unit_s == NULL) + unit_s = "m"; + argv[argc] = unit_s; + lens[argc] = strlen(unit_s); + argc++; + + if ((with & GEO_WITH_COORD) != 0) + { + argv[argc] = "WITHCOORD"; + lens[argc] = sizeof("WITHCOORD") - 1; + argc++; + } + if ((with & GEO_WITH_DIST) != 0) + { + argv[argc] = "WITHDIST"; + lens[argc] = sizeof("WITHDIST") - 1; + argc++; + } + if ((with & GEO_WITH_HASH) != 0) + { + argv[argc] = "WITHHASH"; + lens[argc] = sizeof("WITHHASH") - 1; + argc++; + } + + if (sort == GEO_SORT_ASC) + { + argv[argc] = "ASC"; + lens[argc] = sizeof("ASC") - 1; + argc++; + } + else if (sort == GEO_SORT_DESC) + { + argv[argc] = "DESC"; + lens[argc] = sizeof("DESC") - 1; + argc++; + } + + hash_slot(key); + build_request(argc, argv, lens); + const redis_result* result = run(); + if (result == NULL || result->get_type() != REDIS_RESULT_ARRAY) + return positions_; + + size_t size; + const redis_result** children = result->get_children(&size); + if (children == NULL) + return positions_; + + for (size_t i = 0; i < size; i++) + add_one_pos(*children[i]); + + return positions_; +} + +const std::vector& redis_geo::georadiusbymember(const char* key, + const char* member, double radius, + int unit /* = GEO_UNIT_M */, + int with /* = GEO_WITH_COORD | GEO_WITH_DIST */, + int sort /* = GEO_SORT_ASC */) +{ + positions_.clear(); + + const char* argv[9]; + size_t lens[9]; + size_t argc = 0; + + argv[argc] = "GEORADIUSBYMEMBER"; + lens[argc] = sizeof("GEORADIUSBYMEMBER") - 1; + argc++; + + argv[argc] = key; + lens[argc] = strlen(key); + argc++; + + argv[argc] = member; + lens[argc] = strlen(member); + argc++; + + char* buf = (char*) pool_->dbuf_alloc(BUFLEN); + safe_snprintf(buf, BUFLEN, "%.8f", radius); + argv[argc] = buf; + lens[argc] = strlen(buf); + argc++; + + const char* unit_s = get_unit(unit); + if (unit_s == NULL) + unit_s = "m"; + argv[argc] = unit_s; + lens[argc] = strlen(unit_s); + argc++; + + if ((with & GEO_WITH_COORD) != 0) + { + argv[argc] = "WITHCOORD"; + lens[argc] = sizeof("WITHCOORD") - 1; + argc++; + } + if ((with & GEO_WITH_DIST) != 0) + { + argv[argc] = "WITHDIST"; + lens[argc] = sizeof("WITHDIST") - 1; + argc++; + } + if ((with & GEO_WITH_HASH) != 0) + { + argv[argc] = "WITHHASH"; + lens[argc] = sizeof("WITHHASH") - 1; + argc++; + } + + if (sort == GEO_SORT_ASC) + { + argv[argc] = "ASC"; + lens[argc] = sizeof("ASC") - 1; + argc++; + } + else if (sort == GEO_SORT_DESC) + { + argv[argc] = "DESC"; + lens[argc] = sizeof("DESC") - 1; + argc++; + } + + hash_slot(key); + build_request(argc, argv, lens); + const redis_result* result = run(); + if (result == NULL || result->get_type() != REDIS_RESULT_ARRAY) + return positions_; + + size_t size; + const redis_result** children = result->get_children(&size); + if (children == NULL) + return positions_; + + for (size_t i = 0; i < size; i++) + add_one_pos(*children[i]); + + return positions_; +} + +void redis_geo::add_one_pos(const redis_result& rr) +{ + string buf; + acl::redis_result_t type = rr.get_type(); + if (type == REDIS_RESULT_STRING) + { + rr.argv_to_string(buf); + positions_.push_back(geo_member(buf.c_str())); + return; + } + if (type != REDIS_RESULT_ARRAY) + return; + + size_t size; + const redis_result** children = rr.get_children(&size); + if (children == NULL || size == 0) + return; + + if (children[0]->get_type() != REDIS_RESULT_STRING) + return; + children[0]->argv_to_string(buf); + geo_member pos(buf.c_str()); + + for (size_t i = 1; i < size; i++) + { + type = children[i]->get_type(); + if (type == REDIS_RESULT_STRING) + pos.set_dist(children[i]->get_double()); + else if (type == REDIS_RESULT_INTEGER) + { + bool ok; + acl_int64 hash = children[i]->get_integer64(&ok); + if (ok) + pos.set_hash(hash); + } + else if (type != REDIS_RESULT_ARRAY) + continue; + + size_t n; + const redis_result** results = children[i]->get_children(&n); + if (results != NULL && n == 2 + && results[0]->get_type() == REDIS_RESULT_STRING + && results[1]->get_type() == REDIS_RESULT_STRING) + { + pos.set_coordinate(results[0]->get_double(), + results[1]->get_double()); + } + } + + positions_.push_back(pos); +} + +///////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int unit; + const char* str; +} UNIT_MAP; + +const char* redis_geo::get_unit(int unit) +{ + static const UNIT_MAP _map[] = { + { GEO_UNIT_FT, "ft" }, + { GEO_UNIT_M, "m" }, + { GEO_UNIT_MI, "mi" }, + { GEO_UNIT_KM, "km" }, + }; + + if (unit < GEO_UNIT_FT || unit > GEO_UNIT_KM) + return NULL; + return _map[unit].str; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/redis/redis_result.cpp b/lib_acl_cpp/src/redis/redis_result.cpp index be8725e33..594fb382e 100644 --- a/lib_acl_cpp/src/redis/redis_result.cpp +++ b/lib_acl_cpp/src/redis/redis_result.cpp @@ -128,6 +128,20 @@ long long int redis_result::get_integer64(bool* success /* = NULL */) const return acl_atoi64(ptr); } +double redis_result::get_double(bool* success /* = NULL */) const +{ + if (success) + *success = false; + if (result_type_ != REDIS_RESULT_STRING) + return -1; + const char* ptr = get(0); + if (ptr == NULL || *ptr == 0) + return -1; + if (success) + *success = true; + return atof(ptr); +} + const char* redis_result::get_status() const { if (result_type_ != REDIS_RESULT_STATUS)