init.
This commit is contained in:
commit
be46fb9db8
|
|
@ -0,0 +1 @@
|
|||
build
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(HP-Socket LANGUAGES C CXX)
|
||||
|
||||
# 设置编译选项
|
||||
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
set(CMAKE_BUILD_TYPE Debug) # 发布模式(可选 Debug)
|
||||
|
||||
# 定义源码目录和头文件目录
|
||||
set(HP_SOCKET_SRC_DIR ${PROJECT_SOURCE_DIR}/src)
|
||||
set(HP_SOCKET_INC_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
# 收集所有源文件(根据实际源码结构调整)
|
||||
file(GLOB HP_SOCKET_SOURCES
|
||||
${HP_SOCKET_SRC_DIR}/*.c
|
||||
${HP_SOCKET_SRC_DIR}/*.cpp
|
||||
${HP_SOCKET_SRC_DIR}/linux/*.c
|
||||
${HP_SOCKET_SRC_DIR}/linux/*.c
|
||||
${HP_SOCKET_SRC_DIR}/common/*.cpp
|
||||
${HP_SOCKET_SRC_DIR}/common/http/*.c
|
||||
${HP_SOCKET_SRC_DIR}/common/kcp/*.c
|
||||
${PROJECT_SOURCE_DIR}/global/*.cpp
|
||||
)
|
||||
|
||||
# 收集头文件(用于 IDE 索引)
|
||||
file(GLOB HP_SOCKET_HEADERS
|
||||
${HP_SOCKET_INC_DIR}/*.h
|
||||
${HP_SOCKET_INC_DIR}/*.hpp
|
||||
)
|
||||
|
||||
# 包含头文件目录
|
||||
include_directories(${HP_SOCKET_INC_DIR})
|
||||
include_directories(${HP_SOCKET_SRC_DIR})
|
||||
include_directories(${HP_SOCKET_SRC_DIR}/linux) # Linux 平台相关头文件
|
||||
include_directories(${PROJECT_SOURCE_DIR}/global)
|
||||
|
||||
# 定义库目标(动态库:SHARED,静态库:STATIC)
|
||||
add_library(hp-socket SHARED ${HP_SOCKET_SOURCES} ${HP_SOCKET_HEADERS})
|
||||
|
||||
|
||||
|
||||
|
||||
# 链接系统库(Linux 需链接 pthread 和 rt)
|
||||
target_link_libraries(hp-socket PRIVATE pthread rt)
|
||||
|
||||
|
||||
add_executable(client ${PROJECT_SOURCE_DIR}/client/client.cpp)
|
||||
target_link_libraries(client PRIVATE pthread rt)
|
||||
target_link_libraries(client PRIVATE hp-socket)
|
||||
|
||||
add_executable(server ${PROJECT_SOURCE_DIR}/server/server.cpp)
|
||||
target_link_libraries(server PRIVATE pthread rt)
|
||||
target_link_libraries(server PRIVATE hp-socket)
|
||||
|
||||
# 可选:若启用 SSL,链接 OpenSSL
|
||||
# find_package(OpenSSL REQUIRED)
|
||||
# target_link_libraries(hp-socket PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
|
@ -0,0 +1,159 @@
|
|||

|
||||
---
|
||||
*高性能跨平台网络通信框架*
|
||||
## 描述
|
||||
- ***Server*** 基于IOCP / EPOLL通信模型,并结合缓存池、私有堆等技术实现高效内存管理,支持超大规模、高并发通信场景。
|
||||
- ***Agent*** Agent组件实质上是Multi-Client组件,与Server组件采用相同的技术架构。一个Agent组件对象可同时建立和高效处理大规模Socket连接。
|
||||
- ***Client*** 基于Event Select / POLL通信模型,每个组件对象创建一个通信线程并管理一个Socket连接,适用于小规模客户端场景。
|
||||
## 文档
|
||||
- HP-Socket开发指南
|
||||
[[pdf]](Doc/HP-Socket%20Development%20Guide.pdf)
|
||||
- HP-Socket基础组件类图
|
||||
[[uml]](Doc/HP-Socket%20Class%20Diagram.uml)
|
||||
- HP-Socket基础组件类图
|
||||
[[jpg]](Doc/HP-Socket%20Class%20Diagram.jpg)
|
||||
- HP-Socket SSL组件类图组件
|
||||
[[jpg]](Doc/HP-Socket%20SSL%20Class%20Diagram.jpg)
|
||||
- HP-Socket HTTP组件类图
|
||||
[[jpg]](Doc/HP-Socket%20HTTP%20Class%20Diagram.jpg)
|
||||
## 工作流程
|
||||
1. 创建监听器
|
||||
2. 创建通信组件(同时绑定监听器)
|
||||
3. 启动通信组件
|
||||
4. 连接到目标主机(*Agent*组件)
|
||||
5. 处理通信事件(*OnConnect/OnReceive/OnClose*等)
|
||||
6. 停止通信组件(可选:在第7步销毁通信组件时会自动停止组件)
|
||||
7. 销毁通信组件
|
||||
8. 销毁监听器
|
||||
|
||||

|
||||
## 示例
|
||||
- ***C++示例***
|
||||
|
||||
``` C++
|
||||
#include <hpsocket/HPSocket.h>
|
||||
|
||||
/* Listener Class */
|
||||
class CListenerImpl : public CTcpPullServerListener
|
||||
{
|
||||
|
||||
public:
|
||||
// 5. process network events
|
||||
virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen);
|
||||
virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient);
|
||||
virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID);
|
||||
virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength);
|
||||
virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode);
|
||||
virtual EnHandleResult OnShutdown(ITcpServer* pSender);
|
||||
};
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
// 1. Create listener object
|
||||
CListenerImpl s_listener;
|
||||
// 2. Create component object (and binding with listener object)
|
||||
CTcpPullServerPtr s_pserver(&s_listener);
|
||||
|
||||
// 3. Start component object
|
||||
if(!s_pserver->Start("0.0.0.0", 5555))
|
||||
exit(1);
|
||||
|
||||
/* wait for exit */
|
||||
// ... ...
|
||||
|
||||
// 6. (optional) Stop component object
|
||||
s_pserver->Stop();
|
||||
|
||||
return 0;
|
||||
|
||||
// 7. Destroy component object automatically
|
||||
// 8. Destroy listener object automatically
|
||||
}
|
||||
```
|
||||
|
||||
- ***C示例***
|
||||
|
||||
``` C
|
||||
#include <hpsocket/HPSocket4C.h>
|
||||
|
||||
// 5. process network events
|
||||
EnHandleResult __HP_CALL OnConnect(HP_Agent pSender, HP_CONNID dwConnID);
|
||||
EnHandleResult __HP_CALL OnReceive(HP_Agent pSender, HP_CONNID dwConnID, int iLength);
|
||||
EnHandleResult __HP_CALL OnSend(HP_Agent pSender, HP_CONNID dwConnID, const BYTE* pData, int iLength);
|
||||
EnHandleResult __HP_CALL OnClose(HP_Agent pSender, HP_CONNID dwConnID, En_HP_SocketOperation enOperation, int iErrorCode);
|
||||
EnHandleResult __HP_CALL OnShutdown(HP_Agent pSender);
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
HP_TcpPullAgentListener s_listener;
|
||||
HP_TcpPullAgent s_agent;
|
||||
|
||||
// 1. Create listener object
|
||||
s_listener = ::Create_HP_TcpPullAgentListener();
|
||||
// 2. Create component object (and binding with listener object)
|
||||
s_agent = ::Create_HP_TcpPullAgent(s_listener);
|
||||
|
||||
/* Set listener callbacks */
|
||||
::HP_Set_FN_Agent_OnConnect(s_listener, OnConnect);
|
||||
::HP_Set_FN_Agent_OnSend(s_listener, OnSend);
|
||||
::HP_Set_FN_Agent_OnPullReceive(s_listener, OnReceive);
|
||||
::HP_Set_FN_Agent_OnClose(s_listener, OnClose);
|
||||
::HP_Set_FN_Agent_OnShutdown(s_listener, OnShutdown);
|
||||
|
||||
// 3. Start component object
|
||||
if(!::HP_Agent_Start(s_agent, "0.0.0.0", TRUE))
|
||||
exit(1);
|
||||
|
||||
// 4. Connect to dest host
|
||||
::HP_Agent_Connect(s_agent, REMOTE_HOST_1, REMOTE_PORT_1, nullptr);
|
||||
::HP_Agent_Connect(s_agent, REMOTE_HOST_2, REMOTE_PORT_2, nullptr);
|
||||
::HP_Agent_Connect(s_agent, REMOTE_HOST_3, REMOTE_PORT_3, nullptr);
|
||||
|
||||
/* wait for exit */
|
||||
// ... ...
|
||||
|
||||
// 6. (optional) Stop component object
|
||||
::HP_Agent_Stop(s_agent);
|
||||
|
||||
// 7. Destroy component object
|
||||
::Destroy_HP_TcpPullAgent(s_agent);
|
||||
// 8. Destroy listener object
|
||||
::Destroy_HP_TcpPullAgentListener(s_listener);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 组件列表
|
||||
- ***基础组件***
|
||||
|
||||

|
||||
|
||||
- ***SSL组件***
|
||||
|
||||

|
||||
|
||||
- ***HTTP组件***
|
||||
|
||||

|
||||
|
||||
## 引用项目
|
||||
|
||||
- *[mimalloc](https://github.com/microsoft/mimalloc)*
|
||||
- *[jemalloc](https://github.com/jemalloc/jemalloc)*
|
||||
- *[openssl](https://github.com/openssl/openssl)*
|
||||
- *[llhttp](https://github.com/nodejs/llhttp)*
|
||||
- *[zlib](https://github.com/madler/zlib)*
|
||||
- *[brotli](https://github.com/google/brotli)*
|
||||
- *[kcp](https://github.com/skywind3000/kcp)*
|
||||
|
||||
## 扩展项目
|
||||
|
||||
- *[HP-Socket for MacOS](https://gitee.com/xin_chong/HP-Socket-for-macOS)*
|
||||
- *[HP-Socket for .Net](https://gitee.com/int2e/HPSocket.Net)*
|
||||
|
||||
## 技术交流
|
||||
|
||||
- *[怪兽乐园①群](https://jq.qq.com/?_wv=1027&k=3UAbrhTG)*
|
||||
- *[怪兽乐园②群](https://jq.qq.com/?_wv=1027&k=uYBpc6bG)*
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
#undef _BROTLI_SUPPORT
|
||||
|
||||
#include "helper.h"
|
||||
#include "TcpClient.h"
|
||||
|
||||
class CListenerImpl : public CTcpClientListener
|
||||
{
|
||||
|
||||
public:
|
||||
virtual EnHandleResult OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket) override
|
||||
{
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID) override
|
||||
{
|
||||
TCHAR szAddress[100];
|
||||
int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
|
||||
USHORT usPort;
|
||||
|
||||
pSender->GetRemoteHost(szAddress, iAddressLen, usPort);
|
||||
|
||||
::PostOnConnect2(dwConnID, szAddress, usPort);
|
||||
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnHandShake(ITcpClient* pSender, CONNID dwConnID) override
|
||||
{
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override
|
||||
{
|
||||
::PostOnReceive(dwConnID, pData, iLength);
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override
|
||||
{
|
||||
::PostOnSend(dwConnID, pData, iLength);
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) override
|
||||
{
|
||||
iErrorCode == SE_OK ? ::PostOnClose(dwConnID) :
|
||||
::PostOnError(dwConnID, enOperation, iErrorCode);
|
||||
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CListenerImpl s_listener;
|
||||
CTcpClient s_client(&s_listener);
|
||||
|
||||
void OnCmdStart(CCommandParser* pParser)
|
||||
{
|
||||
if(s_client.Start(g_app_arg.remote_addr, g_app_arg.port, g_app_arg.async, g_app_arg.bind_addr))
|
||||
::LogClientStart(g_app_arg.remote_addr, g_app_arg.port);
|
||||
else
|
||||
::LogClientStartFail(s_client.GetLastError(), s_client.GetLastErrorDesc());
|
||||
}
|
||||
|
||||
void OnCmdStop(CCommandParser* pParser)
|
||||
{
|
||||
if(s_client.Stop())
|
||||
::LogClientStop();
|
||||
else
|
||||
::LogClientStopFail(s_client.GetLastError(), s_client.GetLastErrorDesc());
|
||||
}
|
||||
|
||||
void OnCmdStatus(CCommandParser* pParser)
|
||||
{
|
||||
pParser->PrintStatus(s_client.GetState());
|
||||
}
|
||||
|
||||
void OnCmdSend(CCommandParser* pParser)
|
||||
{
|
||||
if(s_client.Send((LPBYTE)(LPCTSTR)pParser->m_strMessage, pParser->m_strMessage.GetLength()))
|
||||
::LogSend(s_client.GetConnectionID(), pParser->m_strMessage);
|
||||
else
|
||||
::LogSendFail(s_client.GetConnectionID(), ::GetLastError(), ::GetLastErrorStr());
|
||||
}
|
||||
|
||||
void OnCmdPause(CCommandParser* pParser)
|
||||
{
|
||||
if(s_client.PauseReceive(pParser->m_bFlag))
|
||||
::LogPause(s_client.GetConnectionID(), pParser->m_bFlag);
|
||||
else
|
||||
::LogPauseFail(s_client.GetConnectionID(), pParser->m_bFlag);
|
||||
}
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
CTermAttrInitializer term_attr;
|
||||
CAppSignalHandler s_signal_handler({SIGTTOU, SIGINT});
|
||||
|
||||
g_app_arg.ParseArgs(argc, argv);
|
||||
|
||||
s_client.SetKeepAliveTime(g_app_arg.keep_alive ? TCP_KEEPALIVE_TIME : 0);
|
||||
|
||||
CCommandParser::CMD_FUNC fnCmds[CCommandParser::CT_MAX] = {0};
|
||||
|
||||
fnCmds[CCommandParser::CT_START] = OnCmdStart;
|
||||
fnCmds[CCommandParser::CT_STOP] = OnCmdStop;
|
||||
fnCmds[CCommandParser::CT_STATUS] = OnCmdStatus;
|
||||
fnCmds[CCommandParser::CT_SEND] = OnCmdSend;
|
||||
fnCmds[CCommandParser::CT_PAUSE] = OnCmdPause;
|
||||
|
||||
CCommandParser s_cmd_parser(CCommandParser::AT_CLIENT, fnCmds);
|
||||
s_cmd_parser.Run();
|
||||
|
||||
return EXIT_CODE_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x86">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x86</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x86">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x86</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A72AD679-483D-4754-AAF6-9DCFCDF49F14}</ProjectGuid>
|
||||
<Keyword>Linux</Keyword>
|
||||
<RootNamespace>client</RootNamespace>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
<ApplicationType>Linux</ApplicationType>
|
||||
<ApplicationTypeRevision>1.0</ApplicationTypeRevision>
|
||||
<TargetLinuxPlatform>Generic</TargetLinuxPlatform>
|
||||
<LinuxProjectType>{D51BCBC9-82E9-4017-911E-C93873C4EA2B}</LinuxProjectType>
|
||||
<ProjectName>client</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<RemoteRootDir>$HOME/MyWork/HP-Socket/Linux/demo</RemoteRootDir>
|
||||
<RemoteProjectRelDir>$(SolutionName)</RemoteProjectRelDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<RemoteRootDir>$HOME/MyWork/HP-Socket/Linux/demo</RemoteRootDir>
|
||||
<RemoteProjectRelDir>$(SolutionName)</RemoteProjectRelDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<RemoteRootDir>$HOME/MyWork/HP-Socket/Linux/demo</RemoteRootDir>
|
||||
<RemoteProjectRelDir>$(SolutionName)</RemoteProjectRelDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<RemoteRootDir>$HOME/MyWork/HP-Socket/Linux/demo</RemoteRootDir>
|
||||
<RemoteProjectRelDir>$(SolutionName)</RemoteProjectRelDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<RemoteRootDir>$HOME/MyWork/HP-Socket/Linux/demo</RemoteRootDir>
|
||||
<RemoteProjectRelDir>$(SolutionName)</RemoteProjectRelDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<RemoteRootDir>$HOME/MyWork/HP-Socket/Linux/demo</RemoteRootDir>
|
||||
<RemoteProjectRelDir>$(SolutionName)</RemoteProjectRelDir>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="Shared" />
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<OutDir>../../$(Configuration)/$(Platform)/</OutDir>
|
||||
<IntDir>$(OutDir)obj/$(SolutionName)/$(ProjectName)/</IntDir>
|
||||
<TargetName>hp-$(SolutionName)-$(ProjectName)</TargetName>
|
||||
<TargetExt>.exe</TargetExt>
|
||||
<RemoteProjectDir>$(RemoteRootDir)/$(SolutionName)/$(ProjectName)</RemoteProjectDir>
|
||||
<LocalRemoteCopySources>false</LocalRemoteCopySources>
|
||||
<RemoteLinkLocalCopyOutput>false</RemoteLinkLocalCopyOutput>
|
||||
<RemoteIntRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(IntDir)</RemoteIntRelDir>
|
||||
<RemoteOutRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(OutDir)</RemoteOutRelDir>
|
||||
<RemoteDeployDir>$(RemoteOutputRelDir)</RemoteDeployDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<OutDir>../../$(Configuration)/$(Platform)/</OutDir>
|
||||
<IntDir>$(OutDir)obj/$(SolutionName)/$(ProjectName)/</IntDir>
|
||||
<TargetName>hp-$(SolutionName)-$(ProjectName)</TargetName>
|
||||
<TargetExt>.exe</TargetExt>
|
||||
<RemoteProjectDir>$(RemoteRootDir)/$(SolutionName)/$(ProjectName)</RemoteProjectDir>
|
||||
<LocalRemoteCopySources>false</LocalRemoteCopySources>
|
||||
<RemoteLinkLocalCopyOutput>false</RemoteLinkLocalCopyOutput>
|
||||
<RemoteIntRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(IntDir)</RemoteIntRelDir>
|
||||
<RemoteOutRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(OutDir)</RemoteOutRelDir>
|
||||
<RemoteDeployDir>$(RemoteOutputRelDir)</RemoteDeployDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>../../$(Configuration)/$(Platform)/</OutDir>
|
||||
<IntDir>$(OutDir)obj/$(SolutionName)/$(ProjectName)/</IntDir>
|
||||
<TargetName>hp-$(SolutionName)-$(ProjectName)</TargetName>
|
||||
<TargetExt>.exe</TargetExt>
|
||||
<RemoteProjectDir>$(RemoteRootDir)/$(SolutionName)/$(ProjectName)</RemoteProjectDir>
|
||||
<LocalRemoteCopySources>false</LocalRemoteCopySources>
|
||||
<RemoteLinkLocalCopyOutput>false</RemoteLinkLocalCopyOutput>
|
||||
<RemoteIntRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(IntDir)</RemoteIntRelDir>
|
||||
<RemoteOutRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(OutDir)</RemoteOutRelDir>
|
||||
<RemoteDeployDir>$(RemoteOutputRelDir)</RemoteDeployDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>../../$(Configuration)/$(Platform)/</OutDir>
|
||||
<IntDir>$(OutDir)obj/$(SolutionName)/$(ProjectName)/</IntDir>
|
||||
<TargetName>hp-$(SolutionName)-$(ProjectName)</TargetName>
|
||||
<TargetExt>.exe</TargetExt>
|
||||
<RemoteProjectDir>$(RemoteRootDir)/$(SolutionName)/$(ProjectName)</RemoteProjectDir>
|
||||
<LocalRemoteCopySources>false</LocalRemoteCopySources>
|
||||
<RemoteLinkLocalCopyOutput>false</RemoteLinkLocalCopyOutput>
|
||||
<RemoteIntRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(IntDir)</RemoteIntRelDir>
|
||||
<RemoteOutRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(OutDir)</RemoteOutRelDir>
|
||||
<RemoteDeployDir>$(RemoteOutputRelDir)</RemoteDeployDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||
<OutDir>../../$(Configuration)/$(Platform)/</OutDir>
|
||||
<IntDir>$(OutDir)obj/$(SolutionName)/$(ProjectName)/</IntDir>
|
||||
<TargetName>hp-$(SolutionName)-$(ProjectName)</TargetName>
|
||||
<TargetExt>.exe</TargetExt>
|
||||
<RemoteProjectDir>$(RemoteRootDir)/$(SolutionName)/$(ProjectName)</RemoteProjectDir>
|
||||
<LocalRemoteCopySources>false</LocalRemoteCopySources>
|
||||
<RemoteLinkLocalCopyOutput>false</RemoteLinkLocalCopyOutput>
|
||||
<RemoteIntRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(IntDir)</RemoteIntRelDir>
|
||||
<RemoteOutRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(OutDir)</RemoteOutRelDir>
|
||||
<RemoteDeployDir>$(RemoteOutputRelDir)</RemoteDeployDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
||||
<OutDir>../../$(Configuration)/$(Platform)/</OutDir>
|
||||
<IntDir>$(OutDir)obj/$(SolutionName)/$(ProjectName)/</IntDir>
|
||||
<TargetName>hp-$(SolutionName)-$(ProjectName)</TargetName>
|
||||
<TargetExt>.exe</TargetExt>
|
||||
<RemoteProjectDir>$(RemoteRootDir)/$(SolutionName)/$(ProjectName)</RemoteProjectDir>
|
||||
<LocalRemoteCopySources>false</LocalRemoteCopySources>
|
||||
<RemoteLinkLocalCopyOutput>false</RemoteLinkLocalCopyOutput>
|
||||
<RemoteIntRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(IntDir)</RemoteIntRelDir>
|
||||
<RemoteOutRelDir>$(RemoteProjectRelDir)/$(ProjectName)/$(OutDir)</RemoteOutRelDir>
|
||||
<RemoteDeployDir>$(RemoteOutputRelDir)</RemoteDeployDir>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\src\common\BufferPool.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\Event.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\FileHelper.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\FuncHelper.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\IODispatcher.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\PollHelper.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\RWLock.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\SysHelper.cpp" />
|
||||
<ClCompile Include="..\..\..\src\common\Thread.cpp" />
|
||||
<ClCompile Include="..\..\..\src\SocketHelper.cpp" />
|
||||
<ClCompile Include="..\..\..\src\TcpClient.cpp" />
|
||||
<ClCompile Include="..\..\Global\helper.cpp" />
|
||||
<ClCompile Include="client.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\common\BufferPool.h" />
|
||||
<ClInclude Include="..\..\..\src\common\BufferPtr.h" />
|
||||
<ClInclude Include="..\..\..\src\common\CriSec.h" />
|
||||
<ClInclude Include="..\..\..\src\common\Event.h" />
|
||||
<ClInclude Include="..\..\..\src\common\FileHelper.h" />
|
||||
<ClInclude Include="..\..\..\src\common\FuncHelper.h" />
|
||||
<ClInclude Include="..\..\..\src\common\GeneralHelper.h" />
|
||||
<ClInclude Include="..\..\..\include\hpsocket\GlobalDef.h" />
|
||||
<ClInclude Include="..\..\..\include\hpsocket\GlobalErrno.h" />
|
||||
<ClInclude Include="..\..\..\src\common\IODispatcher.h" />
|
||||
<ClInclude Include="..\..\..\src\common\PollHelper.h" />
|
||||
<ClInclude Include="..\..\..\src\common\PrivateHeap.h" />
|
||||
<ClInclude Include="..\..\..\src\common\RingBuffer.h" />
|
||||
<ClInclude Include="..\..\..\src\common\RWLock.h" />
|
||||
<ClInclude Include="..\..\..\src\common\Semaphore.h" />
|
||||
<ClInclude Include="..\..\..\src\common\SignalHandler.h" />
|
||||
<ClInclude Include="..\..\..\src\common\Singleton.h" />
|
||||
<ClInclude Include="..\..\..\src\common\STLHelper.h" />
|
||||
<ClInclude Include="..\..\..\src\common\StringT.h" />
|
||||
<ClInclude Include="..\..\..\src\common\SysHelper.h" />
|
||||
<ClInclude Include="..\..\..\src\common\Thread.h" />
|
||||
<ClInclude Include="..\..\..\include\hpsocket\HPTypeDef.h" />
|
||||
<ClInclude Include="..\..\..\src\SocketHelper.h" />
|
||||
<ClInclude Include="..\..\..\include\hpsocket\SocketInterface.h" />
|
||||
<ClInclude Include="..\..\..\src\TcpClient.h" />
|
||||
<ClInclude Include="..\..\Global\helper.h" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<ClCompile>
|
||||
<CppAdditionalWarning>no-class-memaccess;no-reorder;switch;no-deprecated-declarations;empty-body;conversion;return-type;parentheses;no-format;uninitialized;unreachable-code;unused-function;unused-value;unused-variable;%(CppAdditionalWarning)</CppAdditionalWarning>
|
||||
<CppLanguageStandard>c++17</CppLanguageStandard>
|
||||
<SymbolsHiddenByDefault>true</SymbolsHiddenByDefault>
|
||||
<AdditionalIncludeDirectories>../../../dependent/$(Platform)/include;$(StlIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_UDP_DISABLED;_SSL_DISABLED;_HTTP_DISABLED;_ZLIB_DISABLED;_BROTLI_DISABLED;</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LibraryDependencies>rt;pthread;dl</LibraryDependencies>
|
||||
<AdditionalLibraryDirectories>../../../dependent/$(Platform)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>-L"$(RemoteRootDir)/../dependent/$(Platform)/lib" %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<ClCompile>
|
||||
<CppAdditionalWarning>no-class-memaccess;no-reorder;switch;no-deprecated-declarations;empty-body;conversion;return-type;parentheses;no-format;uninitialized;unreachable-code;unused-function;unused-value;unused-variable;%(CppAdditionalWarning)</CppAdditionalWarning>
|
||||
<CppLanguageStandard>c++17</CppLanguageStandard>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<SymbolsHiddenByDefault>true</SymbolsHiddenByDefault>
|
||||
<AdditionalIncludeDirectories>../../../dependent/$(Platform)/include;$(StlIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_UDP_DISABLED;_SSL_DISABLED;_HTTP_DISABLED;_ZLIB_DISABLED;_BROTLI_DISABLED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LibraryDependencies>mimalloc;rt;pthread;dl</LibraryDependencies>
|
||||
<AdditionalLibraryDirectories>../../../dependent/$(Platform)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>-L"$(RemoteRootDir)/../dependent/$(Platform)/lib" %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<CppAdditionalWarning>no-class-memaccess;no-reorder;switch;no-deprecated-declarations;empty-body;conversion;return-type;parentheses;no-format;uninitialized;unreachable-code;unused-function;unused-value;unused-variable;%(CppAdditionalWarning)</CppAdditionalWarning>
|
||||
<CppLanguageStandard>c++17</CppLanguageStandard>
|
||||
<SymbolsHiddenByDefault>true</SymbolsHiddenByDefault>
|
||||
<AdditionalIncludeDirectories>../../../dependent/$(Platform)/include;$(StlIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_UDP_DISABLED;_SSL_DISABLED;_HTTP_DISABLED;_ZLIB_DISABLED;_BROTLI_DISABLED;</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LibraryDependencies>rt;pthread;dl</LibraryDependencies>
|
||||
<AdditionalLibraryDirectories>../../../dependent/$(Platform)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>-L"$(RemoteRootDir)/../dependent/$(Platform)/lib" %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<CppAdditionalWarning>no-class-memaccess;no-reorder;switch;no-deprecated-declarations;empty-body;conversion;return-type;parentheses;no-format;uninitialized;unreachable-code;unused-function;unused-value;unused-variable;%(CppAdditionalWarning)</CppAdditionalWarning>
|
||||
<CppLanguageStandard>c++17</CppLanguageStandard>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<SymbolsHiddenByDefault>true</SymbolsHiddenByDefault>
|
||||
<AdditionalIncludeDirectories>../../../dependent/$(Platform)/include;$(StlIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_UDP_DISABLED;_SSL_DISABLED;_HTTP_DISABLED;_ZLIB_DISABLED;_BROTLI_DISABLED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LibraryDependencies>mimalloc;rt;pthread;dl</LibraryDependencies>
|
||||
<AdditionalLibraryDirectories>../../../dependent/$(Platform)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>-L"$(RemoteRootDir)/../dependent/$(Platform)/lib" %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||
<ClCompile>
|
||||
<CppAdditionalWarning>no-class-memaccess;no-reorder;switch;no-deprecated-declarations;empty-body;conversion;return-type;parentheses;no-format;uninitialized;unreachable-code;unused-function;unused-value;unused-variable;%(CppAdditionalWarning)</CppAdditionalWarning>
|
||||
<CppLanguageStandard>c++17</CppLanguageStandard>
|
||||
<SymbolsHiddenByDefault>true</SymbolsHiddenByDefault>
|
||||
<AdditionalIncludeDirectories>../../../dependent/$(Platform)/include;$(StlIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_UDP_DISABLED;_SSL_DISABLED;_HTTP_DISABLED;_ZLIB_DISABLED;_BROTLI_DISABLED;</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LibraryDependencies>rt;pthread;dl</LibraryDependencies>
|
||||
<AdditionalLibraryDirectories>../../../dependent/$(Platform)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>-L"$(RemoteRootDir)/../dependent/$(Platform)/lib" %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
||||
<ClCompile>
|
||||
<CppAdditionalWarning>no-class-memaccess;no-reorder;switch;no-deprecated-declarations;empty-body;conversion;return-type;parentheses;no-format;uninitialized;unreachable-code;unused-function;unused-value;unused-variable;%(CppAdditionalWarning)</CppAdditionalWarning>
|
||||
<CppLanguageStandard>c++17</CppLanguageStandard>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<SymbolsHiddenByDefault>true</SymbolsHiddenByDefault>
|
||||
<AdditionalIncludeDirectories>../../../dependent/$(Platform)/include;$(StlIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_UDP_DISABLED;_SSL_DISABLED;_HTTP_DISABLED;_ZLIB_DISABLED;_BROTLI_DISABLED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LibraryDependencies>mimalloc;rt;pthread;dl</LibraryDependencies>
|
||||
<AdditionalLibraryDirectories>../../../dependent/$(Platform)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>-L"$(RemoteRootDir)/../dependent/$(Platform)/lib" %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Main">
|
||||
<UniqueIdentifier>{89aa27f5-854a-4f0f-b354-ad45f3467e4a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Common">
|
||||
<UniqueIdentifier>{62af1e40-2972-4998-98ce-183503d5b9f1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="HPSocket">
|
||||
<UniqueIdentifier>{6dfe1087-bd2e-422b-b9bb-44ea3edf3d8e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Global">
|
||||
<UniqueIdentifier>{88ead97d-e618-4da0-8572-fcfb5e5cd08c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="client.cpp">
|
||||
<Filter>Main</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\BufferPool.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\Event.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\FileHelper.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\FuncHelper.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\IODispatcher.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\PollHelper.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\RWLock.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\SysHelper.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\SocketHelper.cpp">
|
||||
<Filter>HPSocket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Global\helper.cpp">
|
||||
<Filter>Global</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\TcpClient.cpp">
|
||||
<Filter>HPSocket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\common\Thread.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\common\BufferPool.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\BufferPtr.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\CriSec.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\Event.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\FileHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\FuncHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\GeneralHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\include\hpsocket\GlobalDef.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\include\hpsocket\GlobalErrno.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\IODispatcher.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\PollHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\PrivateHeap.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\RingBuffer.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\RWLock.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\Semaphore.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\SignalHandler.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\Singleton.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\STLHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\SysHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\Thread.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\include\hpsocket\HPTypeDef.h">
|
||||
<Filter>HPSocket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\SocketHelper.h">
|
||||
<Filter>HPSocket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\include\hpsocket\SocketInterface.h">
|
||||
<Filter>HPSocket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Global\helper.h">
|
||||
<Filter>Global</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\common\StringT.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\TcpClient.h">
|
||||
<Filter>HPSocket</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<RemoteTarget>-50468727;192.168.56.13 (username=, port=22, authentication=Password)</RemoteTarget>
|
||||
<RemoteDebuggingMode>gdb</RemoteDebuggingMode>
|
||||
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
|
||||
<RemoteDebuggerCommandArguments>-a 127.0.0.1 -p 5555 -n 0</RemoteDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<RemoteTarget>-50468727;192.168.56.13 (username=, port=22, authentication=Password)</RemoteTarget>
|
||||
<RemoteDebuggingMode>gdb</RemoteDebuggingMode>
|
||||
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
|
||||
<RemoteDebuggerCommandArguments>-a 127.0.0.1 -p 5555 -n 0</RemoteDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||
<RemoteTarget>-561002904;192.168.56.14 (username=, port=22, authentication=Password)</RemoteTarget>
|
||||
<RemoteDebuggingMode>gdb</RemoteDebuggingMode>
|
||||
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
|
||||
<RemoteDebuggerCommandArguments>-a 127.0.0.1 -p 5555 -n 0</RemoteDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
||||
<RemoteTarget>-561002904;192.168.56.14 (username=, port=22, authentication=Password)</RemoteTarget>
|
||||
<RemoteDebuggingMode>gdb</RemoteDebuggingMode>
|
||||
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
|
||||
<RemoteDebuggerCommandArguments>-a 127.0.0.1 -p 5555 -n 0</RemoteDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<RemoteDebuggingMode>gdb</RemoteDebuggingMode>
|
||||
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
|
||||
<RemoteDebuggerCommandArguments>-a 127.0.0.1 -p 5555 -n 0</RemoteDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<RemoteDebuggingMode>gdb</RemoteDebuggingMode>
|
||||
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
|
||||
<RemoteDebuggerCommandArguments>-a 127.0.0.1 -p 5555 -n 0</RemoteDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,258 @@
|
|||
#pragma once
|
||||
|
||||
#include "hpsocket/GlobalDef.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// -------------------------------------------------- BASE64 -------------------------------------------------- //
|
||||
|
||||
// Returns the size of the output. If called with out = NULL, will just return
|
||||
// the size of what the output would have been (without a terminating NULL).
|
||||
size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag);
|
||||
|
||||
// Returns the size of the output. If called with out = NULL, will just return
|
||||
// the size of what the output would have been (without a terminating NULL).
|
||||
size_t base64_decode(const BYTE in[], BYTE out[], size_t len);
|
||||
|
||||
// -------------------------------------------------- URL -------------------------------------------------- //
|
||||
|
||||
int url_encode(const char* src, const int src_size, char* dest, const int dest_size);
|
||||
int url_decode(const char* src, const int src_size, char* dest, const int dest_size);
|
||||
|
||||
// -------------------------------------------------- AES -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
//typedef unsigned char BYTE; // 8-bit byte
|
||||
//typedef unsigned int UINT; // 32-bit word, change to "long" for 16-bit machines
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
///////////////////
|
||||
// AES
|
||||
///////////////////
|
||||
// Key setup must be done before any AES en/de-cryption functions can be used.
|
||||
void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits
|
||||
UINT w[], // Output key schedule to be used later
|
||||
int keysize); // Bit length of the key, 128, 192, or 256
|
||||
|
||||
void aes_encrypt(const BYTE in[], // 16 bytes of plaintext
|
||||
BYTE out[], // 16 bytes of ciphertext
|
||||
const UINT key[], // From the key setup
|
||||
int keysize); // Bit length of the key, 128, 192, or 256
|
||||
|
||||
void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext
|
||||
BYTE out[], // 16 bytes of plaintext
|
||||
const UINT key[], // From the key setup
|
||||
int keysize); // Bit length of the key, 128, 192, or 256
|
||||
|
||||
///////////////////
|
||||
// AES - CBC
|
||||
///////////////////
|
||||
int aes_encrypt_cbc(const BYTE in[], // Plaintext
|
||||
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
|
||||
BYTE out[], // Ciphertext, same length as plaintext
|
||||
const UINT key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
// Only output the CBC-MAC of the input.
|
||||
int aes_encrypt_cbc_mac(const BYTE in[], // plaintext
|
||||
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
|
||||
BYTE out[], // Output MAC
|
||||
const UINT key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
///////////////////
|
||||
// AES - CTR
|
||||
///////////////////
|
||||
void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE
|
||||
int counter_size); // Bytes of the IV used for counting (low end)
|
||||
|
||||
void aes_encrypt_ctr(const BYTE in[], // Plaintext
|
||||
size_t in_len, // Any byte length
|
||||
BYTE out[], // Ciphertext, same length as plaintext
|
||||
const UINT key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
void aes_decrypt_ctr(const BYTE in[], // Ciphertext
|
||||
size_t in_len, // Any byte length
|
||||
BYTE out[], // Plaintext, same length as ciphertext
|
||||
const UINT key[], // From the key setup
|
||||
int keysize, // Bit length of the key, 128, 192, or 256
|
||||
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
|
||||
|
||||
///////////////////
|
||||
// AES - CCM
|
||||
///////////////////
|
||||
// Returns True if the input parameters do not violate any constraint.
|
||||
int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext.
|
||||
UINT plaintext_len, // IN - Plaintext length.
|
||||
const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption.
|
||||
unsigned short associated_data_len, // IN - Associated Data length in bytes.
|
||||
const BYTE nonce[], // IN - The Nonce to be used for encryption.
|
||||
unsigned short nonce_len, // IN - Nonce length in bytes.
|
||||
BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
|
||||
UINT *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
|
||||
UINT mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
|
||||
const BYTE key[], // IN - The AES key for encryption.
|
||||
int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
|
||||
|
||||
// Returns True if the input parameters do not violate any constraint.
|
||||
// Use mac_auth to ensure decryption/validation was preformed correctly.
|
||||
// If authentication does not succeed, the plaintext is zeroed out. To overwride
|
||||
// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
|
||||
// authentication enabled (mac_auth != NULL) and make a second call to that
|
||||
// ignores authentication explicitly if the first call failes.
|
||||
int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
|
||||
UINT ciphertext_len, // IN - Ciphertext length in bytes.
|
||||
const BYTE assoc[], // IN - The Associated Data, required for authentication.
|
||||
unsigned short assoc_len, // IN - Associated Data length in bytes.
|
||||
const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
|
||||
unsigned short nonce_len, // IN - Nonce length in bytes.
|
||||
BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len.
|
||||
UINT *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
|
||||
UINT mac_len, // IN - The length of the MAC that was calculated.
|
||||
int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication.
|
||||
const BYTE key[], // IN - The AES key for decryption.
|
||||
int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
|
||||
|
||||
// -------------------------------------------------- DES -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define DES_BLOCK_SIZE 8 // DES operates on 8 bytes at a time
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
typedef enum {
|
||||
DES_ENCRYPT,
|
||||
DES_DECRYPT
|
||||
} DES_MODE;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode);
|
||||
void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6]);
|
||||
|
||||
void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode);
|
||||
void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6]);
|
||||
|
||||
// -------------------------------------------------- MD2 -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define MD2_BLOCK_SIZE 16
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
typedef struct {
|
||||
BYTE data[16];
|
||||
BYTE state[48];
|
||||
BYTE checksum[16];
|
||||
int len;
|
||||
} _MD2_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void md2_init(_MD2_CTX *ctx);
|
||||
void md2_update(_MD2_CTX *ctx, const BYTE data[], size_t len);
|
||||
void md2_final(_MD2_CTX *ctx, BYTE hash[]); // size of hash must be MD2_BLOCK_SIZE
|
||||
|
||||
// -------------------------------------------------- MD5 -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define MD5_BLOCK_SIZE 16 // MD5 outputs a 16 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
UINT datalen;
|
||||
unsigned long long bitlen;
|
||||
UINT state[4];
|
||||
} _MD5_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void md5_init(_MD5_CTX *ctx);
|
||||
void md5_update(_MD5_CTX *ctx, const BYTE data[], size_t len);
|
||||
void md5_final(_MD5_CTX *ctx, BYTE hash[]);
|
||||
|
||||
// -------------------------------------------------- SHA1 -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
UINT datalen;
|
||||
unsigned long long bitlen;
|
||||
UINT state[5];
|
||||
UINT k[4];
|
||||
} _SHA1_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
|
||||
void sha1_init(_SHA1_CTX *ctx);
|
||||
void sha1_update(_SHA1_CTX *ctx, const BYTE data[], size_t len);
|
||||
void sha1_final(_SHA1_CTX *ctx, BYTE hash[]);
|
||||
|
||||
// -------------------------------------------------- SHA256 -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
UINT datalen;
|
||||
unsigned long long bitlen;
|
||||
UINT state[8];
|
||||
} _SHA256_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void sha256_init(_SHA256_CTX *ctx);
|
||||
void sha256_update(_SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
void sha256_final(_SHA256_CTX *ctx, BYTE hash[]);
|
||||
|
||||
// -------------------------------------------------- ARCFOUR -------------------------------------------------- //
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
// Input: state - the state used to generate the keystream
|
||||
// key - Key to use to initialize the state
|
||||
// len - length of key in bytes (valid lenth is 1 to 256)
|
||||
void arcfour_key_setup(BYTE state[], const BYTE key[], int len);
|
||||
|
||||
// Pseudo-Random Generator Algorithm
|
||||
// Input: state - the state used to generate the keystream
|
||||
// out - Must be allocated to be of at least "len" length
|
||||
// len - number of bytes to generate
|
||||
void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len);
|
||||
|
||||
// -------------------------------------------------- BLOWFISH -------------------------------------------------- //
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define BLOWFISH_BLOCK_SIZE 8 // Blowfish operates on 8 bytes at a time
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
|
||||
typedef struct {
|
||||
WORD p[18];
|
||||
WORD s[4][256];
|
||||
} _BLOWFISH_KEY;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void blowfish_key_setup(const BYTE user_key[], _BLOWFISH_KEY *keystruct, size_t len);
|
||||
void blowfish_encrypt(const BYTE in[], BYTE out[], const _BLOWFISH_KEY *keystruct);
|
||||
void blowfish_decrypt(const BYTE in[], BYTE out[], const _BLOWFISH_KEY *keystruct);
|
||||
|
||||
// -------------------------------------------------- ROT-13 -------------------------------------------------- //
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
// Performs IN PLACE rotation of the input. Assumes input is NULL terminated.
|
||||
// Preserves each charcter's case. Ignores non alphabetic characters.
|
||||
void rot13(char str[]);
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,604 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/GeneralHelper.h"
|
||||
|
||||
#ifdef _USE_HP_LIB
|
||||
#include <hpsocket/HPTypeDef.h>
|
||||
#else
|
||||
#include "hpsocket/HPTypeDef.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define EVT_ON_SEND _T("OnSend")
|
||||
#define EVT_ON_RECEIVE _T("OnReceive")
|
||||
#define EVT_ON_CLOSE _T("OnClose")
|
||||
#define EVT_ON_ERROR _T("OnError")
|
||||
#define EVT_ON_PREPARE_CONNECT _T("OnPrepareConnect")
|
||||
#define EVT_ON_PREPARE_LISTEN _T("OnPrepareListen")
|
||||
#define EVT_ON_ACCEPT _T("OnAccept")
|
||||
#define EVT_ON_CONNECT _T("OnConnect")
|
||||
#define EVT_ON_HAND_SHAKE _T("OnHandShake")
|
||||
#define EVT_ON_SHUTDOWN _T("OnShutdown")
|
||||
#define EVT_ON_END_TEST _T("END TEST")
|
||||
#define EVT_ON_STAT_TEST _T("STAT TEST")
|
||||
|
||||
#define EVT_ON_MESSAGE_BEGIN _T("OnMessageBegin")
|
||||
#define EVT_ON_REQUEST_LINE _T("OnRequestLine")
|
||||
#define EVT_ON_STATUS_LINE _T("OnStatusLine")
|
||||
#define EVT_ON_HEADER _T("OnHeader")
|
||||
#define EVT_ON_HEADERS_COMPLETE _T("OnHeadersComplete")
|
||||
#define EVT_ON_BODY _T("OnBody")
|
||||
#define EVT_ON_CHUNK_HEADER _T("OnChunkHeader")
|
||||
#define EVT_ON_CHUNK_COMPLETE _T("OnChunkComplete")
|
||||
#define EVT_ON_MESSAGE_COMPLETE _T("OnMessageComplete")
|
||||
#define EVT_ON_UPGRADE _T("OnUpgrade")
|
||||
#define EVT_ON_PARSE_ERROR _T("OnParseError")
|
||||
|
||||
#define EVT_ON_WS_MSG_HEADER _T("OnWSMessageHeader")
|
||||
#define EVT_ON_WS_MSG_BODY _T("OnWSMessageBody")
|
||||
#define EVT_ON_WS_MSG_COMPLETE _T("OnWSMessageComplete")
|
||||
|
||||
#define EVT_ON_UNCOMPRESS_BODY _T("Uncompress Body")
|
||||
#define EVT_ON_UNCOMPRESS_BODY_FAIL _T("Uncompress Body Fail")
|
||||
|
||||
#define IPV4_LOOPBACK_ADDRESS _T("127.0.0.1")
|
||||
#define IPV6_LOOPBACK_ADDRESS _T("::1")
|
||||
#define IPV4_ANY_ADDRESS _T("0.0.0.0")
|
||||
#define IPV6_ANY_ADDRESS _T("::")
|
||||
#define DEF_MULTI_CAST_ADDRESS _T("233.0.0.1")
|
||||
#define BROAD_CAST_ADDRESS _T("255.255.255.255")
|
||||
#define DEF_TCP_UDP_PORT 5555
|
||||
#define DEF_HTTP_PORT 8080
|
||||
#define DEF_HTTPS_PORT 8443
|
||||
|
||||
#define TCP_KEEPALIVE_TIME (60 * 1000)
|
||||
#define UDP_DETECT_ATTEMPTS 3
|
||||
|
||||
enum EnAppState
|
||||
{
|
||||
ST_STARTING, ST_STARTED, ST_CONNECTING, ST_CONNECTED, ST_STOPPING, ST_STOPPED
|
||||
};
|
||||
|
||||
struct app_arg
|
||||
{
|
||||
static char OPTIONS[];
|
||||
|
||||
// -a
|
||||
CString remote_addr;
|
||||
// -p
|
||||
USHORT port;
|
||||
// -b
|
||||
CString bind_addr;
|
||||
// -d
|
||||
USHORT local_port;
|
||||
// -j
|
||||
CString reject_addr;
|
||||
// -n
|
||||
bool async;
|
||||
// -t
|
||||
DWORD thread_count;
|
||||
// -e
|
||||
DWORD test_times;
|
||||
// -i
|
||||
DWORD test_interval;
|
||||
// -c
|
||||
DWORD conn_count;
|
||||
// -l
|
||||
DWORD data_length;
|
||||
// -s
|
||||
EnSendPolicy send_policy;
|
||||
// -m
|
||||
DWORD max_conn;
|
||||
// -q
|
||||
bool keep_alive;
|
||||
|
||||
// -o
|
||||
EnCastMode cast_mode;
|
||||
// -r
|
||||
EnReuseAddressPolicy reuse_addr;
|
||||
// -u
|
||||
bool ip_loop;
|
||||
// -k
|
||||
int ttl;
|
||||
|
||||
// -x
|
||||
USHORT http_port;
|
||||
// -y
|
||||
USHORT https_port;
|
||||
// -z
|
||||
bool http_use_cookie;
|
||||
// -w
|
||||
bool http_with_listener;
|
||||
|
||||
public:
|
||||
void ParseArgs(int argc, char* const argv[]);
|
||||
void ShowPFMTestArgs(BOOL bAgent);
|
||||
static void PrintUsage();
|
||||
static void PrintVersion();
|
||||
public:
|
||||
app_arg();
|
||||
~app_arg();
|
||||
};
|
||||
|
||||
extern app_arg g_app_arg;
|
||||
|
||||
class CAppSignalHandler
|
||||
{
|
||||
public:
|
||||
|
||||
CAppSignalHandler(const vector<int>&& signals, BOOL bIgnoreSigInt = TRUE)
|
||||
: m_bIgnoreSigInt(bIgnoreSigInt)
|
||||
{
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
|
||||
for(size_t i = 0; i < signals.size(); i++)
|
||||
sigaddset(&ss, signals[i]);
|
||||
|
||||
sh.Setup(this, &CAppSignalHandler::handle_sig, &ss);
|
||||
}
|
||||
|
||||
int WaitForExit()
|
||||
{
|
||||
int rs = evt.Wait();
|
||||
|
||||
PRINTLN(" bye ~ bye ~");
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void handle_sig(const siginfo_t* pSigInfo)
|
||||
{
|
||||
if(pSigInfo->si_signo == SIGINT)
|
||||
m_bIgnoreSigInt || evt.Set();
|
||||
}
|
||||
|
||||
private:
|
||||
CSignalHandler<CAppSignalHandler> sh;
|
||||
CPipeEvent evt;
|
||||
|
||||
BOOL m_bIgnoreSigInt;
|
||||
};
|
||||
|
||||
class CTermAttrInitializer
|
||||
{
|
||||
public:
|
||||
CTermAttrInitializer(tcflag_t l_mask = 0)
|
||||
{
|
||||
tcgetattr(STDIN_FILENO, &old_attr);
|
||||
|
||||
termios new_attr = old_attr;
|
||||
|
||||
new_attr.c_lflag &= ~l_mask;
|
||||
new_attr.c_cc[VERASE]= 0x08;
|
||||
new_attr.c_cc[VTIME] = 0;
|
||||
new_attr.c_cc[VMIN] = 1;
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_attr);
|
||||
}
|
||||
|
||||
~CTermAttrInitializer() {tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_attr);}
|
||||
|
||||
private:
|
||||
termios old_attr;
|
||||
};
|
||||
|
||||
class CCommandParser
|
||||
{
|
||||
public:
|
||||
using CMD_FUNC = void (*)(CCommandParser*);
|
||||
|
||||
enum EnAppType {AT_SERVER, AT_AGENT, AT_CLIENT, AT_NODE};
|
||||
enum EnCmdType {CT_START = 0, CT_STOP, CT_STATUS, CT_CONNECT, CT_SEND, CT_SENDC, CT_PAUSE, CT_KICK, CT_KICK_L, CT_KICK_S, CT_STAT, CT_MAX};
|
||||
|
||||
protected:
|
||||
|
||||
struct TCmdNameFunc
|
||||
{
|
||||
LPCTSTR name;
|
||||
CMD_FUNC func;
|
||||
};
|
||||
|
||||
public:
|
||||
BOOL Run();
|
||||
void PrintStatus(EnServiceState enStatus, LPCTSTR lpszName = nullptr);
|
||||
|
||||
protected:
|
||||
virtual void ParseCmdArgs(EnCmdType type, LPTSTR lpszArg);
|
||||
virtual void Reset();
|
||||
|
||||
void PrintUsage();
|
||||
virtual void PrintCmdUsage();
|
||||
virtual CString GetCmdUsage(EnCmdType type);
|
||||
|
||||
private:
|
||||
BOOL WaitForExit();
|
||||
void WorkerProc(PVOID pv);
|
||||
void Parse(LPTSTR lpszLine, SSIZE_T nSize);
|
||||
|
||||
public:
|
||||
CCommandParser(EnAppType enAppType, CMD_FUNC fnCmds[CT_MAX]);
|
||||
virtual ~CCommandParser() {}
|
||||
|
||||
public:
|
||||
BOOL m_bFlag;
|
||||
CONNID m_dwConnID;
|
||||
CString m_strMessage;
|
||||
CString m_strRemoteAddr;
|
||||
USHORT m_usRemotePort;
|
||||
DWORD m_dwSeconds;
|
||||
|
||||
protected:
|
||||
EnAppType m_enAppType;
|
||||
TCmdNameFunc m_szCmdNameFuncs[CT_MAX];
|
||||
|
||||
CThread<CCommandParser, VOID, VOID> m_thWorker;
|
||||
};
|
||||
|
||||
#ifdef _NEED_HTTP
|
||||
|
||||
class CHttpCommandParser : public CCommandParser
|
||||
{
|
||||
using __super = CCommandParser;
|
||||
|
||||
protected:
|
||||
virtual void ParseCmdArgs(EnCmdType type, LPTSTR lpszArg) override;
|
||||
virtual void Reset() override;
|
||||
|
||||
virtual void PrintCmdUsage() override;
|
||||
virtual CString GetCmdUsage(EnCmdType type) override;
|
||||
|
||||
private:
|
||||
BOOL ParseCmdOptions(LPCTSTR lpszArg, LPCTSTR lpszOptions);
|
||||
|
||||
public:
|
||||
CHttpCommandParser(EnAppType enAppType, CMD_FUNC fnCmds[CT_MAX])
|
||||
: __super(enAppType, fnCmds) {}
|
||||
|
||||
public:
|
||||
BOOL m_bHttps;
|
||||
CString m_strPath;
|
||||
CString m_strMethod;
|
||||
CString m_strData;
|
||||
CString m_strFilePath;
|
||||
vector<CString> m_vtHeaders;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct server_statistics_info
|
||||
{
|
||||
volatile LONG m_lClientCount;
|
||||
volatile LONGLONG m_llTotalReceived;
|
||||
volatile LONGLONG m_llTotalSent;
|
||||
|
||||
CCriSec m_cs;
|
||||
|
||||
void Reset(BOOL bResetClientCount = TRUE);
|
||||
void CheckClientCount();
|
||||
void CheckStatistics();
|
||||
void AddTotalRecv(int iLength);
|
||||
void AddTotalSend(int iLength);
|
||||
|
||||
};
|
||||
|
||||
struct client_statistics_info
|
||||
{
|
||||
volatile LONGLONG m_llTotalReceived;
|
||||
volatile LONGLONG m_llTotalSent;
|
||||
LONGLONG m_llExpectReceived;
|
||||
DWORD m_dwBeginTickCount;
|
||||
DWORD m_dwTimeconsuming;
|
||||
|
||||
volatile int m_iConnected;
|
||||
|
||||
void Reset();
|
||||
void StartTest();
|
||||
void CheckStatistics(BOOL bCheckSend = TRUE);
|
||||
void AddTotalRecv(int iLength);
|
||||
void AddTotalSend(int iLength);
|
||||
|
||||
void TermConnected();
|
||||
void AddConnected();
|
||||
int GetConnected();
|
||||
};
|
||||
|
||||
struct info_msg
|
||||
{
|
||||
LPCTSTR name;
|
||||
CONNID connID;
|
||||
LPCTSTR evt;
|
||||
int contentLength;
|
||||
LPCTSTR content;
|
||||
|
||||
static info_msg* Construct(CONNID dwConnID, LPCTSTR lpszEvent, int iContentLength = 0, LPCTSTR lpszContent = nullptr, LPCTSTR lpszName = nullptr);
|
||||
static void Destruct(info_msg* pMsg);
|
||||
|
||||
private:
|
||||
info_msg(CONNID dwConnID, LPCTSTR lpszEvent, int iContentLength = 0, LPCTSTR lpszContent = nullptr, LPCTSTR lpszName = nullptr);
|
||||
~info_msg();
|
||||
};
|
||||
|
||||
struct TPkgHeader
|
||||
{
|
||||
DWORD seq;
|
||||
int body_len;
|
||||
};
|
||||
|
||||
struct TPkgBody
|
||||
{
|
||||
char name[30];
|
||||
short age;
|
||||
char desc[1];
|
||||
};
|
||||
|
||||
struct TPkgInfo
|
||||
{
|
||||
bool is_header;
|
||||
int length;
|
||||
|
||||
TPkgInfo(bool header = true, int len = sizeof(TPkgHeader)) : is_header(header), length(len) {}
|
||||
void Reset() {is_header = true, length = sizeof(TPkgHeader);}
|
||||
~TPkgInfo() {}
|
||||
};
|
||||
|
||||
inline TPkgInfo* ConstructPkgInfo()
|
||||
{
|
||||
return new TPkgInfo(true, sizeof(TPkgHeader));
|
||||
}
|
||||
|
||||
inline void DestructPkgInfo(TPkgInfo* pInfo)
|
||||
{
|
||||
delete pInfo;
|
||||
}
|
||||
|
||||
template<class T, typename = enable_if_t<!is_void<decay_t<T>>::value>>
|
||||
inline TPkgInfo* CreatePkgInfo(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
TPkgInfo* pInfo = ConstructPkgInfo();
|
||||
pSender->SetConnectionExtra(dwConnID, pInfo);
|
||||
|
||||
return pInfo;
|
||||
}
|
||||
|
||||
template<class T, typename = enable_if_t<!is_void<decay_t<T>>::value>>
|
||||
inline TPkgInfo* FindPkgInfo(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
PVOID pInfo = nullptr;
|
||||
pSender->GetConnectionExtra(dwConnID, &pInfo);
|
||||
|
||||
return (TPkgInfo*)pInfo;
|
||||
}
|
||||
|
||||
template<class T, typename = enable_if_t<!is_void<decay_t<T>>::value>>
|
||||
inline void RemovePkgInfo(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
TPkgInfo* pInfo = FindPkgInfo(pSender, dwConnID);
|
||||
ASSERT(pInfo != nullptr);
|
||||
|
||||
DestructPkgInfo(pInfo);
|
||||
}
|
||||
|
||||
CBufferPtr* GeneratePkgBuffer(DWORD seq, LPCTSTR lpszName, short age, LPCTSTR lpszDesc);
|
||||
CBufferPtr* GeneratePkgBuffer(const TPkgHeader& header, const TPkgBody& body);
|
||||
|
||||
BOOL SplitStr(LPCTSTR pszSrc, vector<CString>& vtItem, LPCTSTR pszSepectors = nullptr, LPCTSTR pszQMarks = nullptr);
|
||||
|
||||
sa_family_t GuessAddrFamily(LPCTSTR lpszAddress);
|
||||
LPCTSTR GetLoopbackAddress(LPCTSTR lpszLikeAddress);
|
||||
LPCTSTR GetAnyAddress(LPCTSTR lpszLikeAddress);
|
||||
|
||||
void LogServerStart(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
|
||||
void LogServerStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogServerStop(LPCTSTR lpszName = nullptr);
|
||||
void LogServerStopFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogAgentStart(LPCTSTR lpszAddress, BOOL bAsync, LPCTSTR lpszName = nullptr);
|
||||
void LogAgentStarting(LPCTSTR lpszAddress, BOOL bAsync, LPCTSTR lpszName = nullptr);
|
||||
void LogAgentStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogAgentStopping(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogAgentStop(LPCTSTR lpszName = nullptr);
|
||||
void LogAgentStopFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogAgentSendFail(int iSequence, int iSocketIndex, DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogClientStart(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
|
||||
void LogClientStarting(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
|
||||
void LogClientStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogClientStopping(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogClientStop(LPCTSTR lpszName = nullptr);
|
||||
void LogClientStopFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogClientSendFail(int iSequence, int iSocketIndex, DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogStart(LPCTSTR lpszAddress, USHORT port, LPCTSTR lpszName = nullptr);
|
||||
void LogStartFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogStop(LPCTSTR lpszName = nullptr);
|
||||
void LogSend(LPCTSTR lpszContent, LPCTSTR lpszName = nullptr);
|
||||
void LogSend(CONNID dwConnID, LPCTSTR lpszContent, LPCTSTR lpszName = nullptr);
|
||||
void LogSending(CONNID dwConnID, LPCTSTR lpszContent, LPCTSTR lpszName = nullptr);
|
||||
void LogSendFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogSendFail(CONNID dwConnID, DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogDisconnect(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogDisconnectFail(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogDisconnect2(CONNID dwConnID, BOOL bForce, LPCTSTR lpszName = nullptr);
|
||||
void LogDisconnectFail2(CONNID dwConnID, BOOL bForce, LPCTSTR lpszName = nullptr);
|
||||
void LogDisconnectLong(DWORD dwSeconds, BOOL bForce, LPCTSTR lpszName = nullptr);
|
||||
void LogDisconnectFailLong(DWORD dwSeconds, BOOL bForce, LPCTSTR lpszName = nullptr);
|
||||
void LogPause(CONNID dwConnID, BOOL bPause, LPCTSTR lpszName = nullptr);
|
||||
void LogPauseFail(CONNID dwConnID, BOOL bPause, LPCTSTR lpszName = nullptr);
|
||||
void LogConnect(LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
|
||||
void LogConnectFail(DWORD code, LPCTSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void LogRelease(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogReleaseFail(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogDetect(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogDetectFail(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogOnConnect(CONNID dwConnID, const CString& strAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
|
||||
void LogOnConnect2(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogOnConnect3(CONNID dwConnID, const CString& strAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
|
||||
void LogOnHandShake2(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void LogOnClose(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
|
||||
void PostOnSend(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnSendTo(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnReceive(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnReceiveFrom(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnReceiveCast(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnClose(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnError(CONNID dwConnID, int enOperation, int iErrorCode, LPCTSTR lpszName = nullptr);
|
||||
void PostOnError2(CONNID dwConnID, int enOperation, int iErrorCode, LPCTSTR lpszAddress, USHORT usPort, const BYTE* pBuffer, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnAccept(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, BOOL bPass, LPCTSTR lpszName = nullptr);
|
||||
void PostOnAccept2(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnHandShake(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnPrepareListen(LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
|
||||
void PostOnPrepareConnect(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnConnect(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
|
||||
void PostOnConnect2(CONNID dwConnID, LPCTSTR lpszAddress, USHORT usPort, LPCTSTR lpszName = nullptr);
|
||||
void PostOnConnect3(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnShutdown(LPCTSTR lpszName = nullptr);
|
||||
void PostServerStatics(const LONGLONG& llTotalSent, const LONGLONG& llTotalReceived, LPCTSTR lpszName = nullptr);
|
||||
void PostServerTemporaryStatics(const LONGLONG& llTotalSent, const LONGLONG& llTotalReceived, LPCTSTR lpszName = nullptr);
|
||||
void PostTimeConsuming(DWORD dwTickCount, LPCTSTR lpszName = nullptr);
|
||||
|
||||
#ifdef _NEED_HTTP
|
||||
void PostOnMessageBegin(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnRequestLine(CONNID dwConnID, LPCSTR lpszMethod, USHORT usUrlFieldSet, LPCSTR lpszUrl, LPCTSTR lpszName = nullptr);
|
||||
void PostOnStatusLine(CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc, LPCTSTR lpszName = nullptr);
|
||||
void PostOnHeader(CONNID dwConnID, LPCSTR lpszHeaderName, LPCSTR lpszHeaderValue, LPCTSTR lpszName = nullptr);
|
||||
void PostOnHeadersComplete(CONNID dwConnID, LPCSTR lpszSummary, LPCTSTR lpszName = nullptr);
|
||||
void PostOnBody(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnChunkHeader(CONNID dwConnID, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnChunkComplete(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnMessageComplete(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
void PostOnUpgrade(CONNID dwConnID, EnHttpUpgradeType enUpgradeType, LPCTSTR lpszName = nullptr);
|
||||
void PostOnParseError(CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc, LPCTSTR lpszName = nullptr);
|
||||
|
||||
void PostOnWSMessageHeader(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen, LPCTSTR lpszName = nullptr);
|
||||
void PostOnWSMessageBody(CONNID dwConnID, const BYTE* pData, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostOnWSMessageComplete(CONNID dwConnID, LPCTSTR lpszName = nullptr);
|
||||
|
||||
void PostUncompressBody(CONNID dwConnID, int iLength, LPCTSTR lpszName = nullptr);
|
||||
void PostUncompressBodyFail(CONNID dwConnID, int iResult, LPCTSTR lpszName = nullptr);
|
||||
#endif
|
||||
|
||||
void PostInfoMsg(info_msg* msg);
|
||||
void LogInfoMsg(info_msg* pInfoMsg);
|
||||
void LogMsg(const CString& msg);
|
||||
|
||||
extern LPCTSTR g_lpszDefaultCookieFile;
|
||||
|
||||
LPCTSTR GetDefaultCookieFile();
|
||||
|
||||
#ifdef _NEED_SSL
|
||||
|
||||
extern int g_c_iVerifyMode;
|
||||
extern BOOL g_c_bNeedClientVerification;
|
||||
extern LPCSTR g_c_lpszPemCert;
|
||||
extern LPCSTR g_c_lpszPemKey;
|
||||
extern LPCSTR g_c_lpszCAPemCert;
|
||||
extern LPCSTR g_s_lpszPemCert;
|
||||
extern LPCSTR g_s_lpszPemKey;
|
||||
extern LPCSTR g_s_lpszCAPemCert;
|
||||
extern LPCTSTR g_c_lpszCAPemCertFileOrPath;
|
||||
extern LPCTSTR g_c_lpszPemCertFile;
|
||||
extern LPCTSTR g_c_lpszPemKeyFile;
|
||||
extern LPCTSTR g_c_lpszKeyPasswod;
|
||||
|
||||
extern int g_s_iVerifyMode;
|
||||
extern BOOL g_s_bNeedClientVerification;
|
||||
extern LPCTSTR g_s_lpszCAPemCertFileOrPath;
|
||||
extern LPCTSTR g_s_lpszPemCertFile;
|
||||
extern LPCTSTR g_s_lpszPemKeyFile;
|
||||
extern LPCTSTR g_s_lpszKeyPasswod;
|
||||
|
||||
extern int g_c_iVerifyMode2;
|
||||
extern BOOL g_c_bNeedClientVerification2;
|
||||
extern LPCTSTR g_c_lpszCAPemCertFileOrPath2;
|
||||
extern LPCTSTR g_c_lpszPemCertFile2;
|
||||
extern LPCTSTR g_c_lpszPemKeyFile2;
|
||||
extern LPCTSTR g_c_lpszKeyPasswod2;
|
||||
|
||||
extern int g_s_iVerifyMode2;
|
||||
extern BOOL g_s_bNeedClientVerification2;
|
||||
extern LPCTSTR g_s_lpszCAPemCertFileOrPath2;
|
||||
extern LPCTSTR g_s_lpszPemCertFile2;
|
||||
extern LPCTSTR g_s_lpszPemKeyFile2;
|
||||
extern LPCTSTR g_s_lpszKeyPasswod2;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _NEED_HTTP
|
||||
|
||||
#include "Crypto.h"
|
||||
|
||||
#define HTTP_NAME _T("http")
|
||||
#define HTTPS_NAME _T("https")
|
||||
#define STR_HTTP_SCHEMA "http://"
|
||||
#define STR_HTTPS_SCHEMA "https://"
|
||||
#define CRLF "\r\n"
|
||||
#define NV_SEPARATOR_CHAR '='
|
||||
#define HEADER_SEPARATOR ": "
|
||||
#define COOKIE_TOKENIZE "; "
|
||||
#define STR_HTTP_1_0 "HTTP/1.0"
|
||||
#define STR_HTTP_1_1 "HTTP/1.1"
|
||||
#define HOST_HEADER "Host"
|
||||
#define COOKIE_HEADER "Cookie"
|
||||
#define SET_COOKIE_HEADER "Set-Cookie"
|
||||
#define CONTENT_TYPE_HEADER "Content-Type"
|
||||
#define CONTENT_LENGTH_HEADER "Content-Length"
|
||||
#define TRANSFER_ENCODING_HEADER "Transfer-Encoding"
|
||||
#define UPGRADE_HEADER "Upgrade"
|
||||
#define WEB_SOCKET_HEADER_VALUE "WebSocket"
|
||||
|
||||
#define HTTP_METHOD_POST "POST"
|
||||
#define HTTP_METHOD_PUT "PUT"
|
||||
#define HTTP_METHOD_PATCH "PATCH"
|
||||
#define HTTP_METHOD_GET "GET"
|
||||
#define HTTP_METHOD_DELETE "DELETE"
|
||||
#define HTTP_METHOD_HEAD "HEAD"
|
||||
#define HTTP_METHOD_TRACE "TRACE"
|
||||
#define HTTP_METHOD_OPTIONS "OPTIONS"
|
||||
#define HTTP_METHOD_CONNECT "CONNECT"
|
||||
|
||||
#define HTTP_WEB_SOCKET_SEC_SALT "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
|
||||
extern LPCSTR HTTP_WEB_SOCKET_CLOSE_FLAG;
|
||||
extern const BYTE HTTP_WEB_SOCKET_MASK_KEY[];
|
||||
|
||||
|
||||
struct THttpHeader
|
||||
{
|
||||
CStringA strName;
|
||||
CStringA strValue;
|
||||
|
||||
THttpHeader(LPCTSTR lpszName, LPCTSTR lpszValue) : strName(lpszName), strValue(lpszValue) {}
|
||||
|
||||
struct hash
|
||||
{
|
||||
size_t operator() (const CStringA& str) const
|
||||
{
|
||||
return hash_value(str);
|
||||
}
|
||||
};
|
||||
|
||||
struct equal_to
|
||||
{
|
||||
bool operator () (const CStringA& strA, const CStringA& strB) const
|
||||
{
|
||||
return strA == strB;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
typedef unordered_multimap<CStringA, CStringA,
|
||||
THttpHeader::hash, THttpHeader::equal_to> THttpHeaderMap;
|
||||
typedef THttpHeaderMap::const_iterator THttpHeaderMapCI;
|
||||
typedef THttpHeaderMap::iterator THttpHeaderMapI;
|
||||
|
||||
CStringA& HttpVersionToString(EnHttpVersion enVersion, CStringA& strResult);
|
||||
CStringA& MakeSecWebSocketAccept(LPCSTR lpszKey, CStringA& strAccept);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef int BOOL;
|
||||
typedef float FLOAT;
|
||||
typedef FLOAT *PFLOAT, *LPFLOAT;
|
||||
typedef double DOUBLE;
|
||||
typedef DOUBLE *PDOUBLE, *LPDOUBLE;
|
||||
typedef short SHORT, INT16;
|
||||
typedef SHORT *PSHORT, *LPSHORT;
|
||||
typedef unsigned short USHORT, UINT16;
|
||||
typedef USHORT *PUSHORT, *LPUSHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef WORD *PWORD, *LPWORD;
|
||||
typedef unsigned int DWORD;
|
||||
typedef DWORD *PDWORD, *LPDWORD;
|
||||
typedef long LONG, LID;
|
||||
typedef LONG *PLONG, *LPLONG;
|
||||
typedef unsigned long ULONG, ULID;
|
||||
typedef ULONG *PULONG, *LPULONG;
|
||||
typedef long long LONGLONG, LLONG, INT64;
|
||||
typedef LONGLONG *PLONGLONG, *LPLONGLONG, *PLLONG, *LPLLONG;
|
||||
typedef unsigned long long ULONGLONG, ULLONG, UINT64;
|
||||
typedef ULONGLONG *PULONGLONG, *LPULONGLONG, *PULLONG, *LPULLONG;
|
||||
typedef int INT, IID, INT32;
|
||||
typedef INT *PINT, *LPINT;
|
||||
typedef unsigned int UINT, UIID, UINT32;
|
||||
typedef UINT *PUINT, *LPUINT;
|
||||
typedef void VOID;
|
||||
typedef VOID *PVOID, *LPVOID;
|
||||
typedef char CHAR, INT8;
|
||||
typedef CHAR *PCHAR, *LPCHAR, *PSTR, *LPSTR;
|
||||
typedef const char *PCSTR, *LPCSTR;
|
||||
typedef unsigned char BYTE, UINT8;
|
||||
typedef BYTE *PBYTE, *LPBYTE;
|
||||
typedef const BYTE *PCBYTE, *LPCBYTE;
|
||||
typedef wchar_t WCHAR;
|
||||
typedef WCHAR *PWSTR, *LPWSTR;
|
||||
typedef const WCHAR *PCWSTR, *LPCWSTR;
|
||||
typedef LONG INT_PTR, LONG_PTR, LPARAM;
|
||||
typedef ULONG UINT_PTR, ULONG_PTR, DWORD_PTR, WPARAM;
|
||||
|
||||
typedef IID FD, HANDLE, SOCKET;
|
||||
typedef INT LRESULT, HRESULT;
|
||||
|
||||
typedef LLONG __time64_t;
|
||||
typedef INT __time32_t;
|
||||
|
||||
typedef LID NTHR_ID;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
typedef LID THR_ID;
|
||||
#else
|
||||
typedef ULID THR_ID;
|
||||
#endif
|
||||
|
||||
typedef size_t SIZE_T;
|
||||
typedef ssize_t SSIZE_T;
|
||||
|
||||
#ifdef _UNICODE
|
||||
typedef WCHAR TCHAR;
|
||||
#else
|
||||
typedef CHAR TCHAR;
|
||||
#endif
|
||||
|
||||
typedef TCHAR *PTSTR, *LPTSTR;
|
||||
typedef const TCHAR *PCTSTR, *LPCTSTR;
|
||||
|
||||
#define MAXUINT8 ((UINT8)~((UINT8)0))
|
||||
#define MAXINT8 ((INT8)(MAXUINT8 >> 1))
|
||||
#define MININT8 ((INT8)~MAXINT8)
|
||||
|
||||
#define MAXUINT16 ((UINT16)~((UINT16)0))
|
||||
#define MAXINT16 ((INT16)(MAXUINT16 >> 1))
|
||||
#define MININT16 ((INT16)~MAXINT16)
|
||||
|
||||
#define MAXUINT32 ((UINT32)~((UINT32)0))
|
||||
#define MAXINT32 ((INT32)(MAXUINT32 >> 1))
|
||||
#define MININT32 ((INT32)~MAXINT32)
|
||||
|
||||
#define MAXUINT64 ((UINT64)~((UINT64)0))
|
||||
#define MAXINT64 ((INT64)(MAXUINT64 >> 1))
|
||||
#define MININT64 ((INT64)~MAXINT64)
|
||||
|
||||
#define MAXULONG ((ULONG)~((ULONG)0))
|
||||
#define MAXLONG ((LONG)(MAXULONG >> 1))
|
||||
#define MINLONG ((LONG)~MAXLONG)
|
||||
|
||||
#define MAXULONGLONG ((ULONGLONG)~((ULONGLONG)0))
|
||||
#define MINLONGLONG ((LONGLONG)~MAXLONGLONG)
|
||||
|
||||
#define MAXSIZE_T ((SIZE_T)~((SIZE_T)0))
|
||||
#define MAXSSIZE_T ((SSIZE_T)(MAXSIZE_T >> 1))
|
||||
#define MINSSIZE_T ((SSIZE_T)~MAXSSIZE_T)
|
||||
|
||||
#define MAXUINT ((UINT)~((UINT)0))
|
||||
#define MAXINT ((INT)(MAXUINT >> 1))
|
||||
#define MININT ((INT)~MAXINT)
|
||||
|
||||
#define MAXDWORD32 ((DWORD32)~((DWORD32)0))
|
||||
#define MAXDWORD64 ((DWORD64)~((DWORD64)0))
|
||||
|
||||
#define MINBYTE 0x00
|
||||
#define MAXBYTE 0xFF
|
||||
#define MINCHAR 0x80
|
||||
#define MAXCHAR 0x7F
|
||||
#define MINSHORT 0x8000
|
||||
#define MAXSHORT 0x7FFF
|
||||
#define MINUSHORT 0x0000
|
||||
#define MAXUSHORT 0xFFFF
|
||||
#define MINWORD 0x0000
|
||||
#define MAXWORD 0xFFFF
|
||||
#define MINDWORD 0x00000000
|
||||
#define MAXDWORD 0xFFFFFFFF
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define __T(x) L ## x
|
||||
#else
|
||||
#define __T(x) x
|
||||
#define T2A(p) (p)
|
||||
#define A2T(p) (p)
|
||||
#define A2CT(p) (p)
|
||||
#define T2CA(p) (p)
|
||||
#define CT2A(p) (p)
|
||||
#define CA2T(p) (p)
|
||||
#define CA2CT(p) (p)
|
||||
#endif
|
||||
|
||||
#define _T(x) __T(x)
|
||||
#define _TEXT(x) __T(x)
|
||||
|
||||
#define _In_
|
||||
#define _Out_
|
||||
#define _Inout_
|
||||
#define _In_opt_
|
||||
#define _Out_opt_
|
||||
#define _Inout_opt_
|
||||
#define USES_CONVERSION
|
||||
|
||||
#define INFINITE -1
|
||||
#define NO_ERROR 0
|
||||
#define HAS_ERROR -1
|
||||
#define TIMEOUT 0
|
||||
#define RS_OK NO_ERROR
|
||||
#define RS_FAIL HAS_ERROR
|
||||
#define RS_TIMEOUT TIMEOUT
|
||||
#define INVALID_FD -1
|
||||
#define INVALID_HANDLE_VALUE INVALID_FD
|
||||
#define INVALID_PVOID ((PVOID)-1)
|
||||
#define _MAX_PATH 256
|
||||
#define MAX_PATH _MAX_PATH
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define CONST const
|
||||
|
||||
#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
|
||||
#define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
|
||||
#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
|
||||
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
|
||||
#define LOBYTE(w) ((BYTE)(((DWORD_PTR)(w)) & 0xff))
|
||||
#define HIBYTE(w) ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
|
||||
|
||||
#if !defined(MAX)
|
||||
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#if !defined(MIN)
|
||||
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#if !defined(_max)
|
||||
#define _max(a,b) MAX(a,b)
|
||||
#endif
|
||||
|
||||
#if !defined(_min)
|
||||
#define _min(a,b) MIN(a,b)
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#if !defined(_NDEBUG)
|
||||
#define _NDEBUG
|
||||
#endif
|
||||
#if defined(DEBUG)
|
||||
#undef DEBUG
|
||||
#endif
|
||||
#if defined(_DEBUG)
|
||||
#undef _DEBUG
|
||||
#endif
|
||||
#if defined(DEBUG_TRACE)
|
||||
#undef DEBUG_TRACE
|
||||
#endif
|
||||
#else
|
||||
#if defined(_NDEBUG)
|
||||
#undef _NDEBUG
|
||||
#endif
|
||||
#if !defined(DEBUG)
|
||||
#define DEBUG
|
||||
#endif
|
||||
#if !defined(_DEBUG)
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm64__) && !defined(__aarch64__)
|
||||
#define __aarch64__ __arm64__
|
||||
#elif defined(__aarch64__) && !defined(__arm64__)
|
||||
#define __arm64__ __aarch64__
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C extern "C"
|
||||
#define EXTERN_C_BEGIN EXTERN_C {
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C extern
|
||||
#define EXTERN_C_BEGIN
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
|
||||
#if !defined(__stdcall)
|
||||
#define __stdcall __attribute__ ((__stdcall__))
|
||||
#endif
|
||||
|
||||
#if !defined(__cdecl)
|
||||
#define __cdecl __attribute__ ((__cdecl__))
|
||||
#endif
|
||||
|
||||
#if !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if !defined(CALLBACK)
|
||||
#define CALLBACK
|
||||
#endif
|
||||
|
||||
#if !defined(WINAPI)
|
||||
#define WINAPI
|
||||
#endif
|
||||
|
||||
#if !defined(FORCEINLINE)
|
||||
#ifdef __GNUC__
|
||||
#define FORCEINLINE __attribute__ ((always_inline))
|
||||
#else
|
||||
#define FORCEINLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(STATIC_FORCEINLINE)
|
||||
#define STATIC_FORCEINLINE static FORCEINLINE
|
||||
#endif
|
||||
|
||||
#if !defined(EXTERN_FORCEINLINE)
|
||||
#define EXTERN_FORCEINLINE extern FORCEINLINE
|
||||
#endif
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GlobalDef.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#define ERROR_INVALID_STATE EPERM
|
||||
#define ERROR_INVALID_PARAMETER EINVAL
|
||||
#define ERROR_BROKEN_PIPE EPIPE
|
||||
#define ERROR_AGAIN EAGAIN
|
||||
#define ERROR_WOULDBLOCK EAGAIN
|
||||
#define ERROR_READ_FAULT EFAULT
|
||||
#define ERROR_WRITE_FAULT EFAULT
|
||||
#define ERROR_HANDLES_CLOSED EBADFD
|
||||
#define ERROR_IO_PENDING EINPROGRESS
|
||||
#define ERROR_INTR EINTR
|
||||
#define ERROR_EMPTY ENODATA
|
||||
#define ERROR_NO_DATA ENODATA
|
||||
#define ERROR_FILE_TOO_LARGE EFBIG
|
||||
#define ERROR_INVALID_OPERATION EPERM
|
||||
#define ERROR_CANCELLED ECANCELED
|
||||
#define ERROR_UNKNOWN ENOMSG
|
||||
#define ERROR_OBJECT_NOT_FOUND EBADSLT
|
||||
#define ERROR_NOT_FOUND EBADSLT
|
||||
#define ERROR_INVALID_INDEX ENOANO
|
||||
#define ERROR_OPERATION_ABORTED ECANCELED
|
||||
#define ERROR_CONNABORTED ECONNABORTED
|
||||
#define ERROR_ADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define ERROR_INCORRECT_ADDRESS EADDRNOTAVAIL
|
||||
#define ERROR_PFNOSUPPORT EPFNOSUPPORT
|
||||
#define ERROR_AFNOSUPPORT EAFNOSUPPORT
|
||||
#define ERROR_TIMEOUT ETIMEDOUT
|
||||
#define ERROR_TIMEDOUT ETIMEDOUT
|
||||
#define ERROR_PROTO EPROTO
|
||||
#define ERROR_CONNECTION_COUNT_LIMIT ENOSR
|
||||
#define ERROR_VERIFY_CHECK EBADRQC
|
||||
#define ERROR_CREATE_FAILED EMFILE
|
||||
#define ERROR_INVALID_DATA EBADMSG
|
||||
#define ERROR_BAD_LENGTH EMSGSIZE
|
||||
#define ERROR_CALL_NOT_IMPLEMENTED EPERM
|
||||
#define ERROR_INCORRECT_SIZE EMSGSIZE
|
||||
#define ERROR_CONNRESET ECONNRESET
|
||||
#define ERROR_CONNREFUSED ECONNREFUSED
|
||||
#define ERROR_HOSTUNREACH EHOSTUNREACH
|
||||
#define ERROR_INVALID_NAME ENOENT
|
||||
#define ERROR_BAD_FILE_TYPE EBADF
|
||||
#define ERROR_FILE_NOT_FOUND ENOENT
|
||||
#define ERROR_FUNCTION_FAILED EFAULT
|
||||
#define ERROR_INVALID_PASSWORD EACCES
|
||||
#define ERROR_INVALID_ACCESS EACCES
|
||||
#define ERROR_NOT_READY EPERM
|
||||
#define ERROR_NOT_SUPPORTED EPERM
|
||||
#define ERROR_BAD_FORMAT EBADMSG
|
||||
#define ERROR_BUFFER_OVERFLOW E2BIG
|
||||
#define ERROR_OUT_OF_RANGE ERANGE
|
||||
#define ERROR_DESTINATION_ELEMENT_FULL EXFULL
|
||||
#define ERROR_ALREADY_INITIALIZED EALREADY
|
||||
#define ERROR_CANT_WAIT EIO
|
||||
|
||||
#define EXIT_CODE_OK EX_OK
|
||||
#define EXIT_CODE_CONFIG EX_CONFIG
|
||||
#define EXIT_CODE_SOFTWARE EX_SOFTWARE
|
||||
|
||||
/*
|
||||
* Socket error codes.
|
||||
*/
|
||||
#ifndef WSABASEERR
|
||||
|
||||
/*
|
||||
* All Sockets error constants are biased by WSABASEERR from
|
||||
* the "normal"
|
||||
*/
|
||||
#define WSABASEERR 10000
|
||||
|
||||
/*
|
||||
* Sockets definitions of regular Microsoft C error constants
|
||||
*/
|
||||
#define WSAEINTR (WSABASEERR+4)
|
||||
#define WSAEBADF (WSABASEERR+9)
|
||||
#define WSAEACCES (WSABASEERR+13)
|
||||
#define WSAEFAULT (WSABASEERR+14)
|
||||
#define WSAEINVAL (WSABASEERR+22)
|
||||
#define WSAEMFILE (WSABASEERR+24)
|
||||
|
||||
/*
|
||||
* Sockets definitions of regular Berkeley error constants
|
||||
*/
|
||||
#define WSAEWOULDBLOCK (WSABASEERR+35)
|
||||
#define WSAEINPROGRESS (WSABASEERR+36)
|
||||
#define WSAEALREADY (WSABASEERR+37)
|
||||
#define WSAENOTSOCK (WSABASEERR+38)
|
||||
#define WSAEDESTADDRREQ (WSABASEERR+39)
|
||||
#define WSAEMSGSIZE (WSABASEERR+40)
|
||||
#define WSAEPROTOTYPE (WSABASEERR+41)
|
||||
#define WSAENOPROTOOPT (WSABASEERR+42)
|
||||
#define WSAEPROTONOSUPPORT (WSABASEERR+43)
|
||||
#define WSAESOCKTNOSUPPORT (WSABASEERR+44)
|
||||
#define WSAEOPNOTSUPP (WSABASEERR+45)
|
||||
#define WSAEPFNOSUPPORT (WSABASEERR+46)
|
||||
#define WSAEAFNOSUPPORT (WSABASEERR+47)
|
||||
#define WSAEADDRINUSE (WSABASEERR+48)
|
||||
#define WSAEADDRNOTAVAIL (WSABASEERR+49)
|
||||
#define WSAENETDOWN (WSABASEERR+50)
|
||||
#define WSAENETUNREACH (WSABASEERR+51)
|
||||
#define WSAENETRESET (WSABASEERR+52)
|
||||
#define WSAECONNABORTED (WSABASEERR+53)
|
||||
#define WSAECONNRESET (WSABASEERR+54)
|
||||
#define WSAENOBUFS (WSABASEERR+55)
|
||||
#define WSAEISCONN (WSABASEERR+56)
|
||||
#define WSAENOTCONN (WSABASEERR+57)
|
||||
#define WSAESHUTDOWN (WSABASEERR+58)
|
||||
#define WSAETOOMANYREFS (WSABASEERR+59)
|
||||
#define WSAETIMEDOUT (WSABASEERR+60)
|
||||
#define WSAECONNREFUSED (WSABASEERR+61)
|
||||
#define WSAELOOP (WSABASEERR+62)
|
||||
#define WSAENAMETOOLONG (WSABASEERR+63)
|
||||
#define WSAEHOSTDOWN (WSABASEERR+64)
|
||||
#define WSAEHOSTUNREACH (WSABASEERR+65)
|
||||
#define WSAENOTEMPTY (WSABASEERR+66)
|
||||
#define WSAEPROCLIM (WSABASEERR+67)
|
||||
#define WSAEUSERS (WSABASEERR+68)
|
||||
#define WSAEDQUOT (WSABASEERR+69)
|
||||
#define WSAESTALE (WSABASEERR+70)
|
||||
#define WSAEREMOTE (WSABASEERR+71)
|
||||
|
||||
/*
|
||||
* Extended Sockets error constant definitions
|
||||
*/
|
||||
#define WSASYSNOTREADY (WSABASEERR+91)
|
||||
#define WSAVERNOTSUPPORTED (WSABASEERR+92)
|
||||
#define WSANOTINITIALISED (WSABASEERR+93)
|
||||
#define WSAEDISCON (WSABASEERR+101)
|
||||
#define WSAENOMORE (WSABASEERR+102)
|
||||
#define WSAECANCELLED (WSABASEERR+103)
|
||||
#define WSAEINVALIDPROCTABLE (WSABASEERR+104)
|
||||
#define WSAEINVALIDPROVIDER (WSABASEERR+105)
|
||||
#define WSAEPROVIDERFAILEDINIT (WSABASEERR+106)
|
||||
#define WSASYSCALLFAILURE (WSABASEERR+107)
|
||||
#define WSASERVICE_NOT_FOUND (WSABASEERR+108)
|
||||
#define WSATYPE_NOT_FOUND (WSABASEERR+109)
|
||||
#define WSA_E_NO_MORE (WSABASEERR+110)
|
||||
#define WSA_E_CANCELLED (WSABASEERR+111)
|
||||
#define WSAEREFUSED (WSABASEERR+112)
|
||||
|
||||
/*
|
||||
* Error return codes from gethostbyname() and gethostbyaddr()
|
||||
* (when using the resolver). Note that these errors are
|
||||
* retrieved via WSAGetLastError() and must therefore follow
|
||||
* the rules for avoiding clashes with error numbers from
|
||||
* specific implementations or language run-time systems.
|
||||
* For this reason the codes are based at WSABASEERR+1001.
|
||||
* Note also that [WSA]NO_ADDRESS is defined only for
|
||||
* compatibility purposes.
|
||||
*/
|
||||
|
||||
/* Authoritative Answer: Host not found */
|
||||
#define WSAHOST_NOT_FOUND (WSABASEERR+1001)
|
||||
|
||||
/* Non-Authoritative: Host not found, or SERVERFAIL */
|
||||
#define WSATRY_AGAIN (WSABASEERR+1002)
|
||||
|
||||
/* Non-recoverable errors, FORMERR, REFUSED, NOTIMP */
|
||||
#define WSANO_RECOVERY (WSABASEERR+1003)
|
||||
|
||||
/* Valid name, no data record of requested type */
|
||||
#define WSANO_DATA (WSABASEERR+1004)
|
||||
|
||||
/*
|
||||
* Define QOS related error return codes
|
||||
*
|
||||
*/
|
||||
#define WSA_QOS_RECEIVERS (WSABASEERR + 1005)
|
||||
/* at least one Reserve has arrived */
|
||||
#define WSA_QOS_SENDERS (WSABASEERR + 1006)
|
||||
/* at least one Path has arrived */
|
||||
#define WSA_QOS_NO_SENDERS (WSABASEERR + 1007)
|
||||
/* there are no senders */
|
||||
#define WSA_QOS_NO_RECEIVERS (WSABASEERR + 1008)
|
||||
/* there are no receivers */
|
||||
#define WSA_QOS_REQUEST_CONFIRMED (WSABASEERR + 1009)
|
||||
/* Reserve has been confirmed */
|
||||
#define WSA_QOS_ADMISSION_FAILURE (WSABASEERR + 1010)
|
||||
/* error due to lack of resources */
|
||||
#define WSA_QOS_POLICY_FAILURE (WSABASEERR + 1011)
|
||||
/* rejected for administrative reasons - bad credentials */
|
||||
#define WSA_QOS_BAD_STYLE (WSABASEERR + 1012)
|
||||
/* unknown or conflicting style */
|
||||
#define WSA_QOS_BAD_OBJECT (WSABASEERR + 1013)
|
||||
/* problem with some part of the filterspec or providerspecific
|
||||
* buffer in general */
|
||||
#define WSA_QOS_TRAFFIC_CTRL_ERROR (WSABASEERR + 1014)
|
||||
/* problem with some part of the flowspec */
|
||||
#define WSA_QOS_GENERIC_ERROR (WSABASEERR + 1015)
|
||||
/* general error */
|
||||
#define WSA_QOS_ESERVICETYPE (WSABASEERR + 1016)
|
||||
/* invalid service type in flowspec */
|
||||
#define WSA_QOS_EFLOWSPEC (WSABASEERR + 1017)
|
||||
/* invalid flowspec */
|
||||
#define WSA_QOS_EPROVSPECBUF (WSABASEERR + 1018)
|
||||
/* invalid provider specific buffer */
|
||||
#define WSA_QOS_EFILTERSTYLE (WSABASEERR + 1019)
|
||||
/* invalid filter style */
|
||||
#define WSA_QOS_EFILTERTYPE (WSABASEERR + 1020)
|
||||
/* invalid filter type */
|
||||
#define WSA_QOS_EFILTERCOUNT (WSABASEERR + 1021)
|
||||
/* incorrect number of filters */
|
||||
#define WSA_QOS_EOBJLENGTH (WSABASEERR + 1022)
|
||||
/* invalid object length */
|
||||
#define WSA_QOS_EFLOWCOUNT (WSABASEERR + 1023)
|
||||
/* incorrect number of flows */
|
||||
#define WSA_QOS_EUNKOWNPSOBJ (WSABASEERR + 1024)
|
||||
/* unknown object in provider specific buffer */
|
||||
#define WSA_QOS_EPOLICYOBJ (WSABASEERR + 1025)
|
||||
/* invalid policy object in provider specific buffer */
|
||||
#define WSA_QOS_EFLOWDESC (WSABASEERR + 1026)
|
||||
/* invalid flow descriptor in the list */
|
||||
#define WSA_QOS_EPSFLOWSPEC (WSABASEERR + 1027)
|
||||
/* inconsistent flow spec in provider specific buffer */
|
||||
#define WSA_QOS_EPSFILTERSPEC (WSABASEERR + 1028)
|
||||
/* invalid filter spec in provider specific buffer */
|
||||
#define WSA_QOS_ESDMODEOBJ (WSABASEERR + 1029)
|
||||
/* invalid shape discard mode object in provider specific buffer */
|
||||
#define WSA_QOS_ESHAPERATEOBJ (WSABASEERR + 1030)
|
||||
/* invalid shaping rate object in provider specific buffer */
|
||||
#define WSA_QOS_RESERVED_PETYPE (WSABASEERR + 1031)
|
||||
/* reserved policy element in provider specific buffer */
|
||||
|
||||
#endif /* ifdef WSABASEERR */
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "HPSocket.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/******************************************************************** SSL Exports ********************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
/**************************************************/
|
||||
/************** HPSocket-SSL 导出函数 **************/
|
||||
|
||||
// 创建 SSL ITcpServer 对象
|
||||
HPSOCKET_API ITcpServer* HP_Create_SSLServer(ITcpServerListener* pListener);
|
||||
// 创建 SSL ITcpAgent 对象
|
||||
HPSOCKET_API ITcpAgent* HP_Create_SSLAgent(ITcpAgentListener* pListener);
|
||||
// 创建 SSL ITcpClient 对象
|
||||
HPSOCKET_API ITcpClient* HP_Create_SSLClient(ITcpClientListener* pListener);
|
||||
// 创建 SSL ITcpPullServer 对象
|
||||
HPSOCKET_API ITcpPullServer* HP_Create_SSLPullServer(ITcpServerListener* pListener);
|
||||
// 创建 SSL ITcpPullAgent 对象
|
||||
HPSOCKET_API ITcpPullAgent* HP_Create_SSLPullAgent(ITcpAgentListener* pListener);
|
||||
// 创建 SSL ITcpPullClient 对象
|
||||
HPSOCKET_API ITcpPullClient* HP_Create_SSLPullClient(ITcpClientListener* pListener);
|
||||
// 创建 SSL ITcpPackServer 对象
|
||||
HPSOCKET_API ITcpPackServer* HP_Create_SSLPackServer(ITcpServerListener* pListener);
|
||||
// 创建 SSL ITcpPackAgent 对象
|
||||
HPSOCKET_API ITcpPackAgent* HP_Create_SSLPackAgent(ITcpAgentListener* pListener);
|
||||
// 创建 SSL ITcpPackClient 对象
|
||||
HPSOCKET_API ITcpPackClient* HP_Create_SSLPackClient(ITcpClientListener* pListener);
|
||||
|
||||
// 销毁 SSL ITcpServer 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLServer(ITcpServer* pServer);
|
||||
// 销毁 SSL ITcpAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLAgent(ITcpAgent* pAgent);
|
||||
// 销毁 SSL ITcpClient 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLClient(ITcpClient* pClient);
|
||||
// 销毁 SSL ITcpPullServer 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLPullServer(ITcpPullServer* pServer);
|
||||
// 销毁 SSL ITcpPullAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLPullAgent(ITcpPullAgent* pAgent);
|
||||
// 销毁 SSL ITcpPullClient 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLPullClient(ITcpPullClient* pClient);
|
||||
// 销毁 SSL ITcpPackServer 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLPackServer(ITcpPackServer* pServer);
|
||||
// 销毁 SSL ITcpPackAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLPackAgent(ITcpPackAgent* pAgent);
|
||||
// 销毁 SSL ITcpPackClient 对象
|
||||
HPSOCKET_API void HP_Destroy_SSLPackClient(ITcpPackClient* pClient);
|
||||
|
||||
// SSL ITcpServer 对象创建器
|
||||
struct SSLServer_Creator
|
||||
{
|
||||
static ITcpServer* Create(ITcpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpServer* pServer)
|
||||
{
|
||||
HP_Destroy_SSLServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpAgent 对象创建器
|
||||
struct SSLAgent_Creator
|
||||
{
|
||||
static ITcpAgent* Create(ITcpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_SSLAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpClient 对象创建器
|
||||
struct SSLClient_Creator
|
||||
{
|
||||
static ITcpClient* Create(ITcpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpClient* pClient)
|
||||
{
|
||||
HP_Destroy_SSLClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpPullServer 对象创建器
|
||||
struct SSLPullServer_Creator
|
||||
{
|
||||
static ITcpPullServer* Create(ITcpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLPullServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPullServer* pServer)
|
||||
{
|
||||
HP_Destroy_SSLPullServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpPullAgent 对象创建器
|
||||
struct SSLPullAgent_Creator
|
||||
{
|
||||
static ITcpPullAgent* Create(ITcpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLPullAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPullAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_SSLPullAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpPullClient 对象创建器
|
||||
struct SSLPullClient_Creator
|
||||
{
|
||||
static ITcpPullClient* Create(ITcpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLPullClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPullClient* pClient)
|
||||
{
|
||||
HP_Destroy_SSLPullClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpPackServer 对象创建器
|
||||
struct SSLPackServer_Creator
|
||||
{
|
||||
static ITcpPackServer* Create(ITcpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLPackServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPackServer* pServer)
|
||||
{
|
||||
HP_Destroy_SSLPackServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpPackAgent 对象创建器
|
||||
struct SSLPackAgent_Creator
|
||||
{
|
||||
static ITcpPackAgent* Create(ITcpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLPackAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPackAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_SSLPackAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpPackClient 对象创建器
|
||||
struct SSLPackClient_Creator
|
||||
{
|
||||
static ITcpPackClient* Create(ITcpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_SSLPackClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPackClient* pClient)
|
||||
{
|
||||
HP_Destroy_SSLPackClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// SSL ITcpServer 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpServer, ITcpServerListener, SSLServer_Creator> CSSLServerPtr;
|
||||
// SSL ITcpAgent 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpAgent, ITcpAgentListener, SSLAgent_Creator> CSSLAgentPtr;
|
||||
// SSL ITcpClient 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpClient, ITcpClientListener, SSLClient_Creator> CSSLClientPtr;
|
||||
// SSL ITcpPullServer 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPullServer, ITcpServerListener, SSLPullServer_Creator> CSSLPullServerPtr;
|
||||
// SSL ITcpPullAgent 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPullAgent, ITcpAgentListener, SSLPullAgent_Creator> CSSLPullAgentPtr;
|
||||
// SSL ITcpPullClient 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPullClient, ITcpClientListener, SSLPullClient_Creator> CSSLPullClientPtr;
|
||||
// SSL ITcpPackServer 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPackServer, ITcpServerListener, SSLPackServer_Creator> CSSLPackServerPtr;
|
||||
// SSL ITcpPackAgent 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPackAgent, ITcpAgentListener, SSLPackAgent_Creator> CSSLPackAgentPtr;
|
||||
// SSL ITcpPackClient 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPackClient, ITcpClientListener, SSLPackClient_Creator> CSSLPackClientPtr;
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/*************************************************************** Global Function Exports *************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
/*
|
||||
* 名称:SNI 默认回调函数
|
||||
* 描述:SSL Server 的 SetupSSLContext 方法中如果不指定 SNI 回调函数则使用此 SNI 默认回调函数
|
||||
*
|
||||
* 参数: lpszServerName -- 请求域名
|
||||
* pContext -- SSL Context 对象
|
||||
*
|
||||
* 返回值:SNI 主机证书对应的索引
|
||||
*/
|
||||
HPSOCKET_API int __HP_CALL HP_SSL_DefaultServerNameCallback(LPCTSTR lpszServerName, PVOID pContext);
|
||||
|
||||
/*
|
||||
* 名称:清理线程局部环境 SSL 资源
|
||||
* 描述:任何一个操作 SSL 的线程,通信结束时都需要清理线程局部环境 SSL 资源
|
||||
* 1、主线程和 HP-Socket 工作线程在通信结束时会自动清理线程局部环境 SSL 资源。因此,一般情况下不必手工调用本方法
|
||||
* 2、特殊情况下,当自定义线程参与 HP-Socket 通信操作并检查到 SSL 内存泄漏时,需在每次通信结束时自定义线程调用本方法
|
||||
*
|
||||
* 参数: dwThreadID -- 线程 ID(0:当前线程)
|
||||
*
|
||||
* 返回值:无
|
||||
*/
|
||||
HPSOCKET_API void HP_SSL_RemoveThreadLocalState(THR_ID dwThreadID);
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/******************************************************************** HTTPS Exports ******************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
// 创建 IHttpsServer 对象
|
||||
HPSOCKET_API IHttpServer* HP_Create_HttpsServer(IHttpServerListener* pListener);
|
||||
// 创建 IHttpsAgent 对象
|
||||
HPSOCKET_API IHttpAgent* HP_Create_HttpsAgent(IHttpAgentListener* pListener);
|
||||
// 创建 IHttpsClient 对象
|
||||
HPSOCKET_API IHttpClient* HP_Create_HttpsClient(IHttpClientListener* pListener);
|
||||
// 创建 IHttpsSyncClient 对象
|
||||
HPSOCKET_API IHttpSyncClient* HP_Create_HttpsSyncClient(IHttpClientListener* pListener = nullptr);
|
||||
|
||||
// 销毁 IHttpsServer 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpsServer(IHttpServer* pServer);
|
||||
// 销毁 IHttpsAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpsAgent(IHttpAgent* pAgent);
|
||||
// 销毁 IHttpsClient 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpsClient(IHttpClient* pClient);
|
||||
// 销毁 IHttpsSyncClient 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpsSyncClient(IHttpSyncClient* pClient);
|
||||
|
||||
// IHttpsServer 对象创建器
|
||||
struct HttpsServer_Creator
|
||||
{
|
||||
static IHttpServer* Create(IHttpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_HttpsServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpServer* pServer)
|
||||
{
|
||||
HP_Destroy_HttpsServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpsAgent 对象创建器
|
||||
struct HttpsAgent_Creator
|
||||
{
|
||||
static IHttpAgent* Create(IHttpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_HttpsAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_HttpsAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpsClient 对象创建器
|
||||
struct HttpsClient_Creator
|
||||
{
|
||||
static IHttpClient* Create(IHttpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_HttpsClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpClient* pClient)
|
||||
{
|
||||
HP_Destroy_HttpsClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpsSyncClient 对象创建器
|
||||
struct HttpsSyncClient_Creator
|
||||
{
|
||||
static IHttpSyncClient* Create(IHttpClientListener* pListener = nullptr)
|
||||
{
|
||||
return HP_Create_HttpsSyncClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpSyncClient* pClient)
|
||||
{
|
||||
HP_Destroy_HttpsSyncClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpsServer 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpServer, IHttpServerListener, HttpsServer_Creator> CHttpsServerPtr;
|
||||
// IHttpsAgent 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpAgent, IHttpAgentListener, HttpsAgent_Creator> CHttpsAgentPtr;
|
||||
// IHttpsClient 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpClient, IHttpClientListener, HttpsClient_Creator> CHttpsClientPtr;
|
||||
// IHttpsSyncClient 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpSyncClient, IHttpClientListener, HttpsSyncClient_Creator> CHttpsSyncClientPtr;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,818 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
Module: HPSocket
|
||||
|
||||
Usage:
|
||||
方法一:
|
||||
--------------------------------------------------------------------------------------
|
||||
0. 应用程序包含 HPTypeDef.h / SocketInterface.h / HPSocket.h 头文件
|
||||
1. 调用 HP_Create_Xxx() 函数创建 HPSocket 对象
|
||||
2. 使用完毕后调用 HP_Destroy_Xxx() 函数销毁 HPSocket 对象
|
||||
|
||||
方法二:
|
||||
--------------------------------------------------------------------------------------
|
||||
0. 应用程序包含 SocketInterface.h 和 HPSocket.h 头文件
|
||||
1. 创建 CXxxPtr 智能指针,通过智能指针使用 HPSocket 对象
|
||||
|
||||
Release:
|
||||
<-- 动态链接库 -->
|
||||
1. x86/libhpsocket.so - (32位/MBCS/Release)
|
||||
2. x86/libhpsocket_d.so - (32位/MBCS/DeBug)
|
||||
3. x64/libhpsocket.so - (64位/MBCS/Release)
|
||||
4. x64/libhpsocket_d.so - (64位/MBCS/DeBug)
|
||||
|
||||
<-- 静态链接库 -->
|
||||
1. x86/static/libhpsocket.a - (32位/MBCS/Release)
|
||||
2. x86/static/libhpsocket_d.a - (32位/MBCS/DeBug)
|
||||
3. x64/static/libhpsocket.a - (64位/MBCS/Release)
|
||||
4. x64/static/libhpsocket_d.a - (64位/MBCS/DeBug)
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketInterface.h"
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/****************************************************************** TCP/UDP Exports ******************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
/**************************************************/
|
||||
/************** HPSocket 对象智能指针 **************/
|
||||
|
||||
template<class T, class _Listener, class _Creator> class CHPObjectPtr
|
||||
{
|
||||
public:
|
||||
CHPObjectPtr& Reset(T* pObj = nullptr)
|
||||
{
|
||||
if(pObj != m_pObj)
|
||||
{
|
||||
if(m_pObj)
|
||||
_Creator::Destroy(m_pObj);
|
||||
|
||||
m_pObj = pObj;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CHPObjectPtr& Attach(T* pObj)
|
||||
{
|
||||
return Reset(pObj);
|
||||
}
|
||||
|
||||
T* Detach()
|
||||
{
|
||||
T* pObj = m_pObj;
|
||||
m_pObj = nullptr;
|
||||
|
||||
return pObj;
|
||||
}
|
||||
|
||||
BOOL IsValid () const {return m_pObj != nullptr ;}
|
||||
T* Get () const {return m_pObj ;}
|
||||
T* operator -> () const {return m_pObj ;}
|
||||
operator T* () const {return m_pObj ;}
|
||||
|
||||
CHPObjectPtr& operator = (T* pObj) {return Reset(pObj) ;}
|
||||
|
||||
public:
|
||||
CHPObjectPtr(_Listener* pListener = nullptr)
|
||||
{
|
||||
m_pObj = _Creator::Create(pListener);
|
||||
}
|
||||
|
||||
CHPObjectPtr(BOOL bCreate, _Listener* pListener = nullptr)
|
||||
{
|
||||
m_pObj = bCreate ? _Creator::Create(pListener) : nullptr;
|
||||
}
|
||||
|
||||
virtual ~CHPObjectPtr()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
private:
|
||||
CHPObjectPtr(const CHPObjectPtr&) = delete;
|
||||
CHPObjectPtr& operator = (const CHPObjectPtr&) = delete;
|
||||
|
||||
protected:
|
||||
T* m_pObj;
|
||||
};
|
||||
|
||||
/**************************************************/
|
||||
/**************** HPSocket 导出函数 ****************/
|
||||
|
||||
// 创建 ITcpServer 对象
|
||||
HPSOCKET_API ITcpServer* HP_Create_TcpServer(ITcpServerListener* pListener);
|
||||
// 创建 ITcpAgent 对象
|
||||
HPSOCKET_API ITcpAgent* HP_Create_TcpAgent(ITcpAgentListener* pListener);
|
||||
// 创建 ITcpClient 对象
|
||||
HPSOCKET_API ITcpClient* HP_Create_TcpClient(ITcpClientListener* pListener);
|
||||
// 创建 ITcpPullServer 对象
|
||||
HPSOCKET_API ITcpPullServer* HP_Create_TcpPullServer(ITcpServerListener* pListener);
|
||||
// 创建 ITcpPullAgent 对象
|
||||
HPSOCKET_API ITcpPullAgent* HP_Create_TcpPullAgent(ITcpAgentListener* pListener);
|
||||
// 创建 ITcpPullClient 对象
|
||||
HPSOCKET_API ITcpPullClient* HP_Create_TcpPullClient(ITcpClientListener* pListener);
|
||||
// 创建 ITcpPackServer 对象
|
||||
HPSOCKET_API ITcpPackServer* HP_Create_TcpPackServer(ITcpServerListener* pListener);
|
||||
// 创建 ITcpPackAgent 对象
|
||||
HPSOCKET_API ITcpPackAgent* HP_Create_TcpPackAgent(ITcpAgentListener* pListener);
|
||||
// 创建 ITcpPackClient 对象
|
||||
HPSOCKET_API ITcpPackClient* HP_Create_TcpPackClient(ITcpClientListener* pListener);
|
||||
|
||||
// 销毁 ITcpServer 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpServer(ITcpServer* pServer);
|
||||
// 销毁 ITcpAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpAgent(ITcpAgent* pAgent);
|
||||
// 销毁 ITcpClient 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpClient(ITcpClient* pClient);
|
||||
// 销毁 ITcpPullServer 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpPullServer(ITcpPullServer* pServer);
|
||||
// 销毁 ITcpPullAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpPullAgent(ITcpPullAgent* pAgent);
|
||||
// 销毁 ITcpPullClient 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpPullClient(ITcpPullClient* pClient);
|
||||
// 销毁 ITcpPackServer 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpPackServer(ITcpPackServer* pServer);
|
||||
// 销毁 ITcpPackAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpPackAgent(ITcpPackAgent* pAgent);
|
||||
// 销毁 ITcpPackClient 对象
|
||||
HPSOCKET_API void HP_Destroy_TcpPackClient(ITcpPackClient* pClient);
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
// 创建 IUdpServer 对象
|
||||
HPSOCKET_API IUdpServer* HP_Create_UdpServer(IUdpServerListener* pListener);
|
||||
// 创建 IUdpClient 对象
|
||||
HPSOCKET_API IUdpClient* HP_Create_UdpClient(IUdpClientListener* pListener);
|
||||
// 创建 IUdpCast 对象
|
||||
HPSOCKET_API IUdpCast* HP_Create_UdpCast(IUdpCastListener* pListener);
|
||||
// 创建 IUdpNode 对象
|
||||
HPSOCKET_API IUdpNode* HP_Create_UdpNode(IUdpNodeListener* pListener);
|
||||
// 创建 IUdpArqServer 对象
|
||||
HPSOCKET_API IUdpArqServer* HP_Create_UdpArqServer(IUdpServerListener* pListener);
|
||||
// 创建 IUdpArqClient 对象
|
||||
HPSOCKET_API IUdpArqClient* HP_Create_UdpArqClient(IUdpClientListener* pListener);
|
||||
|
||||
// 销毁 IUdpServer 对象
|
||||
HPSOCKET_API void HP_Destroy_UdpServer(IUdpServer* pServer);
|
||||
// 销毁 IUdpClient 对象
|
||||
HPSOCKET_API void HP_Destroy_UdpClient(IUdpClient* pClient);
|
||||
// 销毁 IUdpCast 对象
|
||||
HPSOCKET_API void HP_Destroy_UdpCast(IUdpCast* pCast);
|
||||
// 销毁 IUdpNode 对象
|
||||
HPSOCKET_API void HP_Destroy_UdpNode(IUdpNode* pNode);
|
||||
// 销毁 IUdpArqServer 对象
|
||||
HPSOCKET_API void HP_Destroy_UdpArqServer(IUdpArqServer* pServer);
|
||||
// 销毁 IUdpArqClient 对象
|
||||
HPSOCKET_API void HP_Destroy_UdpArqClient(IUdpArqClient* pClient);
|
||||
|
||||
#endif
|
||||
|
||||
// ITcpServer 对象创建器
|
||||
struct TcpServer_Creator
|
||||
{
|
||||
static ITcpServer* Create(ITcpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpServer* pServer)
|
||||
{
|
||||
HP_Destroy_TcpServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpAgent 对象创建器
|
||||
struct TcpAgent_Creator
|
||||
{
|
||||
static ITcpAgent* Create(ITcpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_TcpAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpClient 对象创建器
|
||||
struct TcpClient_Creator
|
||||
{
|
||||
static ITcpClient* Create(ITcpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpClient* pClient)
|
||||
{
|
||||
HP_Destroy_TcpClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpPullServer 对象创建器
|
||||
struct TcpPullServer_Creator
|
||||
{
|
||||
static ITcpPullServer* Create(ITcpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpPullServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPullServer* pServer)
|
||||
{
|
||||
HP_Destroy_TcpPullServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpPullAgent 对象创建器
|
||||
struct TcpPullAgent_Creator
|
||||
{
|
||||
static ITcpPullAgent* Create(ITcpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpPullAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPullAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_TcpPullAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpPullClient 对象创建器
|
||||
struct TcpPullClient_Creator
|
||||
{
|
||||
static ITcpPullClient* Create(ITcpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpPullClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPullClient* pClient)
|
||||
{
|
||||
HP_Destroy_TcpPullClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpPackServer 对象创建器
|
||||
struct TcpPackServer_Creator
|
||||
{
|
||||
static ITcpPackServer* Create(ITcpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpPackServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPackServer* pServer)
|
||||
{
|
||||
HP_Destroy_TcpPackServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpPackAgent 对象创建器
|
||||
struct TcpPackAgent_Creator
|
||||
{
|
||||
static ITcpPackAgent* Create(ITcpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpPackAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPackAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_TcpPackAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpPackClient 对象创建器
|
||||
struct TcpPackClient_Creator
|
||||
{
|
||||
static ITcpPackClient* Create(ITcpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_TcpPackClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(ITcpPackClient* pClient)
|
||||
{
|
||||
HP_Destroy_TcpPackClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// ITcpServer 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpServer, ITcpServerListener, TcpServer_Creator> CTcpServerPtr;
|
||||
// ITcpAgent 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpAgent, ITcpAgentListener, TcpAgent_Creator> CTcpAgentPtr;
|
||||
// ITcpClient 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpClient, ITcpClientListener, TcpClient_Creator> CTcpClientPtr;
|
||||
// ITcpPullServer 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPullServer, ITcpServerListener, TcpPullServer_Creator> CTcpPullServerPtr;
|
||||
// ITcpPullAgent 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPullAgent, ITcpAgentListener, TcpPullAgent_Creator> CTcpPullAgentPtr;
|
||||
// ITcpPullClient 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPullClient, ITcpClientListener, TcpPullClient_Creator> CTcpPullClientPtr;
|
||||
// ITcpPackServer 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPackServer, ITcpServerListener, TcpPackServer_Creator> CTcpPackServerPtr;
|
||||
// ITcpPackAgent 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPackAgent, ITcpAgentListener, TcpPackAgent_Creator> CTcpPackAgentPtr;
|
||||
// ITcpPackClient 对象智能指针
|
||||
typedef CHPObjectPtr<ITcpPackClient, ITcpClientListener, TcpPackClient_Creator> CTcpPackClientPtr;
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
// IUdpServer 对象创建器
|
||||
struct UdpServer_Creator
|
||||
{
|
||||
static IUdpServer* Create(IUdpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_UdpServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IUdpServer* pServer)
|
||||
{
|
||||
HP_Destroy_UdpServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// IUdpClient 对象创建器
|
||||
struct UdpClient_Creator
|
||||
{
|
||||
static IUdpClient* Create(IUdpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_UdpClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IUdpClient* pClient)
|
||||
{
|
||||
HP_Destroy_UdpClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// IUdpCast 对象创建器
|
||||
struct UdpCast_Creator
|
||||
{
|
||||
static IUdpCast* Create(IUdpCastListener* pListener)
|
||||
{
|
||||
return HP_Create_UdpCast(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IUdpCast* pCast)
|
||||
{
|
||||
HP_Destroy_UdpCast(pCast);
|
||||
}
|
||||
};
|
||||
|
||||
// IUdpNode 对象创建器
|
||||
struct UdpNode_Creator
|
||||
{
|
||||
static IUdpNode* Create(IUdpNodeListener* pListener)
|
||||
{
|
||||
return HP_Create_UdpNode(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IUdpNode* pNode)
|
||||
{
|
||||
HP_Destroy_UdpNode(pNode);
|
||||
}
|
||||
};
|
||||
|
||||
// IUdpArqServer 对象创建器
|
||||
struct UdpArqServer_Creator
|
||||
{
|
||||
static IUdpArqServer* Create(IUdpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_UdpArqServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IUdpArqServer* pServer)
|
||||
{
|
||||
HP_Destroy_UdpArqServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// IUdpArqClient 对象创建器
|
||||
struct UdpArqClient_Creator
|
||||
{
|
||||
static IUdpArqClient* Create(IUdpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_UdpArqClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IUdpArqClient* pClient)
|
||||
{
|
||||
HP_Destroy_UdpArqClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// IUdpServer 对象智能指针
|
||||
typedef CHPObjectPtr<IUdpServer, IUdpServerListener, UdpServer_Creator> CUdpServerPtr;
|
||||
// IUdpClient 对象智能指针
|
||||
typedef CHPObjectPtr<IUdpClient, IUdpClientListener, UdpClient_Creator> CUdpClientPtr;
|
||||
// IUdpCast 对象智能指针
|
||||
typedef CHPObjectPtr<IUdpCast, IUdpCastListener, UdpCast_Creator> CUdpCastPtr;
|
||||
// IUdpNode 对象智能指针
|
||||
typedef CHPObjectPtr<IUdpNode, IUdpNodeListener, UdpNode_Creator> CUdpNodePtr;
|
||||
// IUdpArqServer 对象智能指针
|
||||
typedef CHPObjectPtr<IUdpArqServer, IUdpServerListener, UdpArqServer_Creator> CUdpArqServerPtr;
|
||||
// IUdpArqClient 对象智能指针
|
||||
typedef CHPObjectPtr<IUdpArqClient, IUdpClientListener, UdpArqClient_Creator> CUdpArqClientPtr;
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/*************************************************************** Global Function Exports *************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
// 获取 HPSocket 版本号(4 个字节分别为:主版本号,子版本号,修正版本号,构建编号)
|
||||
HPSOCKET_API DWORD HP_GetHPSocketVersion();
|
||||
|
||||
// 获取错误描述文本
|
||||
HPSOCKET_API LPCTSTR HP_GetSocketErrorDesc(EnSocketError enCode);
|
||||
// 调用系统的 errno 方法获取系统错误代码
|
||||
HPSOCKET_API DWORD SYS_GetLastError();
|
||||
// 调用系统的 strerror() 方法获取系统错误代码描述
|
||||
HPSOCKET_API LPCSTR SYS_GetLastErrorStr();
|
||||
// 调用系统的 setsockopt()
|
||||
HPSOCKET_API int SYS_SetSocketOption(SOCKET sock, int level, int name, LPVOID val, int len);
|
||||
// 调用系统的 getsockopt()
|
||||
HPSOCKET_API int SYS_GetSocketOption(SOCKET sock, int level, int name, LPVOID val, int* len);
|
||||
// 调用系统的 ioctlsocket()
|
||||
HPSOCKET_API int SYS_IoctlSocket(SOCKET sock, long cmd, ULONG* arg);
|
||||
|
||||
// 调用系统的 fcntl() 设置 F_SETFL 属性
|
||||
HPSOCKET_API BOOL SYS_fcntl_SETFL(FD fd, INT fl, BOOL bSet = TRUE);
|
||||
|
||||
// 设置 FD 选项:O_NONBLOCK
|
||||
HPSOCKET_API int SYS_SSO_NoBlock(SOCKET sock, BOOL bNoBlock = TRUE);
|
||||
// 设置 socket 选项:IPPROTO_TCP -> TCP_NODELAY
|
||||
HPSOCKET_API int SYS_SSO_NoDelay(SOCKET sock, BOOL bNoDelay = TRUE);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_DONTLINGER
|
||||
HPSOCKET_API int SYS_SSO_DontLinger(SOCKET sock, BOOL bDont = TRUE);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_LINGER
|
||||
HPSOCKET_API int SYS_SSO_Linger(SOCKET sock, USHORT l_onoff, USHORT l_linger);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_RCVBUF
|
||||
HPSOCKET_API int SYS_SSO_RecvBuffSize(SOCKET sock, int size);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_SNDBUF
|
||||
HPSOCKET_API int SYS_SSO_SendBuffSize(SOCKET sock, int size);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_RCVTIMEO
|
||||
HPSOCKET_API int SYS_SSO_RecvTimeOut(SOCKET sock, int ms);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_SNDTIMEO
|
||||
HPSOCKET_API int SYS_SSO_SendTimeOut(SOCKET sock, int ms);
|
||||
// 设置 socket 选项:SOL_SOCKET -> SO_REUSEADDR / SO_REUSEPORT
|
||||
HPSOCKET_API int SYS_SSO_ReuseAddress(SOCKET sock, EnReuseAddressPolicy opt);
|
||||
|
||||
// 获取 SOCKET 本地地址信息
|
||||
HPSOCKET_API BOOL SYS_GetSocketLocalAddress(SOCKET socket, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
// 获取 SOCKET 远程地址信息
|
||||
HPSOCKET_API BOOL SYS_GetSocketRemoteAddress(SOCKET socket, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
|
||||
/* 枚举主机 IP 地址 */
|
||||
HPSOCKET_API BOOL SYS_EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount);
|
||||
/* 释放 LPTIPAddr* */
|
||||
HPSOCKET_API BOOL SYS_FreeHostIPAddresses(LPTIPAddr* lppIPAddr);
|
||||
/* 检查字符串是否符合 IP 地址格式 */
|
||||
HPSOCKET_API BOOL SYS_IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType = nullptr);
|
||||
/* 通过主机名获取 IP 地址 */
|
||||
HPSOCKET_API BOOL SYS_GetIPAddress(LPCTSTR lpszHost, TCHAR lpszIP[], int& iIPLenth, EnIPAddrType& enType);
|
||||
|
||||
/* 64 位网络字节序转主机字节序 */
|
||||
HPSOCKET_API ULONGLONG SYS_NToH64(ULONGLONG value);
|
||||
/* 64 位主机字节序转网络字节序 */
|
||||
HPSOCKET_API ULONGLONG SYS_HToN64(ULONGLONG value);
|
||||
/* 短整型高低字节交换 */
|
||||
HPSOCKET_API USHORT SYS_SwapEndian16(USHORT value);
|
||||
/* 长整型高低字节交换 */
|
||||
HPSOCKET_API DWORD SYS_SwapEndian32(DWORD value);
|
||||
/* 检查是否小端字节序 */
|
||||
HPSOCKET_API BOOL SYS_IsLittleEndian();
|
||||
|
||||
/* 分配内存 */
|
||||
HPSOCKET_API LPBYTE SYS_Malloc(int size);
|
||||
/* 重新分配内存 */
|
||||
HPSOCKET_API LPBYTE SYS_Realloc(LPBYTE p, int size);
|
||||
/* 释放内存 */
|
||||
HPSOCKET_API VOID SYS_Free(LPBYTE p);
|
||||
/* 分配内存块 */
|
||||
HPSOCKET_API LPVOID SYS_Calloc(int number, int size);
|
||||
|
||||
// 计算 Base64 编码后长度
|
||||
HPSOCKET_API DWORD SYS_GuessBase64EncodeBound(DWORD dwSrcLen);
|
||||
// 计算 Base64 解码后长度
|
||||
HPSOCKET_API DWORD SYS_GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
|
||||
// Base64 编码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// Base64 解码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
|
||||
// 计算 URL 编码后长度
|
||||
HPSOCKET_API DWORD SYS_GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
|
||||
// 计算 URL 解码后长度
|
||||
HPSOCKET_API DWORD SYS_GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
|
||||
// URL 编码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// URL 解码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
|
||||
#ifdef _ZLIB_SUPPORT
|
||||
|
||||
// 普通压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
// (默认参数:iLevel -> -1,iMethod -> 8,iWindowBits -> 15,iMemLevel -> 8,iStrategy -> 0)
|
||||
HPSOCKET_API int SYS_Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// 高级压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
//(默认参数:iLevel -> -1,iMethod -> 8,iWindowBits -> 15,iMemLevel -> 8,iStrategy -> 0)
|
||||
HPSOCKET_API int SYS_CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel = -1, int iMethod = 8, int iWindowBits = 15, int iMemLevel = 8, int iStrategy = 0);
|
||||
// 普通解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
//(默认参数:iWindowBits -> 15)
|
||||
HPSOCKET_API int SYS_Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// 高级解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
//(默认参数:iWindowBits -> 15)
|
||||
HPSOCKET_API int SYS_UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits = 15);
|
||||
// 推测压缩结果长度
|
||||
HPSOCKET_API DWORD SYS_GuessCompressBound(DWORD dwSrcLen, BOOL bGZip = FALSE);
|
||||
|
||||
// Gzip 压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// Gzip 解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// 推测 Gzip 解压结果长度(如果返回 0 或不合理值则说明输入内容并非有效的 Gzip 格式)
|
||||
HPSOCKET_API DWORD SYS_GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _BROTLI_SUPPORT
|
||||
|
||||
// Brotli 压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
// (默认参数:iQuality -> 11,iWindow -> 22,iMode -> 0)
|
||||
HPSOCKET_API int SYS_BrotliCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// Brotli 高级压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
//(默认参数:iQuality -> 11,iWindow -> 22,iMode -> 0)
|
||||
HPSOCKET_API int SYS_BrotliCompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iQuality = 11, int iWindow = 22, int iMode = 0);
|
||||
// Brotli 解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||||
HPSOCKET_API int SYS_BrotliUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||||
// Brotli 推测压缩结果长度
|
||||
HPSOCKET_API DWORD SYS_BrotliGuessCompressBound(DWORD dwSrcLen);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _ICONV_SUPPORT
|
||||
|
||||
// Charset A -> Charset B
|
||||
HPSOCKET_API BOOL SYS_CharsetConvert(LPCSTR lpszFromCharset, LPCSTR lpszToCharset, LPCSTR lpszInBuf, int iInBufLen, LPSTR lpszOutBuf, int& iOutBufLen);
|
||||
|
||||
// GBK -> UNICODE
|
||||
HPSOCKET_API BOOL SYS_GbkToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength);
|
||||
// UNICODE -> GBK
|
||||
HPSOCKET_API BOOL SYS_UnicodeToGbkEx(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||||
// UTF8 -> UNICODE
|
||||
HPSOCKET_API BOOL SYS_Utf8ToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength);
|
||||
// UNICODE -> UTF8
|
||||
HPSOCKET_API BOOL SYS_UnicodeToUtf8Ex(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||||
// GBK -> UTF8
|
||||
HPSOCKET_API BOOL SYS_GbkToUtf8Ex(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||||
// UTF8 -> GBK
|
||||
HPSOCKET_API BOOL SYS_Utf8ToGbkEx(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||||
|
||||
// GBK -> UNICODE
|
||||
HPSOCKET_API BOOL SYS_GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength);
|
||||
// UNICODE -> GBK
|
||||
HPSOCKET_API BOOL SYS_UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength);
|
||||
// UTF8 -> UNICODE
|
||||
HPSOCKET_API BOOL SYS_Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength);
|
||||
// UNICODE -> UTF8
|
||||
HPSOCKET_API BOOL SYS_UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength);
|
||||
// GBK -> UTF8
|
||||
HPSOCKET_API BOOL SYS_GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength);
|
||||
// UTF8 -> GBK
|
||||
HPSOCKET_API BOOL SYS_Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength);
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/******************************************************************** HTTP Exports *******************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
// 创建 IHttpServer 对象
|
||||
HPSOCKET_API IHttpServer* HP_Create_HttpServer(IHttpServerListener* pListener);
|
||||
// 创建 IHttpAgent 对象
|
||||
HPSOCKET_API IHttpAgent* HP_Create_HttpAgent(IHttpAgentListener* pListener);
|
||||
// 创建 IHttpClient 对象
|
||||
HPSOCKET_API IHttpClient* HP_Create_HttpClient(IHttpClientListener* pListener);
|
||||
// 创建 IHttpSyncClient 对象
|
||||
HPSOCKET_API IHttpSyncClient* HP_Create_HttpSyncClient(IHttpClientListener* pListener = nullptr);
|
||||
|
||||
// 销毁 IHttpServer 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpServer(IHttpServer* pServer);
|
||||
// 销毁 IHttpAgent 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpAgent(IHttpAgent* pAgent);
|
||||
// 销毁 IHttpClient 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpClient(IHttpClient* pClient);
|
||||
// 销毁 IHttpSyncClient 对象
|
||||
HPSOCKET_API void HP_Destroy_HttpSyncClient(IHttpSyncClient* pClient);
|
||||
|
||||
// IHttpServer 对象创建器
|
||||
struct HttpServer_Creator
|
||||
{
|
||||
static IHttpServer* Create(IHttpServerListener* pListener)
|
||||
{
|
||||
return HP_Create_HttpServer(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpServer* pServer)
|
||||
{
|
||||
HP_Destroy_HttpServer(pServer);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpAgent 对象创建器
|
||||
struct HttpAgent_Creator
|
||||
{
|
||||
static IHttpAgent* Create(IHttpAgentListener* pListener)
|
||||
{
|
||||
return HP_Create_HttpAgent(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpAgent* pAgent)
|
||||
{
|
||||
HP_Destroy_HttpAgent(pAgent);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpClient 对象创建器
|
||||
struct HttpClient_Creator
|
||||
{
|
||||
static IHttpClient* Create(IHttpClientListener* pListener)
|
||||
{
|
||||
return HP_Create_HttpClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpClient* pClient)
|
||||
{
|
||||
HP_Destroy_HttpClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpSyncClient 对象创建器
|
||||
struct HttpSyncClient_Creator
|
||||
{
|
||||
static IHttpSyncClient* Create(IHttpClientListener* pListener = nullptr)
|
||||
{
|
||||
return HP_Create_HttpSyncClient(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHttpSyncClient* pClient)
|
||||
{
|
||||
HP_Destroy_HttpSyncClient(pClient);
|
||||
}
|
||||
};
|
||||
|
||||
// IHttpServer 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpServer, IHttpServerListener, HttpServer_Creator> CHttpServerPtr;
|
||||
// IHttpAgent 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpAgent, IHttpAgentListener, HttpAgent_Creator> CHttpAgentPtr;
|
||||
// IHttpClient 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpClient, IHttpClientListener, HttpClient_Creator> CHttpClientPtr;
|
||||
// IHttpSyncClient 对象智能指针
|
||||
typedef CHPObjectPtr<IHttpSyncClient, IHttpClientListener, HttpSyncClient_Creator> CHttpSyncClientPtr;
|
||||
|
||||
/**************************************************************************/
|
||||
/*************************** HTTP Cookie 管理方法 **************************/
|
||||
|
||||
/* 从文件加载 Cookie */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_LoadFromFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE);
|
||||
/* 保存 Cookie 到文件 */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_SaveToFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE);
|
||||
/* 清理 Cookie */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_ClearCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr);
|
||||
/* 清理过期 Cookie */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_RemoveExpiredCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr);
|
||||
/* 设置 Cookie */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_SetCookie(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, int enSameSite = 0, BOOL bOnlyUpdateValueIfExists = TRUE);
|
||||
/* 删除 Cookie */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_DeleteCookie(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName);
|
||||
/* 设置是否允许第三方 Cookie */
|
||||
HPSOCKET_API void HP_HttpCookie_MGR_SetEnableThirdPartyCookie(BOOL bEnableThirdPartyCookie = TRUE);
|
||||
/* 检查是否允许第三方 Cookie */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_IsEnableThirdPartyCookie();
|
||||
|
||||
/* Cookie expires 字符串转换为整数 */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_HLP_ParseExpires(LPCSTR lpszExpires, __time64_t& tmExpires);
|
||||
/* 整数转换为 Cookie expires 字符串 */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_HLP_MakeExpiresStr(char lpszBuff[], int& iBuffLen, __time64_t tmExpires);
|
||||
/* 生成 Cookie 字符串 */
|
||||
HPSOCKET_API BOOL HP_HttpCookie_HLP_ToString(char lpszBuff[], int& iBuffLen, LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge /*= -1*/, BOOL bHttpOnly /*= FALSE*/, BOOL bSecure /*= FALSE*/, int enSameSite /*= 0*/);
|
||||
/* 获取当前 UTC 时间 */
|
||||
HPSOCKET_API __time64_t HP_HttpCookie_HLP_CurrentUTCTime();
|
||||
/* Max-Age -> expires */
|
||||
HPSOCKET_API __time64_t HP_HttpCookie_HLP_MaxAgeToExpires(int iMaxAge);
|
||||
/* expires -> Max-Age */
|
||||
HPSOCKET_API int HP_HttpCookie_HLP_ExpiresToMaxAge(__time64_t tmExpires);
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/************************************************************* HTTP Global Function Exports **********************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/**************************************************************** Thread Pool Exports ****************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
// 创建 IHPThreadPool 对象
|
||||
HPSOCKET_API IHPThreadPool* HP_Create_ThreadPool(IHPThreadPoolListener* pListener = nullptr);
|
||||
// 销毁 IHPThreadPool 对象
|
||||
HPSOCKET_API void HP_Destroy_ThreadPool(IHPThreadPool* pThreadPool);
|
||||
|
||||
/*
|
||||
* 名称:创建 TSocketTask 对象
|
||||
* 描述:创建任务对象,该对象最终需由 HP_Destroy_SocketTaskObj() 销毁
|
||||
*
|
||||
* 参数: fnTaskProc -- 任务处理函数
|
||||
* pSender -- 发起对象
|
||||
* dwConnID -- 连接 ID
|
||||
* pBuffer -- 数据缓冲区
|
||||
* iBuffLen -- 数据缓冲区长度
|
||||
* enBuffType -- 数据缓冲区类型(默认:TBT_COPY)
|
||||
* TBT_COPY :(深拷贝)pBuffer 复制到 TSocketTask 对象。此后 TSocketTask 对象与 pBuffer 不再有任何关联
|
||||
* -> 适用于 pBuffer 不大或 pBuffer 生命周期不受控的场景
|
||||
* TBT_REFER :(浅拷贝)pBuffer 不复制到 TSocketTask 对象,需确保 TSocketTask 对象生命周期内 pBuffer 必须有效
|
||||
* -> 适用于 pBuffer 较大或 pBuffer 可重用,并且 pBuffer 生命周期受控的场景
|
||||
* TBT_ATTACH :(附属)执行浅拷贝,但 TSocketTask 对象会获得 pBuffer 的所有权,并负责释放 pBuffer,避免多次缓冲区拷贝
|
||||
* -> 注意:pBuffer 必须由 SYS_Malloc()/SYS_Calloc() 函数分配才能使用本类型,否则可能会发生内存访问错误
|
||||
* wParam -- 自定义参数
|
||||
* lParam -- 自定义参数
|
||||
* 返回值: LPTSocketTask
|
||||
*/
|
||||
HPSOCKET_API LPTSocketTask HP_Create_SocketTaskObj(Fn_SocketTaskProc fnTaskProc, PVOID pSender, CONNID dwConnID, LPCBYTE pBuffer, INT iBuffLen, EnTaskBufferType enBuffType = TBT_COPY, WPARAM wParam = 0, LPARAM lParam = 0);
|
||||
|
||||
// 销毁 TSocketTask 对象
|
||||
HPSOCKET_API void HP_Destroy_SocketTaskObj(LPTSocketTask pTask);
|
||||
|
||||
// IHPThreadPool 对象创建器
|
||||
struct HPThreadPool_Creator
|
||||
{
|
||||
static IHPThreadPool* Create(IHPThreadPoolListener* pListener = nullptr)
|
||||
{
|
||||
return HP_Create_ThreadPool(pListener);
|
||||
}
|
||||
|
||||
static void Destroy(IHPThreadPool* pThreadPool)
|
||||
{
|
||||
HP_Destroy_ThreadPool(pThreadPool);
|
||||
}
|
||||
};
|
||||
|
||||
// IHPThreadPool 对象智能指针
|
||||
typedef CHPObjectPtr<IHPThreadPool, IHPThreadPoolListener, HPThreadPool_Creator> CHPThreadPoolPtr;
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/********************************************************* Compressor / Decompressor Exports *********************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
/* 销毁压缩器对象 */
|
||||
HPSOCKET_API void HP_Destroy_Compressor(IHPCompressor* pCompressor);
|
||||
/* 销毁解压器对象 */
|
||||
HPSOCKET_API void HP_Destroy_Decompressor(IHPDecompressor* pDecompressor);
|
||||
|
||||
#ifdef _ZLIB_SUPPORT
|
||||
|
||||
/* 创建 ZLib 压缩器对象 */
|
||||
HPSOCKET_API IHPCompressor* HP_Create_ZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits = 15, int iLevel = -1, int iMethod = 8, int iMemLevel = 8, int iStrategy = 0, DWORD dwBuffSize = 16 * 1024);
|
||||
/* 创建 GZip 压缩器对象 */
|
||||
HPSOCKET_API IHPCompressor* HP_Create_GZipCompressor(Fn_CompressDataCallback fnCallback, int iLevel = -1, int iMethod = 8, int iMemLevel = 8, int iStrategy = 0, DWORD dwBuffSize = 16 * 1024);
|
||||
/* 创建 ZLib 解压器对象 */
|
||||
HPSOCKET_API IHPDecompressor* HP_Create_ZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits = 15, DWORD dwBuffSize = 16 * 1024);
|
||||
/* 创建 GZip 解压器对象 */
|
||||
HPSOCKET_API IHPDecompressor* HP_Create_GZipDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = 16 * 1024);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _BROTLI_SUPPORT
|
||||
|
||||
/* 创建 Brotli 压缩器对象 */
|
||||
HPSOCKET_API IHPCompressor* HP_Create_BrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality = 11, int iWindow = 22, int iMode = 0, DWORD dwBuffSize = 16 * 1024);
|
||||
/* 创建 Brotli 解压器对象 */
|
||||
HPSOCKET_API IHPDecompressor* HP_Create_BrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = 16 * 1024);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,600 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GlobalDef.h"
|
||||
|
||||
/* HP-Socket 版本号 */
|
||||
#define HP_VERSION_MAJOR 6 // 主版本号
|
||||
#define HP_VERSION_MINOR 0 // 子版本号
|
||||
#define HP_VERSION_REVISE 7 // 修正版本号
|
||||
#define HP_VERSION_BUILD 1 // 构建编号
|
||||
|
||||
//#define _UDP_DISABLED // 禁用 UDP
|
||||
#define _SSL_DISABLED // 禁用 SSL
|
||||
#define _HTTP_DISABLED // 禁用 HTTP
|
||||
#define _ZLIB_DISABLED // 禁用 ZLIB
|
||||
#define _ICONV_DISABLED // 禁用 ICONV
|
||||
#define _BROTLI_DISABLED // 禁用 BROTLI
|
||||
|
||||
/* 是否启用 UDP,如果定义了 _UDP_DISABLED 则禁用(默认:启用) */
|
||||
#if !defined(_UDP_DISABLED)
|
||||
#ifndef _UDP_SUPPORT
|
||||
#define _UDP_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 是否启用 SSL,如果定义了 _SSL_DISABLED 则禁用(默认:启用) */
|
||||
#if !defined(_SSL_DISABLED)
|
||||
#ifndef _SSL_SUPPORT
|
||||
#define _SSL_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 是否启用 HTTP,如果定义了 _HTTP_DISABLED 则禁用(默认:启用) */
|
||||
#if !defined(_HTTP_DISABLED)
|
||||
#ifndef _HTTP_SUPPORT
|
||||
#define _HTTP_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 是否启用 ZLIB,如果定义了 _ZLIB_DISABLED 则禁用(默认:启用) */
|
||||
#if !defined(_ZLIB_DISABLED)
|
||||
#ifndef _ZLIB_SUPPORT
|
||||
#define _ZLIB_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 是否启用 BROTLI,如果定义了 _BROTLI_DISABLED 则禁用(默认:启用) */
|
||||
#if !defined(_BROTLI_DISABLED)
|
||||
#ifndef _BROTLI_SUPPORT
|
||||
#define _BROTLI_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 是否启用 ICONV,如果定义了 _ICONV_DISABLED 则禁用(默认:启用) */
|
||||
#if !defined(_ICONV_DISABLED)
|
||||
#ifndef _ICONV_SUPPORT
|
||||
#define _ICONV_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define HPSOCKET_API EXTERN_C __attribute__ ((__visibility__("default")))
|
||||
|
||||
#define __HP_CALL
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/**************************************************************** Base Type Definitions **************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
名称:连接 ID 数据类型
|
||||
描述:应用程序可以把 CONNID 定义为自身需要的类型(如:ULONG / ULONGLONG)
|
||||
************************************************************************/
|
||||
typedef ULID CONNID, HP_CONNID;
|
||||
|
||||
/************************************************************************
|
||||
名称:通信组件服务状态
|
||||
描述:应用程序可以通过通信组件的 GetState() 方法获取组件当前服务状态
|
||||
************************************************************************/
|
||||
typedef enum EnServiceState
|
||||
{
|
||||
SS_STARTING = 0, // 正在启动
|
||||
SS_STARTED = 1, // 已经启动
|
||||
SS_STOPPING = 2, // 正在停止
|
||||
SS_STOPPED = 3, // 已经停止
|
||||
} En_HP_ServiceState;
|
||||
|
||||
/************************************************************************
|
||||
名称:Socket 操作类型
|
||||
描述:应用程序的 OnClose() 事件中通过该参数标识是哪种操作导致的错误
|
||||
************************************************************************/
|
||||
typedef enum EnSocketOperation
|
||||
{
|
||||
SO_UNKNOWN = 0, // Unknown
|
||||
SO_ACCEPT = 1, // Acccept
|
||||
SO_CONNECT = 2, // Connect
|
||||
SO_SEND = 3, // Send
|
||||
SO_RECEIVE = 4, // Receive
|
||||
SO_CLOSE = 5, // Close
|
||||
} En_HP_SocketOperation;
|
||||
|
||||
/************************************************************************
|
||||
名称:事件处理结果
|
||||
描述:事件的返回值,不同的返回值会影响通信组件的后续行为
|
||||
************************************************************************/
|
||||
typedef enum EnHandleResult
|
||||
{
|
||||
HR_OK = 0, // 成功
|
||||
HR_IGNORE = 1, // 忽略
|
||||
HR_ERROR = 2, // 错误
|
||||
} En_HP_HandleResult;
|
||||
|
||||
/************************************************************************
|
||||
名称:数据抓取结果
|
||||
描述:数据抓取操作的返回值
|
||||
************************************************************************/
|
||||
typedef enum EnFetchResult
|
||||
{
|
||||
FR_OK = 0, // 成功
|
||||
FR_LENGTH_TOO_LONG = 1, // 抓取长度过大
|
||||
FR_DATA_NOT_FOUND = 2, // 找不到 ConnID 对应的数据
|
||||
} En_HP_FetchResult;
|
||||
|
||||
/************************************************************************
|
||||
名称:数据发送策略
|
||||
描述:Server 组件和 Agent 组件的数据发送策略
|
||||
|
||||
* 打包发送策略(默认) :尽量把多个发送操作的数据组合在一起发送,增加传输效率
|
||||
* 安全发送策略 :尽量把多个发送操作的数据组合在一起发送,并控制传输速度,避免缓冲区溢出
|
||||
* 直接发送策略 :对每一个发送操作都直接投递,适用于负载不高但要求实时性较高的场合
|
||||
************************************************************************/
|
||||
typedef enum EnSendPolicy
|
||||
{
|
||||
SP_PACK = 0, // 打包模式(默认)
|
||||
SP_SAFE = 1, // 安全模式
|
||||
SP_DIRECT = 2, // 直接模式
|
||||
} En_HP_SendPolicy;
|
||||
|
||||
/************************************************************************
|
||||
名称:OnSend 事件同步策略
|
||||
描述:Server 组件和 Agent 组件的 OnSend 事件同步策略
|
||||
|
||||
* 不同步(默认) :不同步 OnSend 事件,可能同时触发 OnReceive 和 OnClose 事件
|
||||
* 同步 OnClose :只同步 OnClose 事件,可能同时触发 OnReceive 事件
|
||||
* 同步 OnReceive :(只用于 TCP 组件)同步 OnReceive 和 OnClose 事件,不可能同时触发 OnReceive 或 OnClose 事件
|
||||
************************************************************************/
|
||||
typedef enum EnOnSendSyncPolicy
|
||||
{
|
||||
OSSP_NONE = 0, // 不同步(默认)
|
||||
OSSP_CLOSE = 1, // 同步 OnClose
|
||||
OSSP_RECEIVE = 2, // 同步 OnReceive(只用于 TCP 组件)
|
||||
} En_HP_OnSendSyncPolicy;
|
||||
|
||||
/************************************************************************
|
||||
名称:地址重用选项
|
||||
描述:通信组件底层 socket 的地址重用选项
|
||||
************************************************************************/
|
||||
typedef enum EnReuseAddressPolicy
|
||||
{
|
||||
RAP_NONE = 0, // 不重用
|
||||
RAP_ADDR_ONLY = 1, // 仅重用地址
|
||||
RAP_ADDR_AND_PORT = 2, // 重用地址和端口
|
||||
} En_HP_ReuseAddressPolicy;
|
||||
|
||||
/************************************************************************
|
||||
名称:操作结果代码
|
||||
描述:组件 Start() / Stop() 方法执行失败时,可通过 GetLastError() 获取错误代码
|
||||
************************************************************************/
|
||||
typedef enum EnSocketError
|
||||
{
|
||||
SE_OK = NO_ERROR, // 成功
|
||||
SE_ILLEGAL_STATE = 1, // 当前状态不允许操作
|
||||
SE_INVALID_PARAM = 2, // 非法参数
|
||||
SE_SOCKET_CREATE = 3, // 创建 SOCKET 失败
|
||||
SE_SOCKET_BIND = 4, // 绑定 SOCKET 失败
|
||||
SE_SOCKET_PREPARE = 5, // 设置 SOCKET 失败
|
||||
SE_SOCKET_LISTEN = 6, // 监听 SOCKET 失败
|
||||
SE_CP_CREATE = 7, // 创建完成端口失败
|
||||
SE_WORKER_THREAD_CREATE = 8, // 创建工作线程失败
|
||||
SE_DETECT_THREAD_CREATE = 9, // 创建监测线程失败
|
||||
SE_SOCKE_ATTACH_TO_CP = 10, // 绑定完成端口失败
|
||||
SE_CONNECT_SERVER = 11, // 连接服务器失败
|
||||
SE_NETWORK = 12, // 网络错误
|
||||
SE_DATA_PROC = 13, // 数据处理错误
|
||||
SE_DATA_SEND = 14, // 数据发送失败
|
||||
SE_GC_START = 15, // 垃圾回收启动失败
|
||||
|
||||
/***** SSL Socket 扩展操作结果代码 *****/
|
||||
SE_SSL_ENV_NOT_READY = 101, // SSL 环境未就绪
|
||||
} En_HP_SocketError;
|
||||
|
||||
/************************************************************************
|
||||
名称:播送模式
|
||||
描述:UDP 组件的播送模式(组播或广播)
|
||||
************************************************************************/
|
||||
typedef enum EnCastMode
|
||||
{
|
||||
CM_UNICAST = -1, // 单播
|
||||
CM_MULTICAST = 0, // 组播
|
||||
CM_BROADCAST = 1, // 广播
|
||||
} En_HP_CastMode;
|
||||
|
||||
/************************************************************************
|
||||
名称:IP 地址类型
|
||||
描述:IP 地址类型枚举值
|
||||
************************************************************************/
|
||||
typedef enum EnIPAddrType
|
||||
{
|
||||
IPT_ALL = 0, // 所有
|
||||
IPT_IPV4 = 1, // IPv4
|
||||
IPT_IPV6 = 2, // IPv6
|
||||
} En_HP_IPAddrType;
|
||||
|
||||
/************************************************************************
|
||||
名称:IP 地址条目结构体
|
||||
描述:IP 地址的地址簇/地址值结构体
|
||||
************************************************************************/
|
||||
typedef struct TIPAddr
|
||||
{
|
||||
En_HP_IPAddrType type;
|
||||
LPCTSTR address;
|
||||
} *LPTIPAddr, HP_TIPAddr, *HP_LPTIPAddr;
|
||||
|
||||
/************************************************************************
|
||||
名称:缓冲区结构体
|
||||
描述:数据缓冲区
|
||||
************************************************************************/
|
||||
typedef struct _WSABUF
|
||||
{
|
||||
UINT len;
|
||||
LPBYTE buf;
|
||||
} WSABUF, *PWSABUF, *LPWSABUF;
|
||||
|
||||
/************************************************************************
|
||||
名称:拒绝策略
|
||||
描述:调用被拒绝后的处理策略
|
||||
************************************************************************/
|
||||
typedef enum EnRejectedPolicy
|
||||
{
|
||||
TRP_CALL_FAIL = 0, // 立刻返回失败
|
||||
TRP_WAIT_FOR = 1, // 等待(直到成功、超时或线程池关闭等原因导致失败)
|
||||
TRP_CALLER_RUN = 2, // 调用者线程直接执行
|
||||
} En_HP_RejectedPolicy;
|
||||
|
||||
/************************************************************************
|
||||
名称:任务缓冲区类型
|
||||
描述:TSockeTask 对象创建和销毁时,根据不同类型的缓冲区类型作不同的处理
|
||||
************************************************************************/
|
||||
typedef enum EnTaskBufferType
|
||||
{
|
||||
TBT_COPY = 0, // 深拷贝
|
||||
TBT_REFER = 1, // 浅拷贝
|
||||
TBT_ATTACH = 2, // 附属(不负责创建,但负责销毁)
|
||||
} En_HP_TaskBufferType;
|
||||
|
||||
/************************************************************************
|
||||
名称:任务处理函数
|
||||
描述:任务处理入口函数
|
||||
参数:pvArg -- 自定义参数
|
||||
返回值:(无)
|
||||
************************************************************************/
|
||||
typedef VOID (__HP_CALL *Fn_TaskProc)(PVOID pvArg);
|
||||
typedef Fn_TaskProc HP_Fn_TaskProc;
|
||||
|
||||
struct TSocketTask;
|
||||
|
||||
/************************************************************************
|
||||
名称:Socket 任务处理函数
|
||||
描述:Socket 任务处理入口函数
|
||||
参数:pTask -- Socket 任务结构体指针
|
||||
返回值:(无)
|
||||
************************************************************************/
|
||||
typedef VOID (__HP_CALL *Fn_SocketTaskProc)(struct TSocketTask* pTask);
|
||||
typedef Fn_SocketTaskProc HP_Fn_SocketTaskProc;
|
||||
|
||||
/************************************************************************
|
||||
名称:Socket 任务结构体
|
||||
描述:封装 Socket 任务相关数据结构
|
||||
************************************************************************/
|
||||
typedef struct TSocketTask
|
||||
{
|
||||
HP_Fn_SocketTaskProc fn; // 任务处理函数
|
||||
PVOID sender; // 发起对象
|
||||
CONNID connID; // 连接 ID
|
||||
LPCBYTE buf; // 数据缓冲区
|
||||
INT bufLen; // 数据缓冲区长度
|
||||
En_HP_TaskBufferType bufType; // 缓冲区类型
|
||||
WPARAM wparam; // 自定义参数
|
||||
LPARAM lparam; // 自定义参数
|
||||
} *LPTSocketTask, HP_TSocketTask, *HP_LPTSocketTask;
|
||||
|
||||
/************************************************************************
|
||||
名称:获取 HPSocket 版本号
|
||||
描述:版本号(4 个字节分别为:主版本号,子版本号,修正版本号,构建编号)
|
||||
************************************************************************/
|
||||
inline DWORD GetHPSocketVersion()
|
||||
{
|
||||
return (HP_VERSION_MAJOR << 24) | (HP_VERSION_MINOR << 16) | (HP_VERSION_REVISE << 8) | HP_VERSION_BUILD;
|
||||
}
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/**************************************************************** SSL Type Definitions ***************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
/************************************************************************
|
||||
名称:SSL 工作模式
|
||||
描述:标识 SSL 的工作模式,客户端模式或服务端模式
|
||||
************************************************************************/
|
||||
typedef enum EnSSLSessionMode
|
||||
{
|
||||
SSL_SM_CLIENT = 0, // 客户端模式
|
||||
SSL_SM_SERVER = 1, // 服务端模式
|
||||
} En_HP_SSLSessionMode;
|
||||
|
||||
/************************************************************************
|
||||
名称:SSL 验证模式
|
||||
描述:SSL 验证模式选项,SSL_VM_PEER 可以和后面两个选项组合一起
|
||||
************************************************************************/
|
||||
typedef enum EnSSLVerifyMode
|
||||
{
|
||||
SSL_VM_NONE = 0x00, // SSL_VERIFY_NONE
|
||||
SSL_VM_PEER = 0x01, // SSL_VERIFY_PEER
|
||||
SSL_VM_FAIL_IF_NO_PEER_CERT = 0x02, // SSL_VERIFY_FAIL_IF_NO_PEER_CERT
|
||||
SSL_VM_CLIENT_ONCE = 0x04, // SSL_VERIFY_CLIENT_ONCE
|
||||
} En_HP_SSLVerifyMode;
|
||||
|
||||
/************************************************************************
|
||||
名称:SSL Session 信息类型
|
||||
描述:用于 GetSSLSessionInfo(),标识输出的 Session 信息类型
|
||||
************************************************************************/
|
||||
typedef enum EnSSLSessionInfo
|
||||
{
|
||||
SSL_SSI_MIN = 0, //
|
||||
SSL_SSI_CTX = 0, // SSL CTX (输出类型:SSL_CTX*)
|
||||
SSL_SSI_CTX_METHOD = 1, // SSL CTX Mehtod (输出类型:SSL_METHOD*)
|
||||
SSL_SSI_CTX_CIPHERS = 2, // SSL CTX Ciphers (输出类型:STACK_OF(SSL_CIPHER)*)
|
||||
SSL_SSI_CTX_CERT_STORE = 3, // SSL CTX Cert Store (输出类型:X509_STORE*)
|
||||
SSL_SSI_SERVER_NAME_TYPE = 4, // Server Name Type (输出类型:int)
|
||||
SSL_SSI_SERVER_NAME = 5, // Server Name (输出类型:LPCSTR)
|
||||
SSL_SSI_VERSION = 6, // SSL Version (输出类型:LPCSTR)
|
||||
SSL_SSI_METHOD = 7, // SSL Method (输出类型:SSL_METHOD*)
|
||||
SSL_SSI_CERT = 8, // SSL Cert (输出类型:X509*)
|
||||
SSL_SSI_PKEY = 9, // SSL Private Key (输出类型:EVP_PKEY*)
|
||||
SSL_SSI_CURRENT_CIPHER = 10, // SSL Current Cipher (输出类型:SSL_CIPHER*)
|
||||
SSL_SSI_CIPHERS = 11, // SSL Available Ciphers(输出类型:STACK_OF(SSL_CIPHER)*)
|
||||
SSL_SSI_CLIENT_CIPHERS = 12, // SSL Client Ciphers (输出类型:STACK_OF(SSL_CIPHER)*)
|
||||
SSL_SSI_PEER_CERT = 13, // SSL Peer Cert (输出类型:X509*)
|
||||
SSL_SSI_PEER_CERT_CHAIN = 14, // SSL Peer Cert Chain (输出类型:STACK_OF(X509)*)
|
||||
SSL_SSI_VERIFIED_CHAIN = 15, // SSL Verified Chain (输出类型:STACK_OF(X509)*)
|
||||
SSL_SSI_MAX = 15, //
|
||||
} En_HP_SSLSessionInfo;
|
||||
|
||||
/************************************************************************
|
||||
名称:SNI 服务名称回调函数
|
||||
描述:根据服务器名称选择 SSL 证书
|
||||
参数:
|
||||
lpszServerName -- 服务器名称(域名)
|
||||
|
||||
返回值:
|
||||
0 -- 成功,使用默认 SSL 证书索引
|
||||
正数 -- 成功,使用返回值对应的 SNI 主机证书索引
|
||||
负数 -- 失败,中断 SSL 握手
|
||||
|
||||
************************************************************************/
|
||||
typedef int (__HP_CALL *Fn_SNI_ServerNameCallback)(LPCTSTR lpszServerName, PVOID pContext);
|
||||
typedef Fn_SNI_ServerNameCallback HP_Fn_SNI_ServerNameCallback;
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/**************************************************************** HTTP Type Definitions **************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
/************************************************************************
|
||||
名称:HTTP 版本
|
||||
描述:低字节:主版本号,高字节:次版本号
|
||||
************************************************************************/
|
||||
|
||||
typedef enum EnHttpVersion
|
||||
{
|
||||
HV_1_0 = MAKEWORD(1, 0), // HTTP/1.0
|
||||
HV_1_1 = MAKEWORD(1, 1) // HTTP/1.1
|
||||
} En_HP_HttpVersion;
|
||||
|
||||
/************************************************************************
|
||||
名称:URL 域
|
||||
描述:HTTP 请求行中 URL 段位的域定义
|
||||
************************************************************************/
|
||||
typedef enum EnHttpUrlField
|
||||
{
|
||||
HUF_SCHEMA = 0, // Schema
|
||||
HUF_HOST = 1, // Host
|
||||
HUF_PORT = 2, // Port
|
||||
HUF_PATH = 3, // Path
|
||||
HUF_QUERY = 4, // Query String
|
||||
HUF_FRAGMENT = 5, // Fragment
|
||||
HUF_USERINFO = 6, // User Info
|
||||
HUF_MAX = 7, // (Field Count)
|
||||
} En_HP_HttpUrlField;
|
||||
|
||||
/************************************************************************
|
||||
名称:HTTP 解析结果标识
|
||||
描述:指示 HTTP 解析器是否继续执行解析操作
|
||||
************************************************************************/
|
||||
typedef enum EnHttpParseResult
|
||||
{
|
||||
HPR_OK = 0, // 解析成功
|
||||
HPR_SKIP_BODY = 1, // 跳过当前请求 BODY(仅用于 OnHeadersComplete 事件)
|
||||
HPR_UPGRADE = 2, // 升级协议(仅用于 OnHeadersComplete 事件)
|
||||
HPR_ERROR = -1, // 解析错误,终止解析,断开连接
|
||||
} En_HP_HttpParseResult;
|
||||
|
||||
/************************************************************************
|
||||
名称:HTTP 协议升级类型
|
||||
描述:标识 HTTP 升级为哪种协议
|
||||
************************************************************************/
|
||||
typedef enum EnHttpUpgradeType
|
||||
{
|
||||
HUT_NONE = 0, // 没有升级
|
||||
HUT_WEB_SOCKET = 1, // WebSocket
|
||||
HUT_HTTP_TUNNEL = 2, // HTTP 隧道
|
||||
HUT_UNKNOWN = -1, // 未知类型
|
||||
} En_HP_HttpUpgradeType;
|
||||
|
||||
/************************************************************************
|
||||
名称:HTTP 状态码
|
||||
描述:HTTP 标准状态码
|
||||
************************************************************************/
|
||||
typedef enum EnHttpStatusCode
|
||||
{
|
||||
HSC_CONTINUE = 100,
|
||||
HSC_SWITCHING_PROTOCOLS = 101,
|
||||
HSC_PROCESSING = 102,
|
||||
HSC_EARLY_HINTS = 103,
|
||||
HSC_RESPONSE_IS_STALE = 110,
|
||||
HSC_REVALIDATION_FAILED = 111,
|
||||
HSC_DISCONNECTED_OPERATION = 112,
|
||||
HSC_HEURISTIC_EXPIRATION = 113,
|
||||
HSC_MISCELLANEOUS_WARNING = 199,
|
||||
|
||||
HSC_OK = 200,
|
||||
HSC_CREATED = 201,
|
||||
HSC_ACCEPTED = 202,
|
||||
HSC_NON_AUTHORITATIVE_INFORMATION = 203,
|
||||
HSC_NO_CONTENT = 204,
|
||||
HSC_RESET_CONTENT = 205,
|
||||
HSC_PARTIAL_CONTENT = 206,
|
||||
HSC_MULTI_STATUS = 207,
|
||||
HSC_ALREADY_REPORTED = 208,
|
||||
HSC_TRANSFORMATION_APPLIED = 214,
|
||||
HSC_IM_USED = 226,
|
||||
HSC_MISCELLANEOUS_PERSISTENT_WARNING = 299,
|
||||
|
||||
HSC_MULTIPLE_CHOICES = 300,
|
||||
HSC_MOVED_PERMANENTLY = 301,
|
||||
HSC_MOVED_TEMPORARILY = 302,
|
||||
HSC_SEE_OTHER = 303,
|
||||
HSC_NOT_MODIFIED = 304,
|
||||
HSC_USE_PROXY = 305,
|
||||
HSC_SWITCH_PROXY = 306,
|
||||
HSC_TEMPORARY_REDIRECT = 307,
|
||||
HSC_PERMANENT_REDIRECT = 308,
|
||||
|
||||
HSC_BAD_REQUEST = 400,
|
||||
HSC_UNAUTHORIZED = 401,
|
||||
HSC_PAYMENT_REQUIRED = 402,
|
||||
HSC_FORBIDDEN = 403,
|
||||
HSC_NOT_FOUND = 404,
|
||||
HSC_METHOD_NOT_ALLOWED = 405,
|
||||
HSC_NOT_ACCEPTABLE = 406,
|
||||
HSC_PROXY_AUTHENTICATION_REQUIRED = 407,
|
||||
HSC_REQUEST_TIMEOUT = 408,
|
||||
HSC_CONFLICT = 409,
|
||||
HSC_GONE = 410,
|
||||
HSC_LENGTH_REQUIRED = 411,
|
||||
HSC_PRECONDITION_FAILED = 412,
|
||||
HSC_REQUEST_ENTITY_TOO_LARGE = 413,
|
||||
HSC_REQUEST_URI_TOO_LONG = 414,
|
||||
HSC_UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
HSC_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
|
||||
HSC_EXPECTATION_FAILED = 417,
|
||||
HSC_IM_A_TEAPOT = 418,
|
||||
HSC_PAGE_EXPIRED = 419,
|
||||
HSC_ENHANCE_YOUR_CALM = 420,
|
||||
HSC_MISDIRECTED_REQUEST = 421,
|
||||
HSC_UNPROCESSABLE_ENTITY = 422,
|
||||
HSC_LOCKED = 423,
|
||||
HSC_FAILED_DEPENDENCY = 424,
|
||||
HSC_UNORDERED_COLLECTION = 425,
|
||||
HSC_UPGRADE_REQUIRED = 426,
|
||||
HSC_PRECONDITION_REQUIRED = 428,
|
||||
HSC_TOO_MANY_REQUESTS = 429,
|
||||
HSC_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430,
|
||||
HSC_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
|
||||
HSC_LOGIN_TIMEOUT = 440,
|
||||
HSC_NO_RESPONSE = 444,
|
||||
HSC_RETRY_WITH = 449,
|
||||
HSC_BLOCKED_BY_PARENTAL_CONTROL = 450,
|
||||
HSC_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
|
||||
HSC_CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460,
|
||||
HSC_INVALID_X_FORWARDED_FOR = 463,
|
||||
HSC_REQUEST_HEADER_TOO_LARGE = 494,
|
||||
HSC_SSL_CERTIFICATE_ERROR = 495,
|
||||
HSC_SSL_CERTIFICATE_REQUIRED = 496,
|
||||
HSC_HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497,
|
||||
HSC_INVALID_TOKEN = 498,
|
||||
HSC_CLIENT_CLOSED_REQUEST = 499,
|
||||
|
||||
HSC_INTERNAL_SERVER_ERROR = 500,
|
||||
HSC_NOT_IMPLEMENTED = 501,
|
||||
HSC_BAD_GATEWAY = 502,
|
||||
HSC_SERVICE_UNAVAILABLE = 503,
|
||||
HSC_GATEWAY_TIMEOUT = 504,
|
||||
HSC_HTTP_VERSION_NOT_SUPPORTED = 505,
|
||||
HSC_VARIANT_ALSO_NEGOTIATES = 506,
|
||||
HSC_INSUFFICIENT_STORAGE = 507,
|
||||
HSC_LOOP_DETECTED = 508,
|
||||
HSC_BANDWIDTH_LIMIT_EXCEEDED = 509,
|
||||
HSC_NOT_EXTENDED = 510,
|
||||
HSC_NETWORK_AUTHENTICATION_REQUIRED = 511,
|
||||
HSC_WEB_SERVER_UNKNOWN_ERROR = 520,
|
||||
HSC_WEB_SERVER_IS_DOWN = 521,
|
||||
HSC_CONNECTION_TIMEOUT = 522,
|
||||
HSC_ORIGIN_IS_UNREACHABLE = 523,
|
||||
HSC_TIMEOUT_OCCURED = 524,
|
||||
HSC_SSL_HANDSHAKE_FAILED = 525,
|
||||
HSC_INVALID_SSL_CERTIFICATE = 526,
|
||||
HSC_RAILGUN_ERROR = 527,
|
||||
HSC_SITE_IS_OVERLOADED = 529,
|
||||
HSC_SITE_IS_FROZEN = 530,
|
||||
HSC_IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561,
|
||||
HSC_NETWORK_READ_TIMEOUT = 598,
|
||||
HSC_NETWORK_CONNECT_TIMEOUT = 599,
|
||||
|
||||
HSC_UNPARSEABLE_RESPONSE_HEADERS = 600
|
||||
} En_HP_HttpStatusCode;
|
||||
|
||||
/************************************************************************
|
||||
名称:Name/Value 结构体
|
||||
描述:字符串名值对结构体
|
||||
************************************************************************/
|
||||
typedef struct TNVPair
|
||||
{
|
||||
LPCSTR name;
|
||||
LPCSTR value;
|
||||
} HP_TNVPair,
|
||||
TParam, HP_TParam, *LPPARAM, *HP_LPPARAM,
|
||||
THeader, HP_THeader, *LPHEADER, *HP_LPHEADER,
|
||||
TCookie, HP_TCookie, *LPCOOKIE, *HP_LPCOOKIE;
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/********************************************************** Compress / Decompress Definitions ********************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
名称:数据回调函数
|
||||
描述:回调处理过程中产生的数据输出
|
||||
参数:
|
||||
pData -- 数据缓冲区
|
||||
iLength -- 数据长度
|
||||
pContext -- 回调上下文
|
||||
|
||||
返回值:
|
||||
TRUE -- 成功
|
||||
FALSE -- 失败
|
||||
|
||||
************************************************************************/
|
||||
typedef BOOL (__HP_CALL *Fn_DataCallback)(const BYTE* pData, int iLength, PVOID pContext);
|
||||
typedef Fn_DataCallback Fn_CompressDataCallback;
|
||||
typedef Fn_DataCallback Fn_DecompressDataCallback;
|
||||
typedef Fn_DataCallback HP_Fn_DataCallback;
|
||||
typedef Fn_DataCallback HP_Fn_CompressDataCallback;
|
||||
typedef Fn_DataCallback HP_Fn_DecompressDataCallback;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,165 @@
|
|||
#include "helper.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
class CListenerImpl : public CTcpServerListener
|
||||
{
|
||||
|
||||
public:
|
||||
virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen) override
|
||||
{
|
||||
TCHAR szAddress[100];
|
||||
int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
|
||||
USHORT usPort;
|
||||
|
||||
pSender->GetListenAddress(szAddress, iAddressLen, usPort);
|
||||
::PostOnPrepareListen(szAddress, usPort);
|
||||
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient) override
|
||||
{
|
||||
BOOL bPass = TRUE;
|
||||
TCHAR szAddress[100];
|
||||
int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
|
||||
USHORT usPort;
|
||||
|
||||
pSender->GetRemoteAddress(dwConnID, szAddress, iAddressLen, usPort);
|
||||
|
||||
if(!g_app_arg.reject_addr.IsEmpty())
|
||||
{
|
||||
if(g_app_arg.reject_addr.CompareNoCase(szAddress) == 0)
|
||||
bPass = FALSE;
|
||||
}
|
||||
|
||||
::PostOnAccept(dwConnID, szAddress, usPort, bPass);
|
||||
|
||||
return bPass ? HR_OK : HR_ERROR;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID) override
|
||||
{
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override
|
||||
{
|
||||
::PostOnReceive(dwConnID, pData, iLength);
|
||||
|
||||
if(pSender->Send(dwConnID, pData, iLength))
|
||||
return HR_OK;
|
||||
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override
|
||||
{
|
||||
::PostOnSend(dwConnID, pData, iLength);
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) override
|
||||
{
|
||||
iErrorCode == SE_OK ? ::PostOnClose(dwConnID) :
|
||||
::PostOnError(dwConnID, enOperation, iErrorCode);
|
||||
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnShutdown(ITcpServer* pSender) override
|
||||
{
|
||||
::PostOnShutdown();
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CListenerImpl s_listener;
|
||||
CTcpServer s_server(&s_listener);
|
||||
|
||||
void OnCmdStart(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.Start(g_app_arg.bind_addr, g_app_arg.port))
|
||||
::LogServerStart(g_app_arg.bind_addr, g_app_arg.port);
|
||||
else
|
||||
::LogServerStartFail(s_server.GetLastError(), s_server.GetLastErrorDesc());
|
||||
}
|
||||
|
||||
void OnCmdStop(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.Stop())
|
||||
::LogServerStop();
|
||||
else
|
||||
::LogServerStopFail(s_server.GetLastError(), s_server.GetLastErrorDesc());
|
||||
}
|
||||
|
||||
void OnCmdStatus(CCommandParser* pParser)
|
||||
{
|
||||
pParser->PrintStatus(s_server.GetState());
|
||||
}
|
||||
|
||||
void OnCmdSend(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.Send(pParser->m_dwConnID, (LPBYTE)(LPCTSTR)pParser->m_strMessage, pParser->m_strMessage.GetLength()))
|
||||
::LogSend(pParser->m_dwConnID, pParser->m_strMessage);
|
||||
else
|
||||
::LogSendFail(pParser->m_dwConnID, ::GetLastError(), ::GetLastErrorStr());
|
||||
}
|
||||
|
||||
void OnCmdPause(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.PauseReceive(pParser->m_dwConnID, pParser->m_bFlag))
|
||||
::LogPause(pParser->m_dwConnID, pParser->m_bFlag);
|
||||
else
|
||||
::LogPauseFail(pParser->m_dwConnID, pParser->m_bFlag);
|
||||
}
|
||||
|
||||
void OnCmdKick(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.Disconnect(pParser->m_dwConnID, pParser->m_bFlag))
|
||||
::LogDisconnect2(pParser->m_dwConnID, pParser->m_bFlag);
|
||||
else
|
||||
::LogDisconnectFail2(pParser->m_dwConnID, pParser->m_bFlag);
|
||||
}
|
||||
|
||||
void OnCmdKickLong(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.DisconnectLongConnections(pParser->m_dwSeconds * 1000, pParser->m_bFlag))
|
||||
::LogDisconnectLong(pParser->m_dwSeconds, pParser->m_bFlag);
|
||||
else
|
||||
::LogDisconnectFailLong(pParser->m_dwSeconds, pParser->m_bFlag);
|
||||
}
|
||||
|
||||
void OnCmdKickSilence(CCommandParser* pParser)
|
||||
{
|
||||
if(s_server.DisconnectSilenceConnections(pParser->m_dwSeconds * 1000, pParser->m_bFlag))
|
||||
::LogDisconnectLong(pParser->m_dwSeconds, pParser->m_bFlag);
|
||||
else
|
||||
::LogDisconnectFailLong(pParser->m_dwSeconds, pParser->m_bFlag);
|
||||
}
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
CTermAttrInitializer term_attr;
|
||||
CAppSignalHandler s_signal_handler({SIGTTOU, SIGINT});
|
||||
|
||||
g_app_arg.ParseArgs(argc, argv);
|
||||
|
||||
s_server.SetKeepAliveTime(g_app_arg.keep_alive ? TCP_KEEPALIVE_TIME : 0);
|
||||
|
||||
CCommandParser::CMD_FUNC fnCmds[CCommandParser::CT_MAX] = {0};
|
||||
|
||||
fnCmds[CCommandParser::CT_START] = OnCmdStart;
|
||||
fnCmds[CCommandParser::CT_STOP] = OnCmdStop;
|
||||
fnCmds[CCommandParser::CT_STATUS] = OnCmdStatus;
|
||||
fnCmds[CCommandParser::CT_SEND] = OnCmdSend;
|
||||
fnCmds[CCommandParser::CT_PAUSE] = OnCmdPause;
|
||||
fnCmds[CCommandParser::CT_KICK] = OnCmdKick;
|
||||
fnCmds[CCommandParser::CT_KICK_L] = OnCmdKickLong;
|
||||
fnCmds[CCommandParser::CT_KICK_S] = OnCmdKickSilence;
|
||||
|
||||
CCommandParser s_cmd_parser(CCommandParser::AT_SERVER, fnCmds);
|
||||
s_cmd_parser.Run();
|
||||
|
||||
return EXIT_CODE_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ArqHelper.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
DWORD GenerateConversationID()
|
||||
{
|
||||
static volatile DWORD s_dwConvID = ::TimeGetTime();
|
||||
|
||||
DWORD dwConvID = ::InterlockedIncrement(&s_dwConvID);
|
||||
|
||||
if(dwConvID == 0)
|
||||
dwConvID = ::InterlockedIncrement(&s_dwConvID);
|
||||
|
||||
return dwConvID;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/hpsocket/HPTypeDef.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
#include "SocketHelper.h"
|
||||
|
||||
#include "common/FuncHelper.h"
|
||||
#include "common/BufferPool.h"
|
||||
#include "common/IODispatcher.h"
|
||||
#include "common/kcp/ikcp.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define DEFAULT_ARQ_NO_DELAY FALSE
|
||||
#define DEFAULT_ARQ_TURNOFF_NC FALSE
|
||||
#define DEFAULT_ARQ_FLUSH_INTERVAL 60
|
||||
#define DEFAULT_ARQ_RESEND_BY_ACKS 0
|
||||
#define DEFAULT_ARQ_SEND_WND_SIZE 128
|
||||
#define DEFAULT_ARQ_RECV_WND_SIZE 512
|
||||
#define DEFAULT_ARQ_MIN_RTO 30
|
||||
#define DEFAULT_ARQ_FAST_LIMIT 5
|
||||
#define DEFAULT_ARQ_MAX_TRANS_UNIT DEFAULT_UDP_MAX_DATAGRAM_SIZE
|
||||
#define DEFAULT_ARQ_MAX_MSG_SIZE DEFAULT_BUFFER_CACHE_CAPACITY
|
||||
#define DEFAULT_ARQ_HANND_SHAKE_TIMEOUT 5000
|
||||
|
||||
#define KCP_HEADER_SIZE 24
|
||||
#define KCP_MIN_RECV_WND 128
|
||||
|
||||
#define ARQ_MAX_HANDSHAKE_INTERVAL 2000
|
||||
|
||||
using Fn_ArqOutputProc = int (*)(const char* pBuffer, int iLength, IKCPCB* kcp, LPVOID pv);
|
||||
|
||||
DWORD GenerateConversationID();
|
||||
|
||||
/************************************************************************
|
||||
名称:ARQ 握手状态
|
||||
描述:标识当前连接的 ARQ 握手状态
|
||||
************************************************************************/
|
||||
enum EnArqHandShakeStatus
|
||||
{
|
||||
ARQ_HSS_INIT = 0, // 初始状态
|
||||
ARQ_HSS_PROC = 1, // 正在握手
|
||||
ARQ_HSS_SUCC = 2, // 握手成功
|
||||
};
|
||||
|
||||
struct TArqCmd
|
||||
{
|
||||
public:
|
||||
static const UINT16 MAGIC = 0xBB4F;
|
||||
static const UINT8 CMD_HANDSHAKE = 0x01;
|
||||
static const UINT8 FLAG_COMPLETE = 0x01;
|
||||
static const int PACKAGE_LENGTH = 12;
|
||||
|
||||
public:
|
||||
UINT16 magic;
|
||||
UINT8 cmd;
|
||||
UINT8 flag;
|
||||
DWORD selfID;
|
||||
DWORD peerID;
|
||||
|
||||
public:
|
||||
static BYTE* MakePackage(UINT8 cmd, UINT8 flag, DWORD selfID, DWORD peerID, UINT16 magic = MAGIC)
|
||||
{
|
||||
BYTE* buff = new BYTE[PACKAGE_LENGTH];
|
||||
|
||||
*((UINT16*)(buff + 0)) = magic;
|
||||
*((UINT8*)(buff + 2)) = cmd;
|
||||
*((UINT8*)(buff + 3)) = flag;
|
||||
*((DWORD*)(buff + 4)) = selfID;
|
||||
*((DWORD*)(buff + 8)) = peerID;
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
BYTE* MakePackage()
|
||||
{
|
||||
return MakePackage(cmd, flag, selfID, peerID, magic);
|
||||
}
|
||||
|
||||
BOOL Parse(const BYTE buff[PACKAGE_LENGTH])
|
||||
{
|
||||
magic = *((UINT16*)(buff + 0));
|
||||
cmd = *((UINT8*) (buff + 2));
|
||||
flag = *((UINT8*) (buff + 3));
|
||||
selfID = *((DWORD*) (buff + 4));
|
||||
peerID = *((DWORD*) (buff + 8));
|
||||
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
BOOL IsValid() {return (magic == MAGIC && cmd == CMD_HANDSHAKE && (flag & 0xFE) == 0);}
|
||||
|
||||
public:
|
||||
TArqCmd()
|
||||
{
|
||||
::ZeroMemory(this, sizeof(TArqCmd));
|
||||
}
|
||||
|
||||
TArqCmd(UINT8 c, UINT8 f, DWORD sid, DWORD pid)
|
||||
: magic (MAGIC)
|
||||
, cmd (c)
|
||||
, flag (f)
|
||||
, selfID(sid)
|
||||
, peerID(pid)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct TArqAttr
|
||||
{
|
||||
BOOL bNoDelay;
|
||||
BOOL bTurnoffNc;
|
||||
DWORD dwResendByAcks;
|
||||
DWORD dwFlushInterval;
|
||||
DWORD dwSendWndSize;
|
||||
DWORD dwRecvWndSize;
|
||||
DWORD dwMinRto;
|
||||
DWORD dwMtu;
|
||||
DWORD dwFastLimit;
|
||||
DWORD dwMaxMessageSize;
|
||||
DWORD dwHandShakeTimeout;
|
||||
|
||||
public:
|
||||
TArqAttr( BOOL no_delay = DEFAULT_ARQ_NO_DELAY
|
||||
, BOOL turnoff_nc = DEFAULT_ARQ_TURNOFF_NC
|
||||
, DWORD resend_by_acks = DEFAULT_ARQ_RESEND_BY_ACKS
|
||||
, DWORD flush_interval = DEFAULT_ARQ_FLUSH_INTERVAL
|
||||
, DWORD send_wnd_size = DEFAULT_ARQ_SEND_WND_SIZE
|
||||
, DWORD recv_wnd_size = DEFAULT_ARQ_RECV_WND_SIZE
|
||||
, DWORD min_rto = DEFAULT_ARQ_MIN_RTO
|
||||
, DWORD mtu = DEFAULT_ARQ_MAX_TRANS_UNIT
|
||||
, DWORD fast_limit = DEFAULT_ARQ_FAST_LIMIT
|
||||
, DWORD max_msg_size = DEFAULT_ARQ_MAX_MSG_SIZE
|
||||
, DWORD hand_shake_timeout = DEFAULT_ARQ_HANND_SHAKE_TIMEOUT
|
||||
)
|
||||
: bNoDelay (no_delay)
|
||||
, bTurnoffNc (turnoff_nc)
|
||||
, dwResendByAcks (resend_by_acks)
|
||||
, dwFlushInterval (flush_interval)
|
||||
, dwSendWndSize (send_wnd_size)
|
||||
, dwRecvWndSize (recv_wnd_size)
|
||||
, dwMinRto (min_rto)
|
||||
, dwMtu (mtu)
|
||||
, dwFastLimit (fast_limit)
|
||||
, dwMaxMessageSize (max_msg_size)
|
||||
, dwHandShakeTimeout(hand_shake_timeout)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
}
|
||||
|
||||
BOOL IsValid() const
|
||||
{
|
||||
return ((int)dwResendByAcks >= 0) &&
|
||||
((int)dwFlushInterval > 0) &&
|
||||
((int)dwSendWndSize > 0) &&
|
||||
((int)dwRecvWndSize > 0) &&
|
||||
((int)dwMinRto > 0) &&
|
||||
((int)dwFastLimit >= 0) &&
|
||||
((int)dwHandShakeTimeout > 2 * (int)dwMinRto) &&
|
||||
((int)dwMtu >= 3 * KCP_HEADER_SIZE && dwMtu <= MAXIMUM_UDP_MAX_DATAGRAM_SIZE) &&
|
||||
((int)dwMaxMessageSize > 0 && dwMaxMessageSize < ((KCP_MIN_RECV_WND - 1) * (dwMtu - KCP_HEADER_SIZE))) ;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class T, class S> class CArqSessionT
|
||||
{
|
||||
public:
|
||||
CArqSessionT* Renew(T* pContext, S* pSocket, const TArqAttr& attr, DWORD dwPeerConvID = 0)
|
||||
{
|
||||
m_pContext = pContext;
|
||||
m_pSocket = pSocket;
|
||||
m_dwSelfConvID = ::GenerateConversationID();
|
||||
|
||||
DoRenew(attr, dwPeerConvID);
|
||||
RenewExtra(attr);
|
||||
|
||||
m_dwCreateTime = ::TimeGetTime();
|
||||
m_dwHSNextTime = m_dwCreateTime;
|
||||
m_dwHSSndCount = 0;
|
||||
m_bHSComplete = FALSE;
|
||||
m_enStatus = ARQ_HSS_PROC;
|
||||
|
||||
Check();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
BOOL Reset()
|
||||
{
|
||||
if(!IsValid())
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
CReentrantCriSecLock recvlock(m_csRecv);
|
||||
CReentrantCriSecLock sendlock(m_csSend);
|
||||
|
||||
if(!IsValid())
|
||||
return FALSE;
|
||||
|
||||
m_enStatus = ARQ_HSS_INIT;
|
||||
|
||||
DoReset();
|
||||
}
|
||||
|
||||
ResetExtra();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Check()
|
||||
{
|
||||
if(IsReady())
|
||||
{
|
||||
if(m_bHSComplete || DoHandShake())
|
||||
return Flush();
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
else if(IsHandShaking())
|
||||
return DoHandShake();
|
||||
else
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL DoHandShake()
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
unique_ptr<BYTE[]> bufCmdPtr;
|
||||
|
||||
{
|
||||
CReentrantCriSecLock recvlock(m_csRecv);
|
||||
|
||||
if(!IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD dwCurrent = ::TimeGetTime();
|
||||
|
||||
if(::GetTimeGap32(m_dwCreateTime, dwCurrent) > m_pContext->GetHandShakeTimeout())
|
||||
{
|
||||
::SetLastError(ERROR_TIMEOUT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if((int)(::GetTimeGap32(m_dwHSNextTime, dwCurrent)) < 0)
|
||||
return TRUE;
|
||||
|
||||
m_dwHSNextTime = dwCurrent + MIN(m_kcp->interval * (++m_dwHSSndCount), ARQ_MAX_HANDSHAKE_INTERVAL);
|
||||
UINT8 iFlag = IsReady() ? TArqCmd::FLAG_COMPLETE : 0;
|
||||
|
||||
bufCmdPtr.reset(TArqCmd::MakePackage(TArqCmd::CMD_HANDSHAKE, iFlag, m_dwSelfConvID, m_dwPeerConvID));
|
||||
}
|
||||
|
||||
return m_pContext->DoSend(m_pSocket, bufCmdPtr.get(), TArqCmd::PACKAGE_LENGTH);
|
||||
}
|
||||
|
||||
BOOL Flush(BOOL bForce = FALSE)
|
||||
{
|
||||
if(!IsReady())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
CReentrantCriSecTryLock recvlock(m_csRecv);
|
||||
|
||||
if(recvlock.IsValid())
|
||||
{
|
||||
CReentrantCriSecTryLock sendlock(m_csSend);
|
||||
|
||||
if(sendlock.IsValid())
|
||||
{
|
||||
if(!IsReady())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(bForce)
|
||||
::ikcp_flush(m_kcp);
|
||||
else
|
||||
::ikcp_update(m_kcp, ::TimeGetTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int Send(const BYTE* pBuffer, int iLength)
|
||||
{
|
||||
if(!IsReady())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
int rs = NO_ERROR;
|
||||
|
||||
{
|
||||
CReentrantCriSecLock sendlock(m_csSend);
|
||||
|
||||
if(!IsReady())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
rs = ::ikcp_send(m_kcp, (const char*)pBuffer, iLength);
|
||||
if(rs < 0) rs = ERROR_INCORRECT_SIZE;
|
||||
}
|
||||
|
||||
if(rs == NO_ERROR)
|
||||
Flush(TRUE);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
int GetWaitingSend()
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CReentrantCriSecLock sendlock(m_csSend);
|
||||
|
||||
if(!IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ::ikcp_waitsnd(m_kcp);
|
||||
}
|
||||
|
||||
EnHandleResult Receive(const BYTE* pData, int iLength, BYTE* pBuffer, int iCapacity)
|
||||
{
|
||||
if(iLength >= KCP_HEADER_SIZE)
|
||||
return ReceiveArq(pData, iLength, pBuffer, iCapacity);
|
||||
else if(iLength == TArqCmd::PACKAGE_LENGTH)
|
||||
return ReceiveHandShake(pData);
|
||||
else
|
||||
{
|
||||
::WSASetLastError(ERROR_INVALID_DATA);
|
||||
return HR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
EnHandleResult ReceiveHandShake(const BYTE* pBuffer)
|
||||
{
|
||||
TArqCmd cmd;
|
||||
cmd.Parse(pBuffer);
|
||||
|
||||
if(!cmd.IsValid())
|
||||
{
|
||||
::WSASetLastError(ERROR_INVALID_DATA);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
{
|
||||
CReentrantCriSecLock recvlock(m_csRecv);
|
||||
|
||||
if(!IsValid())
|
||||
{
|
||||
::WSASetLastError(ERROR_INVALID_STATE);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
if(IsReady())
|
||||
{
|
||||
BOOL bReset = FALSE;
|
||||
|
||||
if(cmd.selfID != m_dwPeerConvID)
|
||||
bReset = TRUE;
|
||||
else if(cmd.peerID != m_dwSelfConvID)
|
||||
{
|
||||
if(cmd.peerID != 0)
|
||||
bReset = TRUE;
|
||||
else
|
||||
{
|
||||
if(::GetTimeGap32(m_dwCreateTime) > 2 * m_pContext->GetHandShakeTimeout())
|
||||
bReset = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(bReset)
|
||||
{
|
||||
::WSASetLastError(ERROR_CONNRESET);
|
||||
return HR_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_dwPeerConvID == 0)
|
||||
{
|
||||
m_dwPeerConvID = cmd.selfID;
|
||||
m_dwHSNextTime = ::TimeGetTime();
|
||||
m_dwHSSndCount = 0;
|
||||
}
|
||||
else if(cmd.selfID != m_dwPeerConvID)
|
||||
{
|
||||
::WSASetLastError(ERROR_CONNRESET);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
if(cmd.peerID == m_dwSelfConvID)
|
||||
{
|
||||
m_enStatus = ARQ_HSS_SUCC;
|
||||
return m_pContext->DoFireHandShake(m_pSocket);
|
||||
}
|
||||
else if(cmd.peerID != 0)
|
||||
{
|
||||
::WSASetLastError(ERROR_CONNRESET);
|
||||
return HR_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!m_bHSComplete && cmd.flag == TArqCmd::FLAG_COMPLETE)
|
||||
m_bHSComplete = TRUE;
|
||||
|
||||
DoHandShake();
|
||||
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
EnHandleResult ReceiveArq(const BYTE* pData, int iLength, BYTE* pBuffer, int iCapacity)
|
||||
{
|
||||
if(!IsReady()) return HR_IGNORE;
|
||||
|
||||
{
|
||||
CReentrantCriSecLock recvlock(m_csRecv);
|
||||
|
||||
if(!IsReady())
|
||||
{
|
||||
::WSASetLastError(ERROR_INVALID_STATE);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
if(iLength < KCP_HEADER_SIZE)
|
||||
{
|
||||
::WSASetLastError(ERROR_INVALID_DATA);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
int rs = ::ikcp_input(m_kcp, (const char*)pData, iLength);
|
||||
|
||||
if(rs != NO_ERROR)
|
||||
{
|
||||
::WSASetLastError(ERROR_INVALID_DATA);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
int iRead = ::ikcp_recv(m_kcp, (char*)pBuffer, iCapacity);
|
||||
|
||||
if(iRead >= 0)
|
||||
{
|
||||
EnHandleResult result = m_pContext->DoFireReceive(m_pSocket, pBuffer, iRead);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
return result;
|
||||
}
|
||||
else if(iRead == -3)
|
||||
{
|
||||
::WSASetLastError(ERROR_INCORRECT_SIZE);
|
||||
return HR_ERROR;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Flush(TRUE);
|
||||
|
||||
return HR_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
void DoRenew(const TArqAttr& attr, DWORD dwPeerConvID = 0)
|
||||
{
|
||||
ASSERT(attr.IsValid());
|
||||
|
||||
DoReset();
|
||||
|
||||
m_dwPeerConvID = dwPeerConvID;
|
||||
m_kcp = ::ikcp_create(m_dwSelfConvID, m_pSocket);
|
||||
|
||||
::ikcp_nodelay(m_kcp, attr.bNoDelay ? 1 : 0, (int)attr.dwFlushInterval, (int)attr.dwResendByAcks, attr.bTurnoffNc ? 1 : 0);
|
||||
::ikcp_wndsize(m_kcp, (int)attr.dwSendWndSize, (int)attr.dwRecvWndSize);
|
||||
::ikcp_setmtu(m_kcp, attr.dwMtu);
|
||||
|
||||
m_kcp->rx_minrto = (int)attr.dwMinRto;
|
||||
m_kcp->fastlimit = (int)attr.dwFastLimit;
|
||||
m_kcp->output = m_pContext->GetArqOutputProc();
|
||||
}
|
||||
|
||||
void DoReset()
|
||||
{
|
||||
if(m_kcp != nullptr)
|
||||
{
|
||||
::ikcp_release(m_kcp);
|
||||
m_kcp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
BOOL IsValid() const {return GetStatus() != ARQ_HSS_INIT;}
|
||||
BOOL IsHandShaking() const {return GetStatus() == ARQ_HSS_PROC;}
|
||||
BOOL IsReady() const {return GetStatus() == ARQ_HSS_SUCC;}
|
||||
IKCPCB* GetKcp() {return m_kcp;}
|
||||
DWORD GetConvID() const {if(!IsValid()) return 0; return m_kcp->conv;}
|
||||
DWORD GetSelfConvID() const {return m_dwSelfConvID;}
|
||||
DWORD GetPeerConvID() const {return m_dwPeerConvID;}
|
||||
|
||||
EnArqHandShakeStatus GetStatus() const {return m_enStatus;}
|
||||
|
||||
protected:
|
||||
virtual void RenewExtra(const TArqAttr& attr) {}
|
||||
virtual void ResetExtra() {}
|
||||
|
||||
public:
|
||||
CArqSessionT()
|
||||
: m_pContext (nullptr)
|
||||
, m_pSocket (nullptr)
|
||||
, m_kcp (nullptr)
|
||||
, m_enStatus (ARQ_HSS_INIT)
|
||||
, m_dwSelfConvID(0)
|
||||
, m_dwPeerConvID(0)
|
||||
, m_dwCreateTime(0)
|
||||
, m_dwHSNextTime(0)
|
||||
, m_dwHSSndCount(0)
|
||||
, m_bHSComplete (FALSE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CArqSessionT()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
static CArqSessionT* Construct()
|
||||
{return new CArqSessionT();}
|
||||
|
||||
static void Destruct(CArqSessionT* pSession)
|
||||
{if(pSession) delete pSession;}
|
||||
|
||||
protected:
|
||||
T* m_pContext;
|
||||
S* m_pSocket;
|
||||
|
||||
private:
|
||||
BOOL m_bHSComplete;
|
||||
DWORD m_dwHSNextTime;
|
||||
DWORD m_dwHSSndCount;
|
||||
DWORD m_dwCreateTime;
|
||||
DWORD m_dwSelfConvID;
|
||||
DWORD m_dwPeerConvID;
|
||||
EnArqHandShakeStatus m_enStatus;
|
||||
|
||||
CReentrantCriSec m_csRecv;
|
||||
CReentrantCriSec m_csSend;
|
||||
IKCPCB* m_kcp;
|
||||
};
|
||||
|
||||
template<class T, class S> class CArqSessionPoolT;
|
||||
|
||||
template<class T, class S> class CArqSessionExT : public CArqSessionT<T, S>, public CSafeCounter
|
||||
{
|
||||
using __super = CArqSessionT<T, S>;
|
||||
|
||||
using __super::Reset;
|
||||
|
||||
friend class CArqSessionPoolT<T, S>;
|
||||
|
||||
public:
|
||||
DWORD GetFreeTime () const {return m_dwFreeTime;}
|
||||
FD GetTimer () const {return m_fdTimer;}
|
||||
|
||||
protected:
|
||||
virtual void RenewExtra(const TArqAttr& attr)
|
||||
{
|
||||
ResetCount();
|
||||
|
||||
m_fdTimer = m_ioDispatcher.AddTimer(attr.dwFlushInterval, this);
|
||||
ASSERT(IS_VALID_FD(m_fdTimer));
|
||||
}
|
||||
|
||||
virtual void ResetExtra()
|
||||
{
|
||||
m_ioDispatcher.DelTimer(m_fdTimer);
|
||||
|
||||
m_dwFreeTime = ::TimeGetTime();
|
||||
m_fdTimer = INVALID_FD;
|
||||
}
|
||||
|
||||
public:
|
||||
CArqSessionExT(CIODispatcher& ioDispatcher)
|
||||
: m_ioDispatcher(ioDispatcher)
|
||||
, m_fdTimer (INVALID_FD)
|
||||
, m_dwFreeTime (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CArqSessionExT()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
static CArqSessionExT* Construct(CIODispatcher& ioDispatcher)
|
||||
{return new CArqSessionExT(ioDispatcher);}
|
||||
|
||||
static void Destruct(CArqSessionExT* pSession)
|
||||
{if(pSession) delete pSession;}
|
||||
|
||||
private:
|
||||
CIODispatcher& m_ioDispatcher;
|
||||
|
||||
FD m_fdTimer;
|
||||
DWORD m_dwFreeTime;
|
||||
};
|
||||
|
||||
template<class T, class S> class CArqSessionPoolT : private CIOHandler
|
||||
{
|
||||
using CArqSessionEx = CArqSessionExT<T, S>;
|
||||
using TArqSessionList = CRingPool<CArqSessionEx>;
|
||||
using TArqSessionQueue = CCASQueue<CArqSessionEx>;
|
||||
|
||||
public:
|
||||
CArqSessionEx* PickFreeSession(T* pContext, S* pSocket, const TArqAttr& attr)
|
||||
{
|
||||
DWORD dwIndex;
|
||||
CArqSessionEx* pSession = nullptr;
|
||||
|
||||
if(m_lsFreeSession.TryLock(&pSession, dwIndex))
|
||||
{
|
||||
if(::GetTimeGap32(pSession->GetFreeTime()) >= m_dwSessionLockTime)
|
||||
ENSURE(m_lsFreeSession.ReleaseLock(nullptr, dwIndex));
|
||||
else
|
||||
{
|
||||
ENSURE(m_lsFreeSession.ReleaseLock(pSession, dwIndex));
|
||||
pSession = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(!pSession) pSession = CArqSessionEx::Construct(m_ioDispatcher);
|
||||
|
||||
ASSERT(pSession);
|
||||
return (CArqSessionEx*)pSession->Renew(pContext, pSocket, attr);
|
||||
}
|
||||
|
||||
void PutFreeSession(CArqSessionEx* pSession)
|
||||
{
|
||||
if(pSession->Reset())
|
||||
{
|
||||
#ifndef USE_EXTERNAL_GC
|
||||
ReleaseGCSession();
|
||||
#endif
|
||||
if(!m_lsFreeSession.TryPut(pSession))
|
||||
m_lsGCSession.PushBack(pSession);
|
||||
}
|
||||
}
|
||||
|
||||
void Prepare()
|
||||
{
|
||||
m_lsFreeSession.Reset(m_dwSessionPoolSize);
|
||||
|
||||
m_ioDispatcher.Start(this, m_pContext->GetPostReceiveCount(), m_pContext->GetWorkerThreadCount());
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_ioDispatcher.Stop();
|
||||
|
||||
m_lsFreeSession.Clear();
|
||||
|
||||
ReleaseGCSession(TRUE);
|
||||
ENSURE(m_lsGCSession.IsEmpty());
|
||||
}
|
||||
|
||||
void ReleaseGCSession(BOOL bForce = FALSE)
|
||||
{
|
||||
::ReleaseGCObj(m_lsGCSession, m_dwSessionLockTime, bForce);
|
||||
}
|
||||
|
||||
virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) override
|
||||
{
|
||||
|
||||
if(events & _EPOLL_ALL_ERROR_EVENTS)
|
||||
return FALSE;
|
||||
|
||||
CArqSessionEx* pSession = (CArqSessionEx*)pv;
|
||||
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
|
||||
if(!pSession->Check() && pSession->IsValid() && TUdpSocketObj::IsValid(pSession->m_pSocket))
|
||||
pSession->m_pContext->Disconnect(pSession->m_pSocket->connID);
|
||||
|
||||
::ReadTimer(pSession->GetTimer());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public:
|
||||
void SetSessionLockTime (DWORD dwSessionLockTime) {m_dwSessionLockTime = dwSessionLockTime;}
|
||||
void SetSessionPoolSize (DWORD dwSessionPoolSize) {m_dwSessionPoolSize = dwSessionPoolSize;}
|
||||
void SetSessionPoolHold (DWORD dwSessionPoolHold) {m_dwSessionPoolHold = dwSessionPoolHold;}
|
||||
|
||||
DWORD GetSessionLockTime() {return m_dwSessionLockTime;}
|
||||
DWORD GetSessionPoolSize() {return m_dwSessionPoolSize;}
|
||||
DWORD GetSessionPoolHold() {return m_dwSessionPoolHold;}
|
||||
|
||||
public:
|
||||
CArqSessionPoolT(T* pContext,
|
||||
DWORD dwPoolSize = DEFAULT_SESSION_POOL_SIZE,
|
||||
DWORD dwPoolHold = DEFAULT_SESSION_POOL_HOLD,
|
||||
DWORD dwLockTime = DEFAULT_SESSION_LOCK_TIME)
|
||||
: m_pContext(pContext)
|
||||
, m_dwSessionPoolSize(dwPoolSize)
|
||||
, m_dwSessionPoolHold(dwPoolHold)
|
||||
, m_dwSessionLockTime(dwLockTime)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CArqSessionPoolT() {Clear();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CArqSessionPoolT)
|
||||
|
||||
public:
|
||||
static const DWORD DEFAULT_SESSION_LOCK_TIME;
|
||||
static const DWORD DEFAULT_SESSION_POOL_SIZE;
|
||||
static const DWORD DEFAULT_SESSION_POOL_HOLD;
|
||||
|
||||
private:
|
||||
T* m_pContext;
|
||||
|
||||
DWORD m_dwSessionLockTime;
|
||||
DWORD m_dwSessionPoolSize;
|
||||
DWORD m_dwSessionPoolHold;
|
||||
|
||||
TArqSessionList m_lsFreeSession;
|
||||
TArqSessionQueue m_lsGCSession;
|
||||
|
||||
CIODispatcher m_ioDispatcher;
|
||||
};
|
||||
|
||||
template<class T, class S> const DWORD CArqSessionPoolT<T, S>::DEFAULT_SESSION_LOCK_TIME = DEFAULT_OBJECT_CACHE_LOCK_TIME;
|
||||
template<class T, class S> const DWORD CArqSessionPoolT<T, S>::DEFAULT_SESSION_POOL_SIZE = DEFAULT_OBJECT_CACHE_POOL_SIZE;
|
||||
template<class T, class S> const DWORD CArqSessionPoolT<T, S>::DEFAULT_SESSION_POOL_HOLD = DEFAULT_OBJECT_CACHE_POOL_HOLD;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "../include/hpsocket/HPSocket-SSL.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "TcpServer.h"
|
||||
#include "TcpAgent.h"
|
||||
#include "TcpClient.h"
|
||||
#include "TcpPullServer.h"
|
||||
#include "TcpPullClient.h"
|
||||
#include "TcpPullAgent.h"
|
||||
#include "TcpPackServer.h"
|
||||
#include "TcpPackClient.h"
|
||||
#include "TcpPackAgent.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
#include "HttpServer.h"
|
||||
#include "HttpAgent.h"
|
||||
#include "HttpClient.h"
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/******************************************************************** SSL Exports ********************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
HPSOCKET_API ITcpServer* HP_Create_SSLServer(ITcpServerListener* pListener)
|
||||
{
|
||||
return new CSSLServer(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpAgent* HP_Create_SSLAgent(ITcpAgentListener* pListener)
|
||||
{
|
||||
return new CSSLAgent(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpClient* HP_Create_SSLClient(ITcpClientListener* pListener)
|
||||
{
|
||||
return new CSSLClient(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPullServer* HP_Create_SSLPullServer(ITcpServerListener* pListener)
|
||||
{
|
||||
return (ITcpPullServer*)(new CSSLPullServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPullAgent* HP_Create_SSLPullAgent(ITcpAgentListener* pListener)
|
||||
{
|
||||
return (ITcpPullAgent*)(new CSSLPullAgent(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPullClient* HP_Create_SSLPullClient(ITcpClientListener* pListener)
|
||||
{
|
||||
return (ITcpPullClient*)(new CSSLPullClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPackServer* HP_Create_SSLPackServer(ITcpServerListener* pListener)
|
||||
{
|
||||
return (ITcpPackServer*)(new CSSLPackServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPackAgent* HP_Create_SSLPackAgent(ITcpAgentListener* pListener)
|
||||
{
|
||||
return (ITcpPackAgent*)(new CSSLPackAgent(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPackClient* HP_Create_SSLPackClient(ITcpClientListener* pListener)
|
||||
{
|
||||
return (ITcpPackClient*)(new CSSLPackClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLServer(ITcpServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLAgent(ITcpAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLClient(ITcpClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLPullServer(ITcpPullServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLPullAgent(ITcpPullAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLPullClient(ITcpPullClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLPackServer(ITcpPackServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLPackAgent(ITcpPackAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SSLPackClient(ITcpPackClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/*************************************************************** Global Function Exports *************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
HPSOCKET_API int __HP_CALL HP_SSL_DefaultServerNameCallback(LPCTSTR lpszServerName, PVOID pContext)
|
||||
{
|
||||
return CSSLContext::DefaultServerNameCallback(lpszServerName, pContext);
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_SSL_RemoveThreadLocalState(THR_ID dwThreadID)
|
||||
{
|
||||
CSSLContext::RemoveThreadLocalState(dwThreadID);
|
||||
}
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/******************************************************************** HTTPS Exports ******************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
HPSOCKET_API IHttpServer* HP_Create_HttpsServer(IHttpServerListener* pListener)
|
||||
{
|
||||
return (IHttpServer*)(new CHttpsServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IHttpAgent* HP_Create_HttpsAgent(IHttpAgentListener* pListener)
|
||||
{
|
||||
return (IHttpAgent*)(new CHttpsAgent(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IHttpClient* HP_Create_HttpsClient(IHttpClientListener* pListener)
|
||||
{
|
||||
return (IHttpClient*)(new CHttpsClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IHttpSyncClient* HP_Create_HttpsSyncClient(IHttpClientListener* pListener)
|
||||
{
|
||||
return (IHttpSyncClient*)(new CHttpsSyncClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpsServer(IHttpServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpsAgent(IHttpAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpsClient(IHttpClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpsSyncClient(IHttpSyncClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,749 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "../include/hpsocket/HPSocket.h"
|
||||
#include "TcpServer.h"
|
||||
#include "TcpAgent.h"
|
||||
#include "TcpClient.h"
|
||||
#include "TcpPullServer.h"
|
||||
#include "TcpPullClient.h"
|
||||
#include "TcpPullAgent.h"
|
||||
#include "TcpPackServer.h"
|
||||
#include "TcpPackClient.h"
|
||||
#include "TcpPackAgent.h"
|
||||
#include "HPThreadPool.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
#include "UdpServer.h"
|
||||
#include "UdpClient.h"
|
||||
#include "UdpCast.h"
|
||||
#include "UdpNode.h"
|
||||
#include "UdpArqServer.h"
|
||||
#include "UdpArqClient.h"
|
||||
#endif
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
#include "HttpServer.h"
|
||||
#include "HttpAgent.h"
|
||||
#include "HttpClient.h"
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/****************************************************************** TCP/UDP Exports ******************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
HPSOCKET_API ITcpServer* HP_Create_TcpServer(ITcpServerListener* pListener)
|
||||
{
|
||||
return new CTcpServer(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpAgent* HP_Create_TcpAgent(ITcpAgentListener* pListener)
|
||||
{
|
||||
return new CTcpAgent(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpClient* HP_Create_TcpClient(ITcpClientListener* pListener)
|
||||
{
|
||||
return new CTcpClient(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPullServer* HP_Create_TcpPullServer(ITcpServerListener* pListener)
|
||||
{
|
||||
return (ITcpPullServer*)(new CTcpPullServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPullAgent* HP_Create_TcpPullAgent(ITcpAgentListener* pListener)
|
||||
{
|
||||
return (ITcpPullAgent*)(new CTcpPullAgent(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPullClient* HP_Create_TcpPullClient(ITcpClientListener* pListener)
|
||||
{
|
||||
return (ITcpPullClient*)(new CTcpPullClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPackServer* HP_Create_TcpPackServer(ITcpServerListener* pListener)
|
||||
{
|
||||
return (ITcpPackServer*)(new CTcpPackServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPackAgent* HP_Create_TcpPackAgent(ITcpAgentListener* pListener)
|
||||
{
|
||||
return (ITcpPackAgent*)(new CTcpPackAgent(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API ITcpPackClient* HP_Create_TcpPackClient(ITcpClientListener* pListener)
|
||||
{
|
||||
return (ITcpPackClient*)(new CTcpPackClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpServer(ITcpServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpAgent(ITcpAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpClient(ITcpClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpPullServer(ITcpPullServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpPullAgent(ITcpPullAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpPullClient(ITcpPullClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpPackServer(ITcpPackServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpPackAgent(ITcpPackAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_TcpPackClient(ITcpPackClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
HPSOCKET_API IUdpServer* HP_Create_UdpServer(IUdpServerListener* pListener)
|
||||
{
|
||||
return new CUdpServer(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API IUdpClient* HP_Create_UdpClient(IUdpClientListener* pListener)
|
||||
{
|
||||
return new CUdpClient(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API IUdpCast* HP_Create_UdpCast(IUdpCastListener* pListener)
|
||||
{
|
||||
return new CUdpCast(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API IUdpNode* HP_Create_UdpNode(IUdpNodeListener* pListener)
|
||||
{
|
||||
return new CUdpNode(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API IUdpArqServer* HP_Create_UdpArqServer(IUdpServerListener* pListener)
|
||||
{
|
||||
return (IUdpArqServer*)(new CUdpArqServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IUdpArqClient* HP_Create_UdpArqClient(IUdpClientListener* pListener)
|
||||
{
|
||||
return (IUdpArqClient*)(new CUdpArqClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_UdpServer(IUdpServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_UdpClient(IUdpClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_UdpCast(IUdpCast* pCast)
|
||||
{
|
||||
delete pCast;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_UdpNode(IUdpNode* pNode)
|
||||
{
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_UdpArqServer(IUdpArqServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_UdpArqClient(IUdpArqClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/*************************************************************** Global Function Exports *************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
HPSOCKET_API DWORD HP_GetHPSocketVersion()
|
||||
{
|
||||
return ::GetHPSocketVersion();
|
||||
}
|
||||
|
||||
HPSOCKET_API LPCTSTR HP_GetSocketErrorDesc(EnSocketError enCode)
|
||||
{
|
||||
return ::GetSocketErrorDesc(enCode);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GetLastError()
|
||||
{
|
||||
return ::GetLastError();
|
||||
}
|
||||
|
||||
HPSOCKET_API LPCSTR SYS_GetLastErrorStr()
|
||||
{
|
||||
return ::GetLastErrorStr();
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SetSocketOption(SOCKET sock, int level, int name, LPVOID val, int len)
|
||||
{
|
||||
return ::SSO_SetSocketOption(sock, level, name, val, len);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_GetSocketOption(SOCKET sock, int level, int name, LPVOID val, int* len)
|
||||
{
|
||||
return ::SSO_GetSocketOption(sock, level, name, val, len);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_IoctlSocket(SOCKET sock, long cmd, ULONG* arg)
|
||||
{
|
||||
return ::SSO_IoctlSocket(sock, cmd, arg);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_fcntl_SETFL(FD fd, INT fl, BOOL bSet)
|
||||
{
|
||||
return ::fcntl_SETFL(fd, fl, bSet);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_NoBlock(SOCKET sock, BOOL bNoBlock)
|
||||
{
|
||||
return ::SSO_NoBlock(sock, bNoBlock);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_NoDelay(SOCKET sock, BOOL bNoDelay)
|
||||
{
|
||||
return ::SSO_NoDelay(sock, bNoDelay);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_DontLinger(SOCKET sock, BOOL bDont)
|
||||
{
|
||||
return ::SSO_DontLinger(sock, bDont);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_Linger(SOCKET sock, USHORT l_onoff, USHORT l_linger)
|
||||
{
|
||||
return ::SSO_Linger(sock, l_onoff, l_linger);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_RecvBuffSize(SOCKET sock, int size)
|
||||
{
|
||||
return ::SSO_RecvBuffSize(sock, size);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_SendBuffSize(SOCKET sock, int size)
|
||||
{
|
||||
return ::SSO_SendBuffSize(sock, size);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_RecvTimeOut(SOCKET sock, int ms)
|
||||
{
|
||||
return ::SSO_RecvTimeOut(sock, ms);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_SendTimeOut(SOCKET sock, int ms)
|
||||
{
|
||||
return ::SSO_SendTimeOut(sock, ms);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_SSO_ReuseAddress(SOCKET sock, EnReuseAddressPolicy opt)
|
||||
{
|
||||
return ::SSO_ReuseAddress(sock, opt);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GetSocketLocalAddress(SOCKET socket, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
return ::GetSocketLocalAddress(socket, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GetSocketRemoteAddress(SOCKET socket, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
return ::GetSocketRemoteAddress(socket, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount)
|
||||
{
|
||||
return ::EnumHostIPAddresses(lpszHost, enType, lpppIPAddr, iIPAddrCount);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_FreeHostIPAddresses(LPTIPAddr* lppIPAddr)
|
||||
{
|
||||
return ::FreeHostIPAddresses(lppIPAddr);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType)
|
||||
{
|
||||
return ::IsIPAddress(lpszAddress, penType);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GetIPAddress(LPCTSTR lpszHost, TCHAR lpszIP[], int& iIPLenth, EnIPAddrType& enType)
|
||||
{
|
||||
return ::GetIPAddress(lpszHost, lpszIP, iIPLenth, enType);
|
||||
}
|
||||
|
||||
HPSOCKET_API ULONGLONG SYS_NToH64(ULONGLONG value)
|
||||
{
|
||||
return ::NToH64(value);
|
||||
}
|
||||
|
||||
HPSOCKET_API ULONGLONG SYS_HToN64(ULONGLONG value)
|
||||
{
|
||||
return ::HToN64(value);
|
||||
}
|
||||
|
||||
HPSOCKET_API USHORT SYS_SwapEndian16(USHORT value)
|
||||
{
|
||||
return ENDIAN_SWAP_16(value);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_SwapEndian32(DWORD value)
|
||||
{
|
||||
return ENDIAN_SWAP_32(value);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_IsLittleEndian()
|
||||
{
|
||||
return ::IsLittleEndian();
|
||||
}
|
||||
|
||||
HPSOCKET_API LPBYTE SYS_Malloc(int size)
|
||||
{
|
||||
return MALLOC(BYTE, size);
|
||||
}
|
||||
|
||||
HPSOCKET_API LPBYTE SYS_Realloc(LPBYTE p, int size)
|
||||
{
|
||||
return REALLOC(BYTE, p, size);
|
||||
}
|
||||
|
||||
HPSOCKET_API VOID SYS_Free(LPBYTE p)
|
||||
{
|
||||
FREE(p);
|
||||
}
|
||||
|
||||
HPSOCKET_API LPVOID SYS_Calloc(int number, int size)
|
||||
{
|
||||
return CALLOC(number, size);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GuessBase64EncodeBound(DWORD dwSrcLen)
|
||||
{
|
||||
return ::GuessBase64EncodeBound(dwSrcLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
|
||||
{
|
||||
return ::GuessBase64DecodeBound(lpszSrc, dwSrcLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::Base64Encode(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::Base64Decode(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
|
||||
{
|
||||
return ::GuessUrlEncodeBound(lpszSrc, dwSrcLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
|
||||
{
|
||||
return ::GuessUrlDecodeBound(lpszSrc, dwSrcLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::UrlEncode(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::UrlDecode(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
#ifdef _ZLIB_SUPPORT
|
||||
|
||||
HPSOCKET_API int SYS_Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::Compress(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel, int iMethod, int iWindowBits, int iMemLevel, int iStrategy)
|
||||
{
|
||||
return ::CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::Uncompress(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits)
|
||||
{
|
||||
return ::UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, iWindowBits);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GuessCompressBound(DWORD dwSrcLen, BOOL bGZip)
|
||||
{
|
||||
return ::GuessCompressBound(dwSrcLen, bGZip);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::GZipCompress(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::GZipUncompress(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen)
|
||||
{
|
||||
return ::GZipGuessUncompressBound(lpszSrc, dwSrcLen);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _BROTLI_SUPPORT
|
||||
|
||||
HPSOCKET_API int SYS_BrotliCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::BrotliCompress(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_BrotliCompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iQuality, int iWindow, int iMode)
|
||||
{
|
||||
return ::BrotliCompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, iQuality, iWindow, (BrotliEncoderMode)iMode);
|
||||
}
|
||||
|
||||
HPSOCKET_API int SYS_BrotliUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
|
||||
{
|
||||
return ::BrotliUncompress(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API DWORD SYS_BrotliGuessCompressBound(DWORD dwSrcLen)
|
||||
{
|
||||
return ::BrotliGuessCompressBound(dwSrcLen);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _ICONV_SUPPORT
|
||||
|
||||
HPSOCKET_API BOOL SYS_CharsetConvert(LPCSTR lpszFromCharset, LPCSTR lpszToCharset, LPCSTR lpszInBuf, int iInBufLen, LPSTR lpszOutBuf, int& iOutBufLen)
|
||||
{
|
||||
return ::CharsetConvert(lpszFromCharset, lpszToCharset, lpszInBuf, iInBufLen, lpszOutBuf, iOutBufLen);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GbkToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength)
|
||||
{
|
||||
return ::GbkToUnicodeEx(szSrc, iSrcLength, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_UnicodeToGbkEx(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::UnicodeToGbkEx(szSrc, iSrcLength, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_Utf8ToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength)
|
||||
{
|
||||
return ::Utf8ToUnicodeEx(szSrc, iSrcLength, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_UnicodeToUtf8Ex(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::UnicodeToUtf8Ex(szSrc, iSrcLength, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GbkToUtf8Ex(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::GbkToUtf8Ex(szSrc, iSrcLength, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_Utf8ToGbkEx(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::Utf8ToGbkEx(szSrc, iSrcLength, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
|
||||
{
|
||||
return ::GbkToUnicode(szSrc, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::UnicodeToGbk(szSrc, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
|
||||
{
|
||||
return ::Utf8ToUnicode(szSrc, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::UnicodeToUtf8(szSrc, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::GbkToUtf8(szSrc, szDest, iDestLength);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL SYS_Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
|
||||
{
|
||||
return ::Utf8ToGbk(szSrc, szDest, iDestLength);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/******************************************************************** HTTP Exports *******************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
HPSOCKET_API IHttpServer* HP_Create_HttpServer(IHttpServerListener* pListener)
|
||||
{
|
||||
return (IHttpServer*)(new CHttpServer(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IHttpAgent* HP_Create_HttpAgent(IHttpAgentListener* pListener)
|
||||
{
|
||||
return (IHttpAgent*)(new CHttpAgent(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IHttpClient* HP_Create_HttpClient(IHttpClientListener* pListener)
|
||||
{
|
||||
return (IHttpClient*)(new CHttpClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API IHttpSyncClient* HP_Create_HttpSyncClient(IHttpClientListener* pListener)
|
||||
{
|
||||
return (IHttpSyncClient*)(new CHttpSyncClient(pListener));
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpServer(IHttpServer* pServer)
|
||||
{
|
||||
delete pServer;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpAgent(IHttpAgent* pAgent)
|
||||
{
|
||||
delete pAgent;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpClient(IHttpClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_HttpSyncClient(IHttpSyncClient* pClient)
|
||||
{
|
||||
delete pClient;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*************************** HTTP Cookie 管理方法 **************************/
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_LoadFromFile(LPCSTR lpszFile, BOOL bKeepExists)
|
||||
{
|
||||
return g_CookieMgr.LoadFromFile(lpszFile, bKeepExists);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_SaveToFile(LPCSTR lpszFile, BOOL bKeepExists)
|
||||
{
|
||||
return g_CookieMgr.SaveToFile(lpszFile, bKeepExists);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_ClearCookies(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
return g_CookieMgr.ClearCookies(lpszDomain, lpszPath);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_RemoveExpiredCookies(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
return g_CookieMgr.RemoveExpiredCookies(lpszDomain, lpszPath);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_SetCookie(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge, BOOL bHttpOnly, BOOL bSecure, int enSameSite, BOOL bOnlyUpdateValueIfExists)
|
||||
{
|
||||
return g_CookieMgr.SetCookie(lpszName, lpszValue, lpszDomain, lpszPath, iMaxAge, bHttpOnly, bSecure, (CCookie::EnSameSite)enSameSite, bOnlyUpdateValueIfExists);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_DeleteCookie(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName)
|
||||
{
|
||||
return g_CookieMgr.DeleteCookie(lpszDomain, lpszPath, lpszName);
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_HttpCookie_MGR_SetEnableThirdPartyCookie(BOOL bEnableThirdPartyCookie)
|
||||
{
|
||||
g_CookieMgr.SetEnableThirdPartyCookie(bEnableThirdPartyCookie);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_MGR_IsEnableThirdPartyCookie()
|
||||
{
|
||||
return g_CookieMgr.IsEnableThirdPartyCookie();
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_HLP_ParseExpires(LPCSTR lpszExpires, __time64_t& tmExpires)
|
||||
{
|
||||
return CCookie::ParseExpires(lpszExpires, tmExpires);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_HLP_MakeExpiresStr(char lpszBuff[], int& iBuffLen, __time64_t tmExpires)
|
||||
{
|
||||
return CCookie::MakeExpiresStr(lpszBuff, iBuffLen, tmExpires);
|
||||
}
|
||||
|
||||
HPSOCKET_API BOOL HP_HttpCookie_HLP_ToString(char lpszBuff[], int& iBuffLen, LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge, BOOL bHttpOnly, BOOL bSecure, int enSameSite)
|
||||
{
|
||||
return CCookie::ToString(lpszBuff, iBuffLen, lpszName, lpszValue, lpszDomain, lpszPath, iMaxAge, bHttpOnly, bSecure, (CCookie::EnSameSite)enSameSite);
|
||||
}
|
||||
|
||||
HPSOCKET_API __time64_t HP_HttpCookie_HLP_CurrentUTCTime()
|
||||
{
|
||||
return CCookie::CurrentUTCTime();
|
||||
}
|
||||
|
||||
HPSOCKET_API __time64_t HP_HttpCookie_HLP_MaxAgeToExpires(int iMaxAge)
|
||||
{
|
||||
return CCookie::MaxAgeToExpires(iMaxAge);
|
||||
}
|
||||
|
||||
HPSOCKET_API int HP_HttpCookie_HLP_ExpiresToMaxAge(__time64_t tmExpires)
|
||||
{
|
||||
return CCookie::ExpiresToMaxAge(tmExpires);
|
||||
}
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/************************************************************ HTTP Global Function Exports ***********************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/**************************************************************** Thread Pool Exports ****************************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
HPSOCKET_API IHPThreadPool* HP_Create_ThreadPool(IHPThreadPoolListener* pListener)
|
||||
{
|
||||
return new CHPThreadPool(pListener);
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_ThreadPool(IHPThreadPool* pThreadPool)
|
||||
{
|
||||
delete pThreadPool;
|
||||
}
|
||||
|
||||
HPSOCKET_API LPTSocketTask HP_Create_SocketTaskObj(Fn_SocketTaskProc fnTaskProc, PVOID pSender, CONNID dwConnID, LPCBYTE pBuffer, INT iBuffLen, EnTaskBufferType enBuffType, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return ::CreateSocketTaskObj(fnTaskProc, pSender, dwConnID, pBuffer, iBuffLen, enBuffType, wParam, lParam);
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_SocketTaskObj(LPTSocketTask pTask)
|
||||
{
|
||||
::DestroySocketTaskObj(pTask);
|
||||
}
|
||||
|
||||
/*****************************************************************************************************************************************************/
|
||||
/********************************************************* Compressor / Decompressor Exports *********************************************************/
|
||||
/*****************************************************************************************************************************************************/
|
||||
|
||||
HPSOCKET_API void HP_Destroy_Compressor(IHPCompressor* pCompressor)
|
||||
{
|
||||
::DestroyCompressor(pCompressor);
|
||||
}
|
||||
|
||||
HPSOCKET_API void HP_Destroy_Decompressor(IHPDecompressor* pDecompressor)
|
||||
{
|
||||
::DestroyDecompressor(pDecompressor);
|
||||
}
|
||||
|
||||
#ifdef _ZLIB_SUPPORT
|
||||
|
||||
HPSOCKET_API IHPCompressor* HP_Create_ZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
|
||||
{
|
||||
return ::CreateZLibCompressor(fnCallback, iWindowBits, iLevel, iMethod, iMemLevel, iStrategy, dwBuffSize);
|
||||
}
|
||||
|
||||
HPSOCKET_API IHPCompressor* HP_Create_GZipCompressor(Fn_CompressDataCallback fnCallback, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
|
||||
{
|
||||
return ::CreateGZipCompressor(fnCallback, iLevel, iMethod, iMemLevel, iStrategy, dwBuffSize);
|
||||
}
|
||||
|
||||
HPSOCKET_API IHPDecompressor* HP_Create_ZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits, DWORD dwBuffSize)
|
||||
{
|
||||
return ::CreateZLibDecompressor(fnCallback, iWindowBits, dwBuffSize);
|
||||
}
|
||||
|
||||
HPSOCKET_API IHPDecompressor* HP_Create_GZipDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
|
||||
{
|
||||
return ::CreateGZipDecompressor(fnCallback, dwBuffSize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _BROTLI_SUPPORT
|
||||
|
||||
HPSOCKET_API IHPCompressor* HP_Create_BrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality, int iWindow, int iMode, DWORD dwBuffSize)
|
||||
{
|
||||
return ::CreateBrotliCompressor(fnCallback, iQuality, iWindow, iMode, dwBuffSize);
|
||||
}
|
||||
|
||||
HPSOCKET_API IHPDecompressor* HP_Create_BrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
|
||||
{
|
||||
return ::CreateBrotliDecompressor(fnCallback, dwBuffSize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HPThreadPool.h"
|
||||
#include "common/FuncHelper.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
LPTSocketTask CreateSocketTaskObj( Fn_SocketTaskProc fnTaskProc,
|
||||
PVOID pSender, CONNID dwConnID,
|
||||
LPCBYTE pBuffer, INT iBuffLen, EnTaskBufferType enBuffType,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
ASSERT(fnTaskProc != nullptr);
|
||||
ASSERT(iBuffLen >= 0);
|
||||
|
||||
LPTSocketTask pTask = new TSocketTask;
|
||||
|
||||
pTask->fn = fnTaskProc;
|
||||
pTask->sender = pSender;
|
||||
pTask->connID = dwConnID;
|
||||
pTask->bufLen = iBuffLen;
|
||||
pTask->bufType = enBuffType;
|
||||
pTask->wparam = wParam;
|
||||
pTask->lparam = lParam;
|
||||
|
||||
if(enBuffType != TBT_COPY || !pBuffer)
|
||||
pTask->buf = pBuffer;
|
||||
else
|
||||
{
|
||||
pTask->buf = MALLOC(BYTE, iBuffLen);
|
||||
::CopyMemory((LPBYTE)pTask->buf, pBuffer, iBuffLen);
|
||||
}
|
||||
|
||||
return pTask;
|
||||
}
|
||||
|
||||
void DestroySocketTaskObj(LPTSocketTask pTask)
|
||||
{
|
||||
if(pTask)
|
||||
{
|
||||
if(pTask->bufType != TBT_REFER && pTask->buf)
|
||||
FREE(pTask->buf);
|
||||
|
||||
delete pTask;
|
||||
}
|
||||
}
|
||||
|
||||
volatile UINT CHPThreadPool::sm_uiNum = MAXUINT;
|
||||
LPCTSTR CHPThreadPool::POOLED_THREAD_PREFIX = _T("hp-pool-");
|
||||
|
||||
BOOL CHPThreadPool::Start(DWORD dwThreadCount, DWORD dwMaxQueueSize, EnRejectedPolicy enRejectedPolicy, DWORD dwStackSize)
|
||||
{
|
||||
if(!CheckStarting())
|
||||
return FALSE;
|
||||
|
||||
m_dwStackSize = dwStackSize;
|
||||
m_dwMaxQueueSize = dwMaxQueueSize;
|
||||
m_enRejectedPolicy = enRejectedPolicy;
|
||||
|
||||
FireStartup();
|
||||
|
||||
if(!InternalAdjustThreadCount(dwThreadCount))
|
||||
{
|
||||
EXECUTE_RESTORE_ERROR(Stop());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_enState = SS_STARTED;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::Stop(DWORD dwMaxWait)
|
||||
{
|
||||
if(!CheckStoping())
|
||||
return FALSE;
|
||||
|
||||
::WaitFor(15);
|
||||
|
||||
Shutdown(dwMaxWait);
|
||||
|
||||
FireShutdown();
|
||||
|
||||
Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::Shutdown(DWORD dwMaxWait)
|
||||
{
|
||||
BOOL isOK = TRUE;
|
||||
BOOL bLimited = (m_dwMaxQueueSize != 0);
|
||||
BOOL bInfinite = (dwMaxWait == (DWORD)INFINITE || dwMaxWait == 0);
|
||||
auto prdShutdown = [this]() {return m_stThreads.empty();};
|
||||
|
||||
if(m_enRejectedPolicy == TRP_WAIT_FOR && bLimited)
|
||||
m_evQueue.SyncNotifyAll();
|
||||
|
||||
VERIFY(DoAdjustThreadCount(0));
|
||||
|
||||
if(bInfinite)
|
||||
m_evShutdown.Wait(prdShutdown);
|
||||
else
|
||||
m_evShutdown.WaitFor(dwMaxWait, prdShutdown);
|
||||
|
||||
ASSERT(m_lsTasks.Size() == 0);
|
||||
ASSERT(m_stThreads.size() == 0);
|
||||
|
||||
if(!m_lsTasks.IsEmpty())
|
||||
{
|
||||
TTask* pTask = nullptr;
|
||||
|
||||
while(m_lsTasks.PopFront(&pTask))
|
||||
{
|
||||
if(pTask->freeArg)
|
||||
::DestroySocketTaskObj((LPTSocketTask)pTask->arg);
|
||||
|
||||
TTask::Destruct(pTask);
|
||||
}
|
||||
|
||||
::SetLastError(ERROR_CANCELLED);
|
||||
isOK = FALSE;
|
||||
}
|
||||
|
||||
if(!m_stThreads.empty())
|
||||
{
|
||||
CCriSecLock lock(m_csThread);
|
||||
|
||||
if(!m_stThreads.empty())
|
||||
{
|
||||
#if !defined(__ANDROID__)
|
||||
for(auto it = m_stThreads.begin(), end = m_stThreads.end(); it != end; ++it)
|
||||
pthread_cancel(*it);
|
||||
#endif
|
||||
m_stThreads.clear();
|
||||
|
||||
::SetLastError(ERROR_CANCELLED);
|
||||
isOK = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::Submit(Fn_TaskProc fnTaskProc, PVOID pvArg, DWORD dwMaxWait)
|
||||
{
|
||||
return DoSubmit(fnTaskProc, pvArg, FALSE, dwMaxWait);
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::Submit(LPTSocketTask pTask, DWORD dwMaxWait)
|
||||
{
|
||||
return DoSubmit((Fn_TaskProc)pTask->fn, (PVOID)pTask, TRUE, dwMaxWait);
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::DoSubmit(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg, DWORD dwMaxWait)
|
||||
{
|
||||
EnSubmitResult sr = DirectSubmit(fnTaskProc, pvArg, bFreeArg);
|
||||
|
||||
if(sr != SUBMIT_FULL)
|
||||
return (sr == SUBMIT_OK);
|
||||
|
||||
if(m_enRejectedPolicy == TRP_CALL_FAIL)
|
||||
{
|
||||
::SetLastError(ERROR_DESTINATION_ELEMENT_FULL);
|
||||
return FALSE;
|
||||
}
|
||||
else if(m_enRejectedPolicy == TRP_WAIT_FOR)
|
||||
{
|
||||
return CycleWaitSubmit(fnTaskProc, pvArg, dwMaxWait, bFreeArg);
|
||||
}
|
||||
else if(m_enRejectedPolicy == TRP_CALLER_RUN)
|
||||
{
|
||||
DoRunTaskProc(fnTaskProc, pvArg, bFreeArg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CHPThreadPool::DoRunTaskProc(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg)
|
||||
{
|
||||
::InterlockedIncrement(&m_dwTaskCount);
|
||||
fnTaskProc(pvArg);
|
||||
::InterlockedDecrement(&m_dwTaskCount);
|
||||
|
||||
if(bFreeArg)
|
||||
::DestroySocketTaskObj((LPTSocketTask)pvArg);
|
||||
}
|
||||
|
||||
CHPThreadPool::EnSubmitResult CHPThreadPool::DirectSubmit(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg)
|
||||
{
|
||||
if(!CheckStarted())
|
||||
return SUBMIT_ERROR;
|
||||
|
||||
BOOL bLimited = (m_dwMaxQueueSize != 0);
|
||||
|
||||
if(bLimited && m_lsTasks.Size() >= m_dwMaxQueueSize)
|
||||
return SUBMIT_FULL;
|
||||
else
|
||||
{
|
||||
TTask* pTask = TTask::Construct(fnTaskProc, pvArg, bFreeArg);
|
||||
|
||||
m_lsTasks.PushBack(pTask);
|
||||
m_evTask.SyncNotifyOne();
|
||||
}
|
||||
|
||||
return SUBMIT_OK;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::CycleWaitSubmit(Fn_TaskProc fnTaskProc, PVOID pvArg, DWORD dwMaxWait, BOOL bFreeArg)
|
||||
{
|
||||
ASSERT(m_dwMaxQueueSize != 0);
|
||||
|
||||
DWORD dwTime = ::TimeGetTime();
|
||||
BOOL bInfinite = (dwMaxWait == (DWORD)INFINITE || dwMaxWait == 0);
|
||||
auto prdQueue = [this]() {return (m_lsTasks.Size() < m_dwMaxQueueSize);};
|
||||
|
||||
while(CheckStarted())
|
||||
{
|
||||
EnSubmitResult sr = DirectSubmit(fnTaskProc, pvArg, bFreeArg);
|
||||
|
||||
if(sr == SUBMIT_OK)
|
||||
return TRUE;
|
||||
if(sr == SUBMIT_ERROR)
|
||||
return FALSE;
|
||||
|
||||
if(bInfinite)
|
||||
m_evQueue.Wait(prdQueue);
|
||||
else
|
||||
{
|
||||
DWORD dwNow = ::GetTimeGap32(dwTime);
|
||||
|
||||
if(dwNow > dwMaxWait || !m_evQueue.WaitFor(chrono::milliseconds(dwMaxWait - dwNow), prdQueue))
|
||||
{
|
||||
::SetLastError(ERROR_TIMEOUT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::AdjustThreadCount(DWORD dwNewThreadCount)
|
||||
{
|
||||
if(!CheckStarted())
|
||||
return FALSE;
|
||||
|
||||
return InternalAdjustThreadCount(dwNewThreadCount);
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::InternalAdjustThreadCount(DWORD dwNewThreadCount)
|
||||
{
|
||||
int iNewThreadCount = (int)dwNewThreadCount;
|
||||
|
||||
if(iNewThreadCount == 0)
|
||||
iNewThreadCount = ::GetDefaultWorkerThreadCount();
|
||||
else if(iNewThreadCount < 0)
|
||||
iNewThreadCount = PROCESSOR_COUNT * (-iNewThreadCount);
|
||||
|
||||
return DoAdjustThreadCount((DWORD)iNewThreadCount);
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::DoAdjustThreadCount(DWORD dwNewThreadCount)
|
||||
{
|
||||
ASSERT((int)dwNewThreadCount >= 0);
|
||||
|
||||
BOOL bRemove = FALSE;
|
||||
DWORD dwThreadCount = 0;
|
||||
|
||||
if(dwNewThreadCount > m_dwThreadCount)
|
||||
{
|
||||
dwThreadCount = dwNewThreadCount - m_dwThreadCount;
|
||||
return CreateWorkerThreads(dwThreadCount);
|
||||
}
|
||||
else if(dwNewThreadCount < m_dwThreadCount)
|
||||
{
|
||||
bRemove = TRUE;
|
||||
dwThreadCount = m_dwThreadCount - dwNewThreadCount;
|
||||
|
||||
::InterlockedSub(&m_dwThreadCount, dwThreadCount);
|
||||
}
|
||||
|
||||
if(bRemove)
|
||||
{
|
||||
for(DWORD i = 0; i < dwThreadCount; i++)
|
||||
m_evTask.SyncNotifyOne();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::CreateWorkerThreads(DWORD dwThreadCount)
|
||||
{
|
||||
unique_ptr<pthread_attr_t> pThreadAttr;
|
||||
|
||||
if(m_dwStackSize != 0)
|
||||
{
|
||||
pThreadAttr = make_unique<pthread_attr_t>();
|
||||
VERIFY_IS_NO_ERROR(pthread_attr_init(pThreadAttr.get()));
|
||||
|
||||
int rs = pthread_attr_setstacksize(pThreadAttr.get(), m_dwStackSize);
|
||||
|
||||
if(!IS_NO_ERROR(rs))
|
||||
{
|
||||
pthread_attr_destroy(pThreadAttr.get());
|
||||
::SetLastError(rs);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL isOK = TRUE;
|
||||
|
||||
for(DWORD i = 0; i < dwThreadCount; i++)
|
||||
{
|
||||
THR_ID dwThreadID;
|
||||
int rs = pthread_create(&dwThreadID, pThreadAttr.get(), ThreadProc, (PVOID)this);
|
||||
|
||||
if(!IS_NO_ERROR(rs))
|
||||
{
|
||||
::SetLastError(rs);
|
||||
isOK = FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
::InterlockedIncrement(&m_dwThreadCount);
|
||||
|
||||
CCriSecLock lock(m_csThread);
|
||||
m_stThreads.emplace(dwThreadID);
|
||||
}
|
||||
|
||||
if(pThreadAttr != nullptr)
|
||||
pthread_attr_destroy(pThreadAttr.get());
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
PVOID CHPThreadPool::ThreadProc(LPVOID pv)
|
||||
{
|
||||
CHPThreadPool* pThis = (CHPThreadPool*)pv;
|
||||
|
||||
::SetSequenceThreadName(SELF_THREAD_ID, pThis->m_strPrefix, pThis->m_uiSeq);
|
||||
|
||||
pThis->FireWorkerThreadStart();
|
||||
|
||||
PVOID rs = (PVOID)(UINT_PTR)(pThis->WorkerProc());
|
||||
|
||||
pThis->FireWorkerThreadEnd();
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
int CHPThreadPool::WorkerProc()
|
||||
{
|
||||
BOOL bLimited = (m_dwMaxQueueSize != 0);
|
||||
TTask* pTask = nullptr;
|
||||
auto prdTask = [this]() {return (!m_lsTasks.IsEmpty()) || (m_dwThreadCount < m_stThreads.size());};
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
pTask = nullptr;
|
||||
|
||||
while(m_lsTasks.PopFront(&pTask))
|
||||
{
|
||||
if(m_enRejectedPolicy == TRP_WAIT_FOR && bLimited)
|
||||
m_evQueue.SyncNotifyOne();
|
||||
|
||||
DoRunTaskProc(pTask->fn, pTask->arg, pTask->freeArg);
|
||||
|
||||
TTask::Destruct(pTask);
|
||||
}
|
||||
|
||||
if(CheckWorkerThreadExit())
|
||||
break;
|
||||
|
||||
m_evTask.Wait(prdTask);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::CheckWorkerThreadExit()
|
||||
{
|
||||
BOOL bExit = FALSE;
|
||||
BOOL bShutdown = FALSE;
|
||||
|
||||
if(m_dwThreadCount < m_stThreads.size())
|
||||
{
|
||||
CCriSecLock lock(m_csThread);
|
||||
|
||||
if(m_dwThreadCount < m_stThreads.size())
|
||||
{
|
||||
VERIFY(m_stThreads.erase(SELF_THREAD_ID) == 1);
|
||||
|
||||
bExit = TRUE;
|
||||
bShutdown = m_stThreads.empty();
|
||||
}
|
||||
}
|
||||
|
||||
if(bExit)
|
||||
{
|
||||
pthread_detach(SELF_THREAD_ID);
|
||||
|
||||
if(bShutdown)
|
||||
m_evShutdown.SyncNotifyOne();
|
||||
}
|
||||
|
||||
return bExit;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::CheckStarting()
|
||||
{
|
||||
if(::InterlockedCompareExchange(&m_enState, SS_STARTING, SS_STOPPED) != SS_STOPPED)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::CheckStarted()
|
||||
{
|
||||
if(m_enState != SS_STARTED)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CHPThreadPool::CheckStoping()
|
||||
{
|
||||
if( ::InterlockedCompareExchange(&m_enState, SS_STOPPING, SS_STARTED) != SS_STARTED &&
|
||||
::InterlockedCompareExchange(&m_enState, SS_STOPPING, SS_STARTING) != SS_STARTING)
|
||||
{
|
||||
while(m_enState != SS_STOPPED)
|
||||
::WaitFor(5);
|
||||
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CHPThreadPool::Reset(BOOL bSetWaitEvent)
|
||||
{
|
||||
m_uiSeq = MAXUINT;
|
||||
m_dwStackSize = 0;
|
||||
m_dwTaskCount = 0;
|
||||
m_dwThreadCount = 0;
|
||||
m_dwMaxQueueSize = 0;
|
||||
m_enRejectedPolicy = TRP_CALL_FAIL;
|
||||
m_enState = SS_STOPPED;
|
||||
|
||||
if(bSetWaitEvent)
|
||||
m_evWait.SyncNotifyAll();
|
||||
}
|
||||
|
||||
void CHPThreadPool::MakePrefix()
|
||||
{
|
||||
UINT uiNumber = ::InterlockedIncrement(&sm_uiNum);
|
||||
|
||||
m_strPrefix.Format(_T("%s%u-"), POOLED_THREAD_PREFIX, uiNumber);
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/hpsocket/SocketInterface.h"
|
||||
#include "common/STLHelper.h"
|
||||
#include "common/Semaphore.h"
|
||||
#include "common/RingBuffer.h"
|
||||
#include "InternalDef.h"
|
||||
|
||||
LPTSocketTask CreateSocketTaskObj( Fn_SocketTaskProc fnTaskProc,
|
||||
PVOID pSender, CONNID dwConnID,
|
||||
LPCBYTE pBuffer, INT iBuffLen, EnTaskBufferType enBuffType = TBT_COPY,
|
||||
WPARAM wParam = 0, LPARAM lParam = 0);
|
||||
|
||||
void DestroySocketTaskObj(LPTSocketTask pTask);
|
||||
|
||||
class CHPThreadPool : public IHPThreadPool
|
||||
{
|
||||
private:
|
||||
enum EnSubmitResult{SUBMIT_OK, SUBMIT_FULL, SUBMIT_ERROR};
|
||||
|
||||
struct TTask
|
||||
{
|
||||
Fn_TaskProc fn;
|
||||
PVOID arg;
|
||||
BOOL freeArg;
|
||||
|
||||
public:
|
||||
static TTask* Construct(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg)
|
||||
{
|
||||
return new TTask(fnTaskProc, pvArg, bFreeArg);
|
||||
}
|
||||
|
||||
static void Destruct(TTask* pTask)
|
||||
{
|
||||
if(pTask)
|
||||
{
|
||||
delete pTask;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TTask(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg)
|
||||
: fn(fnTaskProc), arg(pvArg), freeArg(bFreeArg)
|
||||
{
|
||||
ASSERT(fn != nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
using CTaskQueue = CCASQueue<TTask>;
|
||||
|
||||
public:
|
||||
virtual BOOL Start(DWORD dwThreadCount = 0, DWORD dwMaxQueueSize = 0, EnRejectedPolicy enRejectedPolicy = TRP_CALL_FAIL, DWORD dwStackSize = 0);
|
||||
virtual BOOL Stop(DWORD dwMaxWait = INFINITE);
|
||||
virtual BOOL Wait(DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
|
||||
virtual BOOL Submit(Fn_TaskProc fnTaskProc, PVOID pvArg, DWORD dwMaxWait = INFINITE);
|
||||
virtual BOOL Submit(LPTSocketTask pTask, DWORD dwMaxWait = INFINITE);
|
||||
virtual BOOL AdjustThreadCount(DWORD dwNewThreadCount);
|
||||
|
||||
public:
|
||||
virtual BOOL HasStarted() {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState() {return m_enState;}
|
||||
|
||||
virtual DWORD GetQueueSize() {return m_lsTasks.Size();}
|
||||
virtual DWORD GetTaskCount() {return m_dwTaskCount;}
|
||||
virtual DWORD GetThreadCount() {return m_dwThreadCount;}
|
||||
virtual DWORD GetMaxQueueSize() {return m_dwMaxQueueSize;}
|
||||
virtual EnRejectedPolicy GetRejectedPolicy() {return m_enRejectedPolicy;}
|
||||
|
||||
private:
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStarted();
|
||||
BOOL CheckStoping();
|
||||
|
||||
BOOL InternalAdjustThreadCount(DWORD dwNewThreadCount);
|
||||
BOOL DoAdjustThreadCount(DWORD dwNewThreadCount);
|
||||
|
||||
BOOL CreateWorkerThreads(DWORD dwThreadCount);
|
||||
|
||||
BOOL Shutdown(DWORD dwMaxWait);
|
||||
BOOL CheckWorkerThreadExit();
|
||||
|
||||
static PVOID ThreadProc(LPVOID pv);
|
||||
int WorkerProc();
|
||||
|
||||
EnSubmitResult DirectSubmit(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg);
|
||||
BOOL CycleWaitSubmit(Fn_TaskProc fnTaskProc, PVOID pvArg, DWORD dwMaxWait, BOOL bFreeArg);
|
||||
BOOL DoSubmit(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg, DWORD dwMaxWait);
|
||||
void DoRunTaskProc(Fn_TaskProc fnTaskProc, PVOID pvArg, BOOL bFreeArg);
|
||||
|
||||
void FireStartup()
|
||||
{if(m_pListener != nullptr) m_pListener->OnStartup(this);}
|
||||
void FireShutdown()
|
||||
{if(m_pListener != nullptr) m_pListener->OnShutdown(this);}
|
||||
void FireWorkerThreadStart()
|
||||
{if(m_pListener != nullptr) m_pListener->OnWorkerThreadStart(this, SELF_THREAD_ID);}
|
||||
void FireWorkerThreadEnd()
|
||||
{if(m_pListener != nullptr) m_pListener->OnWorkerThreadEnd(this, SELF_THREAD_ID);}
|
||||
|
||||
public:
|
||||
CHPThreadPool(IHPThreadPoolListener* pListener = nullptr)
|
||||
: m_pListener(pListener)
|
||||
{
|
||||
MakePrefix();
|
||||
Reset(FALSE);
|
||||
}
|
||||
|
||||
virtual ~CHPThreadPool()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
void Reset(BOOL bSetWaitEvent = TRUE);
|
||||
void MakePrefix();
|
||||
|
||||
private:
|
||||
static LPCTSTR POOLED_THREAD_PREFIX;
|
||||
static volatile UINT sm_uiNum;
|
||||
|
||||
volatile UINT m_uiSeq;
|
||||
CString m_strPrefix;
|
||||
|
||||
private:
|
||||
IHPThreadPoolListener* m_pListener;
|
||||
|
||||
DWORD m_dwStackSize;
|
||||
DWORD m_dwMaxQueueSize;
|
||||
EnRejectedPolicy m_enRejectedPolicy;
|
||||
|
||||
volatile DWORD m_dwTaskCount;
|
||||
volatile DWORD m_dwThreadCount;
|
||||
volatile EnServiceState m_enState;
|
||||
|
||||
CSEM m_evWait;
|
||||
CSEM m_evShutdown;
|
||||
CSEM m_evTask;
|
||||
CSEM m_evQueue;
|
||||
CCriSec m_csThread;
|
||||
|
||||
CTaskQueue m_lsTasks;
|
||||
unordered_set<THR_ID> m_stThreads;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CHPThreadPool)
|
||||
};
|
||||
|
|
@ -0,0 +1,479 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HttpAgent.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::CheckParams()
|
||||
{
|
||||
if(m_enLocalVersion != HV_1_1 && m_enLocalVersion != HV_1_0)
|
||||
{
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return __super::CheckParams();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpAgentT<T, default_port>::PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_objPool.SetHttpObjLockTime(GetFreeSocketObjLockTime());
|
||||
m_objPool.SetHttpObjPoolSize(GetFreeSocketObjPool());
|
||||
m_objPool.SetHttpObjPoolHold(GetFreeSocketObjHold());
|
||||
|
||||
m_objPool.Prepare();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::SendRequest(CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WSABUF szBuffer[2];
|
||||
CStringA strHeader;
|
||||
|
||||
LPCSTR lpszHost = nullptr;
|
||||
USHORT usPort = 0;
|
||||
BOOL bConnect = (stricmp(lpszMethod, HTTP_METHOD_CONNECT) == 0);
|
||||
|
||||
if(!bConnect)
|
||||
{
|
||||
GetRemoteHost(dwConnID, &lpszHost, &usPort);
|
||||
if(usPort == default_port) usPort = 0;
|
||||
}
|
||||
|
||||
CStringA strPath;
|
||||
::AdjustRequestPath(bConnect, lpszPath, strPath);
|
||||
|
||||
pHttpObj->SetRequestPath(lpszMethod, strPath);
|
||||
pHttpObj->ReloadCookies();
|
||||
|
||||
::MakeRequestLine(lpszMethod, strPath, m_enLocalVersion, strHeader);
|
||||
::MakeHeaderLines(lpHeaders, iHeaderCount, &pHttpObj->GetCookieMap(), iLength, TRUE, -1, lpszHost, usPort, strHeader);
|
||||
::MakeHttpPacket(strHeader, pBody, iLength, szBuffer);
|
||||
|
||||
return SendPackets(dwConnID, szBuffer, 2);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount)
|
||||
{
|
||||
CFile file;
|
||||
CFileMapping fmap;
|
||||
|
||||
HRESULT hr = ::ReadSmallFile(CA2T(lpszFileName), file, fmap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
::SetLastError(hr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return SendRequest(dwConnID, lpszMethod, lpszPath, lpHeaders, iHeaderCount, (BYTE*)fmap, (int)fmap.Size());
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::SendChunkData(CONNID dwConnID, const BYTE* pData, int iLength, LPCSTR lpszExtensions)
|
||||
{
|
||||
char szLen[12];
|
||||
WSABUF bufs[5];
|
||||
|
||||
int iCount = MakeChunkPackage(pData, iLength, lpszExtensions, szLen, bufs);
|
||||
|
||||
return SendPackets(dwConnID, bufs, iCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
|
||||
{
|
||||
ASSERT(lpszMask);
|
||||
|
||||
WSABUF szBuffer[2];
|
||||
BYTE szHeader[HTTP_MAX_WS_HEADER_LEN];
|
||||
|
||||
unique_ptr<BYTE[]> szData = make_unique<BYTE[]>(iLength);
|
||||
memcpy(szData.get(), pData, iLength);
|
||||
|
||||
if(!::MakeWSPacket(bFinal, iReserved, iOperationCode, lpszMask, szData.get(), iLength, ullBodyLen, szHeader, szBuffer))
|
||||
return FALSE;
|
||||
|
||||
return SendPackets(dwConnID, szBuffer, 2);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpAgentT<T, default_port>::FireConnect(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
return m_bHttpAutoStart ? __super::FireConnect(pSocketObj) : __super::DoFireConnect(pSocketObj);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpAgentT<T, default_port>::DoFireConnect(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
THttpObj* pHttpObj = DoStartHttp(pSocketObj);
|
||||
EnHandleResult result = __super::DoFireConnect(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
{
|
||||
m_objPool.PutFreeHttpObj(pHttpObj);
|
||||
SetConnectionReserved(pSocketObj, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpAgentT<T, default_port>::DoFireHandShake(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
VERIFY(pHttpObj);
|
||||
|
||||
m_objPool.PutFreeHttpObj(pHttpObj);
|
||||
SetConnectionReserved(pSocketObj, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpAgentT<T, default_port>::DoFireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
return pHttpObj->Execute(pData, iLength);
|
||||
else
|
||||
return DoFireSuperReceive(pSocketObj, pData, iLength);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpAgentT<T, default_port>::DoFireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
pHttpObj->CheckBodyIdentityEof();
|
||||
|
||||
EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
{
|
||||
m_objPool.PutFreeHttpObj(pHttpObj);
|
||||
SetConnectionReserved(pSocketObj, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpAgentT<T, default_port>::DoFireShutdown()
|
||||
{
|
||||
EnHandleResult result = __super::DoFireShutdown();
|
||||
|
||||
m_objPool.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpAgentT<T, default_port>::ReleaseGCSocketObj(BOOL bForce)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_objPool.ReleaseGCHttpObj(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::IsUpgrade(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->IsUpgrade();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::IsKeepAlive(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->IsKeepAlive();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> USHORT CHttpAgentT<T, default_port>::GetVersion(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetVersion();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> ULONGLONG CHttpAgentT<T, default_port>::GetContentLength(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetContentLength();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpAgentT<T, default_port>::GetContentType(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetContentType();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpAgentT<T, default_port>::GetContentEncoding(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetContentEncoding();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpAgentT<T, default_port>::GetTransferEncoding(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetTransferEncoding();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpUpgradeType CHttpAgentT<T, default_port>::GetUpgradeType(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return HUT_NONE;
|
||||
|
||||
return pHttpObj->GetUpgradeType();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> USHORT CHttpAgentT<T, default_port>::GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetParseErrorCode(lpszErrorDesc);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetHeader(lpszName, lpszValue);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetHeaders(lpszName, lpszValue, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetAllHeaders(lpHeaders, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetAllHeaderNames(lpszName, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetCookie(lpszName, lpszValue);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetAllCookies(lpCookies, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> USHORT CHttpAgentT<T, default_port>::GetStatusCode(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetStatusCode();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::GetWSMessageState(CONNID dwConnID, BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetWSMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> inline typename CHttpAgentT<T, default_port>::THttpObj* CHttpAgentT<T, default_port>::FindHttpObj(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = nullptr;
|
||||
GetConnectionReserved(dwConnID, (PVOID*)&pHttpObj);
|
||||
|
||||
return pHttpObj;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> inline typename CHttpAgentT<T, default_port>::THttpObj* CHttpAgentT<T, default_port>::FindHttpObj(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
THttpObj* pHttpObj = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pHttpObj);
|
||||
|
||||
return pHttpObj;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::StartHttp(CONNID dwConnID)
|
||||
{
|
||||
if(IsHttpAutoStart())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TAgentSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return StartHttp(pSocketObj);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpAgentT<T, default_port>::StartHttp(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CReentrantCriSecLock locallock(pSocketObj->csSend);
|
||||
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
{
|
||||
::SetLastError(ERROR_ALREADY_INITIALIZED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoStartHttp(pSocketObj);
|
||||
|
||||
if(!IsSecure())
|
||||
FireHandShake(pSocketObj);
|
||||
else
|
||||
{
|
||||
#ifdef _SSL_SUPPORT
|
||||
if(IsSSLAutoHandShake())
|
||||
StartSSLHandShake(pSocketObj);
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> typename CHttpAgentT<T, default_port>::THttpObj* CHttpAgentT<T, default_port>::DoStartHttp(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
THttpObj* pHttpObj = m_objPool.PickFreeHttpObj(this, pSocketObj);
|
||||
VERIFY(SetConnectionReserved(pSocketObj, pHttpObj));
|
||||
|
||||
return pHttpObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
template class CHttpAgentT<CTcpAgent, HTTP_DEFAULT_PORT>;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLAgent.h"
|
||||
|
||||
template class CHttpAgentT<CSSLAgent, HTTPS_DEFAULT_PORT>;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpAgent.h"
|
||||
#include "HttpHelper.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class T, USHORT default_port> class CHttpAgentT : public IComplexHttpRequester, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::GetConnectionReserved;
|
||||
using __super::SetConnectionReserved;
|
||||
using __super::SetLastError;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
using __super::SendPackets;
|
||||
using __super::HasStarted;
|
||||
using __super::GetRemoteHost;
|
||||
using __super::GetFreeSocketObjLockTime;
|
||||
using __super::GetFreeSocketObjPool;
|
||||
using __super::GetFreeSocketObjHold;
|
||||
|
||||
using __super::IsSecure;
|
||||
using __super::FireHandShake;
|
||||
using __super::FindSocketObj;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
using __super::StartSSLHandShake;
|
||||
using __super::IsSSLAutoHandShake;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
using CHttpObjPool = CHttpObjPoolT<FALSE, CHttpAgentT, TAgentSocketObj>;
|
||||
using THttpObj = THttpObjT<CHttpAgentT, TAgentSocketObj>;
|
||||
|
||||
friend typename CHttpAgentT::THttpObj;
|
||||
|
||||
public:
|
||||
virtual BOOL SendRequest(CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0);
|
||||
virtual BOOL SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0);
|
||||
virtual BOOL SendChunkData(CONNID dwConnID, const BYTE* pData = nullptr, int iLength = 0, LPCSTR lpszExtensions = nullptr);
|
||||
|
||||
virtual BOOL SendPost(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_POST, lpszPath, lpHeaders, iHeaderCount, pBody, iLength);}
|
||||
virtual BOOL SendPut(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_PUT, lpszPath, lpHeaders, iHeaderCount, pBody, iLength);}
|
||||
virtual BOOL SendPatch(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_PATCH, lpszPath, lpHeaders, iHeaderCount, pBody, iLength);}
|
||||
virtual BOOL SendGet(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_GET, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendDelete(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_DELETE, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendHead(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_HEAD, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendTrace(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_TRACE, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendOptions(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_OPTIONS, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendConnect(CONNID dwConnID, LPCSTR lpszHost, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(dwConnID, HTTP_METHOD_CONNECT, lpszHost, lpHeaders, iHeaderCount);}
|
||||
|
||||
virtual BOOL SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0);
|
||||
|
||||
virtual BOOL StartHttp(CONNID dwConnID);
|
||||
|
||||
public:
|
||||
virtual void SetUseCookie(BOOL bUseCookie) {ENSURE_HAS_STOPPED(); m_pCookieMgr = bUseCookie ? &g_CookieMgr : nullptr;}
|
||||
virtual void SetHttpAutoStart(BOOL bAutoStart) {ENSURE_HAS_STOPPED(); m_bHttpAutoStart = bAutoStart;}
|
||||
virtual void SetLocalVersion(EnHttpVersion enLocalVersion) {ENSURE_HAS_STOPPED(); m_enLocalVersion = enLocalVersion;}
|
||||
|
||||
virtual BOOL IsUseCookie() {return m_pCookieMgr != nullptr;}
|
||||
virtual BOOL IsHttpAutoStart() {return m_bHttpAutoStart;}
|
||||
virtual EnHttpVersion GetLocalVersion() {return m_enLocalVersion;}
|
||||
|
||||
virtual BOOL IsUpgrade(CONNID dwConnID);
|
||||
virtual BOOL IsKeepAlive(CONNID dwConnID);
|
||||
virtual USHORT GetVersion(CONNID dwConnID);
|
||||
virtual ULONGLONG GetContentLength(CONNID dwConnID);
|
||||
virtual LPCSTR GetContentType(CONNID dwConnID);
|
||||
virtual LPCSTR GetContentEncoding(CONNID dwConnID);
|
||||
virtual LPCSTR GetTransferEncoding(CONNID dwConnID);
|
||||
virtual EnHttpUpgradeType GetUpgradeType(CONNID dwConnID);
|
||||
virtual USHORT GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc = nullptr);
|
||||
|
||||
virtual BOOL GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue);
|
||||
virtual BOOL GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount);
|
||||
virtual BOOL GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount);
|
||||
virtual BOOL GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount);
|
||||
|
||||
virtual BOOL GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue);
|
||||
virtual BOOL GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount);
|
||||
|
||||
virtual USHORT GetStatusCode(CONNID dwConnID);
|
||||
|
||||
virtual BOOL GetWSMessageState(CONNID dwConnID, BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain);
|
||||
|
||||
private:
|
||||
BOOL StartHttp(TAgentSocketObj* pSocketObj);
|
||||
THttpObj* DoStartHttp(TAgentSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual EnHandleResult FireConnect(TAgentSocketObj* pSocketObj);
|
||||
virtual EnHandleResult DoFireConnect(TAgentSocketObj* pSocketObj);
|
||||
virtual EnHandleResult DoFireHandShake(TAgentSocketObj* pSocketObj);
|
||||
virtual EnHandleResult DoFireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult DoFireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
virtual EnHandleResult DoFireShutdown();
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
EnHandleResult DoFireSuperReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return __super::DoFireReceive(pSocketObj, pData, iLength);}
|
||||
|
||||
EnHttpParseResult FireMessageBegin(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnMessageBegin((IHttpAgent*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireRequestLine(TAgentSocketObj* pSocketObj, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{return m_pListener->OnRequestLine((IHttpAgent*)this, pSocketObj->connID, lpszMethod, lpszUrl);}
|
||||
EnHttpParseResult FireStatusLine(TAgentSocketObj* pSocketObj, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{return m_pListener->OnStatusLine((IHttpAgent*)this, pSocketObj->connID, usStatusCode, lpszDesc);}
|
||||
EnHttpParseResult FireHeader(TAgentSocketObj* pSocketObj, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{return m_pListener->OnHeader((IHttpAgent*)this, pSocketObj->connID, lpszName, lpszValue);}
|
||||
EnHttpParseResult FireHeadersComplete(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnHeadersComplete((IHttpAgent*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireBody(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnBody((IHttpAgent*)this, pSocketObj->connID, pData, iLength);}
|
||||
EnHttpParseResult FireChunkHeader(TAgentSocketObj* pSocketObj, int iLength)
|
||||
{return m_pListener->OnChunkHeader((IHttpAgent*)this, pSocketObj->connID, iLength);}
|
||||
EnHttpParseResult FireChunkComplete(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnChunkComplete((IHttpAgent*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireMessageComplete(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnMessageComplete((IHttpAgent*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireUpgrade(TAgentSocketObj* pSocketObj, EnHttpUpgradeType enUpgradeType)
|
||||
{return m_pListener->OnUpgrade((IHttpAgent*)this, pSocketObj->connID, enUpgradeType);}
|
||||
EnHttpParseResult FireParseError(TAgentSocketObj* pSocketObj, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{return m_pListener->OnParseError((IHttpAgent*)this, pSocketObj->connID, iErrorCode, lpszErrorDesc);}
|
||||
|
||||
EnHandleResult FireWSMessageHeader(TAgentSocketObj* pSocketObj, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{return m_pListener->OnWSMessageHeader((IHttpAgent*)this, pSocketObj->connID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);}
|
||||
EnHandleResult FireWSMessageBody(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnWSMessageBody((IHttpAgent*)this, pSocketObj->connID, pData, iLength);}
|
||||
EnHandleResult FireWSMessageComplete(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnWSMessageComplete((IHttpAgent*)this, pSocketObj->connID);}
|
||||
|
||||
inline THttpObj* FindHttpObj(CONNID dwConnID);
|
||||
inline THttpObj* FindHttpObj(TAgentSocketObj* pSocketObj);
|
||||
|
||||
CCookieMgr* GetCookieMgr() {return m_pCookieMgr;}
|
||||
LPCSTR GetRemoteDomain(TAgentSocketObj* pSocketObj) {LPCSTR lpszDomain; pSocketObj->GetRemoteHost(&lpszDomain); return lpszDomain;}
|
||||
|
||||
public:
|
||||
CHttpAgentT(IHttpAgentListener* pListener)
|
||||
: T (pListener)
|
||||
, m_pListener (pListener)
|
||||
, m_pCookieMgr (&g_CookieMgr)
|
||||
, m_bHttpAutoStart (TRUE)
|
||||
, m_enLocalVersion (DEFAULT_HTTP_VERSION)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CHttpAgentT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
IHttpAgentListener* m_pListener;
|
||||
CCookieMgr* m_pCookieMgr;
|
||||
EnHttpVersion m_enLocalVersion;
|
||||
|
||||
BOOL m_bHttpAutoStart;
|
||||
|
||||
CHttpObjPool m_objPool;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
typedef CHttpAgentT<CTcpAgent, HTTP_DEFAULT_PORT> CHttpAgent;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLAgent.h"
|
||||
|
||||
typedef CHttpAgentT<CSSLAgent, HTTPS_DEFAULT_PORT> CHttpsAgent;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HttpClient.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::CheckParams()
|
||||
{
|
||||
if(m_enLocalVersion != HV_1_1 && m_enLocalVersion != HV_1_0)
|
||||
{
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return __super::CheckParams();
|
||||
}
|
||||
|
||||
template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
WSABUF szBuffer[2];
|
||||
CStringA strHeader;
|
||||
|
||||
LPCSTR lpszHost = nullptr;
|
||||
USHORT usPort = 0;
|
||||
BOOL bConnect = (stricmp(lpszMethod, HTTP_METHOD_CONNECT) == 0);
|
||||
|
||||
if(!bConnect)
|
||||
{
|
||||
GetRemoteHost(&lpszHost, &usPort);
|
||||
if(usPort == default_port) usPort = 0;
|
||||
}
|
||||
|
||||
CStringA strPath;
|
||||
::AdjustRequestPath(bConnect, lpszPath, strPath);
|
||||
|
||||
m_objHttp.SetRequestPath(lpszMethod, strPath);
|
||||
m_objHttp.ReloadCookies();
|
||||
|
||||
::MakeRequestLine(lpszMethod, strPath, m_enLocalVersion, strHeader);
|
||||
::MakeHeaderLines(lpHeaders, iHeaderCount, &m_objHttp.GetCookieMap(), iLength, TRUE, -1, lpszHost, usPort, strHeader);
|
||||
::MakeHttpPacket(strHeader, pBody, iLength, szBuffer);
|
||||
|
||||
return SendPackets(szBuffer, 2);
|
||||
}
|
||||
|
||||
template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendLocalFile(LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount)
|
||||
{
|
||||
CFile file;
|
||||
CFileMapping fmap;
|
||||
|
||||
HRESULT hr = ::ReadSmallFile(CA2T(lpszFileName), file, fmap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
::SetLastError(hr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return SendRequest(lpszMethod, lpszPath, lpHeaders, iHeaderCount, (BYTE*)fmap, (int)fmap.Size());
|
||||
}
|
||||
|
||||
template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendChunkData(const BYTE* pData, int iLength, LPCSTR lpszExtensions)
|
||||
{
|
||||
char szLen[12];
|
||||
WSABUF bufs[5];
|
||||
|
||||
int iCount = MakeChunkPackage(pData, iLength, lpszExtensions, szLen, bufs);
|
||||
|
||||
return SendPackets(bufs, iCount);
|
||||
}
|
||||
|
||||
template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
|
||||
{
|
||||
ASSERT(lpszMask);
|
||||
|
||||
WSABUF szBuffer[2];
|
||||
BYTE szHeader[HTTP_MAX_WS_HEADER_LEN];
|
||||
|
||||
unique_ptr<BYTE[]> szData = make_unique<BYTE[]>(iLength);
|
||||
memcpy(szData.get(), pData, iLength);
|
||||
|
||||
if(!::MakeWSPacket(bFinal, iReserved, iOperationCode, lpszMask, szData.get(), iLength, ullBodyLen, szHeader, szBuffer))
|
||||
return FALSE;
|
||||
|
||||
return SendPackets(szBuffer, 2);
|
||||
}
|
||||
|
||||
template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::StartHttp()
|
||||
{
|
||||
if(IsHttpAutoStart())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CReentrantCriSecLock locallock(m_csHttp);
|
||||
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(m_objHttp.IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_ALREADY_INITIALIZED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoStartHttp();
|
||||
|
||||
if(!IsSecure())
|
||||
FireHandShake();
|
||||
else
|
||||
{
|
||||
#ifdef _SSL_SUPPORT
|
||||
if(IsSSLAutoHandShake())
|
||||
StartSSLHandShakeNoCheck();
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress, USHORT usLocalPort)
|
||||
{
|
||||
CleanupRequestResult();
|
||||
|
||||
if(!__super::Start(lpszRemoteAddress, usPort, TRUE, lpszBindAddress, usLocalPort))
|
||||
return FALSE;
|
||||
|
||||
BOOL isOK = WaitForEvent(m_dwConnectTimeout);
|
||||
|
||||
if(!isOK || m_enProgress != HSRP_DONE)
|
||||
{
|
||||
int ec = m_enProgress == HSRP_WAITING ? ERROR_TIMEDOUT : ERROR_CONNREFUSED;
|
||||
|
||||
if(!isOK) Stop();
|
||||
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ec);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{
|
||||
CleanupRequestResult();
|
||||
|
||||
if(!__super::SendRequest(lpszMethod, lpszPath, lpHeaders, iHeaderCount, pBody, iLength))
|
||||
return FALSE;
|
||||
|
||||
BOOL isOK = WaitForEvent(m_dwRequestTimeout);
|
||||
|
||||
if(!isOK || m_enProgress != HSRP_DONE)
|
||||
{
|
||||
int ec = m_enProgress == HSRP_WAITING ? ERROR_TIMEDOUT :
|
||||
(m_enProgress == HSRP_CLOSE ? ERROR_CONNABORTED : ERROR_INVALID_DATA);
|
||||
|
||||
if(!isOK) Stop();
|
||||
|
||||
SetLastError(SE_DATA_SEND, __FUNCTION__, ec);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
|
||||
{
|
||||
CleanupRequestResult();
|
||||
|
||||
if(!__super::SendWSMessage(bFinal, iReserved, iOperationCode, lpszMask, pData, iLength, ullBodyLen))
|
||||
return FALSE;
|
||||
|
||||
BOOL isOK = WaitForEvent(m_dwRequestTimeout);
|
||||
|
||||
if(!isOK || m_enProgress != HSRP_DONE)
|
||||
{
|
||||
int ec = m_enProgress == HSRP_WAITING ? ERROR_TIMEDOUT :
|
||||
(m_enProgress == HSRP_CLOSE ? ERROR_CONNABORTED : ERROR_INVALID_DATA);
|
||||
|
||||
if(!isOK) Stop();
|
||||
|
||||
SetLastError(SE_DATA_SEND, __FUNCTION__, ec);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::OpenUrl(LPCSTR lpszMethod, LPCSTR lpszUrl, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength, BOOL bForceReconnect)
|
||||
{
|
||||
BOOL bHttps;
|
||||
USHORT usPort;
|
||||
CStringA strHost;
|
||||
CStringA strPath;
|
||||
|
||||
if(!IsHttpAutoStart())
|
||||
{
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!::ParseUrl(lpszUrl, bHttps, strHost, usPort, strPath))
|
||||
{
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ERROR_ADDRNOTAVAIL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if((bHttps && default_port == HTTP_DEFAULT_PORT) || (!bHttps && default_port == HTTPS_DEFAULT_PORT))
|
||||
{
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ERROR_PROTO);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(HasStarted())
|
||||
{
|
||||
BOOL bNeedStop = bForceReconnect;
|
||||
|
||||
if(!bNeedStop)
|
||||
{
|
||||
LPCSTR lpszHost = nullptr;
|
||||
USHORT usPort2 = 0;
|
||||
|
||||
GetRemoteHost(&lpszHost, &usPort2);
|
||||
|
||||
if(usPort != usPort2)
|
||||
bNeedStop = TRUE;
|
||||
else
|
||||
{
|
||||
HP_SCOPE_HOST host(CA2T((LPCSTR)strHost));
|
||||
|
||||
if(lstricmp(host.name, CA2T(lpszHost)) != 0)
|
||||
bNeedStop = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(bNeedStop) Stop();
|
||||
}
|
||||
|
||||
EnServiceState state = GetState();
|
||||
|
||||
if(state != SS_STARTED)
|
||||
{
|
||||
if(state == SS_STARTING)
|
||||
{
|
||||
do
|
||||
{
|
||||
::WaitFor(10);
|
||||
state = GetState();
|
||||
} while(state != SS_STARTED && state != SS_STOPPED);
|
||||
}
|
||||
else
|
||||
{
|
||||
while(state != SS_STOPPED)
|
||||
{
|
||||
::WaitFor(10);
|
||||
state = GetState();
|
||||
}
|
||||
|
||||
Start(CA2T(strHost), usPort, FALSE, nullptr);
|
||||
state = GetState();
|
||||
}
|
||||
|
||||
if(state == SS_STOPPED)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(iLength < 0 && !::IsStrEmptyA((LPCSTR)pBody))
|
||||
return SendLocalFile((LPCSTR)pBody, lpszMethod, strPath, lpHeaders, iHeaderCount);
|
||||
|
||||
return SendRequest(lpszMethod, strPath, lpHeaders, iHeaderCount, pBody, iLength);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::CleanupRequestResult()
|
||||
{
|
||||
m_pHttpObj = &m_objHttp;
|
||||
m_enProgress = HSRP_WAITING;
|
||||
|
||||
m_szBuffer.Free();
|
||||
m_objHttp2.Reset();
|
||||
m_evWait.Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpSyncClientT<T, default_port>::SetRequestEvent(EnHttpSyncRequestProgress enProgress, BOOL bCopyHttpObj)
|
||||
{
|
||||
if(m_enProgress != HSRP_WAITING)
|
||||
return;
|
||||
|
||||
m_enProgress = enProgress;
|
||||
|
||||
if(bCopyHttpObj)
|
||||
{
|
||||
m_objHttp2.CopyData(m_objHttp);
|
||||
m_objHttp2.CopyWSContext(m_objHttp);
|
||||
|
||||
m_pHttpObj = &m_objHttp2;
|
||||
}
|
||||
|
||||
m_evWait.Set();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::WaitForEvent(DWORD dwWait)
|
||||
{
|
||||
LONG lTimeout = INFINITE;
|
||||
|
||||
if(dwWait != 0)
|
||||
lTimeout = (LONG)dwWait;
|
||||
|
||||
return (m_evWait.Wait(lTimeout) > TIMEOUT);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::GetResponseBody(LPCBYTE* lpszBody, int* iLength)
|
||||
{
|
||||
ASSERT(lpszBody && iLength);
|
||||
|
||||
*lpszBody = m_szBuffer.Ptr();
|
||||
*iLength = (int)m_szBuffer.Size();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnHandShake(ITcpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnHandShake(pSender, dwConnID);
|
||||
|
||||
if(rs != HR_ERROR)
|
||||
SetRequestEvent(HSRP_DONE, FALSE);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnClose(pSender, dwConnID, enOperation, iErrorCode);
|
||||
|
||||
SetRequestEvent(HSRP_CLOSE);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnBody(pSender, dwConnID, pData, iLength);
|
||||
|
||||
if(rs != HPR_ERROR)
|
||||
m_szBuffer.Cat(pData, iLength);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnMessageComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnMessageComplete(pSender, dwConnID);
|
||||
|
||||
if(rs != HPR_ERROR)
|
||||
{
|
||||
if(GetUpgradeType() == HUT_NONE)
|
||||
SetRequestEvent(HSRP_DONE);
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnUpgrade(IHttpClient* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnUpgrade(pSender, dwConnID, enUpgradeType);
|
||||
|
||||
if(rs != HPR_ERROR)
|
||||
{
|
||||
if(enUpgradeType == HUT_WEB_SOCKET)
|
||||
{
|
||||
SetRequestEvent(HSRP_DONE);
|
||||
rs = HPR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRequestEvent(HSRP_ERROR);
|
||||
rs = HPR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnParseError(IHttpClient* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnParseError(pSender, dwConnID, iErrorCode, lpszErrorDesc);
|
||||
|
||||
SetRequestEvent(HSRP_ERROR);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnWSMessageBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnWSMessageBody(pSender, dwConnID, pData, iLength);
|
||||
|
||||
if(rs != HR_ERROR)
|
||||
m_szBuffer.Cat(pData, iLength);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnWSMessageComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnWSMessageComplete(pSender, dwConnID);
|
||||
|
||||
if(rs != HR_ERROR)
|
||||
SetRequestEvent(HSRP_DONE);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
return m_pListener2->OnPrepareConnect(pSender, dwConnID, socket);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnConnect(ITcpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
return m_pListener2->OnConnect(pSender, dwConnID);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
return m_pListener2->OnSend(pSender, dwConnID, pData, iLength);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
return m_pListener2->OnReceive(pSender, dwConnID, pData, iLength);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnMessageBegin(IHttpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnMessageBegin(pSender, dwConnID);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnStatusLine(IHttpClient* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnStatusLine(pSender, dwConnID, usStatusCode, lpszDesc);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnHeader(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnHeader(pSender, dwConnID, lpszName, lpszValue);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnHeadersComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnHeadersComplete(pSender, dwConnID);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnChunkHeader(IHttpClient* pSender, CONNID dwConnID, int iLength)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnChunkHeader(pSender, dwConnID, iLength);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnChunkComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{
|
||||
EnHttpParseResult rs = HPR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnChunkComplete(pSender, dwConnID);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnWSMessageHeader(IHttpClient* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
if(m_pListener2 != nullptr)
|
||||
rs = m_pListener2->OnWSMessageHeader(pSender, dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
template class CHttpClientT<IHttpRequester, CTcpClient, HTTP_DEFAULT_PORT>;
|
||||
template class CHttpSyncClientT<CTcpClient, HTTP_DEFAULT_PORT>;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLClient.h"
|
||||
|
||||
template class CHttpClientT<IHttpRequester, CSSLClient, HTTPS_DEFAULT_PORT>;
|
||||
template class CHttpSyncClientT<CSSLClient, HTTPS_DEFAULT_PORT>;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpClient.h"
|
||||
#include "HttpHelper.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class R, class T, USHORT default_port> class CHttpClientT : public R, public T
|
||||
{
|
||||
using __super = T;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
using __super::SendPackets;
|
||||
using __super::HasStarted;
|
||||
using __super::GetRemoteHost;
|
||||
|
||||
using __super::IsSecure;
|
||||
using __super::IsConnected;
|
||||
using __super::FireHandShake;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
using __super::IsSSLAutoHandShake;
|
||||
using __super::StartSSLHandShakeNoCheck;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
using __super::SetLastError;
|
||||
|
||||
using THttpObj = THttpObjT<CHttpClientT, IHttpClient>;
|
||||
friend typename CHttpClientT::THttpObj;
|
||||
|
||||
public:
|
||||
virtual BOOL SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0);
|
||||
virtual BOOL SendLocalFile(LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0);
|
||||
virtual BOOL SendChunkData(const BYTE* pData = nullptr, int iLength = 0, LPCSTR lpszExtensions = nullptr);
|
||||
|
||||
virtual BOOL SendPost(LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{return SendRequest(HTTP_METHOD_POST, lpszPath, lpHeaders, iHeaderCount, pBody, iLength);}
|
||||
virtual BOOL SendPut(LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{return SendRequest(HTTP_METHOD_PUT, lpszPath, lpHeaders, iHeaderCount, pBody, iLength);}
|
||||
virtual BOOL SendPatch(LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
|
||||
{return SendRequest(HTTP_METHOD_PATCH, lpszPath, lpHeaders, iHeaderCount, pBody, iLength);}
|
||||
virtual BOOL SendGet(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(HTTP_METHOD_GET, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendDelete(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(HTTP_METHOD_DELETE, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendHead(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(HTTP_METHOD_HEAD, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendTrace(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(HTTP_METHOD_TRACE, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendOptions(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(HTTP_METHOD_OPTIONS, lpszPath, lpHeaders, iHeaderCount);}
|
||||
virtual BOOL SendConnect(LPCSTR lpszHost, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)
|
||||
{return SendRequest(HTTP_METHOD_CONNECT, lpszHost, lpHeaders, iHeaderCount);}
|
||||
|
||||
virtual BOOL SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0);
|
||||
|
||||
virtual BOOL StartHttp();
|
||||
|
||||
public:
|
||||
virtual void SetUseCookie(BOOL bUseCookie) {ENSURE_HAS_STOPPED(); m_pCookieMgr = bUseCookie ? &g_CookieMgr : nullptr;}
|
||||
virtual void SetHttpAutoStart(BOOL bAutoStart) {ENSURE_HAS_STOPPED(); m_bHttpAutoStart = bAutoStart;}
|
||||
virtual void SetLocalVersion(EnHttpVersion enLocalVersion) {ENSURE_HAS_STOPPED(); m_enLocalVersion = enLocalVersion;}
|
||||
|
||||
virtual BOOL IsUseCookie() {return m_pCookieMgr != nullptr;}
|
||||
virtual BOOL IsHttpAutoStart() {return m_bHttpAutoStart;}
|
||||
virtual EnHttpVersion GetLocalVersion() {return m_enLocalVersion;}
|
||||
|
||||
virtual BOOL IsUpgrade()
|
||||
{return m_objHttp.IsUpgrade();}
|
||||
virtual BOOL IsKeepAlive()
|
||||
{return m_objHttp.IsKeepAlive();}
|
||||
virtual USHORT GetVersion()
|
||||
{return m_objHttp.GetVersion();}
|
||||
virtual ULONGLONG GetContentLength()
|
||||
{return m_objHttp.GetContentLength();}
|
||||
virtual LPCSTR GetContentType()
|
||||
{return m_objHttp.GetContentType();}
|
||||
virtual LPCSTR GetContentEncoding()
|
||||
{return m_objHttp.GetContentEncoding();}
|
||||
virtual LPCSTR GetTransferEncoding()
|
||||
{return m_objHttp.GetTransferEncoding();}
|
||||
virtual EnHttpUpgradeType GetUpgradeType()
|
||||
{return m_objHttp.GetUpgradeType();}
|
||||
virtual USHORT GetParseErrorCode(LPCSTR* lpszErrorDesc = nullptr)
|
||||
{return m_objHttp.GetParseErrorCode(lpszErrorDesc);}
|
||||
|
||||
virtual BOOL GetHeader(LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{return m_objHttp.GetHeader(lpszName, lpszValue);}
|
||||
virtual BOOL GetHeaders(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
|
||||
{return m_objHttp.GetHeaders(lpszName, lpszValue, dwCount);}
|
||||
virtual BOOL GetAllHeaders(THeader lpHeaders[], DWORD& dwCount)
|
||||
{return m_objHttp.GetAllHeaders(lpHeaders, dwCount);}
|
||||
virtual BOOL GetAllHeaderNames(LPCSTR lpszName[], DWORD& dwCount)
|
||||
{return m_objHttp.GetAllHeaderNames(lpszName, dwCount);}
|
||||
|
||||
virtual BOOL GetCookie(LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{return m_objHttp.GetCookie(lpszName, lpszValue);}
|
||||
virtual BOOL GetAllCookies(TCookie lpCookies[], DWORD& dwCount)
|
||||
{return m_objHttp.GetAllCookies(lpCookies, dwCount);}
|
||||
|
||||
virtual USHORT GetStatusCode()
|
||||
{return m_objHttp.GetStatusCode();}
|
||||
|
||||
virtual BOOL GetWSMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
|
||||
{return m_objHttp.GetWSMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);}
|
||||
|
||||
private:
|
||||
virtual BOOL CheckParams();
|
||||
|
||||
void DoStartHttp()
|
||||
{m_objHttp.SetValid(TRUE);}
|
||||
|
||||
virtual EnHandleResult FireConnect()
|
||||
{return m_bHttpAutoStart ? __super::FireConnect() : __super::DoFireConnect(this);}
|
||||
|
||||
virtual EnHandleResult DoFireConnect(ITcpClient* pSender)
|
||||
{
|
||||
ASSERT(pSender == this);
|
||||
|
||||
DoStartHttp();
|
||||
|
||||
EnHandleResult result = __super::DoFireConnect(this);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
m_objHttp.SetValid(FALSE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireReceive(ITcpClient* pSender, const BYTE* pData, int iLength)
|
||||
{ASSERT(pSender == this); return m_objHttp.IsValid() ? m_objHttp.Execute(pData, iLength) : __super::DoFireReceive(pSender, pData, iLength);}
|
||||
|
||||
EnHandleResult DoFireSuperReceive(IHttpClient* pSender, const BYTE* pData, int iLength)
|
||||
{ASSERT(pSender == (IHttpClient*)this); return __super::DoFireReceive(pSender, pData, iLength);}
|
||||
|
||||
virtual EnHandleResult DoFireClose(ITcpClient* pSender, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
ASSERT(pSender == (IHttpClient*)this);
|
||||
|
||||
m_objHttp.CheckBodyIdentityEof();
|
||||
|
||||
return __super::DoFireClose(pSender, enOperation, iErrorCode);
|
||||
}
|
||||
|
||||
virtual void Reset()
|
||||
{
|
||||
m_objHttp.Reset();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
EnHttpParseResult FireMessageBegin(IHttpClient* pSender)
|
||||
{return m_pListener->OnMessageBegin(pSender, pSender->GetConnectionID());}
|
||||
EnHttpParseResult FireRequestLine(IHttpClient* pSender, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{return m_pListener->OnRequestLine(pSender, pSender->GetConnectionID(), lpszMethod, lpszUrl);}
|
||||
EnHttpParseResult FireStatusLine(IHttpClient* pSender, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{return m_pListener->OnStatusLine(pSender, pSender->GetConnectionID(), usStatusCode, lpszDesc);}
|
||||
EnHttpParseResult FireHeader(IHttpClient* pSender, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{return m_pListener->OnHeader(pSender, pSender->GetConnectionID(), lpszName, lpszValue);}
|
||||
EnHttpParseResult FireHeadersComplete(IHttpClient* pSender)
|
||||
{return m_pListener->OnHeadersComplete(pSender, pSender->GetConnectionID());}
|
||||
EnHttpParseResult FireBody(IHttpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnBody(pSender, pSender->GetConnectionID(), pData, iLength);}
|
||||
EnHttpParseResult FireChunkHeader(IHttpClient* pSender, int iLength)
|
||||
{return m_pListener->OnChunkHeader(pSender, pSender->GetConnectionID(), iLength);}
|
||||
EnHttpParseResult FireChunkComplete(IHttpClient* pSender)
|
||||
{return m_pListener->OnChunkComplete(pSender, pSender->GetConnectionID());}
|
||||
EnHttpParseResult FireMessageComplete(IHttpClient* pSender)
|
||||
{return m_pListener->OnMessageComplete(pSender, pSender->GetConnectionID());}
|
||||
EnHttpParseResult FireUpgrade(IHttpClient* pSender, EnHttpUpgradeType enUpgradeType)
|
||||
{return m_pListener->OnUpgrade(pSender, pSender->GetConnectionID(), enUpgradeType);}
|
||||
EnHttpParseResult FireParseError(IHttpClient* pSender, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{return m_pListener->OnParseError(pSender, pSender->GetConnectionID(), iErrorCode, lpszErrorDesc);}
|
||||
|
||||
EnHandleResult FireWSMessageHeader(IHttpClient* pSender, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{return m_pListener->OnWSMessageHeader(pSender, pSender->GetConnectionID(), bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);}
|
||||
EnHandleResult FireWSMessageBody(IHttpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnWSMessageBody(pSender, pSender->GetConnectionID(), pData, iLength);}
|
||||
EnHandleResult FireWSMessageComplete(IHttpClient* pSender)
|
||||
{return m_pListener->OnWSMessageComplete(pSender, pSender->GetConnectionID());}
|
||||
|
||||
CCookieMgr* GetCookieMgr() {return m_pCookieMgr;}
|
||||
LPCSTR GetRemoteDomain(IHttpClient* pSender) {LPCSTR lpszDomain; GetRemoteHost(&lpszDomain); return lpszDomain;}
|
||||
|
||||
public:
|
||||
CHttpClientT(IHttpClientListener* pListener)
|
||||
: T (pListener)
|
||||
, m_pListener (pListener)
|
||||
, m_pCookieMgr (&g_CookieMgr)
|
||||
, m_bHttpAutoStart (TRUE)
|
||||
, m_enLocalVersion (DEFAULT_HTTP_VERSION)
|
||||
, m_objHttp (FALSE, this, (IHttpClient*)this)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CHttpClientT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL m_bHttpAutoStart;
|
||||
|
||||
IHttpClientListener* m_pListener;
|
||||
CCookieMgr* m_pCookieMgr;
|
||||
EnHttpVersion m_enLocalVersion;
|
||||
|
||||
CReentrantCriSec m_csHttp;
|
||||
|
||||
protected:
|
||||
THttpObj m_objHttp;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
template<class T, USHORT default_port> class CHttpSyncClientT : public CHttpClientT<IHttpSyncRequester, T, default_port>, private CHttpClientListener
|
||||
{
|
||||
using __super = CHttpClientT<IHttpSyncRequester, T, default_port>;
|
||||
using __super::m_objHttp;
|
||||
using __super::SetLastError;
|
||||
|
||||
using typename __super::THttpObj;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
using __super::HasStarted;
|
||||
using __super::GetRemoteHost;
|
||||
using __super::SendLocalFile;
|
||||
using __super::IsHttpAutoStart;
|
||||
|
||||
public:
|
||||
virtual BOOL Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr, USHORT usLocalPort = 0);
|
||||
public:
|
||||
virtual BOOL SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0);
|
||||
virtual BOOL SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4] = nullptr, const BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0);
|
||||
|
||||
public:
|
||||
virtual BOOL IsUpgrade()
|
||||
{return m_pHttpObj->IsUpgrade();}
|
||||
virtual BOOL IsKeepAlive()
|
||||
{return m_pHttpObj->IsKeepAlive();}
|
||||
virtual USHORT GetVersion()
|
||||
{return m_pHttpObj->GetVersion();}
|
||||
virtual ULONGLONG GetContentLength()
|
||||
{return m_pHttpObj->GetContentLength();}
|
||||
virtual LPCSTR GetContentType()
|
||||
{return m_pHttpObj->GetContentType();}
|
||||
virtual LPCSTR GetContentEncoding()
|
||||
{return m_pHttpObj->GetContentEncoding();}
|
||||
virtual LPCSTR GetTransferEncoding()
|
||||
{return m_pHttpObj->GetTransferEncoding();}
|
||||
virtual EnHttpUpgradeType GetUpgradeType()
|
||||
{return m_pHttpObj->GetUpgradeType();}
|
||||
virtual USHORT GetParseErrorCode(LPCSTR* lpszErrorDesc = nullptr)
|
||||
{return m_pHttpObj->GetParseErrorCode(lpszErrorDesc);}
|
||||
|
||||
virtual BOOL GetHeader(LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{return m_pHttpObj->GetHeader(lpszName, lpszValue);}
|
||||
virtual BOOL GetHeaders(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
|
||||
{return m_pHttpObj->GetHeaders(lpszName, lpszValue, dwCount);}
|
||||
virtual BOOL GetAllHeaders(THeader lpHeaders[], DWORD& dwCount)
|
||||
{return m_pHttpObj->GetAllHeaders(lpHeaders, dwCount);}
|
||||
virtual BOOL GetAllHeaderNames(LPCSTR lpszName[], DWORD& dwCount)
|
||||
{return m_pHttpObj->GetAllHeaderNames(lpszName, dwCount);}
|
||||
|
||||
virtual BOOL GetCookie(LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{return m_pHttpObj->GetCookie(lpszName, lpszValue);}
|
||||
virtual BOOL GetAllCookies(TCookie lpCookies[], DWORD& dwCount)
|
||||
{return m_pHttpObj->GetAllCookies(lpCookies, dwCount);}
|
||||
|
||||
virtual USHORT GetStatusCode()
|
||||
{return m_pHttpObj->GetStatusCode();}
|
||||
|
||||
virtual BOOL GetWSMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
|
||||
{return m_pHttpObj->GetWSMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);}
|
||||
|
||||
public:
|
||||
virtual BOOL OpenUrl(LPCSTR lpszMethod, LPCSTR lpszUrl, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0, BOOL bForceReconnect = FALSE);
|
||||
virtual BOOL CleanupRequestResult();
|
||||
|
||||
public:
|
||||
virtual BOOL GetResponseBody (LPCBYTE* lpszBody, int* iLength);
|
||||
|
||||
virtual void SetConnectTimeout (DWORD dwConnectTimeout) {ENSURE_HAS_STOPPED(); m_dwConnectTimeout = dwConnectTimeout;}
|
||||
virtual void SetRequestTimeout (DWORD dwRequestTimeout) {ENSURE_HAS_STOPPED(); m_dwRequestTimeout = dwRequestTimeout;}
|
||||
|
||||
virtual DWORD GetConnectTimeout () {return m_dwConnectTimeout;}
|
||||
virtual DWORD GetRequestTimeout () {return m_dwRequestTimeout;}
|
||||
|
||||
private:
|
||||
virtual EnHandleResult OnHandShake(ITcpClient* pSender, CONNID dwConnID);
|
||||
virtual EnHandleResult OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode);
|
||||
|
||||
virtual EnHttpParseResult OnBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength);
|
||||
virtual EnHttpParseResult OnMessageComplete(IHttpClient* pSender, CONNID dwConnID);
|
||||
virtual EnHttpParseResult OnUpgrade(IHttpClient* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType);
|
||||
virtual EnHttpParseResult OnParseError(IHttpClient* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc);
|
||||
|
||||
virtual EnHandleResult OnWSMessageBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult OnWSMessageComplete(IHttpClient* pSender, CONNID dwConnID);
|
||||
|
||||
virtual EnHandleResult OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket);
|
||||
virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID);
|
||||
virtual EnHandleResult OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength);
|
||||
|
||||
virtual EnHttpParseResult OnMessageBegin(IHttpClient* pSender, CONNID dwConnID);
|
||||
virtual EnHttpParseResult OnStatusLine(IHttpClient* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc);
|
||||
virtual EnHttpParseResult OnHeader(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue);
|
||||
virtual EnHttpParseResult OnHeadersComplete(IHttpClient* pSender, CONNID dwConnID);
|
||||
virtual EnHttpParseResult OnChunkHeader(IHttpClient* pSender, CONNID dwConnID, int iLength);
|
||||
virtual EnHttpParseResult OnChunkComplete(IHttpClient* pSender, CONNID dwConnID);
|
||||
|
||||
virtual EnHandleResult OnWSMessageHeader(IHttpClient* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen);
|
||||
|
||||
|
||||
private:
|
||||
void SetRequestEvent(EnHttpSyncRequestProgress enProgress, BOOL bCopyHttpObj = TRUE);
|
||||
BOOL WaitForEvent(DWORD dwWait);
|
||||
|
||||
public:
|
||||
CHttpSyncClientT(IHttpClientListener* pListener = nullptr)
|
||||
: __super (this)
|
||||
, m_enProgress (HSRP_DONE)
|
||||
, m_objHttp2 (FALSE, this, (IHttpClient*)this)
|
||||
, m_pHttpObj (nullptr)
|
||||
, m_pListener2 (pListener)
|
||||
, m_dwConnectTimeout (DEFAULT_HTTP_SYNC_CONNECT_TIMEOUT)
|
||||
, m_dwRequestTimeout (DEFAULT_HTTP_SYNC_REQUEST_TIMEOUT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CHttpSyncClientT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwConnectTimeout;
|
||||
DWORD m_dwRequestTimeout;
|
||||
|
||||
CEvt m_evWait;
|
||||
THttpObj m_objHttp2;
|
||||
|
||||
THttpObj* m_pHttpObj;
|
||||
IHttpClientListener* m_pListener2;
|
||||
|
||||
EnHttpSyncRequestProgress m_enProgress;
|
||||
CBufferPtrT<BYTE, 16 * 1024> m_szBuffer;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
typedef CHttpClientT<IHttpRequester, CTcpClient, HTTP_DEFAULT_PORT> CHttpClient;
|
||||
typedef CHttpSyncClientT<CTcpClient, HTTP_DEFAULT_PORT> CHttpSyncClient;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLClient.h"
|
||||
|
||||
typedef CHttpClientT<IHttpRequester, CSSLClient, HTTPS_DEFAULT_PORT> CHttpsClient;
|
||||
typedef CHttpSyncClientT<CSSLClient, HTTPS_DEFAULT_PORT> CHttpsSyncClient;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,927 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HttpCookie.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
static const char* s_short_week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
static const char* s_short_month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
CCookieMgr g_CookieMgr;
|
||||
|
||||
CCookie* CCookie::FromString(const CStringA& strCookie, LPCSTR lpszDefaultDomain, LPCSTR lpszDefaultPath)
|
||||
{
|
||||
CStringA strName;
|
||||
CStringA strValue;
|
||||
CStringA strDomain;
|
||||
CStringA strPath;
|
||||
|
||||
int iMaxAge = -1;
|
||||
BOOL bHttpOnly = FALSE;
|
||||
BOOL bSecure = FALSE;
|
||||
EnSameSite enSameSite = SS_UNKNOWN;
|
||||
|
||||
int i = 0;
|
||||
int iStart = 0;
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
CStringA strField = strCookie.Tokenize(COOKIE_FIELD_SEP, iStart);
|
||||
strField.Trim();
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
ParseFieldKV(strField, strName, strValue, COOKIE_KV_SEP_CHAR);
|
||||
|
||||
if(strName.IsEmpty())
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strField.IsEmpty())
|
||||
break;
|
||||
|
||||
CStringA strKey;
|
||||
CStringA strVal;
|
||||
|
||||
ParseFieldKV(strField, strKey, strVal, COOKIE_KV_SEP_CHAR);
|
||||
|
||||
if(strKey.CompareNoCase(COOKIE_DOMAIN) == 0)
|
||||
strDomain = strVal;
|
||||
else if(strKey.CompareNoCase(COOKIE_PATH) == 0)
|
||||
strPath = strVal;
|
||||
else if(strKey.CompareNoCase(COOKIE_MAX_AGE) == 0 && !strVal.IsEmpty())
|
||||
iMaxAge = atoi(strVal);
|
||||
else if(strKey.CompareNoCase(COOKIE_EXPIRES) == 0 && !strVal.IsEmpty() && iMaxAge == -1)
|
||||
{
|
||||
__time64_t tmExpires = -1;
|
||||
|
||||
if(!ParseExpires(strVal, tmExpires))
|
||||
return nullptr;
|
||||
|
||||
iMaxAge = ExpiresToMaxAge(tmExpires);
|
||||
}
|
||||
else if(strKey.CompareNoCase(COOKIE_HTTPONLY) == 0)
|
||||
bHttpOnly = TRUE;
|
||||
else if(strKey.CompareNoCase(COOKIE_SECURE) == 0)
|
||||
bSecure = TRUE;
|
||||
else if(strKey.CompareNoCase(COOKIE_SAMESITE) == 0)
|
||||
{
|
||||
if(strVal.IsEmpty() || strVal.CompareNoCase(COOKIE_SAMESITE_LAX) == 0)
|
||||
enSameSite = SS_LAX;
|
||||
else if(strVal.CompareNoCase(COOKIE_SAMESITE_STRICT) == 0)
|
||||
enSameSite = SS_STRICT;
|
||||
else if(strVal.CompareNoCase(COOKIE_SAMESITE_NONE) == 0)
|
||||
enSameSite = SS_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if(!AdjustDomain(strDomain, lpszDefaultDomain) || !AdjustPath(strPath, lpszDefaultPath))
|
||||
return nullptr;
|
||||
|
||||
CCookie* pCookie = new CCookie(strName, strValue, strDomain, strPath, iMaxAge, bHttpOnly, bSecure, enSameSite);
|
||||
ASSERT(pCookie->IsValid());
|
||||
|
||||
return pCookie;
|
||||
}
|
||||
|
||||
CStringA CCookie::ToString(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge, BOOL bHttpOnly, BOOL bSecure, EnSameSite enSameSite)
|
||||
{
|
||||
CCookie cookie(lpszName, lpszValue, lpszDomain, lpszPath, iMaxAge, bHttpOnly, bSecure, enSameSite);
|
||||
return cookie.ToString();
|
||||
}
|
||||
|
||||
BOOL CCookie::ToString(char lpszBuff[], int& iBuffLen, LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge, BOOL bHttpOnly, BOOL bSecure, EnSameSite enSameSite)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
CStringA str = ToString(lpszName, lpszValue, lpszDomain, lpszPath, iMaxAge, bHttpOnly, bSecure, enSameSite);
|
||||
int iLength = str.GetLength() + 1;
|
||||
|
||||
if(lpszBuff && iBuffLen >= iLength)
|
||||
{
|
||||
memcpy(lpszBuff, (LPCSTR)str, iLength * sizeof(char));
|
||||
isOK = TRUE;
|
||||
}
|
||||
|
||||
iBuffLen = iLength;
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
CStringA CCookie::ToString()
|
||||
{
|
||||
ASSERT(!name.IsEmpty());
|
||||
|
||||
CStringA strCookie;
|
||||
|
||||
strCookie.AppendFormat("%s=%s", (LPCSTR)name, (LPCSTR)value);
|
||||
|
||||
if(!domain.IsEmpty())
|
||||
strCookie.AppendFormat("; %s=%s", COOKIE_DOMAIN, (LPCSTR)domain);
|
||||
if(!path.IsEmpty())
|
||||
strCookie.AppendFormat("; %s=%s", COOKIE_PATH, (LPCSTR)path);
|
||||
if(expires >= 0)
|
||||
strCookie.AppendFormat("; %s=%s", COOKIE_EXPIRES, (LPCSTR)MakeExpiresStr(expires));
|
||||
if(httpOnly)
|
||||
strCookie.AppendFormat("; %s", COOKIE_HTTPONLY);
|
||||
if(secure)
|
||||
strCookie.AppendFormat("; %s", COOKIE_SECURE);
|
||||
if(sameSite != SS_UNKNOWN)
|
||||
strCookie.AppendFormat("; %s=%s", COOKIE_SAMESITE, sameSite == SS_LAX ? COOKIE_SAMESITE_LAX : (sameSite == SS_STRICT ? COOKIE_SAMESITE_STRICT : COOKIE_SAMESITE_NONE));
|
||||
|
||||
return strCookie;
|
||||
}
|
||||
|
||||
BOOL CCookie::Match(LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure)
|
||||
{
|
||||
int iLen = (int)strlen(lpszDomain);
|
||||
int iDiff = iLen - domain.GetLength();
|
||||
|
||||
if(iDiff < 0 || stricmp(lpszDomain + iDiff, domain) != 0)
|
||||
return FALSE;
|
||||
if(iDiff > 0 && *(lpszDomain + iDiff - 1) != COOKIE_DOMAIN_SEP_CHAR)
|
||||
return FALSE;
|
||||
if(strncmp(lpszPath, path, path.GetLength()) != 0)
|
||||
return FALSE;
|
||||
|
||||
return (bHttp || !httpOnly) && (bSecure || !secure);
|
||||
}
|
||||
|
||||
BOOL CCookie::IsSameDomain(LPCSTR lpszDomain)
|
||||
{
|
||||
int iLen = (int)strlen(lpszDomain);
|
||||
int iDiff = iLen - domain.GetLength();
|
||||
|
||||
LPCSTR lpszLong, lpszShort;
|
||||
|
||||
if(iDiff < 0)
|
||||
{
|
||||
lpszLong = (LPCSTR)domain + iDiff;
|
||||
lpszShort = lpszDomain;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpszLong = lpszDomain + iDiff;
|
||||
lpszShort = (LPCSTR)domain;
|
||||
}
|
||||
|
||||
if(stricmp(lpszLong, lpszShort) != 0)
|
||||
return FALSE;
|
||||
if(iDiff != 0 && *(lpszLong - 1) != COOKIE_DOMAIN_SEP_CHAR)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CCookie::ParseFieldKV(const CStringA& strField, CStringA& strKey, CStringA& strVal, char chSep)
|
||||
{
|
||||
int i = strField.Find(chSep);
|
||||
|
||||
if(i < 0)
|
||||
strKey = strField;
|
||||
else
|
||||
{
|
||||
strKey = strField.Left(i);
|
||||
strVal = strField.Mid(i + 1);
|
||||
|
||||
strVal.Trim();
|
||||
}
|
||||
|
||||
strKey.Trim();
|
||||
}
|
||||
|
||||
BOOL CCookie::ParseExpires(LPCSTR lpszExpires, __time64_t& tmExpires)
|
||||
{
|
||||
int iLength = (int)strlen(lpszExpires);
|
||||
|
||||
if(iLength == 0 || iLength > 50)
|
||||
return FALSE;
|
||||
|
||||
char szMonth[10];
|
||||
char szZone[10];
|
||||
|
||||
tm t = {0};
|
||||
|
||||
if(sscanf( lpszExpires, "%*[^, ]%*[, ]%2d%*[-/ ]%8[^-/ ]%*[-/ ]%4d %2d:%2d:%2d %8s",
|
||||
&t.tm_mday, szMonth, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec, szZone) != 7)
|
||||
return FALSE;
|
||||
|
||||
if(t.tm_year < 70)
|
||||
t.tm_year += 100;
|
||||
else if (t.tm_year > 100)
|
||||
t.tm_year -= 1900;
|
||||
|
||||
int i = 0;
|
||||
int size = _countof(s_short_month);
|
||||
|
||||
for(; i < size; i++)
|
||||
{
|
||||
if(strnicmp(szMonth, s_short_month[i], 3) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i == size)
|
||||
return FALSE;
|
||||
|
||||
t.tm_mon = i;
|
||||
|
||||
CStringA strZone = szZone;
|
||||
|
||||
int iZone = 0;
|
||||
int iMix = 0;
|
||||
int iPos = strZone.Find('+');
|
||||
|
||||
if(iPos >= 0)
|
||||
iMix = 1;
|
||||
else
|
||||
{
|
||||
iPos = strZone.Find('-');
|
||||
|
||||
if(iPos >= 0)
|
||||
iMix = -1;
|
||||
}
|
||||
|
||||
if(iPos >= 0)
|
||||
{
|
||||
strZone = strZone.Mid(iPos + 1);
|
||||
strZone.Remove(':');
|
||||
|
||||
int val = atoi(strZone);
|
||||
|
||||
if(val > 0)
|
||||
{
|
||||
int minutes = val % 100;
|
||||
int hours = val / 100;
|
||||
|
||||
iZone = iMix * (minutes * 60 + hours * 3600);
|
||||
}
|
||||
}
|
||||
|
||||
tmExpires = GetUTCTime(t, iZone);
|
||||
|
||||
return tmExpires >= 0;
|
||||
}
|
||||
|
||||
BOOL CCookie::AdjustDomain(CStringA& strDomain, LPCSTR lpszDefaultDomain)
|
||||
{
|
||||
if(strDomain.IsEmpty() && lpszDefaultDomain)
|
||||
strDomain = lpszDefaultDomain;
|
||||
|
||||
strDomain.TrimLeft(COOKIE_DOMAIN_SEP_CHAR).MakeLower();
|
||||
|
||||
return !strDomain.IsEmpty();
|
||||
}
|
||||
|
||||
BOOL CCookie::AdjustPath(CStringA& strPath, LPCSTR lpszDefaultPath)
|
||||
{
|
||||
if(strPath.IsEmpty() && lpszDefaultPath)
|
||||
strPath = lpszDefaultPath;
|
||||
|
||||
int iLength = strPath.GetLength();
|
||||
|
||||
if(iLength == 0)
|
||||
return FALSE;
|
||||
|
||||
if(strPath.GetAt(iLength - 1) != COOKIE_PATH_SEP_CHAR)
|
||||
{
|
||||
int iPos = strPath.ReverseFind(COOKIE_PATH_SEP_CHAR);
|
||||
|
||||
if(iPos >= 0)
|
||||
strPath = strPath.Left(iPos + 1);
|
||||
else
|
||||
strPath.Empty();
|
||||
}
|
||||
|
||||
if(!strPath.IsEmpty() && strPath.GetAt(0) != COOKIE_PATH_SEP_CHAR)
|
||||
strPath.Insert(0, COOKIE_PATH_SEP_CHAR);
|
||||
|
||||
return !strPath.IsEmpty();
|
||||
}
|
||||
|
||||
__time64_t CCookie::GetUTCTime(tm& t, int iSecondOffsetTZ)
|
||||
{
|
||||
__time64_t v = _mkgmtime64(&t);
|
||||
if(v >= 0) v -= iSecondOffsetTZ;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
CStringA CCookie::MakeExpiresStr(__time64_t tmExpires)
|
||||
{
|
||||
ASSERT( tmExpires >= 0);
|
||||
|
||||
if(tmExpires < 1) tmExpires = 1;
|
||||
|
||||
tm t;
|
||||
VERIFY(_gmtime64(&t, &tmExpires) != nullptr);
|
||||
|
||||
CStringA str;
|
||||
str.Format("%s, %02d-%s-%04d %02d:%02d:%02d GMT",
|
||||
s_short_week[t.tm_wday], t.tm_mday, s_short_month[t.tm_mon], t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
BOOL CCookie::MakeExpiresStr(char lpszBuff[], int& iBuffLen, __time64_t tmExpires)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
CStringA str = MakeExpiresStr(tmExpires);
|
||||
int iLength = str.GetLength() + 1;
|
||||
|
||||
if(lpszBuff && iBuffLen >= iLength)
|
||||
{
|
||||
memcpy(lpszBuff, (LPCSTR)str, iLength * sizeof(char));
|
||||
isOK = TRUE;
|
||||
}
|
||||
|
||||
iBuffLen = iLength;
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
BOOL CCookieMgr::LoadFromFile(LPCSTR lpszFile, BOOL bKeepExists)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
FILE* pFile = nullptr;
|
||||
|
||||
if((pFile = fopen(lpszFile, "r")) == nullptr)
|
||||
goto _ERROR_END;
|
||||
|
||||
{
|
||||
CStringA strDomain;
|
||||
CStringA strPath;
|
||||
CCookie cookie;
|
||||
|
||||
char szBuffer[8192];
|
||||
int iBufferSize = _countof(szBuffer);
|
||||
__time64_t tmCurrent = _time64(nullptr);
|
||||
CCookieSet* pCookieSet = nullptr;
|
||||
|
||||
CWriteLock locallock(m_cs);
|
||||
|
||||
if(!bKeepExists)
|
||||
ClearDomainCookiesNoLock();
|
||||
|
||||
while(fgets(szBuffer, iBufferSize, pFile) != nullptr)
|
||||
{
|
||||
char c = szBuffer[0];
|
||||
|
||||
if(c == '\n' || c == '\r')
|
||||
continue;
|
||||
else if(c != '\t')
|
||||
{
|
||||
if(!LoadDomainAndPath(szBuffer, strDomain, strPath))
|
||||
goto _ERROR_END;
|
||||
|
||||
pCookieSet = GetCookieSetNoLock(strDomain, strPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!LoadCookie(szBuffer, strDomain, strPath, cookie))
|
||||
goto _ERROR_END;
|
||||
|
||||
if(cookie.expires <= tmCurrent)
|
||||
continue;
|
||||
|
||||
if(pCookieSet)
|
||||
{
|
||||
if(bKeepExists)
|
||||
{
|
||||
CCookieSetCI it = pCookieSet->find(cookie);
|
||||
if(it != pCookieSet->end())
|
||||
continue;
|
||||
}
|
||||
|
||||
pCookieSet->emplace(move(cookie));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCookieNoLock(cookie, FALSE);
|
||||
pCookieSet = GetCookieSetNoLock(strDomain, strPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!feof(pFile))
|
||||
goto _ERROR_END;
|
||||
}
|
||||
|
||||
isOK = TRUE;
|
||||
|
||||
_ERROR_END:
|
||||
|
||||
if(pFile) fclose(pFile);
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::SaveToFile(LPCSTR lpszFile, BOOL bKeepExists)
|
||||
{
|
||||
if(bKeepExists)
|
||||
{
|
||||
if(!LoadFromFile(lpszFile, TRUE) && !IS_ERROR(ERROR_FILE_NOT_FOUND))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL isOK = FALSE;
|
||||
FILE* pFile = nullptr;
|
||||
|
||||
if((pFile = fopen(lpszFile, "w")) == nullptr)
|
||||
goto _ERROR_END;
|
||||
|
||||
{
|
||||
__time64_t tmCurrent = _time64(nullptr);
|
||||
|
||||
CReadLock locallock(m_cs);
|
||||
|
||||
for(CCookieDomainMapCI it = m_cookies.begin(), end = m_cookies.end(); it != end; ++it)
|
||||
{
|
||||
const CStringA& strDomain = it->first;
|
||||
const CCookiePathMap& paths = it->second;
|
||||
|
||||
for(CCookiePathMapCI it2 = paths.begin(), end2 = paths.end(); it2 != end2; ++it2)
|
||||
{
|
||||
const CStringA& strPath = it2->first;
|
||||
const CCookieSet& cookies = it2->second;
|
||||
|
||||
if(fprintf(pFile, "%s %s\n", (LPCSTR)strDomain, (LPCSTR)strPath) < 0)
|
||||
goto _ERROR_END;
|
||||
|
||||
for(CCookieSetCI it3 = cookies.begin(), end3 = cookies.end(); it3 != end3; ++it3)
|
||||
{
|
||||
const CCookie& cookie = *it3;
|
||||
|
||||
if(cookie.expires <= tmCurrent)
|
||||
continue;
|
||||
|
||||
LPCSTR lpszValue = (LPCSTR)cookie.value;
|
||||
|
||||
if(lpszValue[0] == 0)
|
||||
lpszValue = " ";
|
||||
|
||||
if(fprintf(pFile, "\t%s;%s;%lld;%d;%d;%d\n", (LPCSTR)cookie.name, lpszValue, cookie.expires, cookie.httpOnly, cookie.secure, cookie.sameSite) < 0)
|
||||
goto _ERROR_END;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOK = TRUE;
|
||||
|
||||
_ERROR_END:
|
||||
|
||||
if(pFile) fclose(pFile);
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::ClearCookies(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
CStringA strDomain;
|
||||
CStringA strPath;
|
||||
|
||||
if(!AdjustDomainAndPath(lpszDomain, lpszPath, strDomain, strPath, TRUE))
|
||||
return FALSE;
|
||||
|
||||
CWriteLock locallock(m_cs);
|
||||
|
||||
ClearDomainCookiesNoLock(lpszDomain, lpszPath);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::RemoveExpiredCookies(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
CStringA strDomain;
|
||||
CStringA strPath;
|
||||
|
||||
if(!AdjustDomainAndPath(lpszDomain, lpszPath, strDomain, strPath, TRUE))
|
||||
return FALSE;
|
||||
|
||||
CWriteLock locallock(m_cs);
|
||||
|
||||
RemoveExpiredCookiesNoLock(lpszDomain, lpszPath);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::GetCookies(CCookieSet& cookies, LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure)
|
||||
{
|
||||
ASSERT(lpszDomain && lpszPath);
|
||||
|
||||
CStringA strDomain;
|
||||
CStringA strPath;
|
||||
|
||||
if(!AdjustDomainAndPath(lpszDomain, lpszPath, strDomain, strPath, FALSE))
|
||||
return FALSE;
|
||||
|
||||
list<LPCSTR> lsDomains(1, lpszDomain);
|
||||
list<CStringA> lsPaths(1, lpszPath);
|
||||
|
||||
char c;
|
||||
LPCSTR lpszTemp = lpszDomain;
|
||||
|
||||
while((c = *(++lpszTemp)) != 0)
|
||||
{
|
||||
if(c == COOKIE_DOMAIN_SEP_CHAR)
|
||||
{
|
||||
if((c = *(++lpszTemp)) != 0)
|
||||
lsDomains.push_back(lpszTemp);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lpszTemp = lpszPath + strlen(lpszPath) - 1;
|
||||
|
||||
while(--lpszTemp >= lpszPath)
|
||||
{
|
||||
if((c = *lpszTemp) == COOKIE_PATH_SEP_CHAR)
|
||||
{
|
||||
*(LPSTR)(lpszTemp + 1) = 0;
|
||||
lsPaths.push_back(lpszPath);
|
||||
}
|
||||
}
|
||||
|
||||
CReadLock locallock(m_cs);
|
||||
|
||||
for(list<LPCSTR>::const_iterator it = lsDomains.begin(), end = lsDomains.end(); it != end; ++it)
|
||||
{
|
||||
for(list<CStringA>::const_iterator it2 = lsPaths.begin(), end2 = lsPaths.end(); it2 != end2; ++it2)
|
||||
MatchCookiesNoLock(cookies, *it, *it2, bHttp, bSecure);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::SetCookie(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge, BOOL bHttpOnly, BOOL bSecure, CCookie::EnSameSite enSameSite, BOOL bOnlyUpdateValueIfExists)
|
||||
{
|
||||
CCookie cookie(lpszName, lpszValue, lpszDomain, lpszPath, iMaxAge, bHttpOnly, bSecure, enSameSite);
|
||||
|
||||
return SetCookie(cookie, bOnlyUpdateValueIfExists);
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::SetCookie(const CStringA& strCookie, BOOL bOnlyUpdateValueIfExists)
|
||||
{
|
||||
unique_ptr<CCookie> pCookie(CCookie::FromString(strCookie));
|
||||
if(!pCookie) return FALSE;
|
||||
|
||||
return SetCookie(*pCookie, bOnlyUpdateValueIfExists);
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::SetCookie(const CCookie& cookie, BOOL bOnlyUpdateValueIfExists)
|
||||
{
|
||||
if(!cookie.IsValid()) return FALSE;
|
||||
|
||||
CWriteLock locallock(m_cs);
|
||||
|
||||
return SetCookieNoLock(cookie, bOnlyUpdateValueIfExists);
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::DeleteCookie(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName)
|
||||
{
|
||||
CCookie cookie(lpszName, nullptr, lpszDomain, lpszPath);
|
||||
|
||||
return DeleteCookie(cookie);
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::DeleteCookie(const CCookie& cookie)
|
||||
{
|
||||
if(!cookie.IsValid()) return FALSE;
|
||||
|
||||
CWriteLock locallock(m_cs);
|
||||
|
||||
return DeleteCookieNoLock(cookie);
|
||||
}
|
||||
|
||||
void CCookieMgr::ClearDomainCookiesNoLock(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
if(!lpszDomain && !lpszPath)
|
||||
m_cookies.clear();
|
||||
else if(!lpszPath)
|
||||
m_cookies.erase(lpszDomain);
|
||||
else
|
||||
{
|
||||
if(!lpszDomain)
|
||||
{
|
||||
for(CCookieDomainMapI it = m_cookies.begin(), end = m_cookies.end(); it != end; ++it)
|
||||
ClearPathCookiesNoLock(it->second, lpszPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
CCookieDomainMapI it = m_cookies.find(lpszDomain);
|
||||
if(it != m_cookies.end())
|
||||
ClearPathCookiesNoLock(it->second, lpszPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCookieMgr::ClearPathCookiesNoLock(CCookiePathMap& paths, LPCSTR lpszPath)
|
||||
{
|
||||
if(!lpszPath)
|
||||
paths.clear();
|
||||
else
|
||||
{
|
||||
CCookiePathMapI it = paths.find(lpszPath);
|
||||
if(it != paths.end())
|
||||
paths.erase(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
void CCookieMgr::RemoveExpiredCookiesNoLock(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
if(!lpszDomain)
|
||||
{
|
||||
for(CCookieDomainMapI it = m_cookies.begin(), end = m_cookies.end(); it != end; ++it)
|
||||
RemoveDomainExpiredCookiesNoLock(it->second, lpszPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
CCookieDomainMapI it = m_cookies.find(lpszDomain);
|
||||
if(it != m_cookies.end())
|
||||
RemoveDomainExpiredCookiesNoLock(it->second, lpszPath);
|
||||
}
|
||||
}
|
||||
|
||||
void CCookieMgr::RemoveDomainExpiredCookiesNoLock(CCookiePathMap& paths, LPCSTR lpszPath)
|
||||
{
|
||||
if(!lpszPath)
|
||||
{
|
||||
for(CCookiePathMapI it = paths.begin(), end = paths.end(); it != end; ++it)
|
||||
RemovePathExpiredCookiesNoLock(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
CCookiePathMapI it = paths.find(lpszPath);
|
||||
if(it != paths.end())
|
||||
RemovePathExpiredCookiesNoLock(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void CCookieMgr::RemovePathExpiredCookiesNoLock(CCookieSet& cookies)
|
||||
{
|
||||
CCookiePtrSet ptrs;
|
||||
|
||||
for(CCookieSetI it = cookies.begin(), end = cookies.end(); it != end; ++it)
|
||||
{
|
||||
if(it->IsExpired())
|
||||
ptrs.emplace(&*it);
|
||||
}
|
||||
|
||||
if(!ptrs.empty())
|
||||
{
|
||||
for(CCookiePtrSetI it = ptrs.begin(), end = ptrs.end(); it != end; ++it)
|
||||
cookies.erase(**it);
|
||||
}
|
||||
}
|
||||
|
||||
const CCookie* CCookieMgr::GetCookieNoLock(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName)
|
||||
{
|
||||
const CCookie cookie(lpszName, nullptr, lpszDomain, lpszPath);
|
||||
return GetCookieNoLock(cookie);
|
||||
}
|
||||
|
||||
const CCookie* CCookieMgr::GetCookieNoLock(const CCookie& cookie)
|
||||
{
|
||||
const CCookie* pCookie = nullptr;
|
||||
|
||||
CCookieDomainMapCI it = m_cookies.find(cookie.domain);
|
||||
if(it != m_cookies.end())
|
||||
{
|
||||
CCookiePathMapCI it2 = it->second.find(cookie.path);
|
||||
if(it2 != it->second.end())
|
||||
{
|
||||
CCookieSetCI it3 = it2->second.find(cookie);
|
||||
if(it3 != it2->second.end())
|
||||
pCookie = &*it3;
|
||||
}
|
||||
}
|
||||
|
||||
return pCookie;
|
||||
}
|
||||
|
||||
void CCookieMgr::MatchCookiesNoLock(CCookieSet& cookies, LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure)
|
||||
{
|
||||
CCookieDomainMapCI it = m_cookies.find(lpszDomain);
|
||||
if(it != m_cookies.end())
|
||||
{
|
||||
CCookiePathMapCI it2 = it->second.find(lpszPath);
|
||||
if(it2 != it->second.end())
|
||||
{
|
||||
for(CCookieSetCI it3 = it2->second.begin(), end3 = it2->second.end(); it3 != end3; ++it3)
|
||||
{
|
||||
const CCookie& cookie = *it3;
|
||||
|
||||
if(!cookie.IsExpired() && (bHttp || !cookie.httpOnly) && (bSecure || !cookie.secure))
|
||||
cookies.emplace(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::SetCookieNoLock(const CCookie& cookie, BOOL bOnlyUpdateValueIfExists)
|
||||
{
|
||||
if(cookie.IsExpired())
|
||||
return DeleteCookieNoLock(cookie);
|
||||
|
||||
CCookieDomainMapI it = m_cookies.find(cookie.domain);
|
||||
|
||||
if(it == m_cookies.end())
|
||||
it = m_cookies.emplace(CCookieDomainMap::value_type(cookie.domain, CCookiePathMap())).first;
|
||||
|
||||
CCookiePathMapI it2 = it->second.find(cookie.path);
|
||||
|
||||
if(it2 == it->second.end())
|
||||
it2 = it->second.emplace(CCookiePathMap::value_type(cookie.path, CCookieSet())).first;
|
||||
|
||||
CCookieSet& cookies = it2->second;
|
||||
CCookieSetI it3 = cookies.find(cookie);
|
||||
|
||||
if(it3 != cookies.end())
|
||||
{
|
||||
if(bOnlyUpdateValueIfExists && !it3->IsExpired() && cookie.IsTransient())
|
||||
{
|
||||
((CCookie*)&*it3)->value = cookie.value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cookies.erase(*it3);
|
||||
}
|
||||
|
||||
return cookies.emplace(cookie).second;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::DeleteCookieNoLock(const CCookie& cookie)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
CCookieDomainMapI it = m_cookies.find(cookie.domain);
|
||||
if(it != m_cookies.end())
|
||||
{
|
||||
CCookiePathMapI it2 = it->second.find(cookie.path);
|
||||
if(it2 != it->second.end())
|
||||
{
|
||||
CCookieSetI it3 = it2->second.find(cookie);
|
||||
if(it3 != it2->second.end())
|
||||
{
|
||||
it2->second.erase(*it3);
|
||||
isOK = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
CCookieSet* CCookieMgr::GetCookieSetNoLock(LPCSTR lpszDomain, LPCSTR lpszPath)
|
||||
{
|
||||
CCookieSet* pCookieSet = nullptr;
|
||||
CCookieDomainMapI it = m_cookies.find(lpszDomain);
|
||||
|
||||
if(it != m_cookies.end())
|
||||
{
|
||||
CCookiePathMapI it2 = it->second.find(lpszPath);
|
||||
if(it2 != it->second.end())
|
||||
pCookieSet = &(it2->second);
|
||||
}
|
||||
|
||||
return pCookieSet;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::LoadDomainAndPath(LPSTR lpszBuff, CStringA& strDomain, CStringA& strPath)
|
||||
{
|
||||
int i = 0;
|
||||
char* lpszCtx = nullptr;
|
||||
|
||||
for(; i < 2; i++)
|
||||
{
|
||||
char* lpszToken = strtok_r(lpszBuff, " \n\r", &lpszCtx);
|
||||
|
||||
if(!lpszToken)
|
||||
{
|
||||
::SetLastError(ERROR_BAD_FORMAT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
strDomain = lpszToken;
|
||||
lpszBuff = nullptr;
|
||||
}
|
||||
else
|
||||
strPath = lpszToken;
|
||||
}
|
||||
|
||||
if(!CCookie::AdjustDomain(strDomain))
|
||||
return FALSE;
|
||||
if(!CCookie::AdjustPath(strPath))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::LoadCookie(LPSTR lpszBuff, LPCSTR lpszDomain, LPCSTR lpszPath, CCookie& cookie)
|
||||
{
|
||||
cookie.domain = lpszDomain;
|
||||
cookie.path = lpszPath;
|
||||
|
||||
int i = 0;
|
||||
char* lpszCtx = nullptr;
|
||||
|
||||
for(; i < 6; i++)
|
||||
{
|
||||
char* lpszToken = strtok_r(lpszBuff, "\t;\n\r", &lpszCtx);
|
||||
|
||||
if(!lpszToken)
|
||||
{
|
||||
::SetLastError(ERROR_BAD_FORMAT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
cookie.name = lpszToken;
|
||||
lpszBuff = nullptr;
|
||||
}
|
||||
else if(i == 1)
|
||||
cookie.value = lpszToken;
|
||||
else if(i == 2)
|
||||
cookie.expires = atoll(lpszToken);
|
||||
else if(i == 3)
|
||||
cookie.httpOnly = (BOOL)atoi(lpszToken);
|
||||
else if(i == 4)
|
||||
cookie.secure = (BOOL)atoi(lpszToken);
|
||||
else if(i == 5)
|
||||
cookie.sameSite = (CCookie::EnSameSite)atoi(lpszToken);
|
||||
}
|
||||
|
||||
cookie.name.Trim();
|
||||
cookie.value.Trim();
|
||||
|
||||
if(cookie.name.IsEmpty() || cookie.expires <= 0 /*|| cookie.httpOnly < 0 || cookie.secure < 0*/ || cookie.sameSite < CCookie::SS_UNKNOWN || cookie.sameSite > CCookie::SS_NONE)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CCookieMgr::AdjustDomainAndPath(LPCSTR& lpszDomain, LPCSTR& lpszPath, CStringA& strDomain, CStringA& strPath, BOOL bKeepNull)
|
||||
{
|
||||
if(!bKeepNull || lpszDomain)
|
||||
{
|
||||
strDomain = lpszDomain;
|
||||
|
||||
if(!CCookie::AdjustDomain(strDomain))
|
||||
return FALSE;
|
||||
|
||||
lpszDomain = (LPCSTR)strDomain;
|
||||
}
|
||||
|
||||
if(!bKeepNull || lpszPath)
|
||||
{
|
||||
strPath = lpszPath;
|
||||
|
||||
if(!CCookie::AdjustPath(strPath))
|
||||
return FALSE;
|
||||
|
||||
lpszPath = (LPCSTR)strPath;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CCookieMgr::CCookieMgr(BOOL bEnableThirdPartyCookie)
|
||||
: m_bEnableThirdPartyCookie(bEnableThirdPartyCookie)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/hpsocket/HPTypeDef.h"
|
||||
#include "common/GeneralHelper.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
#define COOKIE_DOMAIN "domain"
|
||||
#define COOKIE_PATH "path"
|
||||
#define COOKIE_EXPIRES "expires"
|
||||
#define COOKIE_MAX_AGE "Max-Age"
|
||||
#define COOKIE_HTTPONLY "HttpOnly"
|
||||
#define COOKIE_SECURE "secure"
|
||||
#define COOKIE_SAMESITE "SameSite"
|
||||
#define COOKIE_SAMESITE_STRICT "Strict"
|
||||
#define COOKIE_SAMESITE_LAX "Lax"
|
||||
#define COOKIE_SAMESITE_NONE "None"
|
||||
#define COOKIE_DEFAULT_PATH "/"
|
||||
#define COOKIE_FIELD_SEP ";"
|
||||
#define COOKIE_DOMAIN_SEP_CHAR '.'
|
||||
#define COOKIE_PATH_SEP_CHAR '/'
|
||||
#define COOKIE_KV_SEP_CHAR '='
|
||||
|
||||
class CCookie
|
||||
{
|
||||
public:
|
||||
enum EnSameSite
|
||||
{
|
||||
SS_UNKNOWN = 0,
|
||||
SS_STRICT = 1,
|
||||
SS_LAX = 2,
|
||||
SS_NONE = 3
|
||||
};
|
||||
|
||||
CStringA name;
|
||||
CStringA value;
|
||||
CStringA domain;
|
||||
CStringA path;
|
||||
__time64_t expires;
|
||||
BOOL httpOnly;
|
||||
BOOL secure;
|
||||
EnSameSite sameSite;
|
||||
|
||||
CCookie(LPCSTR lpszName = nullptr, LPCSTR lpszValue = nullptr, LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, EnSameSite enSameSite = SS_UNKNOWN)
|
||||
: name (lpszName)
|
||||
, value (lpszValue)
|
||||
, domain (lpszDomain)
|
||||
, path (lpszPath)
|
||||
, expires (MaxAgeToExpires(iMaxAge))
|
||||
, httpOnly (bHttpOnly)
|
||||
, secure (bSecure)
|
||||
, sameSite (enSameSite)
|
||||
{
|
||||
AdjustDomain(domain);
|
||||
AdjustPath(path);
|
||||
}
|
||||
|
||||
static __time64_t CurrentUTCTime() {return _time64(nullptr);}
|
||||
static __time64_t MaxAgeToExpires(int iMaxAge) {return iMaxAge > 0 ? _time64(nullptr) + iMaxAge : (iMaxAge < 0 ? -1 : 0);}
|
||||
static int ExpiresToMaxAge(__time64_t tmExpires) {if(tmExpires < 0) return -1; __time64_t tmDiff = tmExpires - _time64(nullptr); return (tmDiff > 0 ? (int)tmDiff : 0);}
|
||||
|
||||
static __time64_t GetUTCTime(tm& t, int iSecondOffsetTZ);
|
||||
static void ParseFieldKV(const CStringA& strField, CStringA& strKey, CStringA& strVal, char chSep);
|
||||
static BOOL ParseExpires(LPCSTR lpszExpires, __time64_t& tmExpires);
|
||||
static BOOL AdjustDomain(CStringA& strDomain, LPCSTR lpszDefaultDomain = nullptr);
|
||||
static BOOL AdjustPath(CStringA& strPath, LPCSTR lpszDefaultPath = nullptr);
|
||||
static CStringA MakeExpiresStr(__time64_t tmExpires);
|
||||
static BOOL MakeExpiresStr(char lpszBuff[], int& iBuffLen, __time64_t tmExpires);
|
||||
static CCookie* FromString(const CStringA& strCookie, LPCSTR lpszDefaultDomain = nullptr, LPCSTR lpszDefaultPath = nullptr);
|
||||
static CStringA ToString(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, EnSameSite enSameSite = SS_UNKNOWN);
|
||||
static BOOL ToString(char lpszBuff[], int& iBuffLen, LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, EnSameSite enSameSite = SS_UNKNOWN);
|
||||
|
||||
CStringA ToString();
|
||||
BOOL Match(LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure);
|
||||
BOOL IsSameDomain(LPCSTR lpszDomain);
|
||||
|
||||
BOOL IsTransient() const {return expires < 0;}
|
||||
BOOL IsExpired() const {return !IsTransient() && expires <= _time64(nullptr);}
|
||||
BOOL IsValid() const {return !name.IsEmpty() && !domain.IsEmpty() && !path.IsEmpty();}
|
||||
};
|
||||
|
||||
struct ccookie_hash_func
|
||||
{
|
||||
struct hash
|
||||
{
|
||||
size_t operator() (const CCookie& c) const
|
||||
{
|
||||
return hash_value((LPCSTR)(c.name));
|
||||
}
|
||||
};
|
||||
|
||||
struct equal_to
|
||||
{
|
||||
bool operator () (const CCookie& cA, const CCookie& cB) const
|
||||
{
|
||||
return (cA.name == cB.name);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
typedef unordered_set<const CCookie*> CCookiePtrSet;
|
||||
typedef CCookiePtrSet::const_iterator CCookiePtrSetCI;
|
||||
typedef CCookiePtrSet::iterator CCookiePtrSetI;
|
||||
|
||||
typedef unordered_set<CCookie,
|
||||
ccookie_hash_func::hash, ccookie_hash_func::equal_to> CCookieSet;
|
||||
typedef CCookieSet::const_iterator CCookieSetCI;
|
||||
typedef CCookieSet::iterator CCookieSetI;
|
||||
|
||||
typedef unordered_map<CStringA, CCookieSet,
|
||||
cstringa_hash_func::hash, cstringa_hash_func::equal_to> CCookiePathMap;
|
||||
typedef CCookiePathMap::const_iterator CCookiePathMapCI;
|
||||
typedef CCookiePathMap::iterator CCookiePathMapI;
|
||||
|
||||
typedef unordered_map<CStringA, CCookiePathMap,
|
||||
cstringa_nc_hash_func::hash, cstringa_nc_hash_func::equal_to> CCookieDomainMap;
|
||||
typedef CCookieDomainMap::const_iterator CCookieDomainMapCI;
|
||||
typedef CCookieDomainMap::iterator CCookieDomainMapI;
|
||||
|
||||
class CCookieMgr
|
||||
{
|
||||
public:
|
||||
BOOL LoadFromFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE);
|
||||
BOOL SaveToFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE);
|
||||
|
||||
BOOL ClearCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr);
|
||||
BOOL RemoveExpiredCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr);
|
||||
|
||||
BOOL GetCookies(CCookieSet& cookies, LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure);
|
||||
BOOL SetCookie(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, CCookie::EnSameSite enSameSite = CCookie::SS_UNKNOWN, BOOL bOnlyUpdateValueIfExists = TRUE);
|
||||
BOOL SetCookie(const CStringA& strCookie, BOOL bOnlyUpdateValueIfExists = TRUE);
|
||||
BOOL SetCookie(const CCookie& cookie, BOOL bOnlyUpdateValueIfExists = TRUE);
|
||||
BOOL DeleteCookie(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName);
|
||||
BOOL DeleteCookie(const CCookie& cookie);
|
||||
|
||||
private:
|
||||
void ClearDomainCookiesNoLock(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr);
|
||||
void ClearPathCookiesNoLock(CCookiePathMap& paths, LPCSTR lpszPath = nullptr);
|
||||
void RemoveExpiredCookiesNoLock(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr);
|
||||
void RemoveDomainExpiredCookiesNoLock(CCookiePathMap& paths, LPCSTR lpszPath = nullptr);
|
||||
void RemovePathExpiredCookiesNoLock(CCookieSet& cookies);
|
||||
const CCookie* GetCookieNoLock(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName);
|
||||
const CCookie* GetCookieNoLock(const CCookie& cookie);
|
||||
void MatchCookiesNoLock(CCookieSet& cookies, LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp = TRUE, BOOL bSecure = FALSE);
|
||||
BOOL SetCookieNoLock(const CCookie& cookie, BOOL bOnlyUpdateValueIfExists = TRUE);
|
||||
BOOL DeleteCookieNoLock(const CCookie& cookie);
|
||||
CCookieSet* GetCookieSetNoLock(LPCSTR lpszDomain, LPCSTR lpszPath);
|
||||
|
||||
private:
|
||||
static BOOL LoadDomainAndPath(LPSTR lpszBuff, CStringA& strDomain, CStringA& strPath);
|
||||
static BOOL LoadCookie(LPSTR lpszBuff, LPCSTR lpszDomain, LPCSTR lpszPath, CCookie& cookie);
|
||||
static BOOL AdjustDomainAndPath(LPCSTR& lpszDomain, LPCSTR& lpszPath, CStringA& strDomain, CStringA& strPath, BOOL bKeepNull = TRUE);
|
||||
|
||||
public:
|
||||
CCookieMgr(BOOL bEnableThirdPartyCookie = TRUE);
|
||||
|
||||
void SetEnableThirdPartyCookie (BOOL bEnableThirdPartyCookie = TRUE) {m_bEnableThirdPartyCookie = bEnableThirdPartyCookie;}
|
||||
BOOL IsEnableThirdPartyCookie () {return m_bEnableThirdPartyCookie;}
|
||||
|
||||
private:
|
||||
CSimpleRWLock m_cs;
|
||||
CCookieDomainMap m_cookies;
|
||||
BOOL m_bEnableThirdPartyCookie;
|
||||
};
|
||||
|
||||
extern CCookieMgr g_CookieMgr;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HttpHelper.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult)
|
||||
{
|
||||
strResult.Format("HTTP/%d.%d", LOBYTE(enVersion), HIBYTE(enVersion));
|
||||
return strResult;
|
||||
}
|
||||
|
||||
CStringA& AdjustRequestPath(BOOL bConnect, LPCSTR lpszPath, CStringA& strPath)
|
||||
{
|
||||
strPath = lpszPath;
|
||||
|
||||
if(strPath.IsEmpty() || (!bConnect && strPath.GetAt(0) != HTTP_PATH_SEPARATOR_CHAR))
|
||||
strPath.Insert(0, HTTP_PATH_SEPARATOR_CHAR);
|
||||
|
||||
return strPath;
|
||||
}
|
||||
|
||||
LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode)
|
||||
{
|
||||
switch(enCode)
|
||||
{
|
||||
case HSC_CONTINUE : return "Continue";
|
||||
case HSC_SWITCHING_PROTOCOLS : return "Switching Protocols";
|
||||
case HSC_PROCESSING : return "Processing";
|
||||
case HSC_EARLY_HINTS : return "Early Hints";
|
||||
case HSC_RESPONSE_IS_STALE : return "Response Is Stale";
|
||||
case HSC_REVALIDATION_FAILED : return "Revalidation Failed";
|
||||
case HSC_DISCONNECTED_OPERATION : return "Disconnected Operation";
|
||||
case HSC_HEURISTIC_EXPIRATION : return "Heuristic Expiration";
|
||||
case HSC_MISCELLANEOUS_WARNING : return "Miscellaneous Warning";
|
||||
|
||||
case HSC_OK : return "OK";
|
||||
case HSC_CREATED : return "Created";
|
||||
case HSC_ACCEPTED : return "Accepted";
|
||||
case HSC_NON_AUTHORITATIVE_INFORMATION : return "Non-Authoritative Information";
|
||||
case HSC_NO_CONTENT : return "No Content";
|
||||
case HSC_RESET_CONTENT : return "Reset Content";
|
||||
case HSC_PARTIAL_CONTENT : return "Partial Content";
|
||||
case HSC_MULTI_STATUS : return "Multi-Status";
|
||||
case HSC_ALREADY_REPORTED : return "Already Reported";
|
||||
case HSC_TRANSFORMATION_APPLIED : return "Transformation Applied";
|
||||
case HSC_IM_USED : return "IM Used";
|
||||
case HSC_MISCELLANEOUS_PERSISTENT_WARNING : return "Miscellaneous Persistent Warning";
|
||||
|
||||
case HSC_MULTIPLE_CHOICES : return "Multiple Choices";
|
||||
case HSC_MOVED_PERMANENTLY : return "Moved Permanently";
|
||||
case HSC_MOVED_TEMPORARILY : return "Move temporarily";
|
||||
case HSC_SEE_OTHER : return "See Other";
|
||||
case HSC_NOT_MODIFIED : return "Not Modified";
|
||||
case HSC_USE_PROXY : return "Use Proxy";
|
||||
case HSC_SWITCH_PROXY : return "Switch Proxy";
|
||||
case HSC_TEMPORARY_REDIRECT : return "Temporary Redirect";
|
||||
case HSC_PERMANENT_REDIRECT : return "Permanent Redirect";
|
||||
|
||||
case HSC_BAD_REQUEST : return "Bad Request";
|
||||
case HSC_UNAUTHORIZED : return "Unauthorized";
|
||||
case HSC_PAYMENT_REQUIRED : return "Payment Required";
|
||||
case HSC_FORBIDDEN : return "Forbidden";
|
||||
case HSC_NOT_FOUND : return "Not Found";
|
||||
case HSC_METHOD_NOT_ALLOWED : return "Method Not Allowed";
|
||||
case HSC_NOT_ACCEPTABLE : return "Not Acceptable";
|
||||
case HSC_PROXY_AUTHENTICATION_REQUIRED : return "Proxy Authentication Required";
|
||||
case HSC_REQUEST_TIMEOUT : return "Request Timeout";
|
||||
case HSC_CONFLICT : return "Conflict";
|
||||
case HSC_GONE : return "Gone";
|
||||
case HSC_LENGTH_REQUIRED : return "Length Required";
|
||||
case HSC_PRECONDITION_FAILED : return "Precondition Failed";
|
||||
case HSC_REQUEST_ENTITY_TOO_LARGE : return "Request Entity Too Large";
|
||||
case HSC_REQUEST_URI_TOO_LONG : return "Request-URI Too Long";
|
||||
case HSC_UNSUPPORTED_MEDIA_TYPE : return "Unsupported Media Type";
|
||||
case HSC_REQUESTED_RANGE_NOT_SATISFIABLE : return "Requested Range Not Satisfiable";
|
||||
case HSC_EXPECTATION_FAILED : return "Expectation Failed";
|
||||
case HSC_IM_A_TEAPOT : return "I'm a teapot";
|
||||
case HSC_PAGE_EXPIRED : return "Page Expired";
|
||||
case HSC_ENHANCE_YOUR_CALM : return "Enhance Your Calm";
|
||||
case HSC_MISDIRECTED_REQUEST : return "Misdirected Request";
|
||||
case HSC_UNPROCESSABLE_ENTITY : return "Unprocessable Entity";
|
||||
case HSC_LOCKED : return "Locked";
|
||||
case HSC_FAILED_DEPENDENCY : return "Failed Dependency";
|
||||
case HSC_UNORDERED_COLLECTION : return "Unordered Collection";
|
||||
case HSC_UPGRADE_REQUIRED : return "Upgrade Required";
|
||||
case HSC_PRECONDITION_REQUIRED : return "Precondition Required";
|
||||
case HSC_TOO_MANY_REQUESTS : return "Too Many Requests";
|
||||
case HSC_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL : return "Request Header Fields Too Large Unofficial";
|
||||
case HSC_REQUEST_HEADER_FIELDS_TOO_LARGE : return "Request Header Fields Too Large";
|
||||
case HSC_LOGIN_TIMEOUT : return "Login Timeout";
|
||||
case HSC_NO_RESPONSE : return "No Response";
|
||||
case HSC_RETRY_WITH : return "Retry With";
|
||||
case HSC_BLOCKED_BY_PARENTAL_CONTROL : return "Blocked By Parental Control";
|
||||
case HSC_UNAVAILABLE_FOR_LEGAL_REASONS : return "Unavailable For Legal Reasons";
|
||||
case HSC_CLIENT_CLOSED_LOAD_BALANCED_REQUEST : return "Client Closed Load Balance Request";
|
||||
case HSC_INVALID_X_FORWARDED_FOR : return "Invalid X-Forwarded-For";
|
||||
case HSC_REQUEST_HEADER_TOO_LARGE : return "Request Header Too Large";
|
||||
case HSC_SSL_CERTIFICATE_ERROR : return "SSL Certificate Error";
|
||||
case HSC_SSL_CERTIFICATE_REQUIRED : return "SSL Certificate Required";
|
||||
case HSC_HTTP_REQUEST_SENT_TO_HTTPS_PORT : return "HTTP Request Sent To HTTPS Port";
|
||||
case HSC_INVALID_TOKEN : return "Invalid Token";
|
||||
case HSC_CLIENT_CLOSED_REQUEST : return "Client Closed Request";
|
||||
|
||||
case HSC_INTERNAL_SERVER_ERROR : return "Internal Server Error";
|
||||
case HSC_NOT_IMPLEMENTED : return "Not Implemented";
|
||||
case HSC_BAD_GATEWAY : return "Bad Gateway";
|
||||
case HSC_SERVICE_UNAVAILABLE : return "Service Unavailable";
|
||||
case HSC_GATEWAY_TIMEOUT : return "Gateway Timeout";
|
||||
case HSC_HTTP_VERSION_NOT_SUPPORTED : return "HTTP Version Not Supported";
|
||||
case HSC_VARIANT_ALSO_NEGOTIATES : return "Variant Also Negotiates";
|
||||
case HSC_INSUFFICIENT_STORAGE : return "Insufficient Storage";
|
||||
case HSC_LOOP_DETECTED : return "Loop Detected";
|
||||
case HSC_BANDWIDTH_LIMIT_EXCEEDED : return "Bandwidth Limit Exceeded";
|
||||
case HSC_NOT_EXTENDED : return "Not Extended";
|
||||
case HSC_NETWORK_AUTHENTICATION_REQUIRED : return "Network Authentication Required";
|
||||
case HSC_WEB_SERVER_UNKNOWN_ERROR : return "Web Server Unknown Error";
|
||||
case HSC_WEB_SERVER_IS_DOWN : return "Web Server Is Down";
|
||||
case HSC_CONNECTION_TIMEOUT : return "Connection Timeout";
|
||||
case HSC_ORIGIN_IS_UNREACHABLE : return "Origin Is Unreachable";
|
||||
case HSC_TIMEOUT_OCCURED : return "Timeout Occured";
|
||||
case HSC_SSL_HANDSHAKE_FAILED : return "SSL Handshake Failed";
|
||||
case HSC_INVALID_SSL_CERTIFICATE : return "Invalid SSL Certificate";
|
||||
case HSC_RAILGUN_ERROR : return "Railgun Error";
|
||||
case HSC_SITE_IS_OVERLOADED : return "Site Is Overloaded";
|
||||
case HSC_SITE_IS_FROZEN : return "Site Is Frozen";
|
||||
case HSC_IDENTITY_PROVIDER_AUTHENTICATION_ERROR : return "Identity Provider Authentication Error";
|
||||
case HSC_NETWORK_READ_TIMEOUT : return "Network Read Timeout";
|
||||
case HSC_NETWORK_CONNECT_TIMEOUT : return "Network Connect Timeout";
|
||||
|
||||
case HSC_UNPARSEABLE_RESPONSE_HEADERS : return "Unparseable Response Headers";
|
||||
|
||||
default : return "***";
|
||||
}
|
||||
}
|
||||
|
||||
static inline CStringA& AppendHeader(LPCSTR lpszName, LPCSTR lpszValue, CStringA& strValue)
|
||||
{
|
||||
strValue.Append(lpszName);
|
||||
strValue.Append(HTTP_HEADER_SEPARATOR);
|
||||
strValue.Append(lpszValue);
|
||||
strValue.Append(HTTP_CRLF);
|
||||
|
||||
return strValue;
|
||||
}
|
||||
|
||||
void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue)
|
||||
{
|
||||
ASSERT(lpszMethod);
|
||||
|
||||
strValue.Format("%s %s HTTP/%d.%d%s", (LPCSTR)(CStringA(lpszMethod).MakeUpper()), lpszPath, LOBYTE(enVersion), HIBYTE(enVersion), HTTP_CRLF);
|
||||
}
|
||||
|
||||
void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue)
|
||||
{
|
||||
if(!lpszDesc) lpszDesc = ::GetHttpDefaultStatusCodeDesc((EnHttpStatusCode)usStatusCode);
|
||||
strValue.Format("HTTP/%d.%d %d %s%s", LOBYTE(enVersion), HIBYTE(enVersion), usStatusCode, lpszDesc, HTTP_CRLF);
|
||||
}
|
||||
|
||||
void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, const TCookieMap* pCookies, int iBodyLength, BOOL bRequest, int iConnFlag, LPCSTR lpszDefaultHost, USHORT usPort, CStringA& strValue)
|
||||
{
|
||||
unordered_set<LPCSTR, str_nc_hash_func::hash, str_nc_hash_func::equal_to> szHeaderNames;
|
||||
|
||||
if(iHeaderCount > 0)
|
||||
{
|
||||
ASSERT(lpHeaders);
|
||||
|
||||
for(int i = 0; i < iHeaderCount; i++)
|
||||
{
|
||||
const THeader& header = lpHeaders[i];
|
||||
|
||||
ASSERT(!::IsStrEmptyA(header.name));
|
||||
|
||||
if(!::IsStrEmptyA(header.name))
|
||||
{
|
||||
szHeaderNames.emplace(header.name);
|
||||
AppendHeader(header.name, header.value, strValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( (!bRequest || iBodyLength > 0) &&
|
||||
(szHeaderNames.empty() ||
|
||||
(szHeaderNames.find(HTTP_HEADER_CONTENT_LENGTH) == szHeaderNames.end() &&
|
||||
szHeaderNames.find(HTTP_HEADER_TRANSFER_ENCODING) == szHeaderNames.end())))
|
||||
{
|
||||
char szBodyLength[16];
|
||||
itoa(iBodyLength, szBodyLength, 10);
|
||||
|
||||
AppendHeader(HTTP_HEADER_CONTENT_LENGTH, szBodyLength, strValue);
|
||||
}
|
||||
|
||||
if( (iConnFlag == 0 || iConnFlag == 1) &&
|
||||
(szHeaderNames.empty() ||
|
||||
szHeaderNames.find(HTTP_HEADER_CONNECTION) == szHeaderNames.end() ))
|
||||
{
|
||||
LPCSTR lpszValue = iConnFlag == 0 ? HTTP_CONNECTION_CLOSE_VALUE : HTTP_CONNECTION_KEEPALIVE_VALUE;
|
||||
AppendHeader(HTTP_HEADER_CONNECTION, lpszValue, strValue);
|
||||
}
|
||||
|
||||
if( bRequest && !::IsStrEmptyA(lpszDefaultHost) &&
|
||||
(szHeaderNames.empty() ||
|
||||
(szHeaderNames.find(HTTP_HEADER_HOST) == szHeaderNames.end()) ))
|
||||
{
|
||||
CStringA strHost(lpszDefaultHost);
|
||||
if(usPort != 0) strHost.AppendFormat(":%u", usPort);
|
||||
|
||||
AppendHeader(HTTP_HEADER_HOST, strHost, strValue);
|
||||
}
|
||||
|
||||
szHeaderNames.clear();
|
||||
|
||||
if(pCookies != nullptr)
|
||||
{
|
||||
DWORD dwSize = (DWORD)pCookies->size();
|
||||
|
||||
if(dwSize > 0)
|
||||
{
|
||||
strValue.Append(HTTP_HEADER_COOKIE);
|
||||
strValue.Append(HTTP_HEADER_SEPARATOR);
|
||||
|
||||
DWORD dwIndex = 0;
|
||||
|
||||
for(TCookieMapCI it = pCookies->begin(), end = pCookies->end(); it != end; ++it, ++dwIndex)
|
||||
{
|
||||
strValue.Append(it->first);
|
||||
strValue.AppendChar(COOKIE_KV_SEP_CHAR);
|
||||
strValue.Append(it->second);
|
||||
|
||||
if(dwIndex < dwSize - 1)
|
||||
strValue.Append(HTTP_COOKIE_SEPARATOR);
|
||||
}
|
||||
|
||||
strValue.Append(HTTP_CRLF);
|
||||
}
|
||||
}
|
||||
|
||||
strValue.Append(HTTP_CRLF);
|
||||
}
|
||||
|
||||
void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2])
|
||||
{
|
||||
ASSERT(pBody != nullptr || iLength == 0);
|
||||
|
||||
szBuffer[0].buf = (LPBYTE)(LPCSTR)strHeader;
|
||||
szBuffer[0].len = strHeader.GetLength();
|
||||
szBuffer[1].buf = (LPBYTE)pBody;
|
||||
szBuffer[1].len = iLength;
|
||||
}
|
||||
|
||||
int MakeChunkPackage(const BYTE* pData, int iLength, LPCSTR lpszExtensions, char szLen[12], WSABUF bufs[5])
|
||||
{
|
||||
ASSERT(iLength == 0 || pData != nullptr);
|
||||
|
||||
int i = 0;
|
||||
|
||||
if(::IsStrEmptyA(lpszExtensions))
|
||||
{
|
||||
sprintf(szLen, "%x" HTTP_CRLF, iLength);
|
||||
|
||||
bufs[i].buf = (LPBYTE)szLen;
|
||||
bufs[i].len = (int)strlen(szLen);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
LPCSTR lpszSep = lpszExtensions[0] == ';' ? " " : " ;";
|
||||
|
||||
sprintf(szLen, "%x%s", iLength, lpszSep);
|
||||
|
||||
bufs[i].buf = (LPBYTE)szLen;
|
||||
bufs[i].len = (int)strlen(szLen);
|
||||
++i;
|
||||
|
||||
bufs[i].buf = (LPBYTE)lpszExtensions;
|
||||
bufs[i].len = (int)strlen(lpszExtensions);
|
||||
++i;
|
||||
|
||||
bufs[i].buf = (LPBYTE)HTTP_CRLF;
|
||||
bufs[i].len = 2;
|
||||
++i;
|
||||
}
|
||||
|
||||
if(iLength > 0)
|
||||
{
|
||||
bufs[i].buf = (LPBYTE)pData;
|
||||
bufs[i].len = iLength;
|
||||
++i;
|
||||
}
|
||||
|
||||
bufs[i].buf = (LPBYTE)HTTP_CRLF;
|
||||
bufs[i].len = 2;
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
BOOL MakeWSPacket(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], BYTE* pData, int iLength, ULONGLONG ullBodyLen, BYTE szHeader[HTTP_MAX_WS_HEADER_LEN], WSABUF szBuffer[2])
|
||||
{
|
||||
ULONGLONG ullLength = (ULONGLONG)iLength;
|
||||
|
||||
ASSERT(pData != nullptr || iLength == 0);
|
||||
ASSERT(ullBodyLen == 0 || ullBodyLen >= ullLength);
|
||||
|
||||
if(ullBodyLen == 0)
|
||||
ullBodyLen = ullLength;
|
||||
else if(ullBodyLen < ullLength)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TBaseWSHeader bh(szHeader, TRUE);
|
||||
|
||||
int iHeaderLen = HTTP_MIN_WS_HEADER_LEN;
|
||||
|
||||
bh.set_fin(bFinal);
|
||||
bh.set_rsv(iReserved);
|
||||
bh.set_code(iOperationCode);
|
||||
bh.set_mask(lpszMask ? TRUE : FALSE);
|
||||
|
||||
if(ullBodyLen < 126)
|
||||
bh.set_len((BYTE)ullBodyLen);
|
||||
else if(ullBodyLen <= 0xFFFF)
|
||||
{
|
||||
bh.set_len(126);
|
||||
bh.set_extlen((USHORT)ullBodyLen);
|
||||
|
||||
iHeaderLen += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
bh.set_len(127);
|
||||
*(ULONGLONG*)(szHeader + HTTP_MIN_WS_HEADER_LEN) = ::HToN64(ullBodyLen);
|
||||
|
||||
iHeaderLen += 8;
|
||||
}
|
||||
|
||||
if(lpszMask)
|
||||
{
|
||||
memcpy(szHeader + iHeaderLen, lpszMask, 4);
|
||||
|
||||
for(int i = 0; i < iLength; i++)
|
||||
pData[i] = pData[i] ^ lpszMask[i & 0x03];
|
||||
|
||||
iHeaderLen += 4;
|
||||
}
|
||||
|
||||
szBuffer[0].buf = szHeader;
|
||||
szBuffer[0].len = iHeaderLen;
|
||||
szBuffer[1].buf = (LPBYTE)pData;
|
||||
szBuffer[1].len = iLength;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ParseUrl(const CStringA& strUrl, BOOL& bHttps, CStringA& strHost, USHORT& usPort, CStringA& strPath)
|
||||
{
|
||||
int iSchemaLength = (int)strlen(HTTP_SCHEMA);
|
||||
|
||||
if(strnicmp(strUrl, HTTP_SCHEMA, iSchemaLength) == 0)
|
||||
bHttps = FALSE;
|
||||
else
|
||||
{
|
||||
iSchemaLength = (int)strlen(HTTPS_SCHEMA);
|
||||
|
||||
if(strnicmp(strUrl, HTTPS_SCHEMA, iSchemaLength) == 0)
|
||||
bHttps = TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CStringA strFullHost;
|
||||
int i = strUrl.Find(HTTP_PATH_SEPARATOR_CHAR, iSchemaLength);
|
||||
|
||||
if(i > 0)
|
||||
{
|
||||
strFullHost = strUrl.Mid(iSchemaLength, i - iSchemaLength);
|
||||
strPath = strUrl.Mid(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
strFullHost = strUrl.Mid(iSchemaLength);
|
||||
strPath = HTTP_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
if(strFullHost.IsEmpty())
|
||||
return FALSE;
|
||||
|
||||
CStringA strPort;
|
||||
|
||||
char c = strFullHost.GetAt(0);
|
||||
|
||||
if(!::isalnum(c))
|
||||
{
|
||||
if(c != IPV6_ADDR_BEGIN_CHAR)
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
i = strFullHost.ReverseFind(IPV6_ADDR_END_CHAR);
|
||||
|
||||
if(i < 0)
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
if(strFullHost.GetLength() > i + 1)
|
||||
{
|
||||
if(strFullHost.GetAt(i + 1) != PORT_SEPARATOR_CHAR)
|
||||
return FALSE;
|
||||
|
||||
strPort = strFullHost.Mid(i + 2);
|
||||
|
||||
if(strPort.IsEmpty())
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
strHost = strFullHost.Mid(1, i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = strFullHost.Find(PORT_SEPARATOR_CHAR);
|
||||
|
||||
if(i < 0)
|
||||
strHost = strFullHost;
|
||||
else
|
||||
{
|
||||
strPort = strFullHost.Mid(i + 1);
|
||||
|
||||
if(strPort.IsEmpty())
|
||||
return FALSE;
|
||||
|
||||
strHost = strFullHost.Mid(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
if(strPort.IsEmpty())
|
||||
usPort = bHttps ? HTTPS_DEFAULT_PORT : HTTP_DEFAULT_PORT;
|
||||
else
|
||||
usPort = (USHORT)::atoi(strPort);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HttpServer.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::Start(LPCTSTR lpszBindAddress, USHORT usPort)
|
||||
{
|
||||
BOOL isOK = __super::Start(lpszBindAddress, usPort);
|
||||
|
||||
if(isOK) VERIFY(m_thCleaner.Start(this, &CHttpServerT::CleanerThreadProc));
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::CheckParams()
|
||||
{
|
||||
if ((m_enLocalVersion != HV_1_1 && m_enLocalVersion != HV_1_0) ||
|
||||
(m_dwReleaseDelay < MIN_HTTP_RELEASE_DELAY || m_dwReleaseDelay > MAX_HTTP_RELEASE_DELAY))
|
||||
{
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return __super::CheckParams();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpServerT<T, default_port>::PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_objPool.SetHttpObjLockTime(GetFreeSocketObjLockTime());
|
||||
m_objPool.SetHttpObjPoolSize(GetFreeSocketObjPool());
|
||||
m_objPool.SetHttpObjPoolHold(GetFreeSocketObjHold());
|
||||
|
||||
m_objPool.Prepare();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendResponse(CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc, const THeader lpHeaders[], int iHeaderCount, const BYTE* pData, int iLength)
|
||||
{
|
||||
WSABUF szBuffer[2];
|
||||
CStringA strHeader;
|
||||
|
||||
::MakeStatusLine(m_enLocalVersion, usStatusCode, lpszDesc, strHeader);
|
||||
::MakeHeaderLines(lpHeaders, iHeaderCount, nullptr, iLength, FALSE, IsKeepAlive(dwConnID), nullptr, 0, strHeader);
|
||||
::MakeHttpPacket(strHeader, pData, iLength, szBuffer);
|
||||
|
||||
return SendPackets(dwConnID, szBuffer, 2);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, USHORT usStatusCode, LPCSTR lpszDesc, const THeader lpHeaders[], int iHeaderCount)
|
||||
{
|
||||
CFile file;
|
||||
CFileMapping fmap;
|
||||
|
||||
HRESULT hr = ::ReadSmallFile(CA2T(lpszFileName), file, fmap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
::SetLastError(hr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return SendResponse(dwConnID, usStatusCode, lpszDesc, lpHeaders, iHeaderCount, (BYTE*)fmap, (int)fmap.Size());
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendChunkData(CONNID dwConnID, const BYTE* pData, int iLength, LPCSTR lpszExtensions)
|
||||
{
|
||||
char szLen[12];
|
||||
WSABUF bufs[5];
|
||||
|
||||
int iCount = MakeChunkPackage(pData, iLength, lpszExtensions, szLen, bufs);
|
||||
|
||||
return SendPackets(dwConnID, bufs, iCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::Release(CONNID dwConnID)
|
||||
{
|
||||
if(!HasStarted())
|
||||
return FALSE;
|
||||
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr || pHttpObj->HasReleased())
|
||||
return FALSE;
|
||||
|
||||
pHttpObj->Release();
|
||||
|
||||
m_lsDyingQueue.PushBack(TDyingConnection::Construct(dwConnID));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
|
||||
{
|
||||
WSABUF szBuffer[2];
|
||||
BYTE szHeader[HTTP_MAX_WS_HEADER_LEN];
|
||||
|
||||
if(!::MakeWSPacket(bFinal, iReserved, iOperationCode, nullptr, (BYTE*)pData, iLength, ullBodyLen, szHeader, szBuffer))
|
||||
return FALSE;
|
||||
|
||||
return SendPackets(dwConnID, szBuffer, 2);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> UINT CHttpServerT<T, default_port>::CleanerThreadProc(PVOID pv)
|
||||
{
|
||||
TRACE("---------------> Connection Cleaner Thread 0x%08X started <---------------", SELF_THREAD_ID);
|
||||
|
||||
pollfd pfd = {m_evCleaner.GetFD(), POLLIN};
|
||||
DWORD dwInterval = MAX(MIN_HTTP_RELEASE_CHECK_INTERVAL, (m_dwReleaseDelay - MIN_HTTP_RELEASE_DELAY / 2));
|
||||
|
||||
while(HasStarted())
|
||||
{
|
||||
int rs = (int)::PollForSingleObject(pfd, dwInterval);
|
||||
ASSERT(rs >= TIMEOUT);
|
||||
|
||||
if(rs == TIMEOUT)
|
||||
{
|
||||
KillDyingConnection();
|
||||
continue;
|
||||
}
|
||||
|
||||
VERIFY(rs == 1);
|
||||
m_evCleaner.Reset();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseDyingConnection();
|
||||
VERIFY(!HasStarted());
|
||||
|
||||
TRACE("---------------> Connection Cleaner Thread 0x%08X stoped <---------------", SELF_THREAD_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpServerT<T, default_port>::KillDyingConnection()
|
||||
{
|
||||
TDyingConnection* pDyingConn = nullptr;
|
||||
TDyingConnection* pFirstDyingConn = nullptr;
|
||||
DWORD now = ::TimeGetTime();
|
||||
|
||||
while(m_lsDyingQueue.UnsafePeekFront(&pDyingConn))
|
||||
{
|
||||
if((int)(now - pDyingConn->killTime) < (int)m_dwReleaseDelay)
|
||||
break;
|
||||
|
||||
BOOL bDisconnect = TRUE;
|
||||
BOOL bDestruct = TRUE;
|
||||
|
||||
VERIFY(m_lsDyingQueue.UnsafePopFront(&pDyingConn));
|
||||
|
||||
int iPending;
|
||||
if(!GetPendingDataLength(pDyingConn->connID, iPending))
|
||||
bDisconnect = FALSE;
|
||||
else if(iPending > 0)
|
||||
{
|
||||
bDisconnect = FALSE;
|
||||
bDestruct = FALSE;
|
||||
}
|
||||
|
||||
if(bDisconnect)
|
||||
Disconnect(pDyingConn->connID, TRUE);
|
||||
|
||||
if(bDestruct)
|
||||
{
|
||||
TDyingConnection::Destruct(pDyingConn);
|
||||
|
||||
if(pFirstDyingConn == pDyingConn)
|
||||
pFirstDyingConn = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lsDyingQueue.PushBack(pDyingConn);
|
||||
|
||||
if(pFirstDyingConn == nullptr)
|
||||
pFirstDyingConn = pDyingConn;
|
||||
else if(pFirstDyingConn == pDyingConn)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpServerT<T, default_port>::ReleaseDyingConnection()
|
||||
{
|
||||
TDyingConnection* pDyingConn = nullptr;
|
||||
|
||||
while(m_lsDyingQueue.UnsafePopFront(&pDyingConn))
|
||||
TDyingConnection::Destruct(pDyingConn);
|
||||
|
||||
VERIFY(m_lsDyingQueue.IsEmpty());
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::FireAccept(TSocketObj* pSocketObj)
|
||||
{
|
||||
return m_bHttpAutoStart ? __super::FireAccept(pSocketObj) : __super::DoFireAccept(pSocketObj);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireAccept(TSocketObj* pSocketObj)
|
||||
{
|
||||
THttpObj* pHttpObj = DoStartHttp(pSocketObj);
|
||||
EnHandleResult result = __super::DoFireAccept(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
{
|
||||
m_objPool.PutFreeHttpObj(pHttpObj);
|
||||
SetConnectionReserved(pSocketObj, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireHandShake(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
{
|
||||
m_objPool.PutFreeHttpObj(pHttpObj);
|
||||
SetConnectionReserved(pSocketObj, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return DoFireSuperReceive(pSocketObj, pData, iLength);
|
||||
else
|
||||
{
|
||||
if(pHttpObj->HasReleased())
|
||||
return HR_ERROR;
|
||||
|
||||
return pHttpObj->Execute(pData, iLength);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
{
|
||||
m_objPool.PutFreeHttpObj(pHttpObj);
|
||||
SetConnectionReserved(pSocketObj, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireShutdown()
|
||||
{
|
||||
EnHandleResult result = __super::DoFireShutdown();
|
||||
|
||||
m_objPool.Clear();
|
||||
WaitForCleanerThreadEnd();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpServerT<T, default_port>::ReleaseGCSocketObj(BOOL bForce)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_objPool.ReleaseGCHttpObj(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> void CHttpServerT<T, default_port>::WaitForCleanerThreadEnd()
|
||||
{
|
||||
if(m_thCleaner.IsRunning())
|
||||
{
|
||||
m_evCleaner.Set();
|
||||
m_thCleaner.Join();
|
||||
m_evCleaner.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::IsUpgrade(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->IsUpgrade();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::IsKeepAlive(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->IsKeepAlive();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetVersion(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetVersion();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetHost(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetHost();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> ULONGLONG CHttpServerT<T, default_port>::GetContentLength(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetContentLength();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetContentType(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetContentType();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetContentEncoding(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetContentEncoding();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetTransferEncoding(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetTransferEncoding();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> EnHttpUpgradeType CHttpServerT<T, default_port>::GetUpgradeType(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return HUT_NONE;
|
||||
|
||||
return pHttpObj->GetUpgradeType();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetParseErrorCode(lpszErrorDesc);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetHeader(lpszName, lpszValue);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetHeaders(lpszName, lpszValue, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetAllHeaders(lpHeaders, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetAllHeaderNames(lpszName, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetCookie(lpszName, lpszValue);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetAllCookies(lpCookies, dwCount);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetUrlFieldSet(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return 0;
|
||||
|
||||
return pHttpObj->GetUrlFieldSet();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetUrlField(CONNID dwConnID, EnHttpUrlField enField)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetUrlField(enField);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetMethod(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return pHttpObj->GetMethod();
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetWSMessageState(CONNID dwConnID, BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
|
||||
{
|
||||
THttpObj* pHttpObj = FindHttpObj(dwConnID);
|
||||
|
||||
if(pHttpObj == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return pHttpObj->GetWSMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> inline typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::FindHttpObj(CONNID dwConnID)
|
||||
{
|
||||
THttpObj* pHttpObj = nullptr;
|
||||
GetConnectionReserved(dwConnID, (PVOID*)&pHttpObj);
|
||||
|
||||
return pHttpObj;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> inline typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::FindHttpObj(TSocketObj* pSocketObj)
|
||||
{
|
||||
THttpObj* pHttpObj = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pHttpObj);
|
||||
|
||||
return pHttpObj;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::StartHttp(CONNID dwConnID)
|
||||
{
|
||||
if(IsHttpAutoStart())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return StartHttp(pSocketObj);
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::StartHttp(TSocketObj* pSocketObj)
|
||||
{
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CReentrantCriSecLock locallock(pSocketObj->csSend);
|
||||
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
THttpObj* pHttpObj = FindHttpObj(pSocketObj);
|
||||
|
||||
if(pHttpObj != nullptr)
|
||||
{
|
||||
::SetLastError(ERROR_ALREADY_INITIALIZED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoStartHttp(pSocketObj);
|
||||
|
||||
if(!IsSecure())
|
||||
FireHandShake(pSocketObj);
|
||||
else
|
||||
{
|
||||
#ifdef _SSL_SUPPORT
|
||||
if(IsSSLAutoHandShake())
|
||||
StartSSLHandShake(pSocketObj);
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template<class T, USHORT default_port> typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::DoStartHttp(TSocketObj* pSocketObj)
|
||||
{
|
||||
THttpObj* pHttpObj = m_objPool.PickFreeHttpObj(this, pSocketObj);
|
||||
VERIFY(SetConnectionReserved(pSocketObj, pHttpObj));
|
||||
|
||||
return pHttpObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
template class CHttpServerT<CTcpServer, HTTP_DEFAULT_PORT>;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLServer.h"
|
||||
|
||||
template class CHttpServerT<CSSLServer, HTTPS_DEFAULT_PORT>;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpServer.h"
|
||||
#include "HttpHelper.h"
|
||||
#include "common/Thread.h"
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class T, USHORT default_port> class CHttpServerT : public IComplexHttpResponder, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::GetConnectionReserved;
|
||||
using __super::SetConnectionReserved;
|
||||
using __super::SetLastError;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
using __super::SendPackets;
|
||||
using __super::Disconnect;
|
||||
using __super::HasStarted;
|
||||
using __super::GetFreeSocketObjLockTime;
|
||||
using __super::GetFreeSocketObjPool;
|
||||
using __super::GetFreeSocketObjHold;
|
||||
using __super::GetPendingDataLength;
|
||||
|
||||
using __super::IsSecure;
|
||||
using __super::FireHandShake;
|
||||
using __super::FindSocketObj;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
using __super::StartSSLHandShake;
|
||||
using __super::IsSSLAutoHandShake;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
using CCleanThread = CThread<CHttpServerT, VOID, UINT>;
|
||||
using CHttpObjPool = CHttpObjPoolT<TRUE, CHttpServerT, TSocketObj>;
|
||||
using THttpObj = THttpObjT<CHttpServerT, TSocketObj>;
|
||||
|
||||
friend typename CHttpServerT::CCleanThread;
|
||||
friend typename CHttpServerT::THttpObj;
|
||||
|
||||
public:
|
||||
|
||||
virtual BOOL Start(LPCTSTR lpszBindAddress, USHORT usPort);
|
||||
|
||||
virtual BOOL SendResponse(CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc = nullptr, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pData = nullptr, int iLength = 0);
|
||||
virtual BOOL SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, USHORT usStatusCode = HSC_OK, LPCSTR lpszDesc = nullptr, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0);
|
||||
virtual BOOL SendChunkData(CONNID dwConnID, const BYTE* pData = nullptr, int iLength = 0, LPCSTR lpszExtensions = nullptr);
|
||||
|
||||
virtual BOOL Release(CONNID dwConnID);
|
||||
|
||||
virtual BOOL SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0);
|
||||
|
||||
virtual BOOL StartHttp(CONNID dwConnID);
|
||||
|
||||
public:
|
||||
|
||||
virtual void SetHttpAutoStart(BOOL bAutoStart) {ENSURE_HAS_STOPPED(); m_bHttpAutoStart = bAutoStart;}
|
||||
virtual void SetLocalVersion(EnHttpVersion enLocalVersion) {ENSURE_HAS_STOPPED(); m_enLocalVersion = enLocalVersion;}
|
||||
virtual void SetReleaseDelay(DWORD dwReleaseDelay) {ENSURE_HAS_STOPPED(); m_dwReleaseDelay = dwReleaseDelay;}
|
||||
|
||||
virtual BOOL IsHttpAutoStart () {return m_bHttpAutoStart;}
|
||||
virtual EnHttpVersion GetLocalVersion () {return m_enLocalVersion;}
|
||||
virtual DWORD GetReleaseDelay () {return m_dwReleaseDelay;}
|
||||
|
||||
virtual BOOL IsUpgrade(CONNID dwConnID);
|
||||
virtual BOOL IsKeepAlive(CONNID dwConnID);
|
||||
virtual USHORT GetVersion(CONNID dwConnID);
|
||||
virtual LPCSTR GetHost(CONNID dwConnID);
|
||||
virtual ULONGLONG GetContentLength(CONNID dwConnID);
|
||||
virtual LPCSTR GetContentType(CONNID dwConnID);
|
||||
virtual LPCSTR GetContentEncoding(CONNID dwConnID);
|
||||
virtual LPCSTR GetTransferEncoding(CONNID dwConnID);
|
||||
virtual EnHttpUpgradeType GetUpgradeType(CONNID dwConnID);
|
||||
virtual USHORT GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc = nullptr);
|
||||
|
||||
virtual BOOL GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue);
|
||||
virtual BOOL GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount);
|
||||
virtual BOOL GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount);
|
||||
virtual BOOL GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount);
|
||||
|
||||
virtual BOOL GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue);
|
||||
virtual BOOL GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount);
|
||||
|
||||
virtual USHORT GetUrlFieldSet(CONNID dwConnID);
|
||||
virtual LPCSTR GetUrlField(CONNID dwConnID, EnHttpUrlField enField);
|
||||
virtual LPCSTR GetMethod(CONNID dwConnID);
|
||||
|
||||
virtual BOOL GetWSMessageState(CONNID dwConnID, BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain);
|
||||
|
||||
private:
|
||||
BOOL StartHttp(TSocketObj* pSocketObj);
|
||||
THttpObj* DoStartHttp(TSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual EnHandleResult FireAccept(TSocketObj* pSocketObj);
|
||||
virtual EnHandleResult DoFireAccept(TSocketObj* pSocketObj);
|
||||
virtual EnHandleResult DoFireHandShake(TSocketObj* pSocketObj);
|
||||
virtual EnHandleResult DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
virtual EnHandleResult DoFireShutdown();
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
EnHandleResult DoFireSuperReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return __super::DoFireReceive(pSocketObj, pData, iLength);}
|
||||
|
||||
EnHttpParseResult FireMessageBegin(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnMessageBegin((IHttpServer*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireRequestLine(TSocketObj* pSocketObj, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{return m_pListener->OnRequestLine((IHttpServer*)this, pSocketObj->connID, lpszMethod, lpszUrl);}
|
||||
EnHttpParseResult FireStatusLine(TSocketObj* pSocketObj, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{return m_pListener->OnStatusLine((IHttpServer*)this, pSocketObj->connID, usStatusCode, lpszDesc);}
|
||||
EnHttpParseResult FireHeader(TSocketObj* pSocketObj, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{return m_pListener->OnHeader((IHttpServer*)this, pSocketObj->connID, lpszName, lpszValue);}
|
||||
EnHttpParseResult FireHeadersComplete(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnHeadersComplete((IHttpServer*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireBody(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnBody((IHttpServer*)this, pSocketObj->connID, pData, iLength);}
|
||||
EnHttpParseResult FireChunkHeader(TSocketObj* pSocketObj, int iLength)
|
||||
{return m_pListener->OnChunkHeader((IHttpServer*)this, pSocketObj->connID, iLength);}
|
||||
EnHttpParseResult FireChunkComplete(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnChunkComplete((IHttpServer*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireMessageComplete(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnMessageComplete((IHttpServer*)this, pSocketObj->connID);}
|
||||
EnHttpParseResult FireUpgrade(TSocketObj* pSocketObj, EnHttpUpgradeType enUpgradeType)
|
||||
{return m_pListener->OnUpgrade((IHttpServer*)this, pSocketObj->connID, enUpgradeType);}
|
||||
EnHttpParseResult FireParseError(TSocketObj* pSocketObj, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{return m_pListener->OnParseError((IHttpServer*)this, pSocketObj->connID, iErrorCode, lpszErrorDesc);}
|
||||
|
||||
EnHandleResult FireWSMessageHeader(TSocketObj* pSocketObj, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{return m_pListener->OnWSMessageHeader((IHttpServer*)this, pSocketObj->connID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);}
|
||||
EnHandleResult FireWSMessageBody(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnWSMessageBody((IHttpServer*)this, pSocketObj->connID, pData, iLength);}
|
||||
EnHandleResult FireWSMessageComplete(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnWSMessageComplete((IHttpServer*)this, pSocketObj->connID);}
|
||||
|
||||
inline THttpObj* FindHttpObj(CONNID dwConnID);
|
||||
inline THttpObj* FindHttpObj(TSocketObj* pSocketObj);
|
||||
|
||||
CCookieMgr* GetCookieMgr() {return nullptr;}
|
||||
LPCSTR GetRemoteDomain(TSocketObj* pSocketObj) {return nullptr;}
|
||||
|
||||
private:
|
||||
void KillDyingConnection();
|
||||
void ReleaseDyingConnection();
|
||||
|
||||
UINT CleanerThreadProc(PVOID pv = nullptr);
|
||||
void WaitForCleanerThreadEnd();
|
||||
|
||||
public:
|
||||
CHttpServerT(IHttpServerListener* pListener)
|
||||
: T (pListener)
|
||||
, m_pListener (pListener)
|
||||
, m_bHttpAutoStart (TRUE)
|
||||
, m_enLocalVersion (DEFAULT_HTTP_VERSION)
|
||||
, m_dwReleaseDelay (DEFAULT_HTTP_RELEASE_DELAY)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CHttpServerT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
IHttpServerListener* m_pListener;
|
||||
|
||||
CEvt m_evCleaner;
|
||||
CCleanThread m_thCleaner;
|
||||
|
||||
EnHttpVersion m_enLocalVersion;
|
||||
DWORD m_dwReleaseDelay;
|
||||
|
||||
BOOL m_bHttpAutoStart;
|
||||
|
||||
CCASQueue<TDyingConnection> m_lsDyingQueue;
|
||||
|
||||
CHttpObjPool m_objPool;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
typedef CHttpServerT<CTcpServer, HTTP_DEFAULT_PORT> CHttpServer;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLServer.h"
|
||||
|
||||
typedef CHttpServerT<CSSLServer, HTTPS_DEFAULT_PORT> CHttpsServer;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/hpsocket/HPTypeDef.h"
|
||||
|
||||
/************************************************************************
|
||||
名称:全局常量
|
||||
描述:声明组件的公共全局常量
|
||||
************************************************************************/
|
||||
|
||||
/* Socket 缓冲区最小值 */
|
||||
#define MIN_SOCKET_BUFFER_SIZE 8
|
||||
/* 小文件最大字节数 */
|
||||
#define MAX_SMALL_FILE_SIZE 0x3FFFFF
|
||||
/* 最大连接时长 */
|
||||
#define MAX_CONNECTION_PERIOD (MAXINT / 2)
|
||||
/* 处理接收事件时最大读取次数 */
|
||||
#define MAX_CONTINUE_READS 100
|
||||
/* 处理发送事件时最大写入次数 */
|
||||
#define MAX_CONTINUE_WRITES 100
|
||||
|
||||
/* 默认工作队列等待的最大描述符事件数量 */
|
||||
#define DEFAULT_WORKER_MAX_EVENT_COUNT CIODispatcher::DEF_WORKER_MAX_EVENTS
|
||||
|
||||
/* Server/Agent 最大连接数 */
|
||||
#define MAX_CONNECTION_COUNT (5 * 1000 * 1000)
|
||||
/* Server/Agent 默认最大连接数 */
|
||||
#define DEFAULT_CONNECTION_COUNT 10000
|
||||
/* Server/Agent 默认 Socket 对象缓存锁定时间 */
|
||||
#define DEFAULT_FREE_SOCKETOBJ_LOCK_TIME DEFAULT_OBJECT_CACHE_LOCK_TIME
|
||||
/* Server/Agent 默认 Socket 缓存池大小 */
|
||||
#define DEFAULT_FREE_SOCKETOBJ_POOL DEFAULT_OBJECT_CACHE_POOL_SIZE
|
||||
/* Server/Agent 默认 Socket 缓存池回收阀值 */
|
||||
#define DEFAULT_FREE_SOCKETOBJ_HOLD DEFAULT_OBJECT_CACHE_POOL_HOLD
|
||||
/* Server/Agent 默认内存块缓存池大小 */
|
||||
#define DEFAULT_FREE_BUFFEROBJ_POOL DEFAULT_BUFFER_CACHE_POOL_SIZE
|
||||
/* Server/Agent 默认内存块缓存池回收阀值 */
|
||||
#define DEFAULT_FREE_BUFFEROBJ_HOLD DEFAULT_BUFFER_CACHE_POOL_HOLD
|
||||
/* Client 默认内存块缓存池大小 */
|
||||
#define DEFAULT_CLIENT_FREE_BUFFER_POOL_SIZE 60
|
||||
/* Client 默认内存块缓存池回收阀值 */
|
||||
#define DEFAULT_CLIENT_FREE_BUFFER_POOL_HOLD 60
|
||||
/* Client/Agent 默认同步连接超时时间 */
|
||||
#define DEFAULT_SYNC_CONNECT_TIMEOUT 10000
|
||||
/* IPv4 默认绑定地址 */
|
||||
#define DEFAULT_IPV4_BIND_ADDRESS _T("0.0.0.0")
|
||||
/* IPv6 默认绑定地址 */
|
||||
#define DEFAULT_IPV6_BIND_ADDRESS _T("::")
|
||||
/* IPv4 广播地址 */
|
||||
#define DEFAULT_IPV4_BROAD_CAST_ADDRESS _T("255.255.255.255")
|
||||
|
||||
/* TCP 默认通信数据缓冲区大小 */
|
||||
#define DEFAULT_TCP_SOCKET_BUFFER_SIZE DEFAULT_BUFFER_CACHE_CAPACITY
|
||||
/* TCP 默认心跳包间隔 */
|
||||
#define DEFALUT_TCP_KEEPALIVE_TIME (60 * 1000)
|
||||
/* TCP 默认心跳确认包检测间隔 */
|
||||
#define DEFALUT_TCP_KEEPALIVE_INTERVAL (20 * 1000)
|
||||
/* TCP Server 默认 Listen 队列大小 */
|
||||
#define DEFAULT_TCP_SERVER_SOCKET_LISTEN_QUEUE SOMAXCONN
|
||||
|
||||
/* UDP 最大数据报文最大长度 */
|
||||
#define MAXIMUM_UDP_MAX_DATAGRAM_SIZE (16 * DEFAULT_BUFFER_CACHE_CAPACITY)
|
||||
/* UDP 默认数据报文最大长度 */
|
||||
#define DEFAULT_UDP_MAX_DATAGRAM_SIZE 1432
|
||||
/* UDP 默认 Receive 预投递数量 */
|
||||
#define DEFAULT_UDP_POST_RECEIVE_COUNT DEFAULT_WORKER_MAX_EVENT_COUNT
|
||||
/* UDP 默认监测包尝试次数 */
|
||||
#define DEFAULT_UDP_DETECT_ATTEMPTS 3
|
||||
/* UDP 默认监测包发送间隔 */
|
||||
#define DEFAULT_UDP_DETECT_INTERVAL (60 * 1000)
|
||||
|
||||
/* TCP Pack 包长度位数 */
|
||||
#define TCP_PACK_LENGTH_BITS 22
|
||||
/* TCP Pack 包长度掩码 */
|
||||
#define TCP_PACK_LENGTH_MASK 0x3FFFFF
|
||||
/* TCP Pack 包最大长度硬限制 */
|
||||
#define TCP_PACK_MAX_SIZE_LIMIT 0x3FFFFF
|
||||
/* TCP Pack 包默认最大长度 */
|
||||
#define TCP_PACK_DEFAULT_MAX_SIZE 0x040000
|
||||
/* TCP Pack 包头标识值硬限制 */
|
||||
#define TCP_PACK_HEADER_FLAG_LIMIT 0x0003FF
|
||||
/* TCP Pack 包头默认标识值 */
|
||||
#define TCP_PACK_DEFAULT_HEADER_FLAG 0x000000
|
||||
|
||||
/* 默认压缩/解压数据缓冲器长度 */
|
||||
#define DEFAULT_COMPRESS_BUFFER_SIZE (16 * 1024)
|
||||
|
||||
/* 垃圾回收检查间隔(毫秒) */
|
||||
#define GC_CHECK_INTERVAL (15 * 1000)
|
||||
|
||||
#define HOST_SEPARATOR_CHAR '^'
|
||||
#define PORT_SEPARATOR_CHAR ':'
|
||||
#define IPV6_ADDR_BEGIN_CHAR '['
|
||||
#define IPV6_ADDR_END_CHAR ']'
|
||||
#define IPV4_ADDR_SEPARATOR_CHAR '.'
|
||||
#define IPV6_ADDR_SEPARATOR_CHAR ':'
|
||||
#define IPV6_ZONE_INDEX_CHAR '%'
|
||||
|
||||
#define CST_CONNECTING (-1)
|
||||
#define INVALID_SOCKET INVALID_FD
|
||||
#define SOCKET_ERROR HAS_ERROR
|
||||
#define WSASetLastError SetLastError
|
||||
#define WSAGetLastError GetLastError
|
||||
#define InetPton inet_pton
|
||||
#define InetNtop inet_ntop
|
||||
#define closesocket close
|
||||
|
||||
#define ENSURE_STOP() {if(GetState() != SS_STOPPED) {Stop();} Wait();}
|
||||
#define ENSURE_HAS_STOPPED() {ASSERT(GetState() == SS_STOPPED); if(GetState() != SS_STOPPED) return;}
|
||||
#define WAIT_FOR_STOP_PREDICATE [this]() {return GetState() == SS_STOPPED;}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MiscHelper.h"
|
||||
|
||||
BOOL AddPackHeader(const WSABUF * pBuffers, int iCount, unique_ptr<WSABUF[]>& buffers, DWORD dwMaxPackSize, USHORT usPackHeaderFlag, DWORD& dwHeader)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
DWORD iLength = 0;
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
const WSABUF& buf = pBuffers[i];
|
||||
buffers[i + 1] = buf;
|
||||
iLength += buf.len;
|
||||
}
|
||||
|
||||
if(iLength == 0 || iLength > dwMaxPackSize)
|
||||
{
|
||||
::SetLastError(ERROR_BAD_LENGTH);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dwHeader = ::HToLE32((usPackHeaderFlag << TCP_PACK_LENGTH_BITS) | iLength);
|
||||
|
||||
buffers[0].len = sizeof(dwHeader);
|
||||
buffers[0].buf = (LPBYTE)&dwHeader;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
|
||||
/* Pack Data Info */
|
||||
template<typename B = void> struct TPackInfo
|
||||
{
|
||||
bool header;
|
||||
DWORD length;
|
||||
B* pBuffer;
|
||||
|
||||
static TPackInfo* Construct(B* pbuf = nullptr, bool head = true, DWORD len = sizeof(DWORD))
|
||||
{
|
||||
return new TPackInfo(pbuf, head, len);
|
||||
}
|
||||
|
||||
static void Destruct(TPackInfo* pPackInfo)
|
||||
{
|
||||
if(pPackInfo)
|
||||
delete pPackInfo;
|
||||
}
|
||||
|
||||
TPackInfo(B* pbuf = nullptr, bool head = true, DWORD len = sizeof(DWORD))
|
||||
: header(head), length(len), pBuffer(pbuf)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
header = true;
|
||||
length = sizeof(DWORD);
|
||||
pBuffer = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
typedef TPackInfo<TBuffer> TBufferPackInfo;
|
||||
|
||||
BOOL AddPackHeader(const WSABUF * pBuffers, int iCount, unique_ptr<WSABUF[]>& buffers, DWORD dwMaxPackSize, USHORT usPackHeaderFlag, DWORD& dwHeader);
|
||||
|
||||
template<class B> EnFetchResult FetchBuffer(B* pBuffer, BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(pBuffer != nullptr);
|
||||
ASSERT(pData != nullptr && iLength > 0);
|
||||
|
||||
EnFetchResult result = FR_OK;
|
||||
|
||||
if(pBuffer->Length() >= iLength)
|
||||
pBuffer->Fetch(pData, iLength);
|
||||
else
|
||||
result = FR_LENGTH_TOO_LONG;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class B> EnFetchResult PeekBuffer(B* pBuffer, BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(pBuffer != nullptr);
|
||||
ASSERT(pData != nullptr && iLength > 0);
|
||||
|
||||
EnFetchResult result = FR_OK;
|
||||
|
||||
if(pBuffer->Length() >= iLength)
|
||||
pBuffer->Peek(pData, iLength);
|
||||
else
|
||||
result = FR_LENGTH_TOO_LONG;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class B, class S> EnHandleResult ParsePack(T* pThis, TPackInfo<B>* pInfo, B* pBuffer, S* pSocket, DWORD dwMaxPackSize, USHORT usPackHeaderFlag)
|
||||
{
|
||||
EnHandleResult rs = HR_OK;
|
||||
|
||||
int required = pInfo->length;
|
||||
int remain = pBuffer->Length();
|
||||
|
||||
while(remain >= required)
|
||||
{
|
||||
if(pSocket->IsPaused())
|
||||
break;
|
||||
|
||||
remain -= required;
|
||||
CBufferPtr buffer(required);
|
||||
|
||||
pBuffer->Fetch(buffer, (int)buffer.Size());
|
||||
|
||||
if(pInfo->header)
|
||||
{
|
||||
DWORD header = ::HToLE32(*((DWORD*)(BYTE*)buffer));
|
||||
|
||||
if(usPackHeaderFlag != 0)
|
||||
{
|
||||
USHORT flag = (USHORT)(header >> TCP_PACK_LENGTH_BITS);
|
||||
|
||||
if(flag != usPackHeaderFlag)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_DATA);
|
||||
return HR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD len = header & TCP_PACK_LENGTH_MASK;
|
||||
|
||||
if(len == 0 || len > dwMaxPackSize)
|
||||
{
|
||||
::SetLastError(ERROR_BAD_LENGTH);
|
||||
return HR_ERROR;
|
||||
}
|
||||
|
||||
required = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
rs = pThis->DoFireSuperReceive(pSocket, (const BYTE*)buffer, (int)buffer.Size());
|
||||
|
||||
if(rs == HR_ERROR)
|
||||
return rs;
|
||||
|
||||
required = sizeof(DWORD);
|
||||
}
|
||||
|
||||
pInfo->header = !pInfo->header;
|
||||
pInfo->length = required;
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
template<class T, class B, class S> EnHandleResult ParsePack(T* pThis, TPackInfo<B>* pInfo, B* pBuffer, S* pSocket, DWORD dwMaxPackSize, USHORT usPackHeaderFlag, const BYTE* pData, int iLength)
|
||||
{
|
||||
pBuffer->Cat(pData, iLength);
|
||||
|
||||
return ParsePack(pThis, pInfo, pBuffer, pSocket, dwMaxPackSize, usPackHeaderFlag);
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SSLAgent.h"
|
||||
#include "SSLHelper.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
BOOL CSSLAgent::CheckParams()
|
||||
{
|
||||
if(!m_sslCtx.IsValid())
|
||||
{
|
||||
SetLastError(SE_SSL_ENV_NOT_READY, __FUNCTION__, ERROR_NOT_READY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return __super::CheckParams();
|
||||
}
|
||||
|
||||
void CSSLAgent::PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_sslPool.SetItemCapacity (GetSocketBufferSize());
|
||||
m_sslPool.SetItemPoolSize (GetFreeBufferObjPool());
|
||||
m_sslPool.SetItemPoolHold (GetFreeBufferObjHold());
|
||||
m_sslPool.SetSessionLockTime(GetFreeSocketObjLockTime());
|
||||
m_sslPool.SetSessionPoolSize(GetFreeSocketObjPool());
|
||||
m_sslPool.SetSessionPoolHold(GetFreeSocketObjHold());
|
||||
|
||||
m_sslPool.Prepare();
|
||||
}
|
||||
|
||||
void CSSLAgent::Reset()
|
||||
{
|
||||
m_sslPool.Clear();
|
||||
m_sslCtx.RemoveThreadLocalState();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void CSSLAgent::OnWorkerThreadEnd(THR_ID dwThreadID)
|
||||
{
|
||||
m_sslCtx.RemoveThreadLocalState();
|
||||
|
||||
__super::OnWorkerThreadEnd(dwThreadID);
|
||||
}
|
||||
|
||||
void CSSLAgent::ReleaseGCSocketObj(BOOL bForce)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_sslPool.ReleaseGCSession(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL CSSLAgent::SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
TAgentSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
{
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
return ::ProcessSend(this, pSocketObj, pSession, pBuffers, iCount);
|
||||
}
|
||||
|
||||
return DoSendPackets(pSocketObj, pBuffers, iCount);
|
||||
}
|
||||
|
||||
EnHandleResult CSSLAgent::FireConnect(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = DoFireConnect(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR && m_bSSLAutoHandShake)
|
||||
DoSSLHandShake(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EnHandleResult CSSLAgent::FireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
{
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
return ::ProcessReceive(this, pSocketObj, pSession, pData, iLength);
|
||||
}
|
||||
|
||||
return DoFireReceive(pSocketObj, pData, iLength);
|
||||
}
|
||||
|
||||
EnHandleResult CSSLAgent::FireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
m_sslPool.PutFreeSession(pSession);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL CSSLAgent::StartSSLHandShake(CONNID dwConnID)
|
||||
{
|
||||
if(IsSSLAutoHandShake())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TAgentSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return StartSSLHandShake(pSocketObj);
|
||||
}
|
||||
|
||||
BOOL CSSLAgent::StartSSLHandShake(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CReentrantCriSecLock locallock(pSocketObj->csSend);
|
||||
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
{
|
||||
::SetLastError(ERROR_ALREADY_INITIALIZED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoSSLHandShake(pSocketObj);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CSSLAgent::DoSSLHandShake(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
CSSLSession* pSession = m_sslPool.PickFreeSession(pSocketObj->host);
|
||||
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
|
||||
ENSURE(SetConnectionReserved2(pSocketObj, pSession));
|
||||
ENSURE(::ProcessHandShake(this, pSocketObj, pSession) == HR_OK);
|
||||
}
|
||||
|
||||
BOOL CSSLAgent::GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo)
|
||||
{
|
||||
ASSERT(lppInfo != nullptr);
|
||||
|
||||
*lppInfo = nullptr;
|
||||
TAgentSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession == nullptr || !pSession->IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pSession->GetSessionInfo(enInfo, lppInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpAgent.h"
|
||||
#include "SSLHelper.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
class CSSLAgent : public CTcpAgent
|
||||
{
|
||||
using __super = CTcpAgent;
|
||||
|
||||
public:
|
||||
using __super::Wait;
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure() {return TRUE;}
|
||||
virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount);
|
||||
|
||||
virtual BOOL SetupSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr)
|
||||
{return m_sslCtx.Initialize(SSL_SM_CLIENT, iVerifyMode, FALSE, (LPVOID)lpszPemCertFile, (LPVOID)lpszPemKeyFile, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCertFileOrPath, nullptr);}
|
||||
|
||||
virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr)
|
||||
{return m_sslCtx.Initialize(SSL_SM_CLIENT, iVerifyMode, TRUE, (LPVOID)lpszPemCert, (LPVOID)lpszPemKey, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCert, nullptr);}
|
||||
|
||||
|
||||
virtual void CleanupSSLContext()
|
||||
{m_sslCtx.Cleanup();}
|
||||
|
||||
virtual BOOL StartSSLHandShake(CONNID dwConnID);
|
||||
|
||||
public:
|
||||
virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) {ENSURE_HAS_STOPPED(); m_bSSLAutoHandShake = bAutoHandShake;}
|
||||
virtual void SetSSLCipherList (LPCTSTR lpszCipherList){ENSURE_HAS_STOPPED(); m_sslCtx.SetCipherList(lpszCipherList);}
|
||||
virtual BOOL IsSSLAutoHandShake () {return m_bSSLAutoHandShake;}
|
||||
virtual LPCTSTR GetSSLCipherList() {return m_sslCtx.GetCipherList();}
|
||||
|
||||
virtual BOOL GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo);
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FireConnect(TAgentSocketObj* pSocketObj);
|
||||
virtual EnHandleResult FireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult FireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadEnd(THR_ID dwThreadID);
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
protected:
|
||||
virtual BOOL StartSSLHandShake(TAgentSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
void DoSSLHandShake(TAgentSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
friend EnHandleResult ProcessHandShake<>(CSSLAgent* pThis, TAgentSocketObj* pSocketObj, CSSLSession* pSession);
|
||||
friend EnHandleResult ProcessReceive<>(CSSLAgent* pThis, TAgentSocketObj* pSocketObj, CSSLSession* pSession, const BYTE* pData, int iLength);
|
||||
friend BOOL ProcessSend<>(CSSLAgent* pThis, TAgentSocketObj* pSocketObj, CSSLSession* pSession, const WSABUF * pBuffers, int iCount);
|
||||
|
||||
public:
|
||||
CSSLAgent(ITcpAgentListener* pListener)
|
||||
: CTcpAgent(pListener)
|
||||
, m_sslPool(m_sslCtx)
|
||||
, m_bSSLAutoHandShake(TRUE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CSSLAgent()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL m_bSSLAutoHandShake;
|
||||
|
||||
CSSLContext m_sslCtx;
|
||||
CSSLSessionPool m_sslPool;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SSLClient.h"
|
||||
#include "SSLHelper.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
BOOL CSSLClient::CheckParams()
|
||||
{
|
||||
if(!m_sslCtx.IsValid())
|
||||
{
|
||||
SetLastError(SE_SSL_ENV_NOT_READY, __FUNCTION__, ERROR_NOT_READY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return __super::CheckParams();
|
||||
}
|
||||
|
||||
void CSSLClient::PrepareStart()
|
||||
{
|
||||
m_dwMainThreadID = SELF_THREAD_ID;
|
||||
|
||||
__super::PrepareStart();
|
||||
}
|
||||
|
||||
void CSSLClient::Reset()
|
||||
{
|
||||
m_sslSession.Reset();
|
||||
|
||||
if(m_dwMainThreadID != 0)
|
||||
{
|
||||
m_sslCtx.RemoveThreadLocalState(m_dwMainThreadID);
|
||||
m_dwMainThreadID = 0;
|
||||
}
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void CSSLClient::OnWorkerThreadEnd(THR_ID dwThreadID)
|
||||
{
|
||||
m_sslCtx.RemoveThreadLocalState();
|
||||
|
||||
__super::OnWorkerThreadEnd(dwThreadID);
|
||||
}
|
||||
|
||||
BOOL CSSLClient::SendPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
if(m_sslSession.IsValid())
|
||||
return ::ProcessSend(this, this, &m_sslSession, pBuffers, iCount);
|
||||
else
|
||||
return DoSendPackets(this, pBuffers, iCount);
|
||||
}
|
||||
|
||||
EnHandleResult CSSLClient::FireConnect()
|
||||
{
|
||||
EnHandleResult result = DoFireConnect(this);
|
||||
|
||||
if(result != HR_ERROR && m_bSSLAutoHandShake)
|
||||
DoSSLHandShake();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EnHandleResult CSSLClient::FireReceive(const BYTE* pData, int iLength)
|
||||
{
|
||||
if(m_sslSession.IsValid())
|
||||
return ::ProcessReceive(this, this, &m_sslSession, pData, iLength);
|
||||
else
|
||||
return DoFireReceive(this, pData, iLength);
|
||||
}
|
||||
|
||||
BOOL CSSLClient::StartSSLHandShake()
|
||||
{
|
||||
if(IsSSLAutoHandShake())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return StartSSLHandShakeNoCheck();
|
||||
}
|
||||
|
||||
BOOL CSSLClient::StartSSLHandShakeNoCheck()
|
||||
{
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CCriSecLock locallock(m_sslSession.GetSendLock());
|
||||
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(m_sslSession.IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_ALREADY_INITIALIZED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoSSLHandShake();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CSSLClient::DoSSLHandShake()
|
||||
{
|
||||
m_sslSession.Renew(m_sslCtx, m_strHost);
|
||||
ENSURE(::ProcessHandShake(this, this, &m_sslSession) == HR_OK);
|
||||
}
|
||||
|
||||
BOOL CSSLClient::GetSSLSessionInfo(EnSSLSessionInfo enInfo, LPVOID* lppInfo)
|
||||
{
|
||||
if(!m_sslSession.IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return m_sslSession.GetSessionInfo(enInfo, lppInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpClient.h"
|
||||
#include "SSLHelper.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
class CSSLClient : public CTcpClient
|
||||
{
|
||||
using __super = CTcpClient;
|
||||
|
||||
public:
|
||||
using __super::Wait;
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure() {return TRUE;}
|
||||
virtual BOOL SendPackets(const WSABUF pBuffers[], int iCount);
|
||||
|
||||
virtual BOOL SetupSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr)
|
||||
{return m_sslCtx.Initialize(SSL_SM_CLIENT, iVerifyMode, FALSE, (LPVOID)lpszPemCertFile, (LPVOID)lpszPemKeyFile, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCertFileOrPath, nullptr);}
|
||||
|
||||
virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr)
|
||||
{return m_sslCtx.Initialize(SSL_SM_CLIENT, iVerifyMode, TRUE, (LPVOID)lpszPemCert, (LPVOID)lpszPemKey, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCert, nullptr);}
|
||||
|
||||
virtual void CleanupSSLContext()
|
||||
{m_sslCtx.Cleanup();}
|
||||
|
||||
virtual BOOL StartSSLHandShake();
|
||||
|
||||
public:
|
||||
virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) {ENSURE_HAS_STOPPED(); m_bSSLAutoHandShake = bAutoHandShake;}
|
||||
virtual void SetSSLCipherList (LPCTSTR lpszCipherList){ENSURE_HAS_STOPPED(); m_sslCtx.SetCipherList(lpszCipherList);}
|
||||
virtual BOOL IsSSLAutoHandShake () {return m_bSSLAutoHandShake;}
|
||||
virtual LPCTSTR GetSSLCipherList() {return m_sslCtx.GetCipherList();}
|
||||
|
||||
virtual BOOL GetSSLSessionInfo(EnSSLSessionInfo enInfo, LPVOID* lppInfo);
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FireConnect();
|
||||
virtual EnHandleResult FireReceive(const BYTE* pData, int iLength);
|
||||
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadEnd(THR_ID dwThreadID);
|
||||
|
||||
protected:
|
||||
virtual BOOL StartSSLHandShakeNoCheck();
|
||||
|
||||
private:
|
||||
void DoSSLHandShake();
|
||||
|
||||
private:
|
||||
friend EnHandleResult ProcessHandShake<>(CSSLClient* pThis, CSSLClient* pSocketObj, CSSLSession* pSession);
|
||||
friend EnHandleResult ProcessReceive<>(CSSLClient* pThis, CSSLClient* pSocketObj, CSSLSession* pSession, const BYTE* pData, int iLength);
|
||||
friend BOOL ProcessSend<>(CSSLClient* pThis, CSSLClient* pSocketObj, CSSLSession* pSession, const WSABUF * pBuffers, int iCount);
|
||||
|
||||
public:
|
||||
CSSLClient(ITcpClientListener* pListener)
|
||||
: CTcpClient (pListener)
|
||||
, m_sslSession (m_itPool)
|
||||
, m_dwMainThreadID (0)
|
||||
, m_bSSLAutoHandShake (TRUE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CSSLClient()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
THR_ID m_dwMainThreadID;
|
||||
BOOL m_bSSLAutoHandShake;
|
||||
|
||||
CSSLContext m_sslCtx;
|
||||
CSSLSession m_sslSession;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/hpsocket/HPTypeDef.h"
|
||||
#include "common/BufferPool.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "openssl/ssl.h"
|
||||
|
||||
#define OPENSSL_VERSION_1_0_2 0x10002000L
|
||||
#define OPENSSL_VERSION_1_1_0 0x10100000L
|
||||
#define OPENSSL_VERSION_3_0_0 0x30000000L
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
|
||||
#define DEFAULT_CIPHER_LIST _T("DEFAULT:!aNULL:!eNULL:!SSLv2")
|
||||
#else
|
||||
#define DEFAULT_CIPHER_LIST _T("DEFAULT:!aNULL:!eNULL:!SSLv2:!SSLv3")
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_0
|
||||
#define FN_X509_NAME_HASH X509_NAME_hash
|
||||
#else
|
||||
inline unsigned long FN_X509_NAME_HASH(const X509_NAME *x) {return X509_NAME_hash_ex(x, nullptr, nullptr, nullptr);}
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
名称:SSL 全局常量
|
||||
描述:声明 SSL 组件的公共全局常量
|
||||
************************************************************************/
|
||||
|
||||
#define SSL_DOMAIN_SEP_CHAR '.'
|
||||
|
||||
/************************************************************************
|
||||
名称:SSL 握手状态
|
||||
描述:标识当前连接的 SSL 握手状态
|
||||
************************************************************************/
|
||||
enum EnSSLHandShakeStatus
|
||||
{
|
||||
SSL_HSS_INIT = 0, // 初始状态
|
||||
SSL_HSS_PROC = 1, // 正在握手
|
||||
SSL_HSS_SUCC = 2, // 握手成功
|
||||
};
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
|
||||
|
||||
/* SSL CRYPTO DYNLOCK 结构 */
|
||||
typedef struct CRYPTO_dynlock_value
|
||||
{
|
||||
CSimpleRWLock cs;
|
||||
} DynamicLock;
|
||||
|
||||
#endif
|
||||
|
||||
class CSSLInitializer
|
||||
{
|
||||
public:
|
||||
|
||||
static void CleanupThreadState(THR_ID dwThreadID = 0);
|
||||
|
||||
private:
|
||||
|
||||
CSSLInitializer();
|
||||
~CSSLInitializer();
|
||||
|
||||
private:
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
|
||||
static void ssl_lock_callback(int mode, int n, const char *file, int line);
|
||||
static CRYPTO_dynlock_value* ssl_lock_dyn_create_callback(const char *file, int line);
|
||||
static void ssl_lock_dyn_callback(int mode, CRYPTO_dynlock_value* l, const char *file, int line);
|
||||
static void ssl_lock_dyn_destroy_callback(CRYPTO_dynlock_value* l, const char *file, int line);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
|
||||
static int sm_iLockNum;
|
||||
static CSimpleRWLock* sm_pcsLocks;
|
||||
#endif
|
||||
|
||||
static CSSLInitializer sm_instance;
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
名称:SSL Context
|
||||
描述:初始化和清理 SSL 运行环境
|
||||
************************************************************************/
|
||||
class CSSLContext
|
||||
{
|
||||
typedef unordered_map<CString, int, cstring_nc_hash_func::hash, cstring_nc_hash_func::equal_to> CServerNameMap;
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* 名称:初始化 SSL 环境参数
|
||||
* 描述:SSL 环境参数必须在 SSL 通信组件启动前完成初始化,否则启动失败
|
||||
*
|
||||
* 参数: enSessionMode -- SSL 工作模式(参考 EnSSLSessionMode)
|
||||
* iVerifyMode -- SSL 验证模式(参考 EnSSLVerifyMode)
|
||||
* lpPemCert -- 证书文件(客户端可选)
|
||||
* lpPemKey -- 私钥文件(客户端可选)
|
||||
* lpKeyPasswod -- 私钥密码(没有密码则为空)
|
||||
* lpCAPemCert -- CA 证书文件或目录(单向验证或客户端可选)
|
||||
* fnServerNameCallback -- SNI 回调函数指针(可选,只用于服务端,如果为 nullptr 则使用 SNI 默认回调函数)
|
||||
*
|
||||
* 返回值: TRUE -- 成功
|
||||
* FALSE -- 失败,可通过 ::GetLastError() 获取失败原因
|
||||
*/
|
||||
BOOL Initialize(EnSSLSessionMode enSessionMode, int iVerifyMode = SSL_VM_NONE, BOOL bMemory = FALSE, LPVOID lpPemCert = nullptr, LPVOID lpPemKey = nullptr, LPVOID lpKeyPasswod = nullptr, LPVOID lpCAPemCert = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr);
|
||||
|
||||
/*
|
||||
* 名称:增加 SNI 主机证书(只用于服务端)
|
||||
* 描述:SSL 服务端在 Initialize() 成功后可以调用本方法增加多个 SNI 主机证书
|
||||
*
|
||||
* 参数: iVerifyMode -- SSL 验证模式(参考 EnSSLVerifyMode)
|
||||
* lpPemCert -- 证书文件
|
||||
* lpPemKey -- 私钥文件
|
||||
* lpKeyPasswod -- 私钥密码(没有密码则为空)
|
||||
* lpCAPemCert -- CA 证书文件或目录(单向验证可选)
|
||||
*
|
||||
* 返回值: 正数 -- 成功,并返回 SNI 主机证书对应的索引,该索引用于在 SNI 回调函数中定位 SNI 主机
|
||||
* 负数 -- 失败,可通过 ::GetLastError() 获取失败原因
|
||||
*/
|
||||
int AddServerContext(int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod = nullptr, LPVOID lpCAPemCert = nullptr);
|
||||
|
||||
/*
|
||||
* 名称:绑定 SNI 主机域名
|
||||
* 描述:SSL 服务端在 AddServerContext() 成功后可以调用本方法绑定主机域名到 SNI 主机证书
|
||||
*
|
||||
* 参数: lpszServerName -- 主机域名
|
||||
* iContextIndex -- SNI 主机证书对应的索引
|
||||
*
|
||||
* 返回值: TRUE -- 成功
|
||||
* FALSE -- 失败,可通过 ::GetLastError() 获取失败原因
|
||||
*/
|
||||
virtual BOOL BindServerName(LPCTSTR lpszServerName, int iContextIndex);
|
||||
|
||||
/*
|
||||
* 名称:清理 SSL 运行环境
|
||||
* 描述:清理 SSL 运行环境,回收 SSL 相关内存
|
||||
* 1、CSSLContext 的析构函数会自动调用本方法
|
||||
* 2、当要重新设置 SSL 环境参数时,需要先调用本方法清理原先的环境参数
|
||||
*
|
||||
* 参数: 无
|
||||
*
|
||||
* 返回值:无
|
||||
*/
|
||||
void Cleanup();
|
||||
|
||||
/* 获取 SSL 运行环境 SSL_CTX 对象 */
|
||||
SSL_CTX* GetContext (int i) const;
|
||||
/* 获取 SSL 运行环境默认 SSL_CTX 对象 */
|
||||
SSL_CTX* GetDefaultContext () const {return m_sslCtx;}
|
||||
/* 获取 SSL 运行环境的配置模式,配置模式参考:EnSSLSessionMode */
|
||||
EnSSLSessionMode GetSessionMode () const {return m_enSessionMode;}
|
||||
/* 检查 SSL 运行环境是否初始化完成 */
|
||||
BOOL IsValid () const {return m_sslCtx != nullptr;}
|
||||
|
||||
/* 设置 SSL 加密算法列表 */
|
||||
void SetCipherList(LPCTSTR lpszCipherList) {m_strCipherList = lpszCipherList;}
|
||||
/* 获取 SSL 加密算法列表 */
|
||||
LPCTSTR GetCipherList() {return m_strCipherList;}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* 名称:清理线程局部环境 SSL 资源
|
||||
* 描述:任何一个操作 SSL 的线程,在通信结束时都需要清理线程局部环境 SSL 资源
|
||||
* 1、主线程和 HP-Socket 工作线程在通信结束时会自动清理线程局部环境 SSL 资源。因此,一般情况下不必手工调用本方法
|
||||
* 2、特殊情况下,当自定义线程参与 HP-Socket 通信操作并检查到 SSL 内存泄漏时,需在每次通信结束时自定义线程调用本方法
|
||||
*
|
||||
* 参数: dwThreadID -- 线程 ID(0:当前线程)
|
||||
*
|
||||
* 返回值:无
|
||||
*/
|
||||
static void RemoveThreadLocalState(THR_ID dwThreadID = 0) {CSSLInitializer::CleanupThreadState(dwThreadID);}
|
||||
|
||||
public:
|
||||
|
||||
CSSLContext()
|
||||
: m_strCipherList (DEFAULT_CIPHER_LIST)
|
||||
, m_enSessionMode (SSL_SM_SERVER)
|
||||
, m_sslCtx (nullptr)
|
||||
, m_fnServerNameCallback(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CSSLContext() {Cleanup();}
|
||||
|
||||
private:
|
||||
|
||||
void SetServerNameCallback(Fn_SNI_ServerNameCallback fn);
|
||||
int AddContext(int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod, LPVOID lpCAPemCert);
|
||||
BOOL LoadCertAndKey(SSL_CTX* sslCtx, int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod, LPVOID lpCAPemCert);
|
||||
BOOL LoadCertAndKeyByFile(SSL_CTX* sslCtx, int iVerifyMode, LPCTSTR lpszPemCertFile, LPCTSTR lpszPemKeyFile, LPCTSTR lpszKeyPassword, LPCTSTR lpszCAPemCertFileOrPath);
|
||||
BOOL LoadCertAndKeyByMemory(SSL_CTX* sslCtx, int iVerifyMode, LPCSTR lpszPemCert, LPCSTR lpszPemKey, LPCSTR lpszKeyPassword, LPCSTR lpszCAPemCert);
|
||||
BOOL LoadCAPemCertByMemory(SSL_CTX* sslCtx, int iVerifyMode, LPCSTR lpszCAPemCert);
|
||||
BOOL LoadPemCertAndKeyByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert, LPCSTR lpszPemKey, LPCSTR lpszKeyPassword);
|
||||
BOOL AddCAPemCertToStoreByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert);
|
||||
BOOL SetClientCAListByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert);
|
||||
BOOL SetPrivateKeyByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemKey);
|
||||
BOOL SetCertChainByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert);
|
||||
|
||||
private:
|
||||
|
||||
static int InternalServerNameCallback(SSL* ssl, int* ad, void* arg);
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* 名称:SNI 默认回调函数
|
||||
* 描述:Initialize 方法中如果不指定 SNI 回调函数则使用此 SNI 默认回调函数
|
||||
*
|
||||
* 参数: lpszServerName -- 请求域名
|
||||
* pContext -- SSL Context 对象
|
||||
*
|
||||
* 返回值:SNI 主机证书对应的索引
|
||||
*/
|
||||
static int __HP_CALL DefaultServerNameCallback(LPCTSTR lpszServerName, PVOID pContext);
|
||||
|
||||
private:
|
||||
|
||||
CString m_strCipherList;
|
||||
EnSSLSessionMode m_enSessionMode;
|
||||
CServerNameMap m_sslServerNames;
|
||||
vector<SSL_CTX*> m_lsSslCtxs;
|
||||
SSL_CTX* m_sslCtx;
|
||||
|
||||
Fn_SNI_ServerNameCallback m_fnServerNameCallback;
|
||||
};
|
||||
|
||||
class CSSLSession : public CSafeCounter
|
||||
{
|
||||
public:
|
||||
|
||||
BOOL WriteRecvChannel(const BYTE* pData, int iLength);
|
||||
BOOL ReadRecvChannel();
|
||||
|
||||
BOOL WriteSendChannel(const BYTE* pData, int iLength);
|
||||
BOOL WriteSendChannel(const WSABUF pBuffers[], int iCount);
|
||||
BOOL ReadSendChannel();
|
||||
|
||||
const WSABUF& GetRecvBuffer() const {return m_bufRecv;}
|
||||
const WSABUF& GetSendBuffer() const {return m_bufSend;}
|
||||
|
||||
CSSLSession* Renew(const CSSLContext& sslCtx, LPCSTR lpszHostName = nullptr);
|
||||
BOOL Reset();
|
||||
BOOL IsValid() const {return GetStatus() != SSL_HSS_INIT;}
|
||||
BOOL IsHandShaking() const {return GetStatus() == SSL_HSS_PROC;}
|
||||
BOOL IsReady() const {return GetStatus() == SSL_HSS_SUCC;}
|
||||
EnSSLHandShakeStatus GetStatus() const {return m_enStatus;}
|
||||
DWORD GetFreeTime() const {return m_dwFreeTime;}
|
||||
CCriSec& GetSendLock() {return m_csSend;}
|
||||
BOOL GetSessionInfo(EnSSLSessionInfo enInfo, LPVOID* lppInfo);
|
||||
|
||||
private:
|
||||
|
||||
BOOL IsFatalError(int iBytes);
|
||||
|
||||
public:
|
||||
|
||||
CSSLSession(CItemPool& itPool)
|
||||
: m_enStatus(SSL_HSS_INIT)
|
||||
, m_itPool (itPool)
|
||||
, m_ssl (nullptr)
|
||||
, m_bioSend (nullptr)
|
||||
, m_bioRecv (nullptr)
|
||||
, m_pitSend (nullptr)
|
||||
, m_pitRecv (nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CSSLSession()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
static CSSLSession* Construct(CItemPool& itPool)
|
||||
{return new CSSLSession(itPool);}
|
||||
|
||||
static void Destruct(CSSLSession* pSession)
|
||||
{if(pSession) delete pSession;}
|
||||
|
||||
private:
|
||||
CItemPool& m_itPool;
|
||||
CCriSec m_csSend;
|
||||
|
||||
DWORD m_dwFreeTime;
|
||||
EnSSLHandShakeStatus m_enStatus;
|
||||
|
||||
SSL* m_ssl;
|
||||
BIO* m_bioSend;
|
||||
BIO* m_bioRecv;
|
||||
|
||||
TItem* m_pitSend;
|
||||
TItem* m_pitRecv;
|
||||
WSABUF m_bufSend;
|
||||
WSABUF m_bufRecv;
|
||||
};
|
||||
|
||||
class CSSLSessionPool
|
||||
{
|
||||
typedef CRingPool<CSSLSession> TSSLSessionList;
|
||||
typedef CCASQueue<CSSLSession> TSSLSessionQueue;
|
||||
|
||||
public:
|
||||
CSSLSession* PickFreeSession (LPCSTR lpszHostName = nullptr);
|
||||
void PutFreeSession (CSSLSession* pSession);
|
||||
|
||||
void Prepare ();
|
||||
void Clear ();
|
||||
|
||||
void ReleaseGCSession (BOOL bForce = FALSE);
|
||||
|
||||
public:
|
||||
void SetItemCapacity (DWORD dwItemCapacity) {m_itPool.SetItemCapacity(dwItemCapacity);}
|
||||
void SetItemPoolSize (DWORD dwItemPoolSize) {m_itPool.SetPoolSize(dwItemPoolSize);}
|
||||
void SetItemPoolHold (DWORD dwItemPoolHold) {m_itPool.SetPoolHold(dwItemPoolHold);}
|
||||
|
||||
void SetSessionLockTime (DWORD dwSessionLockTime) {m_dwSessionLockTime = dwSessionLockTime;}
|
||||
void SetSessionPoolSize (DWORD dwSessionPoolSize) {m_dwSessionPoolSize = dwSessionPoolSize;}
|
||||
void SetSessionPoolHold (DWORD dwSessionPoolHold) {m_dwSessionPoolHold = dwSessionPoolHold;}
|
||||
|
||||
DWORD GetItemCapacity () {return m_itPool.GetItemCapacity();}
|
||||
DWORD GetItemPoolSize () {return m_itPool.GetPoolSize();}
|
||||
DWORD GetItemPoolHold () {return m_itPool.GetPoolHold();}
|
||||
|
||||
DWORD GetSessionLockTime() {return m_dwSessionLockTime;}
|
||||
DWORD GetSessionPoolSize() {return m_dwSessionPoolSize;}
|
||||
DWORD GetSessionPoolHold() {return m_dwSessionPoolHold;}
|
||||
|
||||
public:
|
||||
CSSLSessionPool(const CSSLContext& sslCtx,
|
||||
DWORD dwPoolSize = DEFAULT_SESSION_POOL_SIZE,
|
||||
DWORD dwPoolHold = DEFAULT_SESSION_POOL_HOLD,
|
||||
DWORD dwLockTime = DEFAULT_SESSION_LOCK_TIME)
|
||||
: m_sslCtx(sslCtx)
|
||||
, m_dwSessionPoolSize(dwPoolSize)
|
||||
, m_dwSessionPoolHold(dwPoolHold)
|
||||
, m_dwSessionLockTime(dwLockTime)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CSSLSessionPool() {Clear();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CSSLSessionPool)
|
||||
|
||||
public:
|
||||
static const DWORD DEFAULT_ITEM_CAPACITY;
|
||||
static const DWORD DEFAULT_ITEM_POOL_SIZE;
|
||||
static const DWORD DEFAULT_ITEM_POOL_HOLD;
|
||||
static const DWORD DEFAULT_SESSION_LOCK_TIME;
|
||||
static const DWORD DEFAULT_SESSION_POOL_SIZE;
|
||||
static const DWORD DEFAULT_SESSION_POOL_HOLD;
|
||||
|
||||
private:
|
||||
CItemPool m_itPool;
|
||||
const CSSLContext& m_sslCtx;
|
||||
|
||||
DWORD m_dwSessionLockTime;
|
||||
DWORD m_dwSessionPoolSize;
|
||||
DWORD m_dwSessionPoolHold;
|
||||
|
||||
TSSLSessionList m_lsFreeSession;
|
||||
TSSLSessionQueue m_lsGCSession;
|
||||
};
|
||||
|
||||
template<class T, class S> EnHandleResult ProcessHandShake(T* pThis, S* pSocketObj, CSSLSession* pSession)
|
||||
{
|
||||
EnHandleResult result = HR_OK;
|
||||
|
||||
CCriSecLock locallock(pSession->GetSendLock());
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
VERIFY(pSession->ReadSendChannel());
|
||||
const WSABUF& buffer = pSession->GetSendBuffer();
|
||||
|
||||
if(buffer.len == 0)
|
||||
break;
|
||||
|
||||
if(!pThis->DoSendPackets(pSocketObj, &buffer, 1))
|
||||
{
|
||||
result = HR_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class S> EnHandleResult ProcessReceive(T* pThis, S* pSocketObj, CSSLSession* pSession, const BYTE* pData, int iLength)
|
||||
{
|
||||
if(!pSession->WriteRecvChannel(pData, iLength))
|
||||
return HR_ERROR;
|
||||
|
||||
EnHandleResult result = HR_OK;
|
||||
EnSSLHandShakeStatus enStatus = pSession->GetStatus();
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
if(!pSession->ReadRecvChannel())
|
||||
return HR_ERROR;
|
||||
|
||||
if(enStatus == SSL_HSS_PROC && pSession->IsReady())
|
||||
{
|
||||
result = ProcessHandShake(pThis, pSocketObj, pSession);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
break;
|
||||
|
||||
enStatus = SSL_HSS_SUCC;
|
||||
result = pThis->DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
const WSABUF& buffer = pSession->GetRecvBuffer();
|
||||
|
||||
if(buffer.len == 0)
|
||||
break;
|
||||
|
||||
result = pThis->DoFireReceive(pSocketObj, (const BYTE*)buffer.buf, buffer.len);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
if(result != HR_ERROR && pSession->IsHandShaking())
|
||||
result = ::ProcessHandShake(pThis, pSocketObj, pSession);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class S> BOOL ProcessSend(T* pThis, S* pSocketObj, CSSLSession* pSession, const WSABUF * pBuffers, int iCount)
|
||||
{
|
||||
if(pSession == nullptr || !pSession->IsReady())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CCriSecLock locallock(pSession->GetSendLock());
|
||||
|
||||
if(!pSession->IsReady())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pSession->WriteSendChannel(pBuffers, iCount))
|
||||
{
|
||||
::SetLastError(ERROR_WRITE_FAULT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
VERIFY(pSession->ReadSendChannel());
|
||||
const WSABUF& buffer = pSession->GetSendBuffer();
|
||||
|
||||
if(buffer.len == 0)
|
||||
break;
|
||||
|
||||
if(!pThis->DoSendPackets(pSocketObj, &buffer, 1))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SSLServer.h"
|
||||
#include "SSLHelper.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
BOOL CSSLServer::CheckParams()
|
||||
{
|
||||
if(!m_sslCtx.IsValid())
|
||||
{
|
||||
SetLastError(SE_SSL_ENV_NOT_READY, __FUNCTION__, ERROR_NOT_READY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return __super::CheckParams();
|
||||
}
|
||||
|
||||
void CSSLServer::PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_sslPool.SetItemCapacity (GetSocketBufferSize());
|
||||
m_sslPool.SetItemPoolSize (GetFreeBufferObjPool());
|
||||
m_sslPool.SetItemPoolHold (GetFreeBufferObjHold());
|
||||
m_sslPool.SetSessionLockTime(GetFreeSocketObjLockTime());
|
||||
m_sslPool.SetSessionPoolSize(GetFreeSocketObjPool());
|
||||
m_sslPool.SetSessionPoolHold(GetFreeSocketObjHold());
|
||||
|
||||
m_sslPool.Prepare();
|
||||
}
|
||||
|
||||
void CSSLServer::Reset()
|
||||
{
|
||||
m_sslPool.Clear();
|
||||
m_sslCtx.RemoveThreadLocalState();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void CSSLServer::OnWorkerThreadEnd(THR_ID dwThreadID)
|
||||
{
|
||||
m_sslCtx.RemoveThreadLocalState();
|
||||
|
||||
__super::OnWorkerThreadEnd(dwThreadID);
|
||||
}
|
||||
|
||||
void CSSLServer::ReleaseGCSocketObj(BOOL bForce)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_sslPool.ReleaseGCSession(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL CSSLServer::SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
TSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
{
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
return ::ProcessSend(this, pSocketObj, pSession, pBuffers, iCount);
|
||||
}
|
||||
|
||||
return DoSendPackets(pSocketObj, pBuffers, iCount);
|
||||
}
|
||||
|
||||
EnHandleResult CSSLServer::FireAccept(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = DoFireAccept(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR && m_bSSLAutoHandShake)
|
||||
DoSSLHandShake(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EnHandleResult CSSLServer::FireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
{
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
return ::ProcessReceive(this, pSocketObj, pSession, pData, iLength);
|
||||
}
|
||||
|
||||
return DoFireReceive(pSocketObj, pData, iLength);
|
||||
}
|
||||
|
||||
EnHandleResult CSSLServer::FireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
m_sslPool.PutFreeSession(pSession);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL CSSLServer::StartSSLHandShake(CONNID dwConnID)
|
||||
{
|
||||
if(IsSSLAutoHandShake())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return StartSSLHandShake(pSocketObj);
|
||||
}
|
||||
|
||||
BOOL CSSLServer::StartSSLHandShake(TSocketObj* pSocketObj)
|
||||
{
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CReentrantCriSecLock locallock(pSocketObj->csSend);
|
||||
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!pSocketObj->HasConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
{
|
||||
::SetLastError(ERROR_ALREADY_INITIALIZED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoSSLHandShake(pSocketObj);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CSSLServer::DoSSLHandShake(TSocketObj* pSocketObj)
|
||||
{
|
||||
CSSLSession* pSession = m_sslPool.PickFreeSession();
|
||||
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
|
||||
ENSURE(SetConnectionReserved2(pSocketObj, pSession));
|
||||
ENSURE(::ProcessHandShake(this, pSocketObj, pSession) == HR_OK);
|
||||
}
|
||||
|
||||
BOOL CSSLServer::GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo)
|
||||
{
|
||||
ASSERT(lppInfo != nullptr);
|
||||
|
||||
*lppInfo = nullptr;
|
||||
TSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CSSLSession* pSession = nullptr;
|
||||
GetConnectionReserved2(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession == nullptr || !pSession->IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pSession->GetSessionInfo(enInfo, lppInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpServer.h"
|
||||
#include "SSLHelper.h"
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
class CSSLServer : public CTcpServer
|
||||
{
|
||||
using __super = CTcpServer;
|
||||
|
||||
public:
|
||||
using __super::Wait;
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure() {return TRUE;}
|
||||
virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount);
|
||||
|
||||
virtual BOOL SetupSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr)
|
||||
{return m_sslCtx.Initialize(SSL_SM_SERVER, iVerifyMode, FALSE, (LPVOID)lpszPemCertFile, (LPVOID)lpszPemKeyFile, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCertFileOrPath, fnServerNameCallback);}
|
||||
|
||||
virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr)
|
||||
{return m_sslCtx.Initialize(SSL_SM_SERVER, iVerifyMode, TRUE, (LPVOID)lpszPemCert, (LPVOID)lpszPemKey, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCert, fnServerNameCallback);}
|
||||
|
||||
virtual int AddSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr)
|
||||
{return m_sslCtx.AddServerContext(iVerifyMode, FALSE, (LPVOID)lpszPemCertFile, (LPVOID)lpszPemKeyFile, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCertFileOrPath);}
|
||||
|
||||
virtual int AddSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr)
|
||||
{return m_sslCtx.AddServerContext(iVerifyMode, TRUE, (LPVOID)lpszPemCert, (LPVOID)lpszPemKey, (LPVOID)lpszKeyPassword, (LPVOID)lpszCAPemCert);}
|
||||
|
||||
virtual BOOL BindSSLServerName(LPCTSTR lpszServerName, int iContextIndex)
|
||||
{return m_sslCtx.BindServerName(lpszServerName, iContextIndex);}
|
||||
|
||||
virtual void CleanupSSLContext()
|
||||
{m_sslCtx.Cleanup();}
|
||||
|
||||
virtual BOOL StartSSLHandShake(CONNID dwConnID);
|
||||
|
||||
public:
|
||||
virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) {ENSURE_HAS_STOPPED(); m_bSSLAutoHandShake = bAutoHandShake;}
|
||||
virtual void SetSSLCipherList (LPCTSTR lpszCipherList){ENSURE_HAS_STOPPED(); m_sslCtx.SetCipherList(lpszCipherList);}
|
||||
virtual BOOL IsSSLAutoHandShake () {return m_bSSLAutoHandShake;}
|
||||
virtual LPCTSTR GetSSLCipherList() {return m_sslCtx.GetCipherList();}
|
||||
|
||||
virtual BOOL GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo);
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FireAccept(TSocketObj* pSocketObj);
|
||||
virtual EnHandleResult FireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult FireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadEnd(THR_ID dwThreadID);
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
protected:
|
||||
virtual BOOL StartSSLHandShake(TSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
void DoSSLHandShake(TSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
friend EnHandleResult ProcessHandShake<>(CSSLServer* pThis, TSocketObj* pSocketObj, CSSLSession* pSession);
|
||||
friend EnHandleResult ProcessReceive<>(CSSLServer* pThis, TSocketObj* pSocketObj, CSSLSession* pSession, const BYTE* pData, int iLength);
|
||||
friend BOOL ProcessSend<>(CSSLServer* pThis, TSocketObj* pSocketObj, CSSLSession* pSession, const WSABUF * pBuffers, int iCount);
|
||||
|
||||
public:
|
||||
CSSLServer(ITcpServerListener* pListener)
|
||||
: CTcpServer(pListener)
|
||||
, m_sslPool(m_sslCtx)
|
||||
, m_bSSLAutoHandShake(TRUE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CSSLServer()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL m_bSSLAutoHandShake;
|
||||
|
||||
CSSLContext m_sslCtx;
|
||||
CSSLSessionPool m_sslPool;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,770 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../include/hpsocket/HPSocket4C.h"
|
||||
#include "../include/hpsocket/SocketInterface.h"
|
||||
#include "common/FuncHelper.h"
|
||||
|
||||
class C_HP_Object
|
||||
{
|
||||
public:
|
||||
template<class T> static inline HP_Object FromFirst(T* pFirst)
|
||||
{
|
||||
return (HP_Object)((char*)pFirst - first);
|
||||
}
|
||||
|
||||
template<class T> static inline T* ToFirst(HP_Object pObject)
|
||||
{
|
||||
return (T*)((char*)pObject + first);
|
||||
}
|
||||
|
||||
template<size_t offset, class T> static inline HP_Object FromSecond(T* pSecond)
|
||||
{
|
||||
return (C_HP_Object*)((char*)pSecond - first - (offset + __DUAL_VPTR_GAP__));
|
||||
}
|
||||
|
||||
template<class T> static inline T* ToSecond(HP_Object pObject)
|
||||
{
|
||||
return (T*)((char*)pObject + ((C_HP_Object*)pObject)->second);
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_Object(int offset = 0) : second(first + (offset + __DUAL_VPTR_GAP__)) {}
|
||||
virtual ~C_HP_Object() {}
|
||||
|
||||
private:
|
||||
static const size_t first = (sizeof(PVOID) + sizeof(size_t));
|
||||
size_t second;
|
||||
};
|
||||
|
||||
template<class T, class L, int offset = 0> class C_HP_ObjectT : private C_HP_Object, public T
|
||||
{
|
||||
public:
|
||||
C_HP_ObjectT(L* pListener) : C_HP_Object(offset), T(pListener) {}
|
||||
};
|
||||
|
||||
template<class T, class L, size_t offset = 0> class C_HP_ServerListenerT : public L
|
||||
{
|
||||
public:
|
||||
virtual EnHandleResult OnPrepareListen(T* pSender, SOCKET soListen)
|
||||
{
|
||||
return (m_fnOnPrepareListen)
|
||||
? m_fnOnPrepareListen(C_HP_Object::FromSecond<offset>(pSender), soListen)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnAccept(T* pSender, CONNID dwConnID, UINT_PTR soClient)
|
||||
{
|
||||
return (m_fnOnAccept)
|
||||
? m_fnOnAccept(C_HP_Object::FromSecond<offset>(pSender), dwConnID, soClient)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnHandShake(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnHandShake)
|
||||
? m_fnOnHandShake(C_HP_Object::FromSecond<offset>(pSender), dwConnID)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnSend(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
return (m_fnOnSend)
|
||||
? m_fnOnSend(C_HP_Object::FromSecond<offset>(pSender), dwConnID, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnReceive);
|
||||
|
||||
return (m_fnOnReceive)
|
||||
? m_fnOnReceive(C_HP_Object::FromSecond<offset>(pSender), dwConnID, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnPullReceive);
|
||||
|
||||
return (m_fnOnPullReceive)
|
||||
? m_fnOnPullReceive(C_HP_Object::FromSecond<offset>(pSender), dwConnID, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnClose(T* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
ASSERT(m_fnOnClose);
|
||||
|
||||
return (m_fnOnClose)
|
||||
? m_fnOnClose(C_HP_Object::FromSecond<offset>(pSender), dwConnID, enOperation, iErrorCode)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnShutdown(T* pSender)
|
||||
{
|
||||
return (m_fnOnShutdown)
|
||||
? m_fnOnShutdown(C_HP_Object::FromSecond<offset>(pSender))
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_ServerListenerT()
|
||||
: m_fnOnPrepareListen (nullptr)
|
||||
, m_fnOnAccept (nullptr)
|
||||
, m_fnOnHandShake (nullptr)
|
||||
, m_fnOnSend (nullptr)
|
||||
, m_fnOnReceive (nullptr)
|
||||
, m_fnOnPullReceive (nullptr)
|
||||
, m_fnOnClose (nullptr)
|
||||
, m_fnOnShutdown (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
HP_FN_Server_OnPrepareListen m_fnOnPrepareListen ;
|
||||
HP_FN_Server_OnAccept m_fnOnAccept ;
|
||||
HP_FN_Server_OnHandShake m_fnOnHandShake ;
|
||||
HP_FN_Server_OnSend m_fnOnSend ;
|
||||
HP_FN_Server_OnReceive m_fnOnReceive ;
|
||||
HP_FN_Server_OnPullReceive m_fnOnPullReceive ;
|
||||
HP_FN_Server_OnClose m_fnOnClose ;
|
||||
HP_FN_Server_OnShutdown m_fnOnShutdown ;
|
||||
};
|
||||
|
||||
template<class T, class L, size_t offset = 0> class C_HP_AgentListenerT : public L
|
||||
{
|
||||
public:
|
||||
virtual EnHandleResult OnPrepareConnect(T* pSender, CONNID dwConnID, SOCKET socket)
|
||||
{
|
||||
return (m_fnOnPrepareConnect)
|
||||
? m_fnOnPrepareConnect(C_HP_Object::FromSecond<offset>(pSender), dwConnID, socket)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnConnect(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnConnect)
|
||||
? m_fnOnConnect(C_HP_Object::FromSecond<offset>(pSender), dwConnID)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnHandShake(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnHandShake)
|
||||
? m_fnOnHandShake(C_HP_Object::FromSecond<offset>(pSender), dwConnID)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnSend(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
return (m_fnOnSend)
|
||||
? m_fnOnSend(C_HP_Object::FromSecond<offset>(pSender), dwConnID, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnReceive);
|
||||
|
||||
return (m_fnOnReceive)
|
||||
? m_fnOnReceive(C_HP_Object::FromSecond<offset>(pSender), dwConnID, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnPullReceive);
|
||||
|
||||
return (m_fnOnPullReceive)
|
||||
? m_fnOnPullReceive(C_HP_Object::FromSecond<offset>(pSender), dwConnID, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnClose(T* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
ASSERT(m_fnOnClose);
|
||||
|
||||
return (m_fnOnClose)
|
||||
? m_fnOnClose(C_HP_Object::FromSecond<offset>(pSender), dwConnID, enOperation, iErrorCode)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnShutdown(T* pSender)
|
||||
{
|
||||
return (m_fnOnShutdown)
|
||||
? m_fnOnShutdown(C_HP_Object::FromSecond<offset>(pSender))
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_AgentListenerT()
|
||||
: m_fnOnPrepareConnect (nullptr)
|
||||
, m_fnOnConnect (nullptr)
|
||||
, m_fnOnHandShake (nullptr)
|
||||
, m_fnOnSend (nullptr)
|
||||
, m_fnOnReceive (nullptr)
|
||||
, m_fnOnPullReceive (nullptr)
|
||||
, m_fnOnClose (nullptr)
|
||||
, m_fnOnShutdown (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
HP_FN_Agent_OnPrepareConnect m_fnOnPrepareConnect;
|
||||
HP_FN_Agent_OnConnect m_fnOnConnect ;
|
||||
HP_FN_Agent_OnHandShake m_fnOnHandShake ;
|
||||
HP_FN_Agent_OnSend m_fnOnSend ;
|
||||
HP_FN_Agent_OnReceive m_fnOnReceive ;
|
||||
HP_FN_Agent_OnPullReceive m_fnOnPullReceive ;
|
||||
HP_FN_Agent_OnClose m_fnOnClose ;
|
||||
HP_FN_Agent_OnShutdown m_fnOnShutdown ;
|
||||
};
|
||||
|
||||
template<class T, class L, size_t offset = 0> class C_HP_ClientListenerT : public L
|
||||
{
|
||||
public:
|
||||
virtual EnHandleResult OnPrepareConnect(T* pSender, CONNID dwConnID, SOCKET socket)
|
||||
{
|
||||
return (m_fnOnPrepareConnect)
|
||||
? m_fnOnPrepareConnect(C_HP_Object::FromSecond<offset>(pSender), dwConnID, socket)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnConnect(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnConnect)
|
||||
? m_fnOnConnect(C_HP_Object::FromSecond<offset>(pSender), dwConnID)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnHandShake(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnHandShake)
|
||||
? m_fnOnHandShake(C_HP_Object::FromSecond<offset>(pSender), dwConnID)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnSend(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
return (m_fnOnSend)
|
||||
? m_fnOnSend(C_HP_Object::FromSecond<offset>(pSender), dwConnID, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnReceive);
|
||||
|
||||
return (m_fnOnReceive)
|
||||
? m_fnOnReceive(C_HP_Object::FromSecond<offset>(pSender), dwConnID, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnPullReceive);
|
||||
|
||||
return (m_fnOnPullReceive)
|
||||
? m_fnOnPullReceive(C_HP_Object::FromSecond<offset>(pSender), dwConnID, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnClose(T* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
ASSERT(m_fnOnClose);
|
||||
|
||||
return (m_fnOnClose)
|
||||
? m_fnOnClose(C_HP_Object::FromSecond<offset>(pSender), dwConnID, enOperation, iErrorCode)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_ClientListenerT()
|
||||
: m_fnOnPrepareConnect (nullptr)
|
||||
, m_fnOnConnect (nullptr)
|
||||
, m_fnOnHandShake (nullptr)
|
||||
, m_fnOnSend (nullptr)
|
||||
, m_fnOnReceive (nullptr)
|
||||
, m_fnOnPullReceive (nullptr)
|
||||
, m_fnOnClose (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
HP_FN_Client_OnPrepareConnect m_fnOnPrepareConnect;
|
||||
HP_FN_Client_OnConnect m_fnOnConnect ;
|
||||
HP_FN_Client_OnHandShake m_fnOnHandShake ;
|
||||
HP_FN_Client_OnSend m_fnOnSend ;
|
||||
HP_FN_Client_OnReceive m_fnOnReceive ;
|
||||
HP_FN_Client_OnPullReceive m_fnOnPullReceive ;
|
||||
HP_FN_Client_OnClose m_fnOnClose ;
|
||||
};
|
||||
|
||||
typedef C_HP_ServerListenerT<ITcpServer, ITcpServerListener> C_HP_TcpServerListener;
|
||||
typedef C_HP_ServerListenerT<ITcpServer, ITcpServerListener, sizeof(IPullSocket)> C_HP_TcpPullServerListener;
|
||||
typedef C_HP_ServerListenerT<ITcpServer, ITcpServerListener, sizeof(IPackSocket)> C_HP_TcpPackServerListener;
|
||||
|
||||
typedef C_HP_AgentListenerT<ITcpAgent, ITcpAgentListener> C_HP_TcpAgentListener;
|
||||
typedef C_HP_AgentListenerT<ITcpAgent, ITcpAgentListener, sizeof(IPullSocket)> C_HP_TcpPullAgentListener;
|
||||
typedef C_HP_AgentListenerT<ITcpAgent, ITcpAgentListener, sizeof(IPackSocket)> C_HP_TcpPackAgentListener;
|
||||
|
||||
typedef C_HP_ClientListenerT<ITcpClient, ITcpClientListener> C_HP_TcpClientListener;
|
||||
typedef C_HP_ClientListenerT<ITcpClient, ITcpClientListener, sizeof(IPullClient)> C_HP_TcpPullClientListener;
|
||||
typedef C_HP_ClientListenerT<ITcpClient, ITcpClientListener, sizeof(IPackClient)> C_HP_TcpPackClientListener;
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
template<class T, class L, size_t offset = 0> class C_HP_UdpNodeListenerT : public L
|
||||
{
|
||||
public:
|
||||
virtual EnHandleResult OnPrepareListen(T* pSender, SOCKET soListen)
|
||||
{
|
||||
return (m_fnOnPrepareListen)
|
||||
? m_fnOnPrepareListen(C_HP_Object::FromSecond<offset>(pSender), soListen)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnSend(T* pSender, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength)
|
||||
{
|
||||
return (m_fnOnSend)
|
||||
? m_fnOnSend(C_HP_Object::FromSecond<offset>(pSender), lpszRemoteAddress, usRemotePort, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnReceive(T* pSender, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnReceive);
|
||||
|
||||
return (m_fnOnReceive)
|
||||
? m_fnOnReceive(C_HP_Object::FromSecond<offset>(pSender), lpszRemoteAddress, usRemotePort, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnError(T* pSender, EnSocketOperation enOperation, int iErrorCode, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnError);
|
||||
|
||||
return (m_fnOnError)
|
||||
? m_fnOnError(C_HP_Object::FromSecond<offset>(pSender), enOperation, iErrorCode, lpszRemoteAddress, usRemotePort, pData, iLength)
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnShutdown(T* pSender)
|
||||
{
|
||||
return (m_fnOnShutdown)
|
||||
? m_fnOnShutdown(C_HP_Object::FromSecond<offset>(pSender))
|
||||
: HR_IGNORE;
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_UdpNodeListenerT()
|
||||
: m_fnOnPrepareListen (nullptr)
|
||||
, m_fnOnSend (nullptr)
|
||||
, m_fnOnReceive (nullptr)
|
||||
, m_fnOnError (nullptr)
|
||||
, m_fnOnShutdown (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
HP_FN_UdpNode_OnPrepareListen m_fnOnPrepareListen ;
|
||||
HP_FN_UdpNode_OnSend m_fnOnSend ;
|
||||
HP_FN_UdpNode_OnReceive m_fnOnReceive ;
|
||||
HP_FN_UdpNode_OnError m_fnOnError ;
|
||||
HP_FN_UdpNode_OnShutdown m_fnOnShutdown ;
|
||||
};
|
||||
|
||||
typedef C_HP_ServerListenerT<IUdpServer, IUdpServerListener> C_HP_UdpServerListener;
|
||||
typedef C_HP_ClientListenerT<IUdpClient, IUdpClientListener> C_HP_UdpClientListener;
|
||||
typedef C_HP_ClientListenerT<IUdpCast, IUdpCastListener> C_HP_UdpCastListener;
|
||||
typedef C_HP_UdpNodeListenerT<IUdpNode, IUdpNodeListener> C_HP_UdpNodeListener;
|
||||
|
||||
typedef C_HP_ServerListenerT<IUdpServer, IUdpServerListener, sizeof(IArqSocket)> C_HP_UdpArqServerListener;
|
||||
typedef C_HP_ClientListenerT<IUdpClient, IUdpClientListener, sizeof(IArqClient)> C_HP_UdpArqClientListener;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _HTTP_SUPPORT
|
||||
|
||||
template<class T> class C_HP_HttpListenerT : public IHttpListenerT<T>
|
||||
{
|
||||
public:
|
||||
virtual EnHttpParseResult OnMessageBegin(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnMessageBegin)
|
||||
? m_fnOnMessageBegin(C_HP_Object::FromFirst(pSender), dwConnID)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnRequestLine(T* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{
|
||||
return (m_fnOnRequestLine)
|
||||
? m_fnOnRequestLine(C_HP_Object::FromFirst(pSender), dwConnID, lpszMethod, lpszUrl)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnStatusLine(T* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{
|
||||
return (m_fnOnStatusLine)
|
||||
? m_fnOnStatusLine(C_HP_Object::FromFirst(pSender), dwConnID, usStatusCode, lpszDesc)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnHeader(T* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{
|
||||
return (m_fnOnHeader)
|
||||
? m_fnOnHeader(C_HP_Object::FromFirst(pSender), dwConnID, lpszName, lpszValue)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnHeadersComplete(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
ASSERT(m_fnOnHeadersComplete);
|
||||
|
||||
return (m_fnOnHeadersComplete)
|
||||
? m_fnOnHeadersComplete(C_HP_Object::FromFirst(pSender), dwConnID)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnBody(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
ASSERT(m_fnOnBody);
|
||||
|
||||
return (m_fnOnBody)
|
||||
? m_fnOnBody(C_HP_Object::FromFirst(pSender), dwConnID, pData, iLength)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnChunkHeader(T* pSender, CONNID dwConnID, int iLength)
|
||||
{
|
||||
return (m_fnOnChunkHeader)
|
||||
? m_fnOnChunkHeader(C_HP_Object::FromFirst(pSender), dwConnID, iLength)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnChunkComplete(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnChunkComplete)
|
||||
? m_fnOnChunkComplete(C_HP_Object::FromFirst(pSender), dwConnID)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnMessageComplete(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
ASSERT(m_fnOnMessageComplete);
|
||||
|
||||
return (m_fnOnMessageComplete)
|
||||
? m_fnOnMessageComplete(C_HP_Object::FromFirst(pSender), dwConnID)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnUpgrade(T* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
|
||||
{
|
||||
return (m_fnOnUpgrade)
|
||||
? m_fnOnUpgrade(C_HP_Object::FromFirst(pSender), dwConnID, enUpgradeType)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHttpParseResult OnParseError(T* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{
|
||||
ASSERT(m_fnOnParseError);
|
||||
|
||||
return (m_fnOnParseError)
|
||||
? m_fnOnParseError(C_HP_Object::FromFirst(pSender), dwConnID, iErrorCode, lpszErrorDesc)
|
||||
: HPR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnWSMessageHeader(T* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{
|
||||
return (m_fnOnWSMessageHeader)
|
||||
? m_fnOnWSMessageHeader(C_HP_Object::FromFirst(pSender), dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen)
|
||||
: HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnWSMessageBody(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{
|
||||
return (m_fnOnWSMessageBody)
|
||||
? m_fnOnWSMessageBody(C_HP_Object::FromFirst(pSender), dwConnID, pData, iLength)
|
||||
: HR_OK;
|
||||
}
|
||||
|
||||
virtual EnHandleResult OnWSMessageComplete(T* pSender, CONNID dwConnID)
|
||||
{
|
||||
return (m_fnOnWSMessageComplete)
|
||||
? m_fnOnWSMessageComplete(C_HP_Object::FromFirst(pSender), dwConnID)
|
||||
: HR_OK;
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_HttpListenerT()
|
||||
: m_fnOnMessageBegin (nullptr)
|
||||
, m_fnOnRequestLine (nullptr)
|
||||
, m_fnOnStatusLine (nullptr)
|
||||
, m_fnOnHeader (nullptr)
|
||||
, m_fnOnHeadersComplete (nullptr)
|
||||
, m_fnOnBody (nullptr)
|
||||
, m_fnOnChunkHeader (nullptr)
|
||||
, m_fnOnChunkComplete (nullptr)
|
||||
, m_fnOnMessageComplete (nullptr)
|
||||
, m_fnOnUpgrade (nullptr)
|
||||
, m_fnOnParseError (nullptr)
|
||||
, m_fnOnWSMessageHeader (nullptr)
|
||||
, m_fnOnWSMessageBody (nullptr)
|
||||
, m_fnOnWSMessageComplete(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
HP_FN_Http_OnMessageBegin m_fnOnMessageBegin ;
|
||||
HP_FN_Http_OnRequestLine m_fnOnRequestLine ;
|
||||
HP_FN_Http_OnStatusLine m_fnOnStatusLine ;
|
||||
HP_FN_Http_OnHeader m_fnOnHeader ;
|
||||
HP_FN_Http_OnHeadersComplete m_fnOnHeadersComplete ;
|
||||
HP_FN_Http_OnBody m_fnOnBody ;
|
||||
HP_FN_Http_OnChunkHeader m_fnOnChunkHeader ;
|
||||
HP_FN_Http_OnChunkComplete m_fnOnChunkComplete ;
|
||||
HP_FN_Http_OnMessageComplete m_fnOnMessageComplete ;
|
||||
HP_FN_Http_OnUpgrade m_fnOnUpgrade ;
|
||||
HP_FN_Http_OnParseError m_fnOnParseError ;
|
||||
HP_FN_Http_OnWSMessageHeader m_fnOnWSMessageHeader ;
|
||||
HP_FN_Http_OnWSMessageBody m_fnOnWSMessageBody ;
|
||||
HP_FN_Http_OnWSMessageComplete m_fnOnWSMessageComplete ;
|
||||
};
|
||||
|
||||
typedef C_HP_HttpListenerT<IHttpServer> C_HP_HttpServerBaseListener1;
|
||||
typedef C_HP_HttpListenerT<IHttpAgent> C_HP_HttpAgentBaseListener1;
|
||||
typedef C_HP_HttpListenerT<IHttpClient> C_HP_HttpClientBaseListener1;
|
||||
|
||||
typedef C_HP_ServerListenerT<ITcpServer, ITcpServerListener, sizeof(IComplexHttpResponder)> C_HP_HttpServerBaseListener2;
|
||||
typedef C_HP_AgentListenerT<ITcpAgent, ITcpAgentListener, sizeof(IComplexHttpRequester)> C_HP_HttpAgentBaseListener2;
|
||||
typedef C_HP_ClientListenerT<ITcpClient, ITcpClientListener, sizeof(IHttpRequester)> C_HP_HttpClientBaseListener2;
|
||||
|
||||
class C_HP_HttpServerListener : public IHttpServerListener
|
||||
{
|
||||
public:
|
||||
virtual EnHttpParseResult OnMessageBegin(IHttpServer* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnMessageBegin(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnRequestLine(IHttpServer* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{return m_lsnHttp.OnRequestLine(pSender, dwConnID, lpszMethod, lpszUrl);}
|
||||
virtual EnHttpParseResult OnStatusLine(IHttpServer* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{return m_lsnHttp.OnStatusLine(pSender, dwConnID, usStatusCode, lpszDesc);}
|
||||
virtual EnHttpParseResult OnHeader(IHttpServer* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{return m_lsnHttp.OnHeader(pSender, dwConnID, lpszName, lpszValue);}
|
||||
virtual EnHttpParseResult OnHeadersComplete(IHttpServer* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnHeadersComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnHttp.OnBody(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHttpParseResult OnChunkHeader(IHttpServer* pSender, CONNID dwConnID, int iLength)
|
||||
{return m_lsnHttp.OnChunkHeader(pSender, dwConnID, iLength);}
|
||||
virtual EnHttpParseResult OnChunkComplete(IHttpServer* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnChunkComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnMessageComplete(IHttpServer* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnMessageComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnUpgrade(IHttpServer* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
|
||||
{return m_lsnHttp.OnUpgrade(pSender, dwConnID, enUpgradeType);}
|
||||
virtual EnHttpParseResult OnParseError(IHttpServer* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{return m_lsnHttp.OnParseError(pSender, dwConnID, iErrorCode, lpszErrorDesc);}
|
||||
|
||||
virtual EnHandleResult OnWSMessageHeader(IHttpServer* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{return m_lsnHttp.OnWSMessageHeader(pSender, dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);}
|
||||
virtual EnHandleResult OnWSMessageBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnHttp.OnWSMessageBody(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnWSMessageComplete(IHttpServer* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnWSMessageComplete(pSender, dwConnID);}
|
||||
|
||||
virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen)
|
||||
{return m_lsnServer.OnPrepareListen(pSender, soListen);}
|
||||
virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient)
|
||||
{return m_lsnServer.OnAccept(pSender, dwConnID, soClient);}
|
||||
virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID)
|
||||
{return m_lsnServer.OnHandShake(pSender, dwConnID);}
|
||||
virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnServer.OnSend(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnServer.OnReceive(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength)
|
||||
{return m_lsnServer.OnReceive(pSender, dwConnID, iLength);}
|
||||
virtual EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_lsnServer.OnClose(pSender, dwConnID, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult OnShutdown(ITcpServer* pSender)
|
||||
{return m_lsnServer.OnShutdown(pSender);}
|
||||
|
||||
public:
|
||||
C_HP_HttpServerBaseListener1 m_lsnHttp;
|
||||
C_HP_HttpServerBaseListener2 m_lsnServer;
|
||||
};
|
||||
|
||||
class C_HP_HttpAgentListener : public IHttpAgentListener
|
||||
{
|
||||
public:
|
||||
virtual EnHttpParseResult OnMessageBegin(IHttpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnMessageBegin(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnRequestLine(IHttpAgent* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{return m_lsnHttp.OnRequestLine(pSender, dwConnID, lpszMethod, lpszUrl);}
|
||||
virtual EnHttpParseResult OnStatusLine(IHttpAgent* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{return m_lsnHttp.OnStatusLine(pSender, dwConnID, usStatusCode, lpszDesc);}
|
||||
virtual EnHttpParseResult OnHeader(IHttpAgent* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{return m_lsnHttp.OnHeader(pSender, dwConnID, lpszName, lpszValue);}
|
||||
virtual EnHttpParseResult OnHeadersComplete(IHttpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnHeadersComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnBody(IHttpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnHttp.OnBody(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHttpParseResult OnChunkHeader(IHttpAgent* pSender, CONNID dwConnID, int iLength)
|
||||
{return m_lsnHttp.OnChunkHeader(pSender, dwConnID, iLength);}
|
||||
virtual EnHttpParseResult OnChunkComplete(IHttpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnChunkComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnMessageComplete(IHttpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnMessageComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnUpgrade(IHttpAgent* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
|
||||
{return m_lsnHttp.OnUpgrade(pSender, dwConnID, enUpgradeType);}
|
||||
virtual EnHttpParseResult OnParseError(IHttpAgent* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{return m_lsnHttp.OnParseError(pSender, dwConnID, iErrorCode, lpszErrorDesc);}
|
||||
|
||||
virtual EnHandleResult OnWSMessageHeader(IHttpAgent* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{return m_lsnHttp.OnWSMessageHeader(pSender, dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);}
|
||||
virtual EnHandleResult OnWSMessageBody(IHttpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnHttp.OnWSMessageBody(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnWSMessageComplete(IHttpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnWSMessageComplete(pSender, dwConnID);}
|
||||
|
||||
virtual EnHandleResult OnPrepareConnect(ITcpAgent* pSender, CONNID dwConnID, SOCKET socket)
|
||||
{return m_lsnAgent.OnPrepareConnect(pSender, dwConnID, socket);}
|
||||
virtual EnHandleResult OnConnect(ITcpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnAgent.OnConnect(pSender, dwConnID);}
|
||||
virtual EnHandleResult OnHandShake(ITcpAgent* pSender, CONNID dwConnID)
|
||||
{return m_lsnAgent.OnHandShake(pSender, dwConnID);}
|
||||
virtual EnHandleResult OnSend(ITcpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnAgent.OnSend(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnAgent.OnReceive(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, int iLength)
|
||||
{return m_lsnAgent.OnReceive(pSender, dwConnID, iLength);}
|
||||
virtual EnHandleResult OnClose(ITcpAgent* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_lsnAgent.OnClose(pSender, dwConnID, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult OnShutdown(ITcpAgent* pSender)
|
||||
{return m_lsnAgent.OnShutdown(pSender);}
|
||||
|
||||
public:
|
||||
C_HP_HttpAgentBaseListener1 m_lsnHttp;
|
||||
C_HP_HttpAgentBaseListener2 m_lsnAgent;
|
||||
};
|
||||
|
||||
class C_HP_HttpClientListener : public IHttpClientListener
|
||||
{
|
||||
public:
|
||||
virtual EnHttpParseResult OnMessageBegin(IHttpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnMessageBegin(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnRequestLine(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)
|
||||
{return m_lsnHttp.OnRequestLine(pSender, dwConnID, lpszMethod, lpszUrl);}
|
||||
virtual EnHttpParseResult OnStatusLine(IHttpClient* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
|
||||
{return m_lsnHttp.OnStatusLine(pSender, dwConnID, usStatusCode, lpszDesc);}
|
||||
virtual EnHttpParseResult OnHeader(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
|
||||
{return m_lsnHttp.OnHeader(pSender, dwConnID, lpszName, lpszValue);}
|
||||
virtual EnHttpParseResult OnHeadersComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnHeadersComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnHttp.OnBody(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHttpParseResult OnChunkHeader(IHttpClient* pSender, CONNID dwConnID, int iLength)
|
||||
{return m_lsnHttp.OnChunkHeader(pSender, dwConnID, iLength);}
|
||||
virtual EnHttpParseResult OnChunkComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnChunkComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnMessageComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnMessageComplete(pSender, dwConnID);}
|
||||
virtual EnHttpParseResult OnUpgrade(IHttpClient* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
|
||||
{return m_lsnHttp.OnUpgrade(pSender, dwConnID, enUpgradeType);}
|
||||
virtual EnHttpParseResult OnParseError(IHttpClient* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
|
||||
{return m_lsnHttp.OnParseError(pSender, dwConnID, iErrorCode, lpszErrorDesc);}
|
||||
|
||||
virtual EnHandleResult OnWSMessageHeader(IHttpClient* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
|
||||
{return m_lsnHttp.OnWSMessageHeader(pSender, dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);}
|
||||
virtual EnHandleResult OnWSMessageBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnHttp.OnWSMessageBody(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnWSMessageComplete(IHttpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnHttp.OnWSMessageComplete(pSender, dwConnID);}
|
||||
|
||||
virtual EnHandleResult OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket)
|
||||
{return m_lsnClient.OnPrepareConnect(pSender, dwConnID, socket);}
|
||||
virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnClient.OnConnect(pSender, dwConnID);}
|
||||
virtual EnHandleResult OnHandShake(ITcpClient* pSender, CONNID dwConnID)
|
||||
{return m_lsnClient.OnHandShake(pSender, dwConnID);}
|
||||
virtual EnHandleResult OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnClient.OnSend(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
|
||||
{return m_lsnClient.OnReceive(pSender, dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, int iLength)
|
||||
{return m_lsnClient.OnReceive(pSender, dwConnID, iLength);}
|
||||
virtual EnHandleResult OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_lsnClient.OnClose(pSender, dwConnID, enOperation, iErrorCode);}
|
||||
|
||||
public:
|
||||
C_HP_HttpClientBaseListener1 m_lsnHttp;
|
||||
C_HP_HttpClientBaseListener2 m_lsnClient;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class C_HP_ThreadPoolListener : public IHPThreadPoolListener
|
||||
{
|
||||
public:
|
||||
virtual void OnStartup(IHPThreadPool* pThreadPool)
|
||||
{
|
||||
if(m_fnOnStartup)
|
||||
m_fnOnStartup((HP_ThreadPool)pThreadPool);
|
||||
}
|
||||
|
||||
virtual void OnShutdown(IHPThreadPool* pThreadPool)
|
||||
{
|
||||
if(m_fnOnShutdown)
|
||||
m_fnOnShutdown((HP_ThreadPool)pThreadPool);
|
||||
}
|
||||
|
||||
virtual void OnWorkerThreadStart(IHPThreadPool* pThreadPool, THR_ID dwThreadID)
|
||||
{
|
||||
if(m_fnOnWorkerThreadStart)
|
||||
m_fnOnWorkerThreadStart((HP_ThreadPool)pThreadPool, dwThreadID);
|
||||
}
|
||||
virtual void OnWorkerThreadEnd(IHPThreadPool* pThreadPool, THR_ID dwThreadID)
|
||||
{
|
||||
if(m_fnOnWorkerThreadEnd)
|
||||
m_fnOnWorkerThreadEnd((HP_ThreadPool)pThreadPool, dwThreadID);
|
||||
}
|
||||
|
||||
public:
|
||||
C_HP_ThreadPoolListener()
|
||||
: m_fnOnStartup (nullptr)
|
||||
, m_fnOnShutdown (nullptr)
|
||||
, m_fnOnWorkerThreadStart (nullptr)
|
||||
, m_fnOnWorkerThreadEnd (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
HP_FN_ThreadPool_OnStartup m_fnOnStartup;
|
||||
HP_FN_ThreadPool_OnShutdown m_fnOnShutdown;
|
||||
HP_FN_ThreadPool_OnWorkerThreadStart m_fnOnWorkerThreadStart;
|
||||
HP_FN_ThreadPool_OnWorkerThreadEnd m_fnOnWorkerThreadEnd;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
#include "./common/IODispatcher.h"
|
||||
|
||||
class CTcpAgent : public ITcpAgent, private CIOHandler
|
||||
{
|
||||
using CGCThread = CGCThreadT<CTcpAgent>;
|
||||
friend class CGCThreadT<CTcpAgent>;
|
||||
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszBindAddress = nullptr, BOOL bAsyncConnect = TRUE);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Connect(LPCTSTR lpszRemoteAddress, USHORT usPort, CONNID* pdwConnID = nullptr, PVOID pExtra = nullptr, USHORT usLocalPort = 0, LPCTSTR lpszLocalAddress = nullptr);
|
||||
virtual BOOL Send (CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendSmallFile (CONNID dwConnID, LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr);
|
||||
virtual BOOL SendPackets (CONNID dwConnID, const WSABUF pBuffers[], int iCount) {return DoSendPackets(dwConnID, pBuffers, iCount);}
|
||||
virtual BOOL PauseReceive (CONNID dwConnID, BOOL bPause = TRUE);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual BOOL Disconnect (CONNID dwConnID, BOOL bForce = TRUE);
|
||||
virtual BOOL DisconnectLongConnections (DWORD dwPeriod, BOOL bForce = TRUE);
|
||||
virtual BOOL DisconnectSilenceConnections(DWORD dwPeriod, BOOL bForce = TRUE);
|
||||
virtual BOOL GetLocalAddress (CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteAddress (CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteHost (CONNID dwConnID, TCHAR lpszHost[], int& iHostLen, USHORT& usPort);
|
||||
|
||||
virtual BOOL IsConnected (CONNID dwConnID);
|
||||
virtual BOOL IsPauseReceive (CONNID dwConnID, BOOL& bPaused);
|
||||
virtual BOOL GetPendingDataLength (CONNID dwConnID, int& iPending);
|
||||
virtual DWORD GetConnectionCount ();
|
||||
virtual BOOL GetAllConnectionIDs (CONNID pIDs[], DWORD& dwCount);
|
||||
virtual BOOL GetConnectPeriod (CONNID dwConnID, DWORD& dwPeriod);
|
||||
virtual BOOL GetSilencePeriod (CONNID dwConnID, DWORD& dwPeriod);
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
virtual BOOL SetupSSLContext (int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr) {return FALSE;}
|
||||
virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr) {return FALSE;}
|
||||
virtual void CleanupSSLContext () {}
|
||||
|
||||
virtual BOOL StartSSLHandShake (CONNID dwConnID) {return FALSE;}
|
||||
virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) {}
|
||||
virtual BOOL IsSSLAutoHandShake () {return FALSE;}
|
||||
virtual void SetSSLCipherList (LPCTSTR lpszCipherList){}
|
||||
virtual LPCTSTR GetSSLCipherList() {return nullptr;}
|
||||
virtual BOOL GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo) {return FALSE;}
|
||||
|
||||
protected:
|
||||
virtual BOOL StartSSLHandShake (TAgentSocketObj* pSocketObj) {return FALSE;}
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) override;
|
||||
virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) override;
|
||||
virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnDispatchThreadStart(THR_ID tid) override;
|
||||
virtual VOID OnDispatchThreadEnd(THR_ID tid) override;
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure () {return FALSE;}
|
||||
|
||||
virtual BOOL SetConnectionExtra(CONNID dwConnID, PVOID pExtra);
|
||||
virtual BOOL GetConnectionExtra(CONNID dwConnID, PVOID* ppExtra);
|
||||
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy) {ENSURE_HAS_STOPPED(); m_enReusePolicy = enReusePolicy;}
|
||||
virtual void SetSendPolicy (EnSendPolicy enSendPolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enSendPolicy == enSendPolicy);}
|
||||
virtual void SetOnSendSyncPolicy (EnOnSendSyncPolicy enOnSendSyncPolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enOnSendSyncPolicy == enOnSendSyncPolicy);}
|
||||
virtual void SetSyncConnectTimeout (DWORD dwSyncConnectTimeout) {ENSURE_HAS_STOPPED(); m_dwSyncConnectTimeout = dwSyncConnectTimeout;}
|
||||
virtual void SetMaxConnectionCount (DWORD dwMaxConnectionCount) {ENSURE_HAS_STOPPED(); m_dwMaxConnectionCount = dwMaxConnectionCount;}
|
||||
virtual void SetWorkerThreadCount (DWORD dwWorkerThreadCount) {ENSURE_HAS_STOPPED(); m_dwWorkerThreadCount = dwWorkerThreadCount;}
|
||||
virtual void SetSocketBufferSize (DWORD dwSocketBufferSize) {ENSURE_HAS_STOPPED(); m_dwSocketBufferSize = dwSocketBufferSize;}
|
||||
virtual void SetFreeSocketObjLockTime (DWORD dwFreeSocketObjLockTime) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjLockTime = dwFreeSocketObjLockTime;}
|
||||
virtual void SetFreeSocketObjPool (DWORD dwFreeSocketObjPool) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjPool = dwFreeSocketObjPool;}
|
||||
virtual void SetFreeBufferObjPool (DWORD dwFreeBufferObjPool) {ENSURE_HAS_STOPPED(); m_dwFreeBufferObjPool = dwFreeBufferObjPool;}
|
||||
virtual void SetFreeSocketObjHold (DWORD dwFreeSocketObjHold) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjHold = dwFreeSocketObjHold;}
|
||||
virtual void SetFreeBufferObjHold (DWORD dwFreeBufferObjHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferObjHold = dwFreeBufferObjHold;}
|
||||
virtual void SetKeepAliveTime (DWORD dwKeepAliveTime) {ENSURE_HAS_STOPPED(); m_dwKeepAliveTime = dwKeepAliveTime;}
|
||||
virtual void SetKeepAliveInterval (DWORD dwKeepAliveInterval) {ENSURE_HAS_STOPPED(); m_dwKeepAliveInterval = dwKeepAliveInterval;}
|
||||
virtual void SetMarkSilence (BOOL bMarkSilence) {ENSURE_HAS_STOPPED(); m_bMarkSilence = bMarkSilence;}
|
||||
virtual void SetNoDelay (BOOL bNoDelay) {ENSURE_HAS_STOPPED(); m_bNoDelay = bNoDelay;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual EnSendPolicy GetSendPolicy () {return m_enSendPolicy;}
|
||||
virtual EnOnSendSyncPolicy GetOnSendSyncPolicy () {return m_enOnSendSyncPolicy;}
|
||||
virtual DWORD GetSyncConnectTimeout () {return m_dwSyncConnectTimeout;}
|
||||
virtual DWORD GetMaxConnectionCount () {return m_dwMaxConnectionCount;}
|
||||
virtual DWORD GetWorkerThreadCount () {return m_dwWorkerThreadCount;}
|
||||
virtual DWORD GetSocketBufferSize () {return m_dwSocketBufferSize;}
|
||||
virtual DWORD GetFreeSocketObjLockTime () {return m_dwFreeSocketObjLockTime;}
|
||||
virtual DWORD GetFreeSocketObjPool () {return m_dwFreeSocketObjPool;}
|
||||
virtual DWORD GetFreeBufferObjPool () {return m_dwFreeBufferObjPool;}
|
||||
virtual DWORD GetFreeSocketObjHold () {return m_dwFreeSocketObjHold;}
|
||||
virtual DWORD GetFreeBufferObjHold () {return m_dwFreeBufferObjHold;}
|
||||
virtual DWORD GetKeepAliveTime () {return m_dwKeepAliveTime;}
|
||||
virtual DWORD GetKeepAliveInterval () {return m_dwKeepAliveInterval;}
|
||||
virtual BOOL IsMarkSilence () {return m_bMarkSilence;}
|
||||
virtual BOOL IsNoDelay () {return m_bNoDelay;}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FirePrepareConnect(CONNID dwConnID, SOCKET socket)
|
||||
{return DoFirePrepareConnect(dwConnID, socket);}
|
||||
virtual EnHandleResult FireConnect(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult rs = DoFireConnect(pSocketObj);
|
||||
if(rs != HR_ERROR) rs = FireHandShake(pSocketObj);
|
||||
return rs;
|
||||
}
|
||||
virtual EnHandleResult FireHandShake(TAgentSocketObj* pSocketObj)
|
||||
{return DoFireHandShake(pSocketObj);}
|
||||
virtual EnHandleResult FireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return DoFireReceive(pSocketObj, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(TAgentSocketObj* pSocketObj, int iLength)
|
||||
{return DoFireReceive(pSocketObj, iLength);}
|
||||
virtual EnHandleResult FireSend(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return DoFireSend(pSocketObj, pData, iLength);}
|
||||
virtual EnHandleResult FireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return DoFireClose(pSocketObj, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult FireShutdown()
|
||||
{return DoFireShutdown();}
|
||||
|
||||
virtual EnHandleResult DoFirePrepareConnect(CONNID dwConnID, SOCKET socket)
|
||||
{return m_pListener->OnPrepareConnect(this, dwConnID, socket);}
|
||||
virtual EnHandleResult DoFireConnect(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnConnect(this, pSocketObj->connID);}
|
||||
virtual EnHandleResult DoFireHandShake(TAgentSocketObj* pSocketObj)
|
||||
{return m_pListener->OnHandShake(this, pSocketObj->connID);}
|
||||
virtual EnHandleResult DoFireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnReceive(this, pSocketObj->connID, pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(TAgentSocketObj* pSocketObj, int iLength)
|
||||
{return m_pListener->OnReceive(this, pSocketObj->connID, iLength);}
|
||||
virtual EnHandleResult DoFireSend(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnSend(this, pSocketObj->connID, pData, iLength);}
|
||||
virtual EnHandleResult DoFireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_pListener->OnClose(this, pSocketObj->connID, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{return m_pListener->OnShutdown(this);}
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual BOOL BeforeUnpause(TAgentSocketObj* pSocketObj) {return TRUE;}
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID tid) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID tid) {}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
BOOL DoSendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount);
|
||||
BOOL DoSendPackets(TAgentSocketObj* pSocketObj, const WSABUF pBuffers[], int iCount);
|
||||
TAgentSocketObj* FindSocketObj(CONNID dwConnID);
|
||||
BOOL GetRemoteHost(CONNID dwConnID, LPCSTR* lpszHost, USHORT* pusPort = nullptr);
|
||||
|
||||
protected:
|
||||
BOOL SetConnectionExtra(TAgentSocketObj* pSocketObj, PVOID pExtra);
|
||||
BOOL GetConnectionExtra(TAgentSocketObj* pSocketObj, PVOID* ppExtra);
|
||||
BOOL SetConnectionReserved(CONNID dwConnID, PVOID pReserved);
|
||||
BOOL GetConnectionReserved(CONNID dwConnID, PVOID* ppReserved);
|
||||
BOOL SetConnectionReserved(TAgentSocketObj* pSocketObj, PVOID pReserved);
|
||||
BOOL GetConnectionReserved(TAgentSocketObj* pSocketObj, PVOID* ppReserved);
|
||||
BOOL SetConnectionReserved2(CONNID dwConnID, PVOID pReserved2);
|
||||
BOOL GetConnectionReserved2(CONNID dwConnID, PVOID* ppReserved2);
|
||||
BOOL SetConnectionReserved2(TAgentSocketObj* pSocketObj, PVOID pReserved2);
|
||||
BOOL GetConnectionReserved2(TAgentSocketObj* pSocketObj, PVOID* ppReserved2);
|
||||
|
||||
private:
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL ParseBindAddress(LPCTSTR lpszBindAddress);
|
||||
BOOL CreateWorkerThreads();
|
||||
|
||||
void DisconnectClientSocket();
|
||||
void WaitForClientSocketClose();
|
||||
void ReleaseClientSocket();
|
||||
void ReleaseFreeSocket();
|
||||
void WaitForWorkerThreadEnd();
|
||||
|
||||
TAgentSocketObj* GetFreeSocketObj(CONNID dwConnID, SOCKET soClient);
|
||||
TAgentSocketObj* CreateSocketObj();
|
||||
void AddFreeSocketObj (TAgentSocketObj* pSocketObj, EnSocketCloseFlag enFlag = SCF_NONE, EnSocketOperation enOperation = SO_UNKNOWN, int iErrorCode = 0);
|
||||
void DeleteSocketObj (TAgentSocketObj* pSocketObj);
|
||||
BOOL InvalidSocketObj (TAgentSocketObj* pSocketObj);
|
||||
void AddClientSocketObj (CONNID dwConnID, TAgentSocketObj* pSocketObj, const HP_SOCKADDR& remoteAddr, LPCTSTR lpszRemoteHostName, PVOID pExtra);
|
||||
void CloseClientSocketObj(TAgentSocketObj* pSocketObj, EnSocketCloseFlag enFlag = SCF_NONE, EnSocketOperation enOperation = SO_UNKNOWN, int iErrorCode = 0, int iShutdownFlag = SHUT_WR);
|
||||
|
||||
private:
|
||||
int CreateClientSocket(LPCTSTR lpszRemoteAddress, USHORT usPort, LPCTSTR lpszLocalAddress, USHORT usLocalPort, SOCKET& soClient, HP_SOCKADDR& addr);
|
||||
int PrepareConnect (CONNID& dwConnID, SOCKET soClient);
|
||||
int ConnectToServer (CONNID dwConnID, LPCTSTR lpszRemoteHostName, SOCKET& soClient, const HP_SOCKADDR& addr, PVOID pExtra);
|
||||
|
||||
VOID HandleCmdSend (const TDispContext* pContext, CONNID dwConnID);
|
||||
VOID HandleCmdUnpause (const TDispContext* pContext, CONNID dwConnID);
|
||||
VOID HandleCmdDisconnect(const TDispContext* pContext, CONNID dwConnID, BOOL bForce);
|
||||
BOOL HandleConnect (const TDispContext* pContext, TAgentSocketObj* pSocketObj, UINT events);
|
||||
BOOL HandleReceive (const TDispContext* pContext, TAgentSocketObj* pSocketObj, int flag);
|
||||
BOOL HandleSend (const TDispContext* pContext, TAgentSocketObj* pSocketObj, int flag);
|
||||
BOOL HandleClose (const TDispContext* pContext, TAgentSocketObj* pSocketObj, EnSocketCloseFlag enFlag, UINT events);
|
||||
|
||||
int SendInternal (TAgentSocketObj* pSocketObj, const WSABUF pBuffers[], int iCount);
|
||||
BOOL SendItem (TAgentSocketObj* pSocketObj, TItem* pItem, BOOL& bBlocked);
|
||||
|
||||
public:
|
||||
CTcpAgent(ITcpAgentListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_bAsyncConnect (TRUE)
|
||||
, m_enReusePolicy (RAP_ADDR_ONLY)
|
||||
, m_enSendPolicy (SP_PACK)
|
||||
, m_enOnSendSyncPolicy (OSSP_RECEIVE)
|
||||
, m_dwSyncConnectTimeout (DEFAULT_SYNC_CONNECT_TIMEOUT)
|
||||
, m_dwMaxConnectionCount (DEFAULT_CONNECTION_COUNT)
|
||||
, m_dwWorkerThreadCount (DEFAULT_WORKER_THREAD_COUNT)
|
||||
, m_dwSocketBufferSize (DEFAULT_TCP_SOCKET_BUFFER_SIZE)
|
||||
, m_dwFreeSocketObjLockTime (DEFAULT_FREE_SOCKETOBJ_LOCK_TIME)
|
||||
, m_dwFreeSocketObjPool (DEFAULT_FREE_SOCKETOBJ_POOL)
|
||||
, m_dwFreeBufferObjPool (DEFAULT_FREE_BUFFEROBJ_POOL)
|
||||
, m_dwFreeSocketObjHold (DEFAULT_FREE_SOCKETOBJ_HOLD)
|
||||
, m_dwFreeBufferObjHold (DEFAULT_FREE_BUFFEROBJ_HOLD)
|
||||
, m_dwKeepAliveTime (DEFALUT_TCP_KEEPALIVE_TIME)
|
||||
, m_dwKeepAliveInterval (DEFALUT_TCP_KEEPALIVE_INTERVAL)
|
||||
, m_bMarkSilence (TRUE)
|
||||
, m_bNoDelay (FALSE)
|
||||
, m_soAddr (AF_UNSPEC, TRUE)
|
||||
, m_thGC (this)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CTcpAgent()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
EnSendPolicy m_enSendPolicy;
|
||||
EnOnSendSyncPolicy m_enOnSendSyncPolicy;
|
||||
DWORD m_dwSyncConnectTimeout;
|
||||
DWORD m_dwMaxConnectionCount;
|
||||
DWORD m_dwWorkerThreadCount;
|
||||
DWORD m_dwSocketBufferSize;
|
||||
DWORD m_dwFreeSocketObjLockTime;
|
||||
DWORD m_dwFreeSocketObjPool;
|
||||
DWORD m_dwFreeBufferObjPool;
|
||||
DWORD m_dwFreeSocketObjHold;
|
||||
DWORD m_dwFreeBufferObjHold;
|
||||
DWORD m_dwKeepAliveTime;
|
||||
DWORD m_dwKeepAliveInterval;
|
||||
BOOL m_bMarkSilence;
|
||||
BOOL m_bNoDelay;
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
ITcpAgentListener* m_pListener;
|
||||
BOOL m_bAsyncConnect;
|
||||
EnServiceState m_enState;
|
||||
EnSocketError m_enLastError;
|
||||
HP_SOCKADDR m_soAddr;
|
||||
|
||||
CReceiveBuffersPtr m_rcBuffers;
|
||||
|
||||
CPrivateHeap m_phSocket;
|
||||
CBufferObjPool m_bfObjPool;
|
||||
|
||||
CSpinGuard m_csState;
|
||||
|
||||
CGCThread m_thGC;
|
||||
|
||||
TAgentSocketObjPtrPool m_bfActiveSockets;
|
||||
|
||||
TAgentSocketObjPtrList m_lsFreeSocket;
|
||||
TAgentSocketObjPtrQueue m_lsGCSocket;
|
||||
|
||||
CIODispatcher m_ioDispatcher;
|
||||
};
|
||||
|
|
@ -0,0 +1,717 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpClient.h"
|
||||
|
||||
#include "./common/FileHelper.h"
|
||||
|
||||
BOOL CTcpClient::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress, USHORT usLocalPort)
|
||||
{
|
||||
if(!CheckParams() || !CheckStarting())
|
||||
return FALSE;
|
||||
|
||||
PrepareStart();
|
||||
m_ccContext.Reset();
|
||||
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
HP_SOCKADDR addrRemote, addrBind;
|
||||
|
||||
if(CreateClientSocket(lpszRemoteAddress, addrRemote, usPort, lpszBindAddress, addrBind))
|
||||
{
|
||||
if(BindClientSocket(addrBind, addrRemote, usLocalPort))
|
||||
{
|
||||
if(TRIGGER(FirePrepareConnect(m_soClient)) != HR_ERROR)
|
||||
{
|
||||
if(ConnectToServer(addrRemote, bAsyncConnect))
|
||||
{
|
||||
if(CreateWorkerThread())
|
||||
isOK = TRUE;
|
||||
else
|
||||
SetLastError(SE_WORKER_THREAD_CREATE, __FUNCTION__, ERROR_CREATE_FAILED);
|
||||
}
|
||||
else
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ::WSAGetLastError());
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_PREPARE, __FUNCTION__, ENSURE_ERROR_CANCELLED);
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_BIND, __FUNCTION__, ::WSAGetLastError());
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
|
||||
|
||||
if(!isOK)
|
||||
{
|
||||
m_ccContext.Reset(FALSE);
|
||||
EXECUTE_RESTORE_ERROR(Stop());
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::CheckParams()
|
||||
{
|
||||
if (((int)m_dwSyncConnectTimeout > 0) &&
|
||||
((int)m_dwSocketBufferSize > 0) &&
|
||||
((int)m_dwFreeBufferPoolSize >= 0) &&
|
||||
((int)m_dwFreeBufferPoolHold >= 0) &&
|
||||
((int)m_dwKeepAliveTime >= 1000 || m_dwKeepAliveTime == 0) &&
|
||||
((int)m_dwKeepAliveInterval >= 1000 || m_dwKeepAliveInterval == 0) )
|
||||
return TRUE;
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CTcpClient::PrepareStart()
|
||||
{
|
||||
m_itPool.SetItemCapacity(m_dwSocketBufferSize);
|
||||
m_itPool.SetPoolSize(m_dwFreeBufferPoolSize);
|
||||
m_itPool.SetPoolHold(m_dwFreeBufferPoolHold);
|
||||
|
||||
m_itPool.Prepare();
|
||||
}
|
||||
|
||||
BOOL CTcpClient::CheckStarting()
|
||||
{
|
||||
CSpinLock locallock(m_csState);
|
||||
|
||||
if(m_enState == SS_STOPPED)
|
||||
m_enState = SS_STARTING;
|
||||
else
|
||||
{
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::CheckStoping()
|
||||
{
|
||||
if(m_enState != SS_STOPPED)
|
||||
{
|
||||
CSpinLock locallock(m_csState);
|
||||
|
||||
if(HasStarted())
|
||||
{
|
||||
m_enState = SS_STOPPING;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::CreateClientSocket(LPCTSTR lpszRemoteAddress, HP_SOCKADDR& addrRemote, USHORT usPort, LPCTSTR lpszBindAddress, HP_SOCKADDR& addrBind)
|
||||
{
|
||||
if(::IsStrNotEmpty(lpszBindAddress))
|
||||
{
|
||||
if(!::sockaddr_A_2_IN(lpszBindAddress, 0, addrBind))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HP_SCOPE_HOST host(lpszRemoteAddress);
|
||||
|
||||
if(!::GetSockAddrByHostName(host.addr, usPort, addrRemote, addrBind.family))
|
||||
return FALSE;
|
||||
|
||||
m_soClient = socket(addrRemote.family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(m_soClient == INVALID_SOCKET)
|
||||
return FALSE;
|
||||
|
||||
BOOL bOnOff = (m_dwKeepAliveTime > 0 && m_dwKeepAliveInterval > 0);
|
||||
VERIFY(::SSO_KeepAliveVals(m_soClient, bOnOff, m_dwKeepAliveTime, m_dwKeepAliveInterval) == NO_ERROR);
|
||||
VERIFY(::SSO_ReuseAddress(m_soClient, m_enReusePolicy) == NO_ERROR);
|
||||
VERIFY(::SSO_NoDelay(m_soClient, m_bNoDelay) == NO_ERROR);
|
||||
|
||||
SetRemoteHost(host.name, usPort);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::BindClientSocket(const HP_SOCKADDR& addrBind, const HP_SOCKADDR& addrRemote, USHORT usLocalPort)
|
||||
{
|
||||
if(addrBind.IsSpecified() && usLocalPort == 0)
|
||||
{
|
||||
if(::bind(m_soClient, addrBind.Addr(), addrBind.AddrSize()) == SOCKET_ERROR)
|
||||
return FALSE;
|
||||
}
|
||||
else if(usLocalPort != 0)
|
||||
{
|
||||
HP_SOCKADDR realBindAddr = addrBind.IsSpecified() ? addrBind : HP_SOCKADDR::AnyAddr(addrRemote.family);
|
||||
|
||||
realBindAddr.SetPort(usLocalPort);
|
||||
|
||||
if(::bind(m_soClient, realBindAddr.Addr(), realBindAddr.AddrSize()) == SOCKET_ERROR)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_dwConnID = ::GenerateConnectionID();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::ConnectToServer(const HP_SOCKADDR& addrRemote, BOOL bAsyncConnect)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
VERIFY(::fcntl_SETFL(m_soClient, O_NOATIME | O_NONBLOCK | O_CLOEXEC));
|
||||
|
||||
int rc = ::connect(m_soClient, addrRemote.Addr(), addrRemote.AddrSize());
|
||||
|
||||
if(IS_NO_ERROR(rc) || IS_IO_PENDING_ERROR())
|
||||
{
|
||||
if(bAsyncConnect)
|
||||
{
|
||||
m_nEvents = POLLOUT;
|
||||
isOK = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_HAS_ERROR(rc))
|
||||
rc = ::WaitForSocketWrite(m_soClient, m_dwSyncConnectTimeout);
|
||||
|
||||
if(!IS_NO_ERROR(rc))
|
||||
::WSASetLastError(rc);
|
||||
else
|
||||
{
|
||||
SetConnected();
|
||||
|
||||
if(TRIGGER(FireConnect()) == HR_ERROR)
|
||||
::WSASetLastError(ENSURE_ERROR_CANCELLED);
|
||||
else
|
||||
{
|
||||
m_nEvents = (SHORT)((m_lsSend.IsEmpty() ? 0 : POLLOUT) | (m_bPaused ? 0 : POLLIN) | POLLRDHUP);
|
||||
isOK = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::Stop()
|
||||
{
|
||||
if(!CheckStoping())
|
||||
return FALSE;
|
||||
|
||||
WaitForWorkerThreadEnd();
|
||||
|
||||
SetConnected(FALSE);
|
||||
|
||||
if(m_ccContext.bFireOnClose)
|
||||
FireClose(m_ccContext.enOperation, m_ccContext.iErrorCode);
|
||||
|
||||
if(m_soClient != INVALID_SOCKET)
|
||||
{
|
||||
shutdown(m_soClient, SHUT_WR);
|
||||
closesocket(m_soClient);
|
||||
|
||||
m_soClient = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CTcpClient::Reset()
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
|
||||
m_evSend.Reset();
|
||||
m_evRecv.Reset();
|
||||
m_evStop.Reset();
|
||||
|
||||
m_lsSend.Clear();
|
||||
m_itPool.Clear();
|
||||
m_rcBuffer.Free();
|
||||
|
||||
m_strHost.Empty();
|
||||
|
||||
m_usPort = 0;
|
||||
m_nEvents = 0;
|
||||
m_bPaused = FALSE;
|
||||
m_enState = SS_STOPPED;
|
||||
|
||||
m_evWait.SyncNotifyAll();
|
||||
}
|
||||
|
||||
void CTcpClient::WaitForWorkerThreadEnd()
|
||||
{
|
||||
if(!m_thWorker.IsRunning())
|
||||
return;
|
||||
|
||||
if(m_thWorker.IsInMyThread())
|
||||
m_thWorker.Detach();
|
||||
else
|
||||
{
|
||||
m_evStop.Set();
|
||||
m_thWorker.Join();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CTcpClient::CreateWorkerThread()
|
||||
{
|
||||
return m_thWorker.Start(this, &CTcpClient::WorkerThreadProc);
|
||||
}
|
||||
|
||||
UINT WINAPI CTcpClient::WorkerThreadProc(LPVOID pv)
|
||||
{
|
||||
::SetCurrentWorkerThreadName();
|
||||
|
||||
TRACE("---------------> Client Worker Thread 0x%08X started <---------------", SELF_THREAD_ID);
|
||||
|
||||
OnWorkerThreadStart(SELF_THREAD_ID);
|
||||
|
||||
BOOL bCallStop = TRUE;
|
||||
pollfd pfds[] = { {m_soClient, m_nEvents},
|
||||
{m_evSend.GetFD(), POLLIN},
|
||||
{m_evRecv.GetFD(), POLLIN},
|
||||
{m_evStop.GetFD(), POLLIN} };
|
||||
int size = ARRAY_SIZE(pfds);
|
||||
|
||||
m_rcBuffer.Malloc(m_dwSocketBufferSize);
|
||||
|
||||
while(HasStarted())
|
||||
{
|
||||
int rs = (int)::PollForMultipleObjects(pfds, size);
|
||||
ASSERT(rs > TIMEOUT);
|
||||
|
||||
if(rs <= 0)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_UNKNOWN, ::WSAGetLastError());
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
if((1 << i) & rs)
|
||||
{
|
||||
SHORT revents = pfds[i].revents;
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
if(!ProcessNetworkEvent(revents))
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 1)
|
||||
{
|
||||
m_evSend.Reset();
|
||||
|
||||
if(!SendData())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 2)
|
||||
{
|
||||
m_evRecv.Reset();
|
||||
|
||||
if(!BeforeUnpause())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
|
||||
if(!ReadData())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 3)
|
||||
{
|
||||
m_evStop.Reset();
|
||||
|
||||
bCallStop = FALSE;
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else
|
||||
VERIFY(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
m_nEvents = (SHORT)((m_lsSend.IsEmpty() ? 0 : POLLOUT) | (m_bPaused ? 0 : POLLIN) | POLLRDHUP);
|
||||
pfds[0].events = m_nEvents;
|
||||
}
|
||||
|
||||
EXIT_WORKER_THREAD:
|
||||
|
||||
OnWorkerThreadEnd(SELF_THREAD_ID);
|
||||
|
||||
if(bCallStop && HasStarted())
|
||||
Stop();
|
||||
|
||||
TRACE("---------------> Client Worker Thread 0x%08X stoped <---------------", SELF_THREAD_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::ProcessNetworkEvent(SHORT events)
|
||||
{
|
||||
BOOL bContinue = TRUE;
|
||||
|
||||
if(bContinue && events & POLLERR)
|
||||
bContinue = HandleClose(events);
|
||||
|
||||
if(bContinue && !IsConnected())
|
||||
bContinue = HandleConnect(events);
|
||||
|
||||
if(bContinue && events & POLLIN)
|
||||
bContinue = HandleRead(events);
|
||||
|
||||
if(bContinue && events & POLLOUT)
|
||||
bContinue = HandleWrite(events);
|
||||
|
||||
if(bContinue && events & _POLL_HUNGUP_EVENTS)
|
||||
bContinue = HandleClose(events);
|
||||
|
||||
return bContinue;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::HandleConnect(SHORT events)
|
||||
{
|
||||
ASSERT(events & POLLOUT);
|
||||
|
||||
int code = ::SSO_GetError(m_soClient);
|
||||
|
||||
if(!IS_NO_ERROR(code) || (events & _POLL_ERROR_EVENTS))
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CONNECT, code);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(events & _POLL_HUNGUP_EVENTS)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CONNECT, NO_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SetConnected();
|
||||
|
||||
if(TRIGGER(FireConnect()) == HR_ERROR)
|
||||
{
|
||||
m_ccContext.Reset(FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::HandleClose(SHORT events)
|
||||
{
|
||||
EnSocketOperation enOperation = SO_CLOSE;
|
||||
|
||||
if(events & _POLL_HUNGUP_EVENTS)
|
||||
enOperation = SO_CLOSE;
|
||||
else if(events & POLLIN)
|
||||
enOperation = SO_RECEIVE;
|
||||
else if(events & POLLOUT)
|
||||
enOperation = SO_SEND;
|
||||
|
||||
m_ccContext.Reset(TRUE, enOperation, ::SSO_GetError(m_soClient));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::HandleRead(SHORT events)
|
||||
{
|
||||
return ReadData();
|
||||
}
|
||||
|
||||
BOOL CTcpClient::HandleWrite(SHORT events)
|
||||
{
|
||||
return SendData();
|
||||
}
|
||||
|
||||
BOOL CTcpClient::ReadData()
|
||||
{
|
||||
while(TRUE)
|
||||
{
|
||||
if(m_bPaused)
|
||||
break;
|
||||
|
||||
int rc = (int)read(m_soClient, (char*)(BYTE*)m_rcBuffer, m_dwSocketBufferSize);
|
||||
|
||||
if(rc > 0)
|
||||
{
|
||||
if(TRIGGER(FireReceive(m_rcBuffer, rc)) == HR_ERROR)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> OnReceive() event return 'HR_ERROR', connection will be closed !", m_dwConnID);
|
||||
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, ENSURE_ERROR_CANCELLED);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
break;
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, code);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(rc == 0)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CLOSE, SE_OK);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::PauseReceive(BOOL bPause)
|
||||
{
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(m_bPaused == bPause)
|
||||
return TRUE;
|
||||
|
||||
m_bPaused = bPause;
|
||||
|
||||
if(!bPause)
|
||||
return m_evRecv.Set();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::SendData()
|
||||
{
|
||||
BOOL bBlocked = FALSE;
|
||||
|
||||
while(m_lsSend.Length() > 0)
|
||||
{
|
||||
TItemPtr itPtr(m_itPool);
|
||||
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
itPtr = m_lsSend.PopFront();
|
||||
}
|
||||
|
||||
if(!itPtr.IsValid())
|
||||
break;
|
||||
|
||||
ASSERT(!itPtr->IsEmpty());
|
||||
|
||||
if(!DoSendData(itPtr, bBlocked))
|
||||
return FALSE;
|
||||
|
||||
if(bBlocked)
|
||||
{
|
||||
ASSERT(!itPtr->IsEmpty());
|
||||
|
||||
CCriSecLock locallock(m_csSend);
|
||||
m_lsSend.PushFront(itPtr.Detach());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::DoSendData(TItem* pItem, BOOL& bBlocked)
|
||||
{
|
||||
while(!pItem->IsEmpty())
|
||||
{
|
||||
int rc = (int)write(m_soClient, (char*)pItem->Ptr(), pItem->Size());
|
||||
|
||||
if(rc > 0)
|
||||
{
|
||||
if(TRIGGER(FireSend(pItem->Ptr(), rc)) == HR_ERROR)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> OnSend() event should not return 'HR_ERROR' !!", m_dwConnID);
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
pItem->Reduce(rc);
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
{
|
||||
bBlocked = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_SEND, code);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::Send(const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
ASSERT(pBuffer && iLength > 0);
|
||||
|
||||
if(iOffset != 0) pBuffer += iOffset;
|
||||
|
||||
WSABUF buffer;
|
||||
buffer.len = iLength;
|
||||
buffer.buf = (BYTE*)pBuffer;
|
||||
|
||||
return SendPackets(&buffer, 1);
|
||||
}
|
||||
|
||||
BOOL CTcpClient::DoSendPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
int result = NO_ERROR;
|
||||
|
||||
if(pBuffers && iCount > 0)
|
||||
{
|
||||
if(IsConnected())
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
|
||||
if(IsConnected())
|
||||
result = SendInternal(pBuffers, iCount);
|
||||
else
|
||||
result = ERROR_INVALID_STATE;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_STATE;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
int CTcpClient::SendInternal(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(m_lsSend.Length() >= 0);
|
||||
|
||||
int iPending = m_lsSend.Length();
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
int iBufLen = pBuffers[i].len;
|
||||
|
||||
if(iBufLen > 0)
|
||||
{
|
||||
BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
|
||||
ASSERT(pBuffer);
|
||||
|
||||
m_lsSend.Cat(pBuffer, iBufLen);
|
||||
ASSERT(m_lsSend.Length() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(iPending == 0 && m_lsSend.Length() > 0) m_evSend.Set();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::SendSmallFile(LPCTSTR lpszFileName, const LPWSABUF pHead, const LPWSABUF pTail)
|
||||
{
|
||||
CFile file;
|
||||
CFileMapping fmap;
|
||||
WSABUF szBuf[3];
|
||||
|
||||
HRESULT hr = ::MakeSmallFilePackage(lpszFileName, file, fmap, szBuf, pHead, pTail);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
::SetLastError(hr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return SendPackets(szBuf, 3);
|
||||
}
|
||||
|
||||
void CTcpClient::SetLastError(EnSocketError code, LPCSTR func, int ec)
|
||||
{
|
||||
TRACE("%s --> Error: %d, EC: %d", func, code, ec);
|
||||
|
||||
m_enLastError = code;
|
||||
::SetLastError(ec);
|
||||
}
|
||||
|
||||
BOOL CTcpClient::GetLocalAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
ASSERT(lpszAddress != nullptr && iAddressLen > 0);
|
||||
|
||||
return ::GetSocketLocalAddress(m_soClient, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
void CTcpClient::SetRemoteHost(LPCTSTR lpszHost, USHORT usPort)
|
||||
{
|
||||
m_strHost = lpszHost;
|
||||
m_usPort = usPort;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::GetRemoteHost(TCHAR lpszHost[], int& iHostLen, USHORT& usPort)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
if(m_strHost.IsEmpty())
|
||||
return isOK;
|
||||
|
||||
int iLen = m_strHost.GetLength() + 1;
|
||||
|
||||
if(iHostLen >= iLen)
|
||||
{
|
||||
memcpy(lpszHost, CA2CT(m_strHost), iLen * sizeof(TCHAR));
|
||||
usPort = m_usPort;
|
||||
|
||||
isOK = TRUE;
|
||||
}
|
||||
|
||||
iHostLen = iLen;
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CTcpClient::GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort)
|
||||
{
|
||||
*lpszHost = m_strHost;
|
||||
|
||||
if(pusPort != nullptr)
|
||||
*pusPort = m_usPort;
|
||||
|
||||
return !m_strHost.IsEmpty();
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
|
||||
class CTcpClient : public ITcpClient
|
||||
{
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr, USHORT usLocalPort = 0);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Send (const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendSmallFile (LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr);
|
||||
virtual BOOL SendPackets (const WSABUF pBuffers[], int iCount) {return DoSendPackets(pBuffers, iCount);}
|
||||
virtual BOOL PauseReceive (BOOL bPause = TRUE);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual CONNID GetConnectionID () {return m_dwConnID;}
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
|
||||
virtual BOOL GetLocalAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteHost (TCHAR lpszHost[], int& iHostLen, USHORT& usPort);
|
||||
virtual BOOL GetPendingDataLength (int& iPending) {iPending = m_lsSend.Length(); return HasStarted();}
|
||||
virtual BOOL IsPauseReceive (BOOL& bPaused) {bPaused = m_bPaused; return HasStarted();}
|
||||
virtual BOOL IsConnected () {return m_bConnected;}
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
virtual BOOL SetupSSLContext (int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr) {return FALSE;}
|
||||
virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr) {return FALSE;}
|
||||
virtual void CleanupSSLContext () {}
|
||||
|
||||
virtual BOOL StartSSLHandShake () {return FALSE;}
|
||||
virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) {}
|
||||
virtual BOOL IsSSLAutoHandShake () {return FALSE;}
|
||||
virtual void SetSSLCipherList (LPCTSTR lpszCipherList){}
|
||||
virtual LPCTSTR GetSSLCipherList() {return nullptr;}
|
||||
virtual BOOL GetSSLSessionInfo(EnSSLSessionInfo enInfo, LPVOID* lppInfo) {return FALSE;}
|
||||
|
||||
protected:
|
||||
virtual BOOL StartSSLHandShakeNoCheck() {return FALSE;}
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure () {return FALSE;}
|
||||
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy){ENSURE_HAS_STOPPED(); m_enReusePolicy = enReusePolicy;}
|
||||
virtual void SetSyncConnectTimeout (DWORD dwSyncConnectTimeout) {ENSURE_HAS_STOPPED(); m_dwSyncConnectTimeout = dwSyncConnectTimeout;}
|
||||
virtual void SetSocketBufferSize (DWORD dwSocketBufferSize) {ENSURE_HAS_STOPPED(); m_dwSocketBufferSize = dwSocketBufferSize;}
|
||||
virtual void SetKeepAliveTime (DWORD dwKeepAliveTime) {ENSURE_HAS_STOPPED(); m_dwKeepAliveTime = dwKeepAliveTime;}
|
||||
virtual void SetKeepAliveInterval (DWORD dwKeepAliveInterval) {ENSURE_HAS_STOPPED(); m_dwKeepAliveInterval = dwKeepAliveInterval;}
|
||||
virtual void SetFreeBufferPoolSize (DWORD dwFreeBufferPoolSize) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolSize = dwFreeBufferPoolSize;}
|
||||
virtual void SetFreeBufferPoolHold (DWORD dwFreeBufferPoolHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolHold = dwFreeBufferPoolHold;}
|
||||
virtual void SetNoDelay (BOOL bNoDelay) {ENSURE_HAS_STOPPED(); m_bNoDelay = bNoDelay;}
|
||||
virtual void SetExtra (PVOID pExtra) {m_pExtra = pExtra;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual DWORD GetSyncConnectTimeout () {return m_dwSyncConnectTimeout;}
|
||||
virtual DWORD GetSocketBufferSize () {return m_dwSocketBufferSize;}
|
||||
virtual DWORD GetKeepAliveTime () {return m_dwKeepAliveTime;}
|
||||
virtual DWORD GetKeepAliveInterval () {return m_dwKeepAliveInterval;}
|
||||
virtual DWORD GetFreeBufferPoolSize () {return m_dwFreeBufferPoolSize;}
|
||||
virtual DWORD GetFreeBufferPoolHold () {return m_dwFreeBufferPoolHold;}
|
||||
virtual BOOL IsNoDelay () {return m_bNoDelay;}
|
||||
virtual PVOID GetExtra () {return m_pExtra;}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FirePrepareConnect(SOCKET socket)
|
||||
{return DoFirePrepareConnect(this, socket);}
|
||||
virtual EnHandleResult FireConnect()
|
||||
{
|
||||
EnHandleResult rs = DoFireConnect(this);
|
||||
if(rs != HR_ERROR) rs = FireHandShake();
|
||||
return rs;
|
||||
}
|
||||
virtual EnHandleResult FireHandShake()
|
||||
{return DoFireHandShake(this);}
|
||||
virtual EnHandleResult FireSend(const BYTE* pData, int iLength)
|
||||
{return DoFireSend(this, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(const BYTE* pData, int iLength)
|
||||
{return DoFireReceive(this, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(int iLength)
|
||||
{return DoFireReceive(this, iLength);}
|
||||
virtual EnHandleResult FireClose(EnSocketOperation enOperation, int iErrorCode)
|
||||
{return DoFireClose(this, enOperation, iErrorCode);}
|
||||
|
||||
virtual EnHandleResult DoFirePrepareConnect(ITcpClient* pSender, SOCKET socket)
|
||||
{return m_pListener->OnPrepareConnect(pSender, pSender->GetConnectionID(), socket);}
|
||||
virtual EnHandleResult DoFireConnect(ITcpClient* pSender)
|
||||
{return m_pListener->OnConnect(pSender, pSender->GetConnectionID());}
|
||||
virtual EnHandleResult DoFireHandShake(ITcpClient* pSender)
|
||||
{return m_pListener->OnHandShake(pSender, pSender->GetConnectionID());}
|
||||
virtual EnHandleResult DoFireSend(ITcpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnSend(pSender, pSender->GetConnectionID(), pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(ITcpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnReceive(pSender, pSender->GetConnectionID(), pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(ITcpClient* pSender, int iLength)
|
||||
{return m_pListener->OnReceive(pSender, pSender->GetConnectionID(), iLength);}
|
||||
virtual EnHandleResult DoFireClose(ITcpClient* pSender, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_pListener->OnClose(pSender, pSender->GetConnectionID(), enOperation, iErrorCode);}
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual BOOL BeforeUnpause() {return TRUE;}
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID tid) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID tid) {}
|
||||
|
||||
BOOL DoSendPackets(const WSABUF pBuffers[], int iCount);
|
||||
|
||||
static BOOL DoSendPackets(CTcpClient* pClient, const WSABUF pBuffers[], int iCount)
|
||||
{return pClient->DoSendPackets(pBuffers, iCount);}
|
||||
|
||||
protected:
|
||||
BOOL IsPaused () {return m_bPaused;}
|
||||
void SetReserved (PVOID pReserved) {m_pReserved = pReserved;}
|
||||
PVOID GetReserved () {return m_pReserved;}
|
||||
BOOL GetRemoteHost (LPCSTR* lpszHost, USHORT* pusPort = nullptr);
|
||||
|
||||
private:
|
||||
void SetRemoteHost (LPCTSTR lpszHost, USHORT usPort);
|
||||
void SetConnected (BOOL bConnected = TRUE) {m_bConnected = bConnected; if(bConnected) m_enState = SS_STARTED;}
|
||||
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL CreateClientSocket(LPCTSTR lpszRemoteAddress, HP_SOCKADDR& addrRemote, USHORT usPort, LPCTSTR lpszBindAddress, HP_SOCKADDR& addrBind);
|
||||
BOOL BindClientSocket(const HP_SOCKADDR& addrBind, const HP_SOCKADDR& addrRemote, USHORT usLocalPort);
|
||||
BOOL ConnectToServer(const HP_SOCKADDR& addrRemote, BOOL bAsyncConnect);
|
||||
BOOL CreateWorkerThread();
|
||||
BOOL ProcessNetworkEvent(SHORT events);
|
||||
BOOL ReadData();
|
||||
BOOL SendData();
|
||||
BOOL DoSendData(TItem* pItem, BOOL& bBlocked);
|
||||
int SendInternal(const WSABUF pBuffers[], int iCount);
|
||||
void WaitForWorkerThreadEnd();
|
||||
|
||||
BOOL HandleConnect (SHORT events);
|
||||
BOOL HandleClose (SHORT events);
|
||||
BOOL HandleRead (SHORT events);
|
||||
BOOL HandleWrite (SHORT events);
|
||||
|
||||
UINT WINAPI WorkerThreadProc(LPVOID pv);
|
||||
|
||||
public:
|
||||
CTcpClient(ITcpClientListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_lsSend (m_itPool)
|
||||
, m_soClient (INVALID_SOCKET)
|
||||
, m_nEvents (0)
|
||||
, m_dwConnID (0)
|
||||
, m_usPort (0)
|
||||
, m_bPaused (FALSE)
|
||||
, m_bConnected (FALSE)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_bNoDelay (FALSE)
|
||||
, m_pExtra (nullptr)
|
||||
, m_pReserved (nullptr)
|
||||
, m_enReusePolicy (RAP_ADDR_ONLY)
|
||||
, m_dwSyncConnectTimeout(DEFAULT_SYNC_CONNECT_TIMEOUT)
|
||||
, m_dwSocketBufferSize (DEFAULT_TCP_SOCKET_BUFFER_SIZE)
|
||||
, m_dwFreeBufferPoolSize(DEFAULT_CLIENT_FREE_BUFFER_POOL_SIZE)
|
||||
, m_dwFreeBufferPoolHold(DEFAULT_CLIENT_FREE_BUFFER_POOL_HOLD)
|
||||
, m_dwKeepAliveTime (DEFALUT_TCP_KEEPALIVE_TIME)
|
||||
, m_dwKeepAliveInterval (DEFALUT_TCP_KEEPALIVE_INTERVAL)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CTcpClient()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
ITcpClientListener* m_pListener;
|
||||
TClientCloseContext m_ccContext;
|
||||
|
||||
SOCKET m_soClient;
|
||||
SHORT m_nEvents;
|
||||
CONNID m_dwConnID;
|
||||
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
DWORD m_dwSyncConnectTimeout;
|
||||
DWORD m_dwSocketBufferSize;
|
||||
DWORD m_dwFreeBufferPoolSize;
|
||||
DWORD m_dwFreeBufferPoolHold;
|
||||
DWORD m_dwKeepAliveTime;
|
||||
DWORD m_dwKeepAliveInterval;
|
||||
BOOL m_bNoDelay;
|
||||
|
||||
EnSocketError m_enLastError;
|
||||
volatile BOOL m_bConnected;
|
||||
volatile EnServiceState m_enState;
|
||||
|
||||
PVOID m_pExtra;
|
||||
PVOID m_pReserved;
|
||||
|
||||
CBufferPtr m_rcBuffer;
|
||||
|
||||
protected:
|
||||
CStringA m_strHost;
|
||||
USHORT m_usPort;
|
||||
|
||||
CItemPool m_itPool;
|
||||
|
||||
private:
|
||||
CSpinGuard m_csState;
|
||||
|
||||
CCriSec m_csSend;
|
||||
TItemListExV m_lsSend;
|
||||
|
||||
CEvt m_evSend;
|
||||
CEvt m_evRecv;
|
||||
CEvt m_evStop;
|
||||
|
||||
volatile BOOL m_bPaused;
|
||||
|
||||
CThread<CTcpClient, VOID, UINT> m_thWorker;
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpPackAgent.h"
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpAgent.h"
|
||||
#include "MiscHelper.h"
|
||||
|
||||
template<class T> class CTcpPackAgentT : public IPackSocket, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::SetConnectionReserved;
|
||||
using __super::GetConnectionReserved;
|
||||
using __super::GetMaxConnectionCount;
|
||||
using __super::GetSocketBufferSize;
|
||||
using __super::GetFreeBufferObjPool;
|
||||
using __super::GetFreeBufferObjHold;
|
||||
using __super::GetFreeSocketObjLockTime;
|
||||
using __super::GetFreeSocketObjPool;
|
||||
using __super::GetFreeSocketObjHold;
|
||||
using __super::SetLastError;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
|
||||
public:
|
||||
virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
int iNewCount = iCount + 1;
|
||||
unique_ptr<WSABUF[]> buffers(new WSABUF[iNewCount]);
|
||||
|
||||
DWORD dwHeader;
|
||||
if(!::AddPackHeader(pBuffers, iCount, buffers, m_dwMaxPackSize, m_usHeaderFlag, dwHeader))
|
||||
return FALSE;
|
||||
|
||||
return __super::SendPackets(dwConnID, buffers.get(), iNewCount);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult DoFireConnect(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireConnect(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool.PickFreeBuffer(pSocketObj->connID);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, TBufferPackInfo::Construct(pBuffer)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireHandShake(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
TBufferPackInfo* pInfo = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pInfo);
|
||||
ASSERT(pInfo);
|
||||
|
||||
TBuffer* pBuffer = (TBuffer*)pInfo->pBuffer;
|
||||
ASSERT(pBuffer && pBuffer->IsValid());
|
||||
|
||||
return ParsePack(this, pInfo, pBuffer, pSocketObj, m_dwMaxPackSize, m_usHeaderFlag, pData, iLength);
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{
|
||||
EnHandleResult result = __super::DoFireShutdown();
|
||||
|
||||
m_bfPool.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual BOOL BeforeUnpause(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
if(!TAgentSocketObj::IsValid(pSocketObj))
|
||||
return FALSE;
|
||||
|
||||
if(pSocketObj->IsPaused())
|
||||
return TRUE;
|
||||
|
||||
TBufferPackInfo* pInfo = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pInfo);
|
||||
ASSERT(pInfo);
|
||||
|
||||
TBuffer* pBuffer = (TBuffer*)pInfo->pBuffer;
|
||||
ASSERT(pBuffer && pBuffer->IsValid());
|
||||
|
||||
return (ParsePack(this, pInfo, pBuffer, pSocketObj, m_dwMaxPackSize, m_usHeaderFlag) != HR_ERROR);
|
||||
}
|
||||
|
||||
virtual BOOL CheckParams()
|
||||
{
|
||||
if ((m_dwMaxPackSize > 0 && m_dwMaxPackSize <= TCP_PACK_MAX_SIZE_LIMIT) &&
|
||||
(m_usHeaderFlag >= 0 && m_usHeaderFlag <= TCP_PACK_HEADER_FLAG_LIMIT) )
|
||||
return __super::CheckParams();
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
virtual void PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_bfPool.SetMaxCacheSize (GetMaxConnectionCount());
|
||||
m_bfPool.SetItemCapacity (GetSocketBufferSize());
|
||||
m_bfPool.SetItemPoolSize (GetFreeBufferObjPool());
|
||||
m_bfPool.SetItemPoolHold (GetFreeBufferObjHold());
|
||||
m_bfPool.SetBufferLockTime (GetFreeSocketObjLockTime());
|
||||
m_bfPool.SetBufferPoolSize (GetFreeSocketObjPool());
|
||||
m_bfPool.SetBufferPoolHold (GetFreeSocketObjHold());
|
||||
|
||||
m_bfPool.Prepare();
|
||||
}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_bfPool.ReleaseGCBuffer(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SetMaxPackSize (DWORD dwMaxPackSize) {ENSURE_HAS_STOPPED(); m_dwMaxPackSize = dwMaxPackSize;}
|
||||
virtual void SetPackHeaderFlag (USHORT usPackHeaderFlag) {ENSURE_HAS_STOPPED(); m_usHeaderFlag = usPackHeaderFlag;}
|
||||
virtual DWORD GetMaxPackSize () {return m_dwMaxPackSize;}
|
||||
virtual USHORT GetPackHeaderFlag() {return m_usHeaderFlag;}
|
||||
|
||||
private:
|
||||
void ReleaseConnectionExtra(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
TBufferPackInfo* pInfo = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pInfo);
|
||||
|
||||
if(pInfo != nullptr)
|
||||
{
|
||||
m_bfPool.PutFreeBuffer(pInfo->pBuffer);
|
||||
TBufferPackInfo::Destruct(pInfo);
|
||||
|
||||
ENSURE(SetConnectionReserved(pSocketObj, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
EnHandleResult DoFireSuperReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return __super::DoFireReceive(pSocketObj, pData, iLength);}
|
||||
|
||||
friend EnHandleResult ParsePack<>(CTcpPackAgentT* pThis, TBufferPackInfo* pInfo, TBuffer* pBuffer, TAgentSocketObj* pSocket, DWORD dwMaxPackSize, USHORT usPackHeaderFlag);
|
||||
|
||||
public:
|
||||
CTcpPackAgentT(ITcpAgentListener* pListener)
|
||||
: T (pListener)
|
||||
, m_dwMaxPackSize (TCP_PACK_DEFAULT_MAX_SIZE)
|
||||
, m_usHeaderFlag (TCP_PACK_DEFAULT_HEADER_FLAG)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CTcpPackAgentT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwMaxPackSize;
|
||||
USHORT m_usHeaderFlag;
|
||||
|
||||
CBufferPool m_bfPool;
|
||||
};
|
||||
|
||||
typedef CTcpPackAgentT<CTcpAgent> CTcpPackAgent;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLAgent.h"
|
||||
typedef CTcpPackAgentT<CSSLAgent> CSSLPackAgent;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpPackClient.h"
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpClient.h"
|
||||
#include "MiscHelper.h"
|
||||
|
||||
template<class T> class CTcpPackClientT : public IPackClient, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::SetLastError;
|
||||
using __super::m_itPool;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
|
||||
public:
|
||||
virtual BOOL SendPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
int iNewCount = iCount + 1;
|
||||
unique_ptr<WSABUF[]> buffers(new WSABUF[iNewCount]);
|
||||
|
||||
DWORD dwHeader;
|
||||
if(!::AddPackHeader(pBuffers, iCount, buffers, m_dwMaxPackSize, m_usHeaderFlag, dwHeader))
|
||||
return FALSE;
|
||||
|
||||
return __super::SendPackets(buffers.get(), iNewCount);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult DoFireReceive(ITcpClient* pSender, const BYTE* pData, int iLength)
|
||||
{
|
||||
return ParsePack(this, &m_pkInfo, &m_lsBuffer, (CTcpPackClientT*)pSender, m_dwMaxPackSize, m_usHeaderFlag, pData, iLength);
|
||||
}
|
||||
|
||||
virtual BOOL BeforeUnpause()
|
||||
{
|
||||
return (ParsePack(this, &m_pkInfo, &m_lsBuffer, (CTcpPackClientT*)this, m_dwMaxPackSize, m_usHeaderFlag) != HR_ERROR);
|
||||
}
|
||||
|
||||
virtual BOOL CheckParams()
|
||||
{
|
||||
if ((m_dwMaxPackSize > 0 && m_dwMaxPackSize <= TCP_PACK_MAX_SIZE_LIMIT) &&
|
||||
(m_usHeaderFlag >= 0 && m_usHeaderFlag <= TCP_PACK_HEADER_FLAG_LIMIT) )
|
||||
return __super::CheckParams();
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
virtual void Reset()
|
||||
{
|
||||
m_lsBuffer.Clear();
|
||||
m_pkInfo.Reset();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SetMaxPackSize (DWORD dwMaxPackSize) {ENSURE_HAS_STOPPED(); m_dwMaxPackSize = dwMaxPackSize;}
|
||||
virtual void SetPackHeaderFlag (USHORT usPackHeaderFlag) {ENSURE_HAS_STOPPED(); m_usHeaderFlag = usPackHeaderFlag;}
|
||||
virtual DWORD GetMaxPackSize () {return m_dwMaxPackSize;}
|
||||
virtual USHORT GetPackHeaderFlag() {return m_usHeaderFlag;}
|
||||
|
||||
private:
|
||||
EnHandleResult DoFireSuperReceive(ITcpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return __super::DoFireReceive(pSender, pData, iLength);}
|
||||
|
||||
friend EnHandleResult ParsePack<> (CTcpPackClientT* pThis, TPackInfo<TItemListEx>* pInfo, TItemListEx* pBuffer, CTcpPackClientT* pSocket,
|
||||
DWORD dwMaxPackSize, USHORT usPackHeaderFlag);
|
||||
|
||||
public:
|
||||
CTcpPackClientT(ITcpClientListener* pListener)
|
||||
: T (pListener)
|
||||
, m_dwMaxPackSize (TCP_PACK_DEFAULT_MAX_SIZE)
|
||||
, m_usHeaderFlag (TCP_PACK_DEFAULT_HEADER_FLAG)
|
||||
, m_pkInfo (nullptr)
|
||||
, m_lsBuffer (m_itPool)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CTcpPackClientT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwMaxPackSize;
|
||||
USHORT m_usHeaderFlag;
|
||||
|
||||
TPackInfo<TItemListEx> m_pkInfo;
|
||||
TItemListEx m_lsBuffer;
|
||||
};
|
||||
|
||||
typedef CTcpPackClientT<CTcpClient> CTcpPackClient;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLClient.h"
|
||||
typedef CTcpPackClientT<CSSLClient> CSSLPackClient;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpPackServer.h"
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpServer.h"
|
||||
#include "MiscHelper.h"
|
||||
|
||||
template<class T> class CTcpPackServerT : public IPackSocket, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::SetConnectionReserved;
|
||||
using __super::GetConnectionReserved;
|
||||
using __super::GetMaxConnectionCount;
|
||||
using __super::GetSocketBufferSize;
|
||||
using __super::GetFreeBufferObjPool;
|
||||
using __super::GetFreeBufferObjHold;
|
||||
using __super::GetFreeSocketObjLockTime;
|
||||
using __super::GetFreeSocketObjPool;
|
||||
using __super::GetFreeSocketObjHold;
|
||||
using __super::SetLastError;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
|
||||
public:
|
||||
virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
int iNewCount = iCount + 1;
|
||||
unique_ptr<WSABUF[]> buffers(new WSABUF[iNewCount]);
|
||||
|
||||
DWORD dwHeader;
|
||||
if(!::AddPackHeader(pBuffers, iCount, buffers, m_dwMaxPackSize, m_usHeaderFlag, dwHeader))
|
||||
return FALSE;
|
||||
|
||||
return __super::SendPackets(dwConnID, buffers.get(), iNewCount);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult DoFireAccept(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireAccept(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool.PickFreeBuffer(pSocketObj->connID);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, TBufferPackInfo::Construct(pBuffer)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireHandShake(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
TBufferPackInfo* pInfo = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pInfo);
|
||||
ASSERT(pInfo);
|
||||
|
||||
TBuffer* pBuffer = (TBuffer*)pInfo->pBuffer;
|
||||
ASSERT(pBuffer && pBuffer->IsValid());
|
||||
|
||||
return ParsePack(this, pInfo, pBuffer, pSocketObj, m_dwMaxPackSize, m_usHeaderFlag, pData, iLength);
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{
|
||||
EnHandleResult result = __super::DoFireShutdown();
|
||||
|
||||
m_bfPool.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual BOOL BeforeUnpause(TSocketObj* pSocketObj)
|
||||
{
|
||||
if(!TSocketObj::IsValid(pSocketObj))
|
||||
return FALSE;
|
||||
|
||||
if(pSocketObj->IsPaused())
|
||||
return TRUE;
|
||||
|
||||
TBufferPackInfo* pInfo = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pInfo);
|
||||
ASSERT(pInfo);
|
||||
|
||||
TBuffer* pBuffer = (TBuffer*)pInfo->pBuffer;
|
||||
ASSERT(pBuffer && pBuffer->IsValid());
|
||||
|
||||
return (ParsePack(this, pInfo, pBuffer, pSocketObj, m_dwMaxPackSize, m_usHeaderFlag) != HR_ERROR);
|
||||
}
|
||||
|
||||
virtual BOOL CheckParams()
|
||||
{
|
||||
if ((m_dwMaxPackSize > 0 && m_dwMaxPackSize <= TCP_PACK_MAX_SIZE_LIMIT) &&
|
||||
(m_usHeaderFlag >= 0 && m_usHeaderFlag <= TCP_PACK_HEADER_FLAG_LIMIT) )
|
||||
return __super::CheckParams();
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
virtual void PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_bfPool.SetMaxCacheSize (GetMaxConnectionCount());
|
||||
m_bfPool.SetItemCapacity (GetSocketBufferSize());
|
||||
m_bfPool.SetItemPoolSize (GetFreeBufferObjPool());
|
||||
m_bfPool.SetItemPoolHold (GetFreeBufferObjHold());
|
||||
m_bfPool.SetBufferLockTime (GetFreeSocketObjLockTime());
|
||||
m_bfPool.SetBufferPoolSize (GetFreeSocketObjPool());
|
||||
m_bfPool.SetBufferPoolHold (GetFreeSocketObjHold());
|
||||
|
||||
m_bfPool.Prepare();
|
||||
}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_bfPool.ReleaseGCBuffer(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SetMaxPackSize (DWORD dwMaxPackSize) {ENSURE_HAS_STOPPED(); m_dwMaxPackSize = dwMaxPackSize;}
|
||||
virtual void SetPackHeaderFlag (USHORT usPackHeaderFlag) {ENSURE_HAS_STOPPED(); m_usHeaderFlag = usPackHeaderFlag;}
|
||||
virtual DWORD GetMaxPackSize () {return m_dwMaxPackSize;}
|
||||
virtual USHORT GetPackHeaderFlag() {return m_usHeaderFlag;}
|
||||
|
||||
private:
|
||||
void ReleaseConnectionExtra(TSocketObj* pSocketObj)
|
||||
{
|
||||
TBufferPackInfo* pInfo = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pInfo);
|
||||
|
||||
if(pInfo != nullptr)
|
||||
{
|
||||
m_bfPool.PutFreeBuffer(pInfo->pBuffer);
|
||||
TBufferPackInfo::Destruct(pInfo);
|
||||
|
||||
ENSURE(SetConnectionReserved(pSocketObj, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
EnHandleResult DoFireSuperReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return __super::DoFireReceive(pSocketObj, pData, iLength);}
|
||||
|
||||
friend EnHandleResult ParsePack<>(CTcpPackServerT* pThis, TBufferPackInfo* pInfo, TBuffer* pBuffer, TSocketObj* pSocket, DWORD dwMaxPackSize, USHORT usPackHeaderFlag);
|
||||
|
||||
public:
|
||||
CTcpPackServerT(ITcpServerListener* pListener)
|
||||
: T (pListener)
|
||||
, m_dwMaxPackSize (TCP_PACK_DEFAULT_MAX_SIZE)
|
||||
, m_usHeaderFlag (TCP_PACK_DEFAULT_HEADER_FLAG)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CTcpPackServerT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwMaxPackSize;
|
||||
USHORT m_usHeaderFlag;
|
||||
|
||||
CBufferPool m_bfPool;
|
||||
};
|
||||
|
||||
typedef CTcpPackServerT<CTcpServer> CTcpPackServer;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLServer.h"
|
||||
typedef CTcpPackServerT<CSSLServer> CSSLPackServer;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpPullAgent.h"
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpAgent.h"
|
||||
#include "MiscHelper.h"
|
||||
|
||||
template<class T> class CTcpPullAgentT : public IPullSocket, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::SetConnectionReserved;
|
||||
using __super::GetConnectionReserved;
|
||||
using __super::GetMaxConnectionCount;
|
||||
using __super::GetSocketBufferSize;
|
||||
using __super::GetFreeBufferObjPool;
|
||||
using __super::GetFreeBufferObjHold;
|
||||
using __super::GetFreeSocketObjLockTime;
|
||||
using __super::GetFreeSocketObjPool;
|
||||
using __super::GetFreeSocketObjHold;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
|
||||
public:
|
||||
virtual EnFetchResult Fetch(CONNID dwConnID, BYTE* pData, int iLength)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool[dwConnID];
|
||||
return ::FetchBuffer(pBuffer, pData, iLength);
|
||||
}
|
||||
|
||||
virtual EnFetchResult Peek(CONNID dwConnID, BYTE* pData, int iLength)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool[dwConnID];
|
||||
return ::PeekBuffer(pBuffer, pData, iLength);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult DoFireConnect(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireConnect(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool.PutCacheBuffer(pSocketObj->connID);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, pBuffer));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireHandShake(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireReceive(TAgentSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
TBuffer* pBuffer = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pBuffer);
|
||||
ASSERT(pBuffer && pBuffer->IsValid());
|
||||
|
||||
pBuffer->Cat(pData, iLength);
|
||||
|
||||
return __super::DoFireReceive(pSocketObj, pBuffer->Length());
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireClose(TAgentSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{
|
||||
EnHandleResult result = __super::DoFireShutdown();
|
||||
|
||||
m_bfPool.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_bfPool.SetMaxCacheSize (GetMaxConnectionCount());
|
||||
m_bfPool.SetItemCapacity (GetSocketBufferSize());
|
||||
m_bfPool.SetItemPoolSize (GetFreeBufferObjPool());
|
||||
m_bfPool.SetItemPoolHold (GetFreeBufferObjHold());
|
||||
m_bfPool.SetBufferLockTime (GetFreeSocketObjLockTime());
|
||||
m_bfPool.SetBufferPoolSize (GetFreeSocketObjPool());
|
||||
m_bfPool.SetBufferPoolHold (GetFreeSocketObjHold());
|
||||
|
||||
m_bfPool.Prepare();
|
||||
}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_bfPool.ReleaseGCBuffer(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
void ReleaseConnectionExtra(TAgentSocketObj* pSocketObj)
|
||||
{
|
||||
TBuffer* pBuffer = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pBuffer);
|
||||
|
||||
if(pBuffer != nullptr)
|
||||
{
|
||||
m_bfPool.PutFreeBuffer(pBuffer);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
CTcpPullAgentT(ITcpAgentListener* pListener)
|
||||
: T(pListener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CTcpPullAgentT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
CBufferPool m_bfPool;
|
||||
};
|
||||
|
||||
typedef CTcpPullAgentT<CTcpAgent> CTcpPullAgent;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLAgent.h"
|
||||
typedef CTcpPullAgentT<CSSLAgent> CSSLPullAgent;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpPullClient.h"
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpClient.h"
|
||||
#include "MiscHelper.h"
|
||||
|
||||
template<class T> class CTcpPullClientT : public IPullClient, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::m_itPool;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
|
||||
public:
|
||||
virtual EnFetchResult Fetch(BYTE* pData, int iLength)
|
||||
{
|
||||
return ::FetchBuffer(&m_lsBuffer, pData, iLength);
|
||||
}
|
||||
|
||||
virtual EnFetchResult Peek(BYTE* pData, int iLength)
|
||||
{
|
||||
return ::PeekBuffer(&m_lsBuffer, pData, iLength);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult DoFireReceive(ITcpClient* pSender, const BYTE* pData, int iLength)
|
||||
{
|
||||
m_lsBuffer.Cat(pData, iLength);
|
||||
|
||||
return __super::DoFireReceive(pSender, m_lsBuffer.Length());
|
||||
}
|
||||
|
||||
virtual void Reset()
|
||||
{
|
||||
m_lsBuffer.Clear();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
public:
|
||||
CTcpPullClientT(ITcpClientListener* pListener)
|
||||
: T (pListener)
|
||||
, m_lsBuffer(m_itPool)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CTcpPullClientT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
TItemListEx m_lsBuffer;
|
||||
};
|
||||
|
||||
typedef CTcpPullClientT<CTcpClient> CTcpPullClient;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLClient.h"
|
||||
typedef CTcpPullClientT<CSSLClient> CSSLPullClient;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TcpPullServer.h"
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TcpServer.h"
|
||||
#include "MiscHelper.h"
|
||||
|
||||
template<class T> class CTcpPullServerT : public IPullSocket, public T
|
||||
{
|
||||
using __super = T;
|
||||
using __super::SetConnectionReserved;
|
||||
using __super::GetConnectionReserved;
|
||||
using __super::GetMaxConnectionCount;
|
||||
using __super::GetSocketBufferSize;
|
||||
using __super::GetFreeBufferObjPool;
|
||||
using __super::GetFreeBufferObjHold;
|
||||
using __super::GetFreeSocketObjLockTime;
|
||||
using __super::GetFreeSocketObjPool;
|
||||
using __super::GetFreeSocketObjHold;
|
||||
|
||||
public:
|
||||
using __super::Stop;
|
||||
using __super::Wait;
|
||||
using __super::GetState;
|
||||
|
||||
public:
|
||||
virtual EnFetchResult Fetch(CONNID dwConnID, BYTE* pData, int iLength)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool[dwConnID];
|
||||
return ::FetchBuffer(pBuffer, pData, iLength);
|
||||
}
|
||||
|
||||
virtual EnFetchResult Peek(CONNID dwConnID, BYTE* pData, int iLength)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool[dwConnID];
|
||||
return ::PeekBuffer(pBuffer, pData, iLength);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult DoFireAccept(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireAccept(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR)
|
||||
{
|
||||
TBuffer* pBuffer = m_bfPool.PutCacheBuffer(pSocketObj->connID);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, pBuffer));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireHandShake(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireHandShake(pSocketObj);
|
||||
|
||||
if(result == HR_ERROR)
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
TBuffer* pBuffer = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pBuffer);
|
||||
ASSERT(pBuffer && pBuffer->IsValid());
|
||||
|
||||
pBuffer->Cat(pData, iLength);
|
||||
|
||||
return __super::DoFireReceive(pSocketObj, pBuffer->Length());
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
ReleaseConnectionExtra(pSocketObj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{
|
||||
EnHandleResult result = __super::DoFireShutdown();
|
||||
|
||||
m_bfPool.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_bfPool.SetMaxCacheSize (GetMaxConnectionCount());
|
||||
m_bfPool.SetItemCapacity (GetSocketBufferSize());
|
||||
m_bfPool.SetItemPoolSize (GetFreeBufferObjPool());
|
||||
m_bfPool.SetItemPoolHold (GetFreeBufferObjHold());
|
||||
m_bfPool.SetBufferLockTime (GetFreeSocketObjLockTime());
|
||||
m_bfPool.SetBufferPoolSize (GetFreeSocketObjPool());
|
||||
m_bfPool.SetBufferPoolHold (GetFreeSocketObjHold());
|
||||
|
||||
m_bfPool.Prepare();
|
||||
}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_bfPool.ReleaseGCBuffer(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
void ReleaseConnectionExtra(TSocketObj* pSocketObj)
|
||||
{
|
||||
TBuffer* pBuffer = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pBuffer);
|
||||
|
||||
if(pBuffer != nullptr)
|
||||
{
|
||||
m_bfPool.PutFreeBuffer(pBuffer);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
CTcpPullServerT(ITcpServerListener* pListener)
|
||||
: T(pListener)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CTcpPullServerT()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
CBufferPool m_bfPool;
|
||||
};
|
||||
|
||||
typedef CTcpPullServerT<CTcpServer> CTcpPullServer;
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
|
||||
#include "SSLServer.h"
|
||||
typedef CTcpPullServerT<CSSLServer> CSSLPullServer;
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
#include "./common/IODispatcher.h"
|
||||
|
||||
class CTcpServer : public ITcpServer, private CIOHandler
|
||||
{
|
||||
using CGCThread = CGCThreadT<CTcpServer>;
|
||||
friend class CGCThreadT<CTcpServer>;
|
||||
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszBindAddress, USHORT usPort);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Send (CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendSmallFile (CONNID dwConnID, LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr);
|
||||
virtual BOOL SendPackets (CONNID dwConnID, const WSABUF pBuffers[], int iCount) {return DoSendPackets(dwConnID, pBuffers, iCount);}
|
||||
virtual BOOL PauseReceive (CONNID dwConnID, BOOL bPause = TRUE);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual BOOL Disconnect (CONNID dwConnID, BOOL bForce = TRUE);
|
||||
virtual BOOL DisconnectLongConnections (DWORD dwPeriod, BOOL bForce = TRUE);
|
||||
virtual BOOL DisconnectSilenceConnections(DWORD dwPeriod, BOOL bForce = TRUE);
|
||||
virtual BOOL GetListenAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetLocalAddress (CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteAddress (CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
|
||||
virtual BOOL IsConnected (CONNID dwConnID);
|
||||
virtual BOOL IsPauseReceive (CONNID dwConnID, BOOL& bPaused);
|
||||
virtual BOOL GetPendingDataLength (CONNID dwConnID, int& iPending);
|
||||
virtual DWORD GetConnectionCount ();
|
||||
virtual BOOL GetAllConnectionIDs (CONNID pIDs[], DWORD& dwCount);
|
||||
virtual BOOL GetConnectPeriod (CONNID dwConnID, DWORD& dwPeriod);
|
||||
virtual BOOL GetSilencePeriod (CONNID dwConnID, DWORD& dwPeriod);
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
|
||||
#ifdef _SSL_SUPPORT
|
||||
virtual BOOL SetupSSLContext (int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr) {return FALSE;}
|
||||
virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr) {return FALSE;}
|
||||
virtual int AddSSLContext (int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr) {return FALSE;}
|
||||
virtual int AddSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr) {return FALSE;}
|
||||
virtual BOOL BindSSLServerName (LPCTSTR lpszServerName, int iContextIndex) {return FALSE;}
|
||||
virtual void CleanupSSLContext () {}
|
||||
|
||||
virtual BOOL StartSSLHandShake (CONNID dwConnID) {return FALSE;}
|
||||
virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) {}
|
||||
virtual BOOL IsSSLAutoHandShake () {return FALSE;}
|
||||
virtual void SetSSLCipherList (LPCTSTR lpszCipherList){}
|
||||
virtual LPCTSTR GetSSLCipherList() {return nullptr;}
|
||||
virtual BOOL GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo) {return FALSE;}
|
||||
|
||||
protected:
|
||||
virtual BOOL StartSSLHandShake (TSocketObj* pSocketObj){return FALSE;}
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) override;
|
||||
virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) override;
|
||||
virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnDispatchThreadStart(THR_ID tid) override;
|
||||
virtual VOID OnDispatchThreadEnd(THR_ID tid) override;
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure () {return FALSE;}
|
||||
|
||||
virtual BOOL SetConnectionExtra(CONNID dwConnID, PVOID pExtra);
|
||||
virtual BOOL GetConnectionExtra(CONNID dwConnID, PVOID* ppExtra);
|
||||
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enReusePolicy == enReusePolicy);}
|
||||
virtual void SetSendPolicy (EnSendPolicy enSendPolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enSendPolicy == enSendPolicy);}
|
||||
virtual void SetOnSendSyncPolicy (EnOnSendSyncPolicy enOnSendSyncPolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enOnSendSyncPolicy == enOnSendSyncPolicy);}
|
||||
virtual void SetMaxConnectionCount (DWORD dwMaxConnectionCount) {ENSURE_HAS_STOPPED(); m_dwMaxConnectionCount = dwMaxConnectionCount;}
|
||||
virtual void SetWorkerThreadCount (DWORD dwWorkerThreadCount) {ENSURE_HAS_STOPPED(); m_dwWorkerThreadCount = dwWorkerThreadCount;}
|
||||
virtual void SetSocketListenQueue (DWORD dwSocketListenQueue) {ENSURE_HAS_STOPPED(); m_dwSocketListenQueue = dwSocketListenQueue;}
|
||||
virtual void SetAcceptSocketCount (DWORD dwAcceptSocketCount) {ENSURE_HAS_STOPPED(); m_dwAcceptSocketCount = dwAcceptSocketCount;}
|
||||
virtual void SetSocketBufferSize (DWORD dwSocketBufferSize) {ENSURE_HAS_STOPPED(); m_dwSocketBufferSize = dwSocketBufferSize;}
|
||||
virtual void SetFreeSocketObjLockTime (DWORD dwFreeSocketObjLockTime) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjLockTime = dwFreeSocketObjLockTime;}
|
||||
virtual void SetFreeSocketObjPool (DWORD dwFreeSocketObjPool) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjPool = dwFreeSocketObjPool;}
|
||||
virtual void SetFreeBufferObjPool (DWORD dwFreeBufferObjPool) {ENSURE_HAS_STOPPED(); m_dwFreeBufferObjPool = dwFreeBufferObjPool;}
|
||||
virtual void SetFreeSocketObjHold (DWORD dwFreeSocketObjHold) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjHold = dwFreeSocketObjHold;}
|
||||
virtual void SetFreeBufferObjHold (DWORD dwFreeBufferObjHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferObjHold = dwFreeBufferObjHold;}
|
||||
virtual void SetKeepAliveTime (DWORD dwKeepAliveTime) {ENSURE_HAS_STOPPED(); m_dwKeepAliveTime = dwKeepAliveTime;}
|
||||
virtual void SetKeepAliveInterval (DWORD dwKeepAliveInterval) {ENSURE_HAS_STOPPED(); m_dwKeepAliveInterval = dwKeepAliveInterval;}
|
||||
virtual void SetMarkSilence (BOOL bMarkSilence) {ENSURE_HAS_STOPPED(); m_bMarkSilence = bMarkSilence;}
|
||||
virtual void SetNoDelay (BOOL bNoDelay) {ENSURE_HAS_STOPPED(); m_bNoDelay = bNoDelay;}
|
||||
virtual void SetDualStack (BOOL bDualStack) {ENSURE_HAS_STOPPED(); m_bDualStack = bDualStack;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual EnSendPolicy GetSendPolicy () {return m_enSendPolicy;}
|
||||
virtual EnOnSendSyncPolicy GetOnSendSyncPolicy () {return m_enOnSendSyncPolicy;}
|
||||
virtual DWORD GetMaxConnectionCount () {return m_dwMaxConnectionCount;}
|
||||
virtual DWORD GetWorkerThreadCount () {return m_dwWorkerThreadCount;}
|
||||
virtual DWORD GetSocketListenQueue () {return m_dwSocketListenQueue;}
|
||||
virtual DWORD GetAcceptSocketCount () {return m_dwAcceptSocketCount;}
|
||||
virtual DWORD GetSocketBufferSize () {return m_dwSocketBufferSize;}
|
||||
virtual DWORD GetFreeSocketObjLockTime () {return m_dwFreeSocketObjLockTime;}
|
||||
virtual DWORD GetFreeSocketObjPool () {return m_dwFreeSocketObjPool;}
|
||||
virtual DWORD GetFreeBufferObjPool () {return m_dwFreeBufferObjPool;}
|
||||
virtual DWORD GetFreeSocketObjHold () {return m_dwFreeSocketObjHold;}
|
||||
virtual DWORD GetFreeBufferObjHold () {return m_dwFreeBufferObjHold;}
|
||||
virtual DWORD GetKeepAliveTime () {return m_dwKeepAliveTime;}
|
||||
virtual DWORD GetKeepAliveInterval () {return m_dwKeepAliveInterval;}
|
||||
virtual BOOL IsMarkSilence () {return m_bMarkSilence;}
|
||||
virtual BOOL IsNoDelay () {return m_bNoDelay;}
|
||||
virtual BOOL IsDualStack () {return m_bDualStack;}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FirePrepareListen(SOCKET soListen)
|
||||
{return DoFirePrepareListen(soListen);}
|
||||
virtual EnHandleResult FireAccept(TSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult rs = DoFireAccept(pSocketObj);
|
||||
if(rs != HR_ERROR) rs = FireHandShake(pSocketObj);
|
||||
return rs;
|
||||
}
|
||||
virtual EnHandleResult FireHandShake(TSocketObj* pSocketObj)
|
||||
{return DoFireHandShake(pSocketObj);}
|
||||
virtual EnHandleResult FireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return DoFireReceive(pSocketObj, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(TSocketObj* pSocketObj, int iLength)
|
||||
{return DoFireReceive(pSocketObj, iLength);}
|
||||
virtual EnHandleResult FireSend(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return DoFireSend(pSocketObj, pData, iLength);}
|
||||
virtual EnHandleResult FireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return DoFireClose(pSocketObj, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult FireShutdown()
|
||||
{return DoFireShutdown();}
|
||||
|
||||
virtual EnHandleResult DoFirePrepareListen(SOCKET soListen)
|
||||
{return m_pListener->OnPrepareListen(this, soListen);}
|
||||
virtual EnHandleResult DoFireAccept(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnAccept(this, pSocketObj->connID, pSocketObj->socket);}
|
||||
virtual EnHandleResult DoFireHandShake(TSocketObj* pSocketObj)
|
||||
{return m_pListener->OnHandShake(this, pSocketObj->connID);}
|
||||
virtual EnHandleResult DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnReceive(this, pSocketObj->connID, pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(TSocketObj* pSocketObj, int iLength)
|
||||
{return m_pListener->OnReceive(this, pSocketObj->connID, iLength);}
|
||||
virtual EnHandleResult DoFireSend(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnSend(this, pSocketObj->connID, pData, iLength);}
|
||||
virtual EnHandleResult DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_pListener->OnClose(this, pSocketObj->connID, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{return m_pListener->OnShutdown(this);}
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual BOOL BeforeUnpause(TSocketObj* pSocketObj) {return TRUE;}
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID tid) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID tid) {}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
BOOL DoSendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount);
|
||||
BOOL DoSendPackets(TSocketObj* pSocketObj, const WSABUF pBuffers[], int iCount);
|
||||
TSocketObj* FindSocketObj(CONNID dwConnID);
|
||||
|
||||
protected:
|
||||
BOOL SetConnectionExtra(TSocketObj* pSocketObj, PVOID pExtra);
|
||||
BOOL GetConnectionExtra(TSocketObj* pSocketObj, PVOID* ppExtra);
|
||||
BOOL SetConnectionReserved(CONNID dwConnID, PVOID pReserved);
|
||||
BOOL GetConnectionReserved(CONNID dwConnID, PVOID* ppReserved);
|
||||
BOOL SetConnectionReserved(TSocketObj* pSocketObj, PVOID pReserved);
|
||||
BOOL GetConnectionReserved(TSocketObj* pSocketObj, PVOID* ppReserved);
|
||||
BOOL SetConnectionReserved2(CONNID dwConnID, PVOID pReserved2);
|
||||
BOOL GetConnectionReserved2(CONNID dwConnID, PVOID* ppReserved2);
|
||||
BOOL SetConnectionReserved2(TSocketObj* pSocketObj, PVOID pReserved2);
|
||||
BOOL GetConnectionReserved2(TSocketObj* pSocketObj, PVOID* ppReserved2);
|
||||
|
||||
private:
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL CreateListenSocket(LPCTSTR lpszBindAddress, USHORT usPort);
|
||||
BOOL CreateWorkerThreads();
|
||||
BOOL StartAccept();
|
||||
|
||||
void CloseListenSocket();
|
||||
void DisconnectClientSocket();
|
||||
void WaitForClientSocketClose();
|
||||
void ReleaseClientSocket();
|
||||
void ReleaseFreeSocket();
|
||||
void WaitForWorkerThreadEnd();
|
||||
|
||||
TSocketObj* GetFreeSocketObj(CONNID dwConnID, SOCKET soClient);
|
||||
TSocketObj* CreateSocketObj();
|
||||
void AddFreeSocketObj (TSocketObj* pSocketObj, EnSocketCloseFlag enFlag = SCF_NONE, EnSocketOperation enOperation = SO_UNKNOWN, int iErrorCode = 0);
|
||||
void DeleteSocketObj (TSocketObj* pSocketObj);
|
||||
BOOL InvalidSocketObj (TSocketObj* pSocketObj);
|
||||
void AddClientSocketObj (CONNID dwConnID, TSocketObj* pSocketObj, const HP_SOCKADDR& remoteAddr);
|
||||
void CloseClientSocketObj(TSocketObj* pSocketObj, EnSocketCloseFlag enFlag = SCF_NONE, EnSocketOperation enOperation = SO_UNKNOWN, int iErrorCode = 0, int iShutdownFlag = SHUT_WR);
|
||||
|
||||
private:
|
||||
VOID HandleCmdSend (const TDispContext* pContext, CONNID dwConnID);
|
||||
VOID HandleCmdUnpause (const TDispContext* pContext, CONNID dwConnID);
|
||||
VOID HandleCmdDisconnect(const TDispContext* pContext, CONNID dwConnID, BOOL bForce);
|
||||
BOOL HandleAccept (const TDispContext* pContext, UINT events);
|
||||
BOOL HandleReceive (const TDispContext* pContext, TSocketObj* pSocketObj, int flag);
|
||||
BOOL HandleSend (const TDispContext* pContext, TSocketObj* pSocketObj, int flag);
|
||||
BOOL HandleClose (const TDispContext* pContext, TSocketObj* pSocketObj, EnSocketCloseFlag enFlag, UINT events);
|
||||
|
||||
int SendInternal (TSocketObj* pSocketObj, const WSABUF pBuffers[], int iCount);
|
||||
BOOL SendItem (TSocketObj* pSocketObj, TItem* pItem, BOOL& bBlocked);
|
||||
|
||||
public:
|
||||
CTcpServer(ITcpServerListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_enReusePolicy (RAP_ADDR_AND_PORT)
|
||||
, m_enSendPolicy (SP_PACK)
|
||||
, m_enOnSendSyncPolicy (OSSP_RECEIVE)
|
||||
, m_dwMaxConnectionCount (DEFAULT_CONNECTION_COUNT)
|
||||
, m_dwWorkerThreadCount (DEFAULT_WORKER_THREAD_COUNT)
|
||||
, m_dwSocketListenQueue (DEFAULT_TCP_SERVER_SOCKET_LISTEN_QUEUE)
|
||||
, m_dwAcceptSocketCount (DEFAULT_WORKER_MAX_EVENT_COUNT)
|
||||
, m_dwSocketBufferSize (DEFAULT_TCP_SOCKET_BUFFER_SIZE)
|
||||
, m_dwFreeSocketObjLockTime (DEFAULT_FREE_SOCKETOBJ_LOCK_TIME)
|
||||
, m_dwFreeSocketObjPool (DEFAULT_FREE_SOCKETOBJ_POOL)
|
||||
, m_dwFreeBufferObjPool (DEFAULT_FREE_BUFFEROBJ_POOL)
|
||||
, m_dwFreeSocketObjHold (DEFAULT_FREE_SOCKETOBJ_HOLD)
|
||||
, m_dwFreeBufferObjHold (DEFAULT_FREE_BUFFEROBJ_HOLD)
|
||||
, m_dwKeepAliveTime (DEFALUT_TCP_KEEPALIVE_TIME)
|
||||
, m_dwKeepAliveInterval (DEFALUT_TCP_KEEPALIVE_INTERVAL)
|
||||
, m_bMarkSilence (TRUE)
|
||||
, m_bNoDelay (FALSE)
|
||||
, m_bDualStack (TRUE)
|
||||
, m_thGC (this)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CTcpServer()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
EnSendPolicy m_enSendPolicy;
|
||||
EnOnSendSyncPolicy m_enOnSendSyncPolicy;
|
||||
DWORD m_dwMaxConnectionCount;
|
||||
DWORD m_dwWorkerThreadCount;
|
||||
DWORD m_dwSocketListenQueue;
|
||||
DWORD m_dwAcceptSocketCount;
|
||||
DWORD m_dwSocketBufferSize;
|
||||
DWORD m_dwFreeSocketObjLockTime;
|
||||
DWORD m_dwFreeSocketObjPool;
|
||||
DWORD m_dwFreeBufferObjPool;
|
||||
DWORD m_dwFreeSocketObjHold;
|
||||
DWORD m_dwFreeBufferObjHold;
|
||||
DWORD m_dwKeepAliveTime;
|
||||
DWORD m_dwKeepAliveInterval;
|
||||
BOOL m_bMarkSilence;
|
||||
BOOL m_bNoDelay;
|
||||
BOOL m_bDualStack;
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
ITcpServerListener* m_pListener;
|
||||
ListenSocketsPtr m_soListens;
|
||||
EnServiceState m_enState;
|
||||
EnSocketError m_enLastError;
|
||||
|
||||
CReceiveBuffersPtr m_rcBuffers;
|
||||
|
||||
CPrivateHeap m_phSocket;
|
||||
CBufferObjPool m_bfObjPool;
|
||||
|
||||
CSpinGuard m_csState;
|
||||
|
||||
CGCThread m_thGC;
|
||||
|
||||
TSocketObjPtrPool m_bfActiveSockets;
|
||||
|
||||
TSocketObjPtrList m_lsFreeSocket;
|
||||
TSocketObjPtrQueue m_lsGCSocket;
|
||||
|
||||
CIODispatcher m_ioDispatcher;
|
||||
};
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UdpArqClient.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
BOOL CUdpArqClient::CheckParams()
|
||||
{
|
||||
DWORD dwMaxDatagramSize = GetMaxDatagramSize();
|
||||
|
||||
if(m_dwMtu == 0)
|
||||
m_arqAttr.dwMtu = dwMaxDatagramSize;
|
||||
else
|
||||
{
|
||||
if(m_dwMtu > dwMaxDatagramSize)
|
||||
return FALSE;
|
||||
|
||||
m_arqAttr.dwMtu = m_dwMtu;
|
||||
}
|
||||
|
||||
return __super::CheckParams() && m_arqAttr.IsValid();
|
||||
}
|
||||
|
||||
void CUdpArqClient::PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
}
|
||||
|
||||
void CUdpArqClient::Reset()
|
||||
{
|
||||
m_arqSession.Reset();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void CUdpArqClient::OnWorkerThreadStart(THR_ID dwThreadID)
|
||||
{
|
||||
m_arqBuffer.Malloc(m_arqAttr.dwMaxMessageSize);
|
||||
m_arqTimer = ::CreateTimer(m_arqAttr.dwFlushInterval);
|
||||
}
|
||||
|
||||
void CUdpArqClient::OnWorkerThreadEnd(THR_ID dwThreadID)
|
||||
{
|
||||
if(IS_VALID_FD(m_arqTimer))
|
||||
{
|
||||
close(m_arqTimer);
|
||||
m_arqTimer = INVALID_FD;
|
||||
}
|
||||
|
||||
m_arqBuffer.Free();
|
||||
}
|
||||
|
||||
HANDLE CUdpArqClient::GetUserEvent()
|
||||
{
|
||||
return m_arqTimer;
|
||||
}
|
||||
|
||||
BOOL CUdpArqClient::OnUserEvent()
|
||||
{
|
||||
::ReadTimer(m_arqTimer);
|
||||
|
||||
return m_arqSession.Check();
|
||||
}
|
||||
|
||||
BOOL CUdpArqClient::Send(const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
ASSERT(pBuffer && iLength > 0 && iLength <= (int)m_arqAttr.dwMaxMessageSize);
|
||||
|
||||
int result = NO_ERROR;
|
||||
|
||||
if(pBuffer && iLength > 0 && iLength <= (int)m_arqAttr.dwMaxMessageSize)
|
||||
{
|
||||
if(IsConnected())
|
||||
{
|
||||
if(iOffset != 0) pBuffer += iOffset;
|
||||
result = m_arqSession.Send(pBuffer, iLength);
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_STATE;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
BOOL CUdpArqClient::SendPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
if(!pBuffers || iCount <= 0)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if(iCount == 1)
|
||||
return Send((const BYTE*)pBuffers[0].buf, pBuffers[0].len);
|
||||
if(!IsConnected())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
int iLength = 0;
|
||||
int iMaxLen = (int)m_arqAttr.dwMaxMessageSize;
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
iLength += pBuffers[i].len;
|
||||
|
||||
if(iLength <= 0 || iLength > iMaxLen)
|
||||
return ERROR_INCORRECT_SIZE;
|
||||
|
||||
CBufferPtr sndBuffer(iLength);
|
||||
sndBuffer.SetSize(0);
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
int iBufLen = pBuffers[i].len;
|
||||
|
||||
if(iBufLen > 0)
|
||||
{
|
||||
BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
|
||||
ASSERT(pBuffer);
|
||||
|
||||
sndBuffer.Cat(pBuffer, iBufLen);
|
||||
}
|
||||
}
|
||||
|
||||
int result = m_arqSession.Send(sndBuffer.Ptr(), (int)sndBuffer.Size());
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
int CUdpArqClient::ArqOutputProc(const char* pBuffer, int iLength, IKCPCB* kcp, LPVOID pv)
|
||||
{
|
||||
CUdpArqClient* pClient = (CUdpArqClient*)pv;
|
||||
|
||||
BOOL isOK = pClient->__super::Send((const BYTE*)pBuffer, iLength);
|
||||
|
||||
return isOK ? NO_ERROR : ::WSAGetLastError();
|
||||
}
|
||||
|
||||
EnHandleResult CUdpArqClient::FireConnect()
|
||||
{
|
||||
EnHandleResult result = DoFireConnect(this);
|
||||
|
||||
if(result != HR_ERROR)
|
||||
m_arqSession.Renew(this, this, m_arqAttr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EnHandleResult CUdpArqClient::FireReceive(const BYTE* pData, int iLength)
|
||||
{
|
||||
return m_arqSession.Receive(pData, iLength, m_arqBuffer.Ptr(), (int)m_arqBuffer.Size());
|
||||
}
|
||||
|
||||
BOOL CUdpArqClient::GetWaitingSendMessageCount(int& iCount)
|
||||
{
|
||||
iCount = m_arqSession.GetWaitingSend();
|
||||
|
||||
return (iCount >= 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UdpClient.h"
|
||||
#include "ArqHelper.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
class CUdpArqClient : public IArqClient, public CUdpClient
|
||||
{
|
||||
using __super = CUdpClient;
|
||||
|
||||
using CArqSession = CArqSessionT<CUdpArqClient, CUdpArqClient>;
|
||||
|
||||
friend typename CUdpArqClient::CArqSession;
|
||||
|
||||
public:
|
||||
virtual BOOL Send (const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendPackets(const WSABUF pBuffers[], int iCount);
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FireConnect();
|
||||
virtual EnHandleResult FireReceive(const BYTE* pData, int iLength);
|
||||
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID dwThreadID);
|
||||
virtual void OnWorkerThreadEnd(THR_ID dwThreadID);
|
||||
|
||||
virtual FD GetUserEvent();
|
||||
virtual BOOL OnUserEvent();
|
||||
|
||||
public:
|
||||
virtual void SetNoDelay (BOOL bNoDelay) {ENSURE_HAS_STOPPED(); m_arqAttr.bNoDelay = bNoDelay;}
|
||||
virtual void SetTurnoffCongestCtrl (BOOL bTurnOff) {ENSURE_HAS_STOPPED(); m_arqAttr.bTurnoffNc = bTurnOff;}
|
||||
virtual void SetFlushInterval (DWORD dwFlushInterval) {ENSURE_HAS_STOPPED(); m_arqAttr.dwFlushInterval = dwFlushInterval;}
|
||||
virtual void SetResendByAcks (DWORD dwResendByAcks) {ENSURE_HAS_STOPPED(); m_arqAttr.dwResendByAcks = dwResendByAcks;}
|
||||
virtual void SetSendWndSize (DWORD dwSendWndSize) {ENSURE_HAS_STOPPED(); m_arqAttr.dwSendWndSize = dwSendWndSize;}
|
||||
virtual void SetRecvWndSize (DWORD dwRecvWndSize) {ENSURE_HAS_STOPPED(); m_arqAttr.dwRecvWndSize = dwRecvWndSize;}
|
||||
virtual void SetMinRto (DWORD dwMinRto) {ENSURE_HAS_STOPPED(); m_arqAttr.dwMinRto = dwMinRto;}
|
||||
virtual void SetFastLimit (DWORD dwFastLimit) {ENSURE_HAS_STOPPED(); m_arqAttr.dwFastLimit = dwFastLimit;}
|
||||
virtual void SetMaxTransUnit (DWORD dwMaxTransUnit) {ENSURE_HAS_STOPPED(); m_dwMtu = dwMaxTransUnit;}
|
||||
virtual void SetMaxMessageSize (DWORD dwMaxMessageSize) {ENSURE_HAS_STOPPED(); m_arqAttr.dwMaxMessageSize = dwMaxMessageSize;}
|
||||
virtual void SetHandShakeTimeout (DWORD dwHandShakeTimeout) {ENSURE_HAS_STOPPED(); m_arqAttr.dwHandShakeTimeout = dwHandShakeTimeout;}
|
||||
|
||||
virtual BOOL IsNoDelay () {return m_arqAttr.bNoDelay;}
|
||||
virtual BOOL IsTurnoffCongestCtrl () {return m_arqAttr.bTurnoffNc;}
|
||||
virtual DWORD GetFlushInterval () {return m_arqAttr.dwFlushInterval;}
|
||||
virtual DWORD GetResendByAcks () {return m_arqAttr.dwResendByAcks;}
|
||||
virtual DWORD GetSendWndSize () {return m_arqAttr.dwSendWndSize;}
|
||||
virtual DWORD GetRecvWndSize () {return m_arqAttr.dwRecvWndSize;}
|
||||
virtual DWORD GetMinRto () {return m_arqAttr.dwMinRto;}
|
||||
virtual DWORD GetFastLimit () {return m_arqAttr.dwFastLimit;}
|
||||
virtual DWORD GetMaxTransUnit () {return m_dwMtu;}
|
||||
virtual DWORD GetMaxMessageSize () {return m_arqAttr.dwMaxMessageSize;}
|
||||
virtual DWORD GetHandShakeTimeout () {return m_arqAttr.dwHandShakeTimeout;}
|
||||
|
||||
virtual BOOL GetWaitingSendMessageCount (int& iCount);
|
||||
|
||||
public:
|
||||
const TArqAttr& GetArqAttribute () {return m_arqAttr;}
|
||||
Fn_ArqOutputProc GetArqOutputProc () {return ArqOutputProc;}
|
||||
|
||||
private:
|
||||
static int ArqOutputProc(const char* pBuffer, int iLength, IKCPCB* kcp, LPVOID pv);
|
||||
|
||||
public:
|
||||
CUdpArqClient(IUdpClientListener* pListener)
|
||||
: CUdpClient(pListener)
|
||||
, m_dwMtu (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CUdpArqClient()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwMtu;
|
||||
TArqAttr m_arqAttr;
|
||||
|
||||
CBufferPtr m_arqBuffer;
|
||||
FD m_arqTimer;
|
||||
|
||||
CArqSession m_arqSession;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UdpArqServer.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
BOOL CUdpArqServer::CheckParams()
|
||||
{
|
||||
DWORD dwMaxDatagramSize = GetMaxDatagramSize();
|
||||
|
||||
if(m_dwMtu == 0)
|
||||
m_arqAttr.dwMtu = dwMaxDatagramSize;
|
||||
else
|
||||
{
|
||||
if(m_dwMtu > dwMaxDatagramSize)
|
||||
return FALSE;
|
||||
|
||||
m_arqAttr.dwMtu = m_dwMtu;
|
||||
}
|
||||
|
||||
return __super::CheckParams() && m_arqAttr.IsValid();
|
||||
}
|
||||
|
||||
void CUdpArqServer::PrepareStart()
|
||||
{
|
||||
__super::PrepareStart();
|
||||
|
||||
m_ssPool.SetSessionLockTime(GetFreeSocketObjLockTime());
|
||||
m_ssPool.SetSessionPoolSize(GetFreeSocketObjPool());
|
||||
m_ssPool.SetSessionPoolHold(GetFreeSocketObjHold());
|
||||
|
||||
m_ssPool.Prepare();
|
||||
}
|
||||
|
||||
void CUdpArqServer::Reset()
|
||||
{
|
||||
::ClearPtrMap(m_rcBuffers);
|
||||
|
||||
m_ssPool.Clear();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void CUdpArqServer::OnWorkerThreadStart(THR_ID dwThreadID)
|
||||
{
|
||||
{
|
||||
CCriSecLock locallock(m_csRcBuffers);
|
||||
m_rcBuffers[dwThreadID] = new CBufferPtr(m_arqAttr.dwMaxMessageSize);
|
||||
}
|
||||
|
||||
while((DWORD)m_rcBuffers.size() < GetWorkerThreadCount())
|
||||
::WaitFor(3);
|
||||
}
|
||||
|
||||
void CUdpArqServer::ReleaseGCSocketObj(BOOL bForce)
|
||||
{
|
||||
__super::ReleaseGCSocketObj(bForce);
|
||||
|
||||
#ifdef USE_EXTERNAL_GC
|
||||
m_ssPool.ReleaseGCSession(bForce);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL CUdpArqServer::Send(CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
ASSERT(pBuffer && iLength > 0 && iLength <= (int)m_arqAttr.dwMaxMessageSize);
|
||||
|
||||
int result = NO_ERROR;
|
||||
|
||||
if(pBuffer && iLength > 0 && iLength <= (int)m_arqAttr.dwMaxMessageSize)
|
||||
{
|
||||
if(iOffset != 0) pBuffer += iOffset;
|
||||
TUdpSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(TUdpSocketObj::IsValid(pSocketObj))
|
||||
result = SendArq(pSocketObj, pBuffer, iLength);
|
||||
else
|
||||
result = ERROR_OBJECT_NOT_FOUND;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
BOOL CUdpArqServer::SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
if(!pBuffers || iCount <= 0)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if(iCount == 1)
|
||||
return Send(dwConnID, (const BYTE*)pBuffers[0].buf, pBuffers[0].len);
|
||||
|
||||
TUdpSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TUdpSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int iLength = 0;
|
||||
int iMaxLen = (int)m_arqAttr.dwMaxMessageSize;
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
iLength += pBuffers[i].len;
|
||||
|
||||
if(iLength <= 0 || iLength > iMaxLen)
|
||||
return ERROR_INCORRECT_SIZE;
|
||||
|
||||
CBufferPtr sndBuffer(iLength);
|
||||
sndBuffer.SetSize(0);
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
int iBufLen = pBuffers[i].len;
|
||||
|
||||
if(iBufLen > 0)
|
||||
{
|
||||
BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
|
||||
ASSERT(pBuffer);
|
||||
|
||||
sndBuffer.Cat(pBuffer, iBufLen);
|
||||
}
|
||||
}
|
||||
|
||||
int result = SendArq(pSocketObj, sndBuffer.Ptr(), (int)sndBuffer.Size());
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
int CUdpArqServer::SendArq(TUdpSocketObj* pSocketObj, const BYTE* pBuffer, int iLength)
|
||||
{
|
||||
CArqSessionEx* pSession = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession == nullptr)
|
||||
return ERROR_OBJECT_NOT_FOUND;
|
||||
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
|
||||
return pSession->Send(pBuffer, iLength);
|
||||
}
|
||||
|
||||
int CUdpArqServer::ArqOutputProc(const char* pBuffer, int iLength, IKCPCB* kcp, LPVOID pv)
|
||||
{
|
||||
TUdpSocketObj* pSocketObj = (TUdpSocketObj*)pv;
|
||||
|
||||
if(!TUdpSocketObj::IsValid(pSocketObj))
|
||||
return ERROR_OBJECT_NOT_FOUND;
|
||||
|
||||
CUdpArqServer* pServer = (CUdpArqServer*)IUdpArqServer::FromS((IUdpServer*)pSocketObj->pHolder);
|
||||
|
||||
TItemPtr itPtr(pServer->m_bfObjPool, pServer->m_bfObjPool.PickFreeItem());
|
||||
itPtr->Cat((const BYTE*)pBuffer, iLength);
|
||||
|
||||
return pServer->SendInternal(pSocketObj, itPtr);
|
||||
}
|
||||
|
||||
EnHandleResult CUdpArqServer::FireAccept(TUdpSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult result = DoFireAccept(pSocketObj);
|
||||
|
||||
if(result != HR_ERROR)
|
||||
{
|
||||
CArqSessionEx* pSession = m_ssPool.PickFreeSession(this, pSocketObj, m_arqAttr);
|
||||
ENSURE(SetConnectionReserved(pSocketObj, pSession));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EnHandleResult CUdpArqServer::FireReceive(TUdpSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{
|
||||
CArqSessionEx* pSession = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
|
||||
CBufferPtr& rcBuffer = *m_rcBuffers[SELF_THREAD_ID];
|
||||
return pSession->Receive(pData, iLength, rcBuffer.Ptr(), (int)rcBuffer.Size());
|
||||
}
|
||||
|
||||
EnHandleResult CUdpArqServer::FireClose(TUdpSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
EnHandleResult result = DoFireClose(pSocketObj, enOperation, iErrorCode);
|
||||
|
||||
CArqSessionEx* pSession = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession != nullptr)
|
||||
m_ssPool.PutFreeSession(pSession);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL CUdpArqServer::GetWaitingSendMessageCount(CONNID dwConnID, int& iCount)
|
||||
{
|
||||
TUdpSocketObj* pSocketObj = FindSocketObj(dwConnID);
|
||||
|
||||
if(!TUdpSocketObj::IsValid(pSocketObj))
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CArqSessionEx* pSession = nullptr;
|
||||
GetConnectionReserved(pSocketObj, (PVOID*)&pSession);
|
||||
|
||||
if(pSession == nullptr)
|
||||
{
|
||||
::SetLastError(ERROR_OBJECT_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
CLocalSafeCounter localcounter(*pSession);
|
||||
|
||||
iCount = pSession->GetWaitingSend();
|
||||
}
|
||||
|
||||
return (iCount >= 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UdpServer.h"
|
||||
#include "ArqHelper.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
#include "common/STLHelper.h"
|
||||
|
||||
class CUdpArqServer : public IArqSocket, public CUdpServer
|
||||
{
|
||||
using __super = CUdpServer;
|
||||
|
||||
using CArqSession = CArqSessionT<CUdpArqServer, TUdpSocketObj>;
|
||||
using CArqSessionEx = CArqSessionExT<CUdpArqServer, TUdpSocketObj>;
|
||||
using CArqSessionPool = CArqSessionPoolT<CUdpArqServer, TUdpSocketObj>;
|
||||
using CRecvBufferMap = unordered_map<THR_ID, CBufferPtr*>;
|
||||
|
||||
friend typename CUdpArqServer::CArqSession;
|
||||
|
||||
public:
|
||||
virtual BOOL Send (CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount);
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FireAccept(TUdpSocketObj* pSocketObj);
|
||||
virtual EnHandleResult FireReceive(TUdpSocketObj* pSocketObj, const BYTE* pData, int iLength);
|
||||
virtual EnHandleResult FireClose(TUdpSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
virtual void OnWorkerThreadStart(THR_ID dwThreadID);
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
public:
|
||||
virtual void SetNoDelay (BOOL bNoDelay) {ENSURE_HAS_STOPPED(); m_arqAttr.bNoDelay = bNoDelay;}
|
||||
virtual void SetTurnoffCongestCtrl (BOOL bTurnOff) {ENSURE_HAS_STOPPED(); m_arqAttr.bTurnoffNc = bTurnOff;}
|
||||
virtual void SetFlushInterval (DWORD dwFlushInterval) {ENSURE_HAS_STOPPED(); m_arqAttr.dwFlushInterval = dwFlushInterval;}
|
||||
virtual void SetResendByAcks (DWORD dwResendByAcks) {ENSURE_HAS_STOPPED(); m_arqAttr.dwResendByAcks = dwResendByAcks;}
|
||||
virtual void SetSendWndSize (DWORD dwSendWndSize) {ENSURE_HAS_STOPPED(); m_arqAttr.dwSendWndSize = dwSendWndSize;}
|
||||
virtual void SetRecvWndSize (DWORD dwRecvWndSize) {ENSURE_HAS_STOPPED(); m_arqAttr.dwRecvWndSize = dwRecvWndSize;}
|
||||
virtual void SetMinRto (DWORD dwMinRto) {ENSURE_HAS_STOPPED(); m_arqAttr.dwMinRto = dwMinRto;}
|
||||
virtual void SetFastLimit (DWORD dwFastLimit) {ENSURE_HAS_STOPPED(); m_arqAttr.dwFastLimit = dwFastLimit;}
|
||||
virtual void SetMaxTransUnit (DWORD dwMaxTransUnit) {ENSURE_HAS_STOPPED(); m_dwMtu = dwMaxTransUnit;}
|
||||
virtual void SetMaxMessageSize (DWORD dwMaxMessageSize) {ENSURE_HAS_STOPPED(); m_arqAttr.dwMaxMessageSize = dwMaxMessageSize;}
|
||||
virtual void SetHandShakeTimeout (DWORD dwHandShakeTimeout) {ENSURE_HAS_STOPPED(); m_arqAttr.dwHandShakeTimeout = dwHandShakeTimeout;}
|
||||
|
||||
virtual BOOL IsNoDelay () {return m_arqAttr.bNoDelay;}
|
||||
virtual BOOL IsTurnoffCongestCtrl () {return m_arqAttr.bTurnoffNc;}
|
||||
virtual DWORD GetFlushInterval () {return m_arqAttr.dwFlushInterval;}
|
||||
virtual DWORD GetResendByAcks () {return m_arqAttr.dwResendByAcks;}
|
||||
virtual DWORD GetSendWndSize () {return m_arqAttr.dwSendWndSize;}
|
||||
virtual DWORD GetRecvWndSize () {return m_arqAttr.dwRecvWndSize;}
|
||||
virtual DWORD GetMinRto () {return m_arqAttr.dwMinRto;}
|
||||
virtual DWORD GetFastLimit () {return m_arqAttr.dwFastLimit;}
|
||||
virtual DWORD GetMaxTransUnit () {return m_dwMtu;}
|
||||
virtual DWORD GetMaxMessageSize () {return m_arqAttr.dwMaxMessageSize;}
|
||||
virtual DWORD GetHandShakeTimeout () {return m_arqAttr.dwHandShakeTimeout;}
|
||||
|
||||
virtual BOOL GetWaitingSendMessageCount (CONNID dwConnID, int& iCount);
|
||||
|
||||
public:
|
||||
const TArqAttr& GetArqAttribute () {return m_arqAttr;}
|
||||
Fn_ArqOutputProc GetArqOutputProc () {return ArqOutputProc;}
|
||||
|
||||
private:
|
||||
int SendArq(TUdpSocketObj* pSocketObj, const BYTE* pBuffer, int iLength);
|
||||
|
||||
static int ArqOutputProc(const char* pBuffer, int iLength, IKCPCB* kcp, LPVOID pv);
|
||||
|
||||
public:
|
||||
CUdpArqServer(IUdpServerListener* pListener)
|
||||
: CUdpServer(pListener)
|
||||
, m_ssPool (this)
|
||||
, m_dwMtu (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CUdpArqServer()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwMtu;
|
||||
TArqAttr m_arqAttr;
|
||||
|
||||
CCriSec m_csRcBuffers;
|
||||
CRecvBufferMap m_rcBuffers;
|
||||
|
||||
CArqSessionPool m_ssPool;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,696 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UdpCast.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
BOOL CUdpCast::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress, USHORT usLocalPort)
|
||||
{
|
||||
ASSERT(usLocalPort == 0);
|
||||
|
||||
if(!CheckParams() || !CheckStarting())
|
||||
return FALSE;
|
||||
|
||||
PrepareStart();
|
||||
m_ccContext.Reset();
|
||||
|
||||
BOOL isOK = FALSE;
|
||||
HP_SOCKADDR bindAddr(AF_UNSPEC, TRUE);
|
||||
|
||||
if(CreateClientSocket(lpszRemoteAddress, usPort, lpszBindAddress, bindAddr))
|
||||
{
|
||||
if(BindClientSocket(bindAddr))
|
||||
{
|
||||
if(TRIGGER(FirePrepareConnect(m_soClient)) != HR_ERROR)
|
||||
{
|
||||
if(ConnectToGroup(bindAddr))
|
||||
{
|
||||
if(CreateWorkerThread())
|
||||
{
|
||||
isOK = TRUE;
|
||||
}
|
||||
else
|
||||
SetLastError(SE_WORKER_THREAD_CREATE, __FUNCTION__, ERROR_CREATE_FAILED);
|
||||
}
|
||||
else
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ::WSAGetLastError());
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_PREPARE, __FUNCTION__, ENSURE_ERROR_CANCELLED);
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_BIND, __FUNCTION__, ::WSAGetLastError());
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
|
||||
|
||||
if(!isOK)
|
||||
{
|
||||
m_ccContext.Reset(FALSE);
|
||||
EXECUTE_RESTORE_ERROR(Stop());
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::CheckParams()
|
||||
{
|
||||
if (((int)m_dwMaxDatagramSize > 0 && m_dwMaxDatagramSize <= MAXIMUM_UDP_MAX_DATAGRAM_SIZE) &&
|
||||
((int)m_dwFreeBufferPoolSize >= 0) &&
|
||||
((int)m_dwFreeBufferPoolHold >= 0) &&
|
||||
(m_enCastMode >= CM_MULTICAST && m_enCastMode <= CM_BROADCAST) &&
|
||||
(m_iMCTtl >= 0 && m_iMCTtl <= 255) &&
|
||||
(m_bMCLoop == TRUE || m_bMCLoop == FALSE) )
|
||||
return TRUE;
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CUdpCast::PrepareStart()
|
||||
{
|
||||
m_itPool.SetItemCapacity(m_dwMaxDatagramSize);
|
||||
m_itPool.SetPoolSize(m_dwFreeBufferPoolSize);
|
||||
m_itPool.SetPoolHold(m_dwFreeBufferPoolHold);
|
||||
|
||||
m_itPool.Prepare();
|
||||
}
|
||||
|
||||
BOOL CUdpCast::CheckStarting()
|
||||
{
|
||||
CSpinLock locallock(m_csState);
|
||||
|
||||
if(m_enState == SS_STOPPED)
|
||||
m_enState = SS_STARTING;
|
||||
else
|
||||
{
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::CheckStoping()
|
||||
{
|
||||
if(m_enState != SS_STOPPED)
|
||||
{
|
||||
CSpinLock locallock(m_csState);
|
||||
|
||||
if(HasStarted())
|
||||
{
|
||||
m_enState = SS_STOPPING;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::CreateClientSocket(LPCTSTR lpszRemoteAddress, USHORT usPort, LPCTSTR lpszBindAddress, HP_SOCKADDR& bindAddr)
|
||||
{
|
||||
if(::IsStrNotEmpty(lpszBindAddress))
|
||||
{
|
||||
if(!::sockaddr_A_2_IN(lpszBindAddress, usPort, bindAddr))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HP_SCOPE_HOST host(lpszRemoteAddress);
|
||||
LPCTSTR lpszRealAddress = host.addr;
|
||||
|
||||
if(m_enCastMode == CM_BROADCAST && ::IsStrEmpty(lpszRealAddress))
|
||||
lpszRealAddress = DEFAULT_IPV4_BROAD_CAST_ADDRESS;
|
||||
|
||||
if(!::GetSockAddrByHostName(lpszRealAddress, usPort, m_castAddr, bindAddr.family))
|
||||
return FALSE;
|
||||
|
||||
if(!bindAddr.IsSpecified())
|
||||
{
|
||||
bindAddr.family = m_castAddr.family;
|
||||
bindAddr.SetPort(usPort);
|
||||
}
|
||||
|
||||
if(m_enCastMode == CM_BROADCAST && bindAddr.IsIPv6())
|
||||
{
|
||||
::WSASetLastError(ERROR_PFNOSUPPORT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_soClient = socket(m_castAddr.family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(m_soClient == INVALID_SOCKET)
|
||||
return FALSE;
|
||||
|
||||
VERIFY(::fcntl_SETFL(m_soClient, O_NOATIME | O_NONBLOCK | O_CLOEXEC));
|
||||
VERIFY(::SSO_ReuseAddress(m_soClient, m_enReusePolicy) == NO_ERROR);
|
||||
|
||||
SetRemoteHost(host.name, usPort);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::BindClientSocket(HP_SOCKADDR& bindAddr)
|
||||
{
|
||||
HP_SOCKADDR anyAddr = HP_SOCKADDR::AnyAddr(m_castAddr.family);
|
||||
anyAddr.SetPort(m_castAddr.Port());
|
||||
|
||||
if(::bind(m_soClient, anyAddr.Addr(), anyAddr.AddrSize()) == SOCKET_ERROR)
|
||||
return FALSE;
|
||||
|
||||
m_dwConnID = ::GenerateConnectionID();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::ConnectToGroup(const HP_SOCKADDR& bindAddr)
|
||||
{
|
||||
if(m_enCastMode == CM_MULTICAST)
|
||||
{
|
||||
if(!::SetMultiCastSocketOptions(m_soClient, bindAddr, m_castAddr, m_iMCTtl, m_bMCLoop))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(m_castAddr.IsIPv4());
|
||||
|
||||
UINT iSet = 1;
|
||||
VERIFY(::SSO_SetSocketOption(m_soClient, SOL_SOCKET, SO_BROADCAST, &iSet, sizeof(UINT)) != SOCKET_ERROR);
|
||||
}
|
||||
|
||||
SetConnected();
|
||||
|
||||
if(TRIGGER(FireConnect()) == HR_ERROR)
|
||||
{
|
||||
::WSASetLastError(ENSURE_ERROR_CANCELLED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_nEvents = (SHORT)((m_lsSend.IsEmpty() ? 0 : POLLOUT) | (m_bPaused ? 0 : POLLIN) | POLLRDHUP);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::Stop()
|
||||
{
|
||||
if(!CheckStoping())
|
||||
return FALSE;
|
||||
|
||||
WaitForWorkerThreadEnd();
|
||||
|
||||
SetConnected(FALSE);
|
||||
|
||||
if(m_ccContext.bFireOnClose)
|
||||
FireClose(m_ccContext.enOperation, m_ccContext.iErrorCode);
|
||||
|
||||
if(m_soClient != INVALID_SOCKET)
|
||||
{
|
||||
shutdown(m_soClient, SHUT_WR);
|
||||
closesocket(m_soClient);
|
||||
|
||||
m_soClient = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CUdpCast::Reset()
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
|
||||
m_evSend.Reset();
|
||||
m_evRecv.Reset();
|
||||
m_evStop.Reset();
|
||||
|
||||
m_lsSend.Clear();
|
||||
m_itPool.Clear();
|
||||
m_rcBuffer.Free();
|
||||
|
||||
m_castAddr.Reset();
|
||||
m_remoteAddr.Reset();
|
||||
|
||||
m_strHost.Empty();
|
||||
|
||||
m_usPort = 0;
|
||||
m_nEvents = 0;
|
||||
m_bPaused = FALSE;
|
||||
m_enState = SS_STOPPED;
|
||||
|
||||
m_evWait.SyncNotifyAll();
|
||||
}
|
||||
|
||||
void CUdpCast::WaitForWorkerThreadEnd()
|
||||
{
|
||||
if(!m_thWorker.IsRunning())
|
||||
return;
|
||||
|
||||
if(m_thWorker.IsInMyThread())
|
||||
m_thWorker.Detach();
|
||||
else
|
||||
{
|
||||
m_evStop.Set();
|
||||
m_thWorker.Join();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CUdpCast::CreateWorkerThread()
|
||||
{
|
||||
return m_thWorker.Start(this, &CUdpCast::WorkerThreadProc);
|
||||
}
|
||||
|
||||
UINT WINAPI CUdpCast::WorkerThreadProc(LPVOID pv)
|
||||
{
|
||||
::SetCurrentWorkerThreadName();
|
||||
|
||||
TRACE("---------------> Cast Worker Thread 0x%08X started <---------------", SELF_THREAD_ID);
|
||||
|
||||
OnWorkerThreadStart(SELF_THREAD_ID);
|
||||
|
||||
BOOL bCallStop = TRUE;
|
||||
pollfd pfds[] = { {m_soClient, m_nEvents},
|
||||
{m_evSend.GetFD(), POLLIN},
|
||||
{m_evRecv.GetFD(), POLLIN},
|
||||
{m_evStop.GetFD(), POLLIN} };
|
||||
int size = ARRAY_SIZE(pfds);
|
||||
|
||||
m_rcBuffer.Malloc(m_dwMaxDatagramSize);
|
||||
|
||||
while(HasStarted())
|
||||
{
|
||||
int rs = (int)::PollForMultipleObjects(pfds, size);
|
||||
ASSERT(rs > TIMEOUT);
|
||||
|
||||
if(rs <= 0)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_UNKNOWN, ::WSAGetLastError());
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
if((1 << i) & rs)
|
||||
{
|
||||
SHORT revents = pfds[i].revents;
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
if(!ProcessNetworkEvent(revents))
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 1)
|
||||
{
|
||||
m_evSend.Reset();
|
||||
|
||||
if(!SendData())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 2)
|
||||
{
|
||||
m_evRecv.Reset();
|
||||
|
||||
if(!ReadData())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 3)
|
||||
{
|
||||
m_evStop.Reset();
|
||||
|
||||
bCallStop = FALSE;
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else
|
||||
VERIFY(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
m_nEvents = (SHORT)((m_lsSend.IsEmpty() ? 0 : POLLOUT) | (m_bPaused ? 0 : POLLIN) | POLLRDHUP);
|
||||
pfds[0].events = m_nEvents;
|
||||
}
|
||||
|
||||
EXIT_WORKER_THREAD:
|
||||
|
||||
OnWorkerThreadEnd(SELF_THREAD_ID);
|
||||
|
||||
if(bCallStop && HasStarted())
|
||||
Stop();
|
||||
|
||||
TRACE("---------------> Cast Worker Thread 0x%08X stoped <---------------", SELF_THREAD_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::ProcessNetworkEvent(SHORT events)
|
||||
{
|
||||
ASSERT(IsConnected());
|
||||
|
||||
BOOL bContinue = TRUE;
|
||||
|
||||
if(bContinue && events & POLLERR)
|
||||
bContinue = HandleClose(events);
|
||||
|
||||
if(bContinue && events & POLLIN)
|
||||
bContinue = HandleRead(events);
|
||||
|
||||
if(bContinue && events & POLLOUT)
|
||||
bContinue = HandleWrite(events);
|
||||
|
||||
if(bContinue && events & _POLL_HUNGUP_EVENTS)
|
||||
bContinue = HandleClose(events);
|
||||
|
||||
return bContinue;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::HandleClose(SHORT events)
|
||||
{
|
||||
EnSocketOperation enOperation = SO_CLOSE;
|
||||
|
||||
if(events & _POLL_HUNGUP_EVENTS)
|
||||
enOperation = SO_CLOSE;
|
||||
else if(events & POLLIN)
|
||||
enOperation = SO_RECEIVE;
|
||||
else if(events & POLLOUT)
|
||||
enOperation = SO_SEND;
|
||||
|
||||
m_ccContext.Reset(TRUE, enOperation, ::SSO_GetError(m_soClient));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::HandleRead(SHORT events)
|
||||
{
|
||||
return ReadData();
|
||||
}
|
||||
|
||||
BOOL CUdpCast::HandleWrite(SHORT events)
|
||||
{
|
||||
return SendData();
|
||||
}
|
||||
|
||||
BOOL CUdpCast::ReadData()
|
||||
{
|
||||
while(TRUE)
|
||||
{
|
||||
if(m_bPaused)
|
||||
break;
|
||||
|
||||
socklen_t addrLen = (socklen_t)m_remoteAddr.AddrSize();
|
||||
int rc = (int)recvfrom(m_soClient, (char*)(BYTE*)m_rcBuffer, m_dwMaxDatagramSize, MSG_TRUNC, m_remoteAddr.Addr(), &addrLen);
|
||||
|
||||
if(rc >= 0)
|
||||
{
|
||||
if(rc > (int)m_dwMaxDatagramSize)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, ERROR_BAD_LENGTH);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(TRIGGER(FireReceive(m_rcBuffer, rc)) == HR_ERROR)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> OnReceive() event return 'HR_ERROR', connection will be closed !", m_dwConnID);
|
||||
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, ENSURE_ERROR_CANCELLED);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
break;
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, code);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::PauseReceive(BOOL bPause)
|
||||
{
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(m_bPaused == bPause)
|
||||
return TRUE;
|
||||
|
||||
m_bPaused = bPause;
|
||||
|
||||
if(!bPause)
|
||||
return m_evRecv.Set();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::SendData()
|
||||
{
|
||||
BOOL bBlocked = FALSE;
|
||||
|
||||
while(m_lsSend.Length() > 0)
|
||||
{
|
||||
TItemPtr itPtr(m_itPool);
|
||||
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
itPtr = m_lsSend.PopFront();
|
||||
}
|
||||
|
||||
if(!itPtr.IsValid())
|
||||
break;
|
||||
|
||||
if(!DoSendData(itPtr, bBlocked))
|
||||
return FALSE;
|
||||
|
||||
if(bBlocked)
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
m_lsSend.PushFront(itPtr.Detach());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::DoSendData(TItem* pItem, BOOL& bBlocked)
|
||||
{
|
||||
int rc = (int)sendto(m_soClient, (char*)pItem->Ptr(), pItem->Size(), 0, m_castAddr.Addr(), m_castAddr.AddrSize());
|
||||
|
||||
if(rc >= 0)
|
||||
{
|
||||
ASSERT(rc == pItem->Size());
|
||||
|
||||
if(rc == 0)
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
m_lsSend.ReduceLength(1);
|
||||
}
|
||||
|
||||
if(TRIGGER(FireSend(pItem->Ptr(), rc)) == HR_ERROR)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> OnSend() event should not return 'HR_ERROR' !!", m_dwConnID);
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
bBlocked = TRUE;
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_SEND, code);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
ASSERT(FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::Send(const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
ASSERT(pBuffer && iLength >= 0 && iLength <= (int)m_dwMaxDatagramSize);
|
||||
|
||||
int result = NO_ERROR;
|
||||
|
||||
if(pBuffer && iLength >= 0 && iLength <= (int)m_dwMaxDatagramSize)
|
||||
{
|
||||
if(IsConnected())
|
||||
{
|
||||
if(iOffset != 0) pBuffer += iOffset;
|
||||
|
||||
TItemPtr itPtr(m_itPool, m_itPool.PickFreeItem());
|
||||
itPtr->Cat(pBuffer, iLength);
|
||||
|
||||
result = SendInternal(itPtr);
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_STATE;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
BOOL CUdpCast::SendPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
if(!pBuffers || iCount <= 0)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if(!IsConnected())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
int result = NO_ERROR;
|
||||
int iLength = 0;
|
||||
int iMaxLen = (int)m_dwMaxDatagramSize;
|
||||
|
||||
TItemPtr itPtr(m_itPool, m_itPool.PickFreeItem());
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
int iBufLen = pBuffers[i].len;
|
||||
|
||||
if(iBufLen > 0)
|
||||
{
|
||||
BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
|
||||
ASSERT(pBuffer);
|
||||
|
||||
iLength += iBufLen;
|
||||
|
||||
if(iLength <= iMaxLen)
|
||||
itPtr->Cat(pBuffer, iBufLen);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(iLength >= 0 && iLength <= iMaxLen)
|
||||
result = SendInternal(itPtr);
|
||||
else
|
||||
result = ERROR_INCORRECT_SIZE;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
int CUdpCast::SendInternal(TItemPtr& itPtr)
|
||||
{
|
||||
int iPending;
|
||||
int iBufferSize;
|
||||
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
|
||||
if(!IsConnected())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
iPending = m_lsSend.Length();
|
||||
iBufferSize = itPtr->Size();
|
||||
|
||||
m_lsSend.PushBack(itPtr.Detach());
|
||||
if(iBufferSize == 0) m_lsSend.IncreaseLength(1);
|
||||
|
||||
ASSERT(m_lsSend.Length() > 0);
|
||||
}
|
||||
|
||||
if(iPending == 0 && m_lsSend.Length() > 0) m_evSend.Set();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void CUdpCast::SetLastError(EnSocketError code, LPCSTR func, int ec)
|
||||
{
|
||||
TRACE("%s --> Error: %d, EC: %d", func, code, ec);
|
||||
|
||||
m_enLastError = code;
|
||||
::SetLastError(ec);
|
||||
}
|
||||
|
||||
BOOL CUdpCast::GetLocalAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
ASSERT(lpszAddress != nullptr && iAddressLen > 0);
|
||||
|
||||
return ::GetSocketLocalAddress(m_soClient, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
void CUdpCast::SetRemoteHost(LPCTSTR lpszHost, USHORT usPort)
|
||||
{
|
||||
m_strHost = lpszHost;
|
||||
m_usPort = usPort;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::GetRemoteHost(TCHAR lpszHost[], int& iHostLen, USHORT& usPort)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
if(m_strHost.IsEmpty())
|
||||
return isOK;
|
||||
|
||||
int iLen = m_strHost.GetLength() + 1;
|
||||
|
||||
if(iHostLen >= iLen)
|
||||
{
|
||||
memcpy(lpszHost, CA2CT(m_strHost), iLen * sizeof(TCHAR));
|
||||
usPort = m_usPort;
|
||||
|
||||
isOK = TRUE;
|
||||
}
|
||||
|
||||
iHostLen = iLen;
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CUdpCast::GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort)
|
||||
{
|
||||
*lpszHost = m_strHost;
|
||||
|
||||
if(pusPort != nullptr)
|
||||
*pusPort = m_usPort;
|
||||
|
||||
return !m_strHost.IsEmpty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
class CUdpCast : public IUdpCast
|
||||
{
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr, USHORT usLocalPort = 0);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Send (const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendPackets (const WSABUF pBuffers[], int iCount);
|
||||
virtual BOOL PauseReceive (BOOL bPause = TRUE);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual CONNID GetConnectionID () {return m_dwConnID;}
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
|
||||
virtual BOOL GetLocalAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteHost (TCHAR lpszHost[], int& iHostLen, USHORT& usPort);
|
||||
virtual BOOL GetPendingDataLength (int& iPending) {iPending = m_lsSend.Length(); return HasStarted();}
|
||||
virtual BOOL IsPauseReceive (BOOL& bPaused) {bPaused = m_bPaused; return HasStarted();}
|
||||
virtual BOOL IsConnected () {return m_bConnected;}
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure () {return FALSE;}
|
||||
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy){ENSURE_HAS_STOPPED(); m_enReusePolicy = enReusePolicy;}
|
||||
virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) {ENSURE_HAS_STOPPED(); m_dwMaxDatagramSize = dwMaxDatagramSize;}
|
||||
virtual void SetFreeBufferPoolSize (DWORD dwFreeBufferPoolSize) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolSize = dwFreeBufferPoolSize;}
|
||||
virtual void SetFreeBufferPoolHold (DWORD dwFreeBufferPoolHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolHold = dwFreeBufferPoolHold;}
|
||||
virtual void SetCastMode (EnCastMode enCastMode) {ENSURE_HAS_STOPPED(); m_enCastMode = enCastMode;}
|
||||
virtual void SetMultiCastTtl (int iMCTtl) {ENSURE_HAS_STOPPED(); m_iMCTtl = iMCTtl;}
|
||||
virtual void SetMultiCastLoop (BOOL bMCLoop) {ENSURE_HAS_STOPPED(); m_bMCLoop = bMCLoop;}
|
||||
virtual void SetExtra (PVOID pExtra) {m_pExtra = pExtra;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual DWORD GetMaxDatagramSize () {return m_dwMaxDatagramSize;}
|
||||
virtual DWORD GetFreeBufferPoolSize () {return m_dwFreeBufferPoolSize;}
|
||||
virtual DWORD GetFreeBufferPoolHold () {return m_dwFreeBufferPoolHold;}
|
||||
virtual EnCastMode GetCastMode () {return m_enCastMode;}
|
||||
virtual int GetMultiCastTtl () {return m_iMCTtl;}
|
||||
virtual BOOL IsMultiCastLoop () {return m_bMCLoop;}
|
||||
virtual PVOID GetExtra () {return m_pExtra;}
|
||||
|
||||
virtual BOOL GetRemoteAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
ADDRESS_FAMILY usFamily;
|
||||
return ::sockaddr_IN_2_A(m_remoteAddr, usFamily, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FirePrepareConnect(SOCKET socket)
|
||||
{return m_pListener->OnPrepareConnect(this, m_dwConnID, socket);}
|
||||
virtual EnHandleResult FireConnect()
|
||||
{
|
||||
EnHandleResult rs = m_pListener->OnConnect(this, m_dwConnID);
|
||||
if(rs != HR_ERROR) rs = FireHandShake();
|
||||
return rs;
|
||||
}
|
||||
virtual EnHandleResult FireHandShake()
|
||||
{return m_pListener->OnHandShake(this, m_dwConnID);}
|
||||
virtual EnHandleResult FireSend(const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnSend(this, m_dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnReceive(this, m_dwConnID, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(int iLength)
|
||||
{return m_pListener->OnReceive(this, m_dwConnID, iLength);}
|
||||
virtual EnHandleResult FireClose(EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_pListener->OnClose(this, m_dwConnID, enOperation, iErrorCode);}
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID tid) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID tid) {}
|
||||
|
||||
protected:
|
||||
void SetReserved (PVOID pReserved) {m_pReserved = pReserved;}
|
||||
PVOID GetReserved () {return m_pReserved;}
|
||||
BOOL GetRemoteHost (LPCSTR* lpszHost, USHORT* pusPort = nullptr);
|
||||
|
||||
private:
|
||||
void SetRemoteHost (LPCTSTR lpszHost, USHORT usPort);
|
||||
void SetConnected (BOOL bConnected = TRUE) {m_bConnected = bConnected; if(bConnected) m_enState = SS_STARTED;}
|
||||
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL CreateClientSocket(LPCTSTR lpszRemoteAddress, USHORT usPort, LPCTSTR lpszBindAddress, HP_SOCKADDR& bindAddr);
|
||||
BOOL BindClientSocket(HP_SOCKADDR& bindAddr);
|
||||
BOOL ConnectToGroup(const HP_SOCKADDR& bindAddr);
|
||||
BOOL CreateWorkerThread();
|
||||
BOOL ProcessNetworkEvent(SHORT events);
|
||||
BOOL ReadData();
|
||||
BOOL SendData();
|
||||
BOOL DoSendData(TItem* pItem, BOOL& bBlocked);
|
||||
int SendInternal(TItemPtr& itPtr);
|
||||
void WaitForWorkerThreadEnd();
|
||||
|
||||
BOOL HandleClose(SHORT events);
|
||||
BOOL HandleRead(SHORT events);
|
||||
BOOL HandleWrite(SHORT events);
|
||||
|
||||
UINT WINAPI WorkerThreadProc(LPVOID pv);
|
||||
|
||||
public:
|
||||
CUdpCast(IUdpCastListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_lsSend (m_itPool)
|
||||
, m_soClient (INVALID_SOCKET)
|
||||
, m_nEvents (0)
|
||||
, m_dwConnID (0)
|
||||
, m_usPort (0)
|
||||
, m_bPaused (FALSE)
|
||||
, m_bConnected (FALSE)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_pExtra (nullptr)
|
||||
, m_pReserved (nullptr)
|
||||
, m_enReusePolicy (RAP_ADDR_ONLY)
|
||||
, m_dwMaxDatagramSize (DEFAULT_UDP_MAX_DATAGRAM_SIZE)
|
||||
, m_dwFreeBufferPoolSize(DEFAULT_CLIENT_FREE_BUFFER_POOL_SIZE)
|
||||
, m_dwFreeBufferPoolHold(DEFAULT_CLIENT_FREE_BUFFER_POOL_HOLD)
|
||||
, m_iMCTtl (1)
|
||||
, m_bMCLoop (FALSE)
|
||||
, m_enCastMode (CM_MULTICAST)
|
||||
, m_castAddr (AF_UNSPEC, TRUE)
|
||||
, m_remoteAddr (AF_UNSPEC, TRUE)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CUdpCast()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
IUdpCastListener* m_pListener;
|
||||
TClientCloseContext m_ccContext;
|
||||
|
||||
SOCKET m_soClient;
|
||||
SHORT m_nEvents;
|
||||
CONNID m_dwConnID;
|
||||
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
DWORD m_dwMaxDatagramSize;
|
||||
DWORD m_dwFreeBufferPoolSize;
|
||||
DWORD m_dwFreeBufferPoolHold;
|
||||
|
||||
int m_iMCTtl;
|
||||
BOOL m_bMCLoop;
|
||||
EnCastMode m_enCastMode;
|
||||
|
||||
EnSocketError m_enLastError;
|
||||
volatile BOOL m_bConnected;
|
||||
volatile EnServiceState m_enState;
|
||||
|
||||
PVOID m_pExtra;
|
||||
PVOID m_pReserved;
|
||||
|
||||
HP_SOCKADDR m_castAddr;
|
||||
HP_SOCKADDR m_remoteAddr;
|
||||
|
||||
CBufferPtr m_rcBuffer;
|
||||
|
||||
protected:
|
||||
CStringA m_strHost;
|
||||
USHORT m_usPort;
|
||||
|
||||
CItemPool m_itPool;
|
||||
|
||||
private:
|
||||
CSpinGuard m_csState;
|
||||
|
||||
CCriSec m_csSend;
|
||||
TItemListExV m_lsSend;
|
||||
|
||||
CEvt m_evSend;
|
||||
CEvt m_evRecv;
|
||||
CEvt m_evStop;
|
||||
|
||||
volatile BOOL m_bPaused;
|
||||
|
||||
CThread<CUdpCast, VOID, UINT> m_thWorker;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,824 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UdpClient.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
BOOL CUdpClient::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress, USHORT usLocalPort)
|
||||
{
|
||||
if(!CheckParams() || !CheckStarting())
|
||||
return FALSE;
|
||||
|
||||
PrepareStart();
|
||||
m_ccContext.Reset();
|
||||
|
||||
BOOL isOK = FALSE;
|
||||
HP_SOCKADDR addrRemote, addrBind;
|
||||
|
||||
if(CreateClientSocket(lpszRemoteAddress, addrRemote, usPort, lpszBindAddress, addrBind))
|
||||
{
|
||||
if(BindClientSocket(addrBind, addrRemote, usLocalPort))
|
||||
{
|
||||
if(TRIGGER(FirePrepareConnect(m_soClient)) != HR_ERROR)
|
||||
{
|
||||
if(ConnectToServer(addrRemote, bAsyncConnect))
|
||||
{
|
||||
if(CreateWorkerThread())
|
||||
isOK = TRUE;
|
||||
else
|
||||
SetLastError(SE_WORKER_THREAD_CREATE, __FUNCTION__, ERROR_CREATE_FAILED);
|
||||
}
|
||||
else
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ::WSAGetLastError());
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_PREPARE, __FUNCTION__, ENSURE_ERROR_CANCELLED);
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_BIND, __FUNCTION__, ::WSAGetLastError());
|
||||
}
|
||||
else
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
|
||||
|
||||
if(!isOK)
|
||||
{
|
||||
m_ccContext.Reset(FALSE);
|
||||
EXECUTE_RESTORE_ERROR(Stop());
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::CheckParams()
|
||||
{
|
||||
if (((int)m_dwMaxDatagramSize > 0 && m_dwMaxDatagramSize <= MAXIMUM_UDP_MAX_DATAGRAM_SIZE) &&
|
||||
((int)m_dwFreeBufferPoolSize >= 0) &&
|
||||
((int)m_dwFreeBufferPoolHold >= 0) &&
|
||||
((int)m_dwDetectAttempts >= 0) &&
|
||||
((int)m_dwDetectInterval >= 1000 || m_dwDetectInterval == 0) )
|
||||
return TRUE;
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CUdpClient::PrepareStart()
|
||||
{
|
||||
m_itPool.SetItemCapacity(m_dwMaxDatagramSize);
|
||||
m_itPool.SetPoolSize(m_dwFreeBufferPoolSize);
|
||||
m_itPool.SetPoolHold(m_dwFreeBufferPoolHold);
|
||||
|
||||
m_itPool.Prepare();
|
||||
}
|
||||
|
||||
BOOL CUdpClient::CheckStarting()
|
||||
{
|
||||
CSpinLock locallock(m_csState);
|
||||
|
||||
if(m_enState == SS_STOPPED)
|
||||
m_enState = SS_STARTING;
|
||||
else
|
||||
{
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::CheckStoping()
|
||||
{
|
||||
if(m_enState != SS_STOPPED)
|
||||
{
|
||||
CSpinLock locallock(m_csState);
|
||||
|
||||
if(HasStarted())
|
||||
{
|
||||
m_enState = SS_STOPPING;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::CreateClientSocket(LPCTSTR lpszRemoteAddress, HP_SOCKADDR& addrRemote, USHORT usPort, LPCTSTR lpszBindAddress, HP_SOCKADDR& addrBind)
|
||||
{
|
||||
if(::IsStrNotEmpty(lpszBindAddress))
|
||||
{
|
||||
if(!::sockaddr_A_2_IN(lpszBindAddress, 0, addrBind))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HP_SCOPE_HOST host(lpszRemoteAddress);
|
||||
|
||||
if(!::GetSockAddrByHostName(host.addr, usPort, addrRemote, addrBind.family))
|
||||
return FALSE;
|
||||
|
||||
m_soClient = socket(addrRemote.family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(m_soClient == INVALID_SOCKET)
|
||||
return FALSE;
|
||||
|
||||
VERIFY(::SSO_ReuseAddress(m_soClient, m_enReusePolicy) == NO_ERROR);
|
||||
|
||||
SetRemoteHost(host.name, usPort);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::BindClientSocket(const HP_SOCKADDR& addrBind, const HP_SOCKADDR& addrRemote, USHORT usLocalPort)
|
||||
{
|
||||
if(addrBind.IsSpecified() && usLocalPort == 0)
|
||||
{
|
||||
if(::bind(m_soClient, addrBind.Addr(), addrBind.AddrSize()) == SOCKET_ERROR)
|
||||
return FALSE;
|
||||
}
|
||||
else if(usLocalPort != 0)
|
||||
{
|
||||
HP_SOCKADDR realBindAddr = addrBind.IsSpecified() ? addrBind : HP_SOCKADDR::AnyAddr(addrRemote.family);
|
||||
|
||||
realBindAddr.SetPort(usLocalPort);
|
||||
|
||||
if(::bind(m_soClient, realBindAddr.Addr(), realBindAddr.AddrSize()) == SOCKET_ERROR)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_dwConnID = ::GenerateConnectionID();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::ConnectToServer(const HP_SOCKADDR& addrRemote, BOOL bAsyncConnect)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
if(bAsyncConnect)
|
||||
{
|
||||
VERIFY(::fcntl_SETFL(m_soClient, O_NOATIME | O_NONBLOCK | O_CLOEXEC));
|
||||
|
||||
int rc = ::connect(m_soClient, addrRemote.Addr(), addrRemote.AddrSize());
|
||||
|
||||
if(IS_NO_ERROR(rc) || IS_IO_PENDING_ERROR())
|
||||
{
|
||||
m_nEvents = POLLOUT;
|
||||
isOK = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(::connect(m_soClient, addrRemote.Addr(), addrRemote.AddrSize()) != SOCKET_ERROR)
|
||||
{
|
||||
VERIFY(::fcntl_SETFL(m_soClient, O_NOATIME | O_NONBLOCK | O_CLOEXEC));
|
||||
|
||||
SetConnected();
|
||||
|
||||
if(TRIGGER(FireConnect()) == HR_ERROR)
|
||||
::WSASetLastError(ENSURE_ERROR_CANCELLED);
|
||||
else
|
||||
{
|
||||
VERIFY(DetectConnection());
|
||||
|
||||
m_nEvents = (SHORT)((m_lsSend.IsEmpty() ? 0 : POLLOUT) | (m_bPaused ? 0 : POLLIN) | POLLRDHUP);
|
||||
isOK = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::Stop()
|
||||
{
|
||||
if(!CheckStoping())
|
||||
return FALSE;
|
||||
|
||||
WaitForWorkerThreadEnd();
|
||||
|
||||
CheckConnected();
|
||||
|
||||
if(m_ccContext.bFireOnClose)
|
||||
FireClose(m_ccContext.enOperation, m_ccContext.iErrorCode);
|
||||
|
||||
if(m_soClient != INVALID_SOCKET)
|
||||
{
|
||||
shutdown(m_soClient, SHUT_WR);
|
||||
closesocket(m_soClient);
|
||||
|
||||
m_soClient = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CUdpClient::Reset()
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
|
||||
m_evSend.Reset();
|
||||
m_evRecv.Reset();
|
||||
m_evStop.Reset();
|
||||
|
||||
m_lsSend.Clear();
|
||||
m_itPool.Clear();
|
||||
m_rcBuffer.Free();
|
||||
|
||||
m_strHost.Empty();
|
||||
|
||||
m_usPort = 0;
|
||||
m_nEvents = 0;
|
||||
m_dwDetectFails = 0;
|
||||
m_bPaused = FALSE;
|
||||
m_enState = SS_STOPPED;
|
||||
|
||||
m_evWait.SyncNotifyAll();
|
||||
}
|
||||
|
||||
void CUdpClient::WaitForWorkerThreadEnd()
|
||||
{
|
||||
if(!m_thWorker.IsRunning())
|
||||
return;
|
||||
|
||||
if(m_thWorker.IsInMyThread())
|
||||
m_thWorker.Detach();
|
||||
else
|
||||
{
|
||||
m_evStop.Set();
|
||||
m_thWorker.Join();
|
||||
}
|
||||
}
|
||||
|
||||
void CUdpClient::CheckConnected()
|
||||
{
|
||||
if(!IsConnected())
|
||||
return;
|
||||
|
||||
if(m_ccContext.bNotify)
|
||||
::SendUdpCloseNotify(m_soClient);
|
||||
|
||||
SetConnected(FALSE);
|
||||
}
|
||||
|
||||
BOOL CUdpClient::CreateWorkerThread()
|
||||
{
|
||||
return m_thWorker.Start(this, &CUdpClient::WorkerThreadProc);
|
||||
}
|
||||
|
||||
UINT WINAPI CUdpClient::WorkerThreadProc(LPVOID pv)
|
||||
{
|
||||
::SetCurrentWorkerThreadName();
|
||||
|
||||
TRACE("---------------> Client Worker Thread 0x%08X started <---------------", SELF_THREAD_ID);
|
||||
|
||||
OnWorkerThreadStart(SELF_THREAD_ID);
|
||||
|
||||
BOOL bCallStop = TRUE;
|
||||
DWORD dwSize = 4;
|
||||
DWORD dwIndex = 0;
|
||||
BOOL bDetect = IsNeedDetect();
|
||||
FD fdUserEvt = GetUserEvent();
|
||||
|
||||
if(bDetect) ++dwSize;
|
||||
if(IS_VALID_FD(fdUserEvt)) ++dwSize;
|
||||
|
||||
pollfd* pfds = CreateLocalObjects(pollfd, dwSize);
|
||||
|
||||
pfds[dwIndex++] = {m_soClient, m_nEvents};
|
||||
pfds[dwIndex++] = {m_evSend.GetFD(), POLLIN};
|
||||
pfds[dwIndex++] = {m_evRecv.GetFD(), POLLIN};
|
||||
pfds[dwIndex++] = {m_evStop.GetFD(), POLLIN};
|
||||
|
||||
unique_ptr<CTimerEvent> evDetectPtr;
|
||||
|
||||
if(bDetect)
|
||||
{
|
||||
evDetectPtr.reset(new CTimerEvent());
|
||||
evDetectPtr->Set(m_dwDetectInterval);
|
||||
pfds[dwIndex++] = {evDetectPtr->GetFD(), POLLIN};
|
||||
}
|
||||
|
||||
if(IS_VALID_FD(fdUserEvt))
|
||||
pfds[dwIndex++] = {fdUserEvt, POLLIN};
|
||||
|
||||
m_rcBuffer.Malloc(m_dwMaxDatagramSize);
|
||||
|
||||
while(HasStarted())
|
||||
{
|
||||
int rs = (int)::PollForMultipleObjects(pfds, dwSize);
|
||||
ASSERT(rs > TIMEOUT);
|
||||
|
||||
if(rs <= 0)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_UNKNOWN, ::WSAGetLastError());
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
|
||||
for(DWORD i = 0; i < dwSize; i++)
|
||||
{
|
||||
if((1 << i) & rs)
|
||||
{
|
||||
SHORT revents = pfds[i].revents;
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
if(!ProcessNetworkEvent(revents))
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 1)
|
||||
{
|
||||
m_evSend.Reset();
|
||||
|
||||
if(!SendData())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 2)
|
||||
{
|
||||
m_evRecv.Reset();
|
||||
|
||||
if(!ReadData())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 3)
|
||||
{
|
||||
m_evStop.Reset();
|
||||
|
||||
bCallStop = FALSE;
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else if(i == 4)
|
||||
{
|
||||
if(bDetect)
|
||||
{
|
||||
evDetectPtr->Reset();
|
||||
|
||||
if(!CheckConnection())
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!OnUserEvent())
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CLOSE, ENSURE_ERROR_CANCELLED);
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(i == 5)
|
||||
{
|
||||
if(!OnUserEvent())
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CLOSE, ENSURE_ERROR_CANCELLED);
|
||||
goto EXIT_WORKER_THREAD;
|
||||
}
|
||||
}
|
||||
else
|
||||
VERIFY(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
m_nEvents = (SHORT)((m_lsSend.IsEmpty() ? 0 : POLLOUT) | (m_bPaused ? 0 : POLLIN) | POLLRDHUP);
|
||||
pfds[0].events = m_nEvents;
|
||||
}
|
||||
|
||||
EXIT_WORKER_THREAD:
|
||||
|
||||
OnWorkerThreadEnd(SELF_THREAD_ID);
|
||||
|
||||
if(bCallStop && HasStarted())
|
||||
Stop();
|
||||
|
||||
TRACE("---------------> Client Worker Thread 0x%08X stoped <---------------", SELF_THREAD_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::CheckConnection()
|
||||
{
|
||||
if(m_dwDetectFails++ >= m_dwDetectAttempts)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CLOSE, NO_ERROR, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DetectConnection();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::DetectConnection()
|
||||
{
|
||||
int result = NO_ERROR;
|
||||
|
||||
if((int)send(m_soClient, nullptr, 0, 0) == SOCKET_ERROR)
|
||||
{
|
||||
result = ::WSAGetLastError();
|
||||
if(result == ERROR_WOULDBLOCK)
|
||||
result = NO_ERROR;
|
||||
}
|
||||
|
||||
BOOL isOK = (result == NO_ERROR);
|
||||
|
||||
if(isOK)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> send 0 bytes (detect package succ)", m_dwConnID);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> send 0 bytes (detect package fail [%d])", m_dwConnID, result);
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::ProcessNetworkEvent(SHORT events)
|
||||
{
|
||||
BOOL bContinue = TRUE;
|
||||
|
||||
if(bContinue && events & POLLERR)
|
||||
bContinue = HandleClose(events);
|
||||
|
||||
if(bContinue && !IsConnected())
|
||||
bContinue = HandleConnect(events);
|
||||
|
||||
if(bContinue && events & POLLIN)
|
||||
bContinue = HandleRead(events);
|
||||
|
||||
if(bContinue && events & POLLOUT)
|
||||
bContinue = HandleWrite(events);
|
||||
|
||||
if(bContinue && events & _POLL_HUNGUP_EVENTS)
|
||||
bContinue = HandleClose(events);
|
||||
|
||||
return bContinue;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::HandleConnect(SHORT events)
|
||||
{
|
||||
ASSERT(events & POLLOUT);
|
||||
|
||||
int code = ::SSO_GetError(m_soClient);
|
||||
|
||||
if(!IS_NO_ERROR(code) || (events & _POLL_ERROR_EVENTS))
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CONNECT, code);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(events & _POLL_HUNGUP_EVENTS)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CONNECT, NO_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SetConnected();
|
||||
|
||||
if(TRIGGER(FireConnect()) != HR_ERROR)
|
||||
VERIFY(DetectConnection());
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(FALSE, SO_CLOSE, ENSURE_ERROR_CANCELLED, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::HandleClose(SHORT events)
|
||||
{
|
||||
EnSocketOperation enOperation = SO_CLOSE;
|
||||
|
||||
if(events & _POLL_HUNGUP_EVENTS)
|
||||
enOperation = SO_CLOSE;
|
||||
else if(events & POLLIN)
|
||||
enOperation = SO_RECEIVE;
|
||||
else if(events & POLLOUT)
|
||||
enOperation = SO_SEND;
|
||||
|
||||
m_ccContext.Reset(TRUE, enOperation, ::SSO_GetError(m_soClient));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::HandleRead(SHORT events)
|
||||
{
|
||||
return ReadData();
|
||||
}
|
||||
|
||||
BOOL CUdpClient::HandleWrite(SHORT events)
|
||||
{
|
||||
return SendData();
|
||||
}
|
||||
|
||||
BOOL CUdpClient::ReadData()
|
||||
{
|
||||
while(TRUE)
|
||||
{
|
||||
if(m_bPaused)
|
||||
break;
|
||||
|
||||
int rc = (int)recv(m_soClient, (char*)(BYTE*)m_rcBuffer, m_dwMaxDatagramSize, MSG_TRUNC);
|
||||
|
||||
if(rc > 0)
|
||||
{
|
||||
m_dwDetectFails = 0;
|
||||
|
||||
if(::IsUdpCloseNotify(m_rcBuffer, rc))
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_CLOSE, NO_ERROR, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(rc > (int)m_dwMaxDatagramSize)
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, ERROR_BAD_LENGTH);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(TRIGGER(FireReceive(m_rcBuffer, rc)) == HR_ERROR)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> OnReceive() event return 'HR_ERROR', connection will be closed !", m_dwConnID);
|
||||
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, ENSURE_ERROR_CANCELLED);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
break;
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_RECEIVE, code);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(rc == 0)
|
||||
{
|
||||
m_dwDetectFails = 0;
|
||||
TRACE("<C-CNNID: %zu> recv 0 bytes (detect ack package)", m_dwConnID);
|
||||
}
|
||||
else
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::PauseReceive(BOOL bPause)
|
||||
{
|
||||
if(!IsConnected())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(m_bPaused == bPause)
|
||||
return TRUE;
|
||||
|
||||
m_bPaused = bPause;
|
||||
|
||||
if(!bPause)
|
||||
return m_evRecv.Set();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::SendData()
|
||||
{
|
||||
BOOL bBlocked = FALSE;
|
||||
|
||||
while(m_lsSend.Length() > 0)
|
||||
{
|
||||
TItemPtr itPtr(m_itPool);
|
||||
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
itPtr = m_lsSend.PopFront();
|
||||
}
|
||||
|
||||
if(!itPtr.IsValid())
|
||||
break;
|
||||
|
||||
ASSERT(!itPtr->IsEmpty());
|
||||
|
||||
if(!DoSendData(itPtr, bBlocked))
|
||||
return FALSE;
|
||||
|
||||
if(bBlocked)
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
m_lsSend.PushFront(itPtr.Detach());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::DoSendData(TItem* pItem, BOOL& bBlocked)
|
||||
{
|
||||
int rc = (int)send(m_soClient, (char*)pItem->Ptr(), pItem->Size(), 0);
|
||||
|
||||
if(rc > 0)
|
||||
{
|
||||
ASSERT(rc == pItem->Size());
|
||||
|
||||
if(TRIGGER(FireSend(pItem->Ptr(), rc)) == HR_ERROR)
|
||||
{
|
||||
TRACE("<C-CNNID: %zu> OnSend() event should not return 'HR_ERROR' !!", m_dwConnID);
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
bBlocked = TRUE;
|
||||
else
|
||||
{
|
||||
m_ccContext.Reset(TRUE, SO_SEND, code);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
ASSERT(FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::DoSend(const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
ASSERT(pBuffer && iLength > 0 && iLength <= (int)m_dwMaxDatagramSize);
|
||||
|
||||
int result = NO_ERROR;
|
||||
|
||||
if(pBuffer && iLength > 0 && iLength <= (int)m_dwMaxDatagramSize)
|
||||
{
|
||||
if(IsConnected())
|
||||
{
|
||||
if(iOffset != 0) pBuffer += iOffset;
|
||||
|
||||
TItemPtr itPtr(m_itPool, m_itPool.PickFreeItem());
|
||||
itPtr->Cat(pBuffer, iLength);
|
||||
|
||||
result = SendInternal(itPtr);
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_STATE;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
BOOL CUdpClient::SendPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
if(!pBuffers || iCount <= 0)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if(!IsConnected())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
int result = NO_ERROR;
|
||||
int iLength = 0;
|
||||
int iMaxLen = (int)m_dwMaxDatagramSize;
|
||||
|
||||
TItemPtr itPtr(m_itPool, m_itPool.PickFreeItem());
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
int iBufLen = pBuffers[i].len;
|
||||
|
||||
if(iBufLen > 0)
|
||||
{
|
||||
BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
|
||||
ASSERT(pBuffer);
|
||||
|
||||
iLength += iBufLen;
|
||||
|
||||
if(iLength <= iMaxLen)
|
||||
itPtr->Cat(pBuffer, iBufLen);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(iLength > 0 && iLength <= iMaxLen)
|
||||
result = SendInternal(itPtr);
|
||||
else
|
||||
result = ERROR_INCORRECT_SIZE;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
int CUdpClient::SendInternal(TItemPtr& itPtr)
|
||||
{
|
||||
int iPending;
|
||||
|
||||
{
|
||||
CCriSecLock locallock(m_csSend);
|
||||
|
||||
if(!IsConnected())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
iPending = m_lsSend.Length();
|
||||
|
||||
m_lsSend.PushBack(itPtr.Detach());
|
||||
ASSERT(m_lsSend.Length() > 0);
|
||||
}
|
||||
|
||||
if(iPending == 0 && m_lsSend.Length() > 0) m_evSend.Set();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void CUdpClient::SetLastError(EnSocketError code, LPCSTR func, int ec)
|
||||
{
|
||||
TRACE("%s --> Error: %d, EC: %d", func, code, ec);
|
||||
|
||||
m_enLastError = code;
|
||||
::SetLastError(ec);
|
||||
}
|
||||
|
||||
BOOL CUdpClient::GetLocalAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
ASSERT(lpszAddress != nullptr && iAddressLen > 0);
|
||||
|
||||
return ::GetSocketLocalAddress(m_soClient, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
void CUdpClient::SetRemoteHost(LPCTSTR lpszHost, USHORT usPort)
|
||||
{
|
||||
m_strHost = lpszHost;
|
||||
m_usPort = usPort;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::GetRemoteHost(TCHAR lpszHost[], int& iHostLen, USHORT& usPort)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
if(m_strHost.IsEmpty())
|
||||
return isOK;
|
||||
|
||||
int iLen = m_strHost.GetLength() + 1;
|
||||
|
||||
if(iHostLen >= iLen)
|
||||
{
|
||||
memcpy(lpszHost, CA2CT(m_strHost), iLen * sizeof(TCHAR));
|
||||
usPort = m_usPort;
|
||||
|
||||
isOK = TRUE;
|
||||
}
|
||||
|
||||
iHostLen = iLen;
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CUdpClient::GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort)
|
||||
{
|
||||
*lpszHost = m_strHost;
|
||||
|
||||
if(pusPort != nullptr)
|
||||
*pusPort = m_usPort;
|
||||
|
||||
return !m_strHost.IsEmpty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
class CUdpClient : public IUdpClient
|
||||
{
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr, USHORT usLocalPort = 0);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Send (const BYTE* pBuffer, int iLength, int iOffset = 0) {return DoSend(pBuffer, iLength, iOffset);}
|
||||
virtual BOOL SendPackets (const WSABUF pBuffers[], int iCount);
|
||||
virtual BOOL PauseReceive (BOOL bPause = TRUE);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual CONNID GetConnectionID () {return m_dwConnID;}
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
|
||||
virtual BOOL GetLocalAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteHost (TCHAR lpszHost[], int& iHostLen, USHORT& usPort);
|
||||
virtual BOOL GetPendingDataLength (int& iPending) {iPending = m_lsSend.Length(); return HasStarted();}
|
||||
virtual BOOL IsPauseReceive (BOOL& bPaused) {bPaused = m_bPaused; return HasStarted();}
|
||||
virtual BOOL IsConnected () {return m_bConnected;}
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure () {return FALSE;}
|
||||
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy){ENSURE_HAS_STOPPED(); m_enReusePolicy = enReusePolicy;}
|
||||
virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) {ENSURE_HAS_STOPPED(); m_dwMaxDatagramSize = dwMaxDatagramSize;}
|
||||
virtual void SetDetectAttempts (DWORD dwDetectAttempts) {ENSURE_HAS_STOPPED(); m_dwDetectAttempts = dwDetectAttempts;}
|
||||
virtual void SetDetectInterval (DWORD dwDetectInterval) {ENSURE_HAS_STOPPED(); m_dwDetectInterval = dwDetectInterval;}
|
||||
virtual void SetFreeBufferPoolSize (DWORD dwFreeBufferPoolSize) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolSize = dwFreeBufferPoolSize;}
|
||||
virtual void SetFreeBufferPoolHold (DWORD dwFreeBufferPoolHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolHold = dwFreeBufferPoolHold;}
|
||||
virtual void SetExtra (PVOID pExtra) {m_pExtra = pExtra;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual DWORD GetMaxDatagramSize () {return m_dwMaxDatagramSize;}
|
||||
virtual DWORD GetDetectAttempts () {return m_dwDetectAttempts;}
|
||||
virtual DWORD GetDetectInterval () {return m_dwDetectInterval;}
|
||||
virtual DWORD GetFreeBufferPoolSize () {return m_dwFreeBufferPoolSize;}
|
||||
virtual DWORD GetFreeBufferPoolHold () {return m_dwFreeBufferPoolHold;}
|
||||
virtual PVOID GetExtra () {return m_pExtra;}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FirePrepareConnect(SOCKET socket)
|
||||
{return DoFirePrepareConnect(this, socket);}
|
||||
virtual EnHandleResult FireConnect()
|
||||
{
|
||||
EnHandleResult rs = DoFireConnect(this);
|
||||
if(rs != HR_ERROR) rs = FireHandShake();
|
||||
return rs;
|
||||
}
|
||||
virtual EnHandleResult FireHandShake()
|
||||
{return DoFireHandShake(this);}
|
||||
virtual EnHandleResult FireSend(const BYTE* pData, int iLength)
|
||||
{return DoFireSend(this, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(const BYTE* pData, int iLength)
|
||||
{return DoFireReceive(this, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(int iLength)
|
||||
{return DoFireReceive(this, iLength);}
|
||||
virtual EnHandleResult FireClose(EnSocketOperation enOperation, int iErrorCode)
|
||||
{return DoFireClose(this, enOperation, iErrorCode);}
|
||||
|
||||
virtual EnHandleResult DoFirePrepareConnect(IUdpClient* pSender, SOCKET socket)
|
||||
{return m_pListener->OnPrepareConnect(pSender, pSender->GetConnectionID(), socket);}
|
||||
virtual EnHandleResult DoFireConnect(IUdpClient* pSender)
|
||||
{return m_pListener->OnConnect(pSender, pSender->GetConnectionID());}
|
||||
virtual EnHandleResult DoFireHandShake(IUdpClient* pSender)
|
||||
{return m_pListener->OnHandShake(pSender, pSender->GetConnectionID());}
|
||||
virtual EnHandleResult DoFireSend(IUdpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnSend(pSender, pSender->GetConnectionID(), pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(IUdpClient* pSender, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnReceive(pSender, pSender->GetConnectionID(), pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(IUdpClient* pSender, int iLength)
|
||||
{return m_pListener->OnReceive(pSender, pSender->GetConnectionID(), iLength);}
|
||||
virtual EnHandleResult DoFireClose(IUdpClient* pSender, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_pListener->OnClose(pSender, pSender->GetConnectionID(), enOperation, iErrorCode);}
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID tid) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID tid) {}
|
||||
|
||||
virtual FD GetUserEvent() {return INVALID_FD;}
|
||||
virtual BOOL OnUserEvent() {return TRUE;}
|
||||
|
||||
static BOOL DoSend(CUdpClient* pClient, const BYTE* pBuffer, int iLength, int iOffset = 0)
|
||||
{return pClient->DoSend(pBuffer, iLength, iOffset);}
|
||||
|
||||
protected:
|
||||
void SetReserved (PVOID pReserved) {m_pReserved = pReserved;}
|
||||
PVOID GetReserved () {return m_pReserved;}
|
||||
BOOL GetRemoteHost (LPCSTR* lpszHost, USHORT* pusPort = nullptr);
|
||||
|
||||
private:
|
||||
BOOL DoSend (const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
|
||||
void SetRemoteHost (LPCTSTR lpszHost, USHORT usPort);
|
||||
void SetConnected (BOOL bConnected = TRUE) {m_bConnected = bConnected; if(bConnected) m_enState = SS_STARTED;}
|
||||
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL CreateClientSocket(LPCTSTR lpszRemoteAddress, HP_SOCKADDR& addrRemote, USHORT usPort, LPCTSTR lpszBindAddress, HP_SOCKADDR& addrBind);
|
||||
BOOL BindClientSocket(const HP_SOCKADDR& addrBind, const HP_SOCKADDR& addrRemote, USHORT usLocalPort);
|
||||
BOOL ConnectToServer(const HP_SOCKADDR& addrRemote, BOOL bAsyncConnect);
|
||||
BOOL CreateWorkerThread();
|
||||
BOOL ProcessNetworkEvent(SHORT events);
|
||||
BOOL ReadData();
|
||||
BOOL SendData();
|
||||
BOOL DoSendData(TItem* pItem, BOOL& bBlocked);
|
||||
int SendInternal(TItemPtr& itPtr);
|
||||
void WaitForWorkerThreadEnd();
|
||||
void CheckConnected();
|
||||
|
||||
BOOL HandleConnect (SHORT events);
|
||||
BOOL HandleClose (SHORT events);
|
||||
BOOL HandleRead (SHORT events);
|
||||
BOOL HandleWrite (SHORT events);
|
||||
|
||||
BOOL CheckConnection ();
|
||||
BOOL DetectConnection ();
|
||||
BOOL IsNeedDetect () {return m_dwDetectAttempts > 0 && m_dwDetectInterval > 0;}
|
||||
|
||||
UINT WINAPI WorkerThreadProc(LPVOID pv);
|
||||
|
||||
public:
|
||||
CUdpClient(IUdpClientListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_lsSend (m_itPool)
|
||||
, m_soClient (INVALID_SOCKET)
|
||||
, m_nEvents (0)
|
||||
, m_dwConnID (0)
|
||||
, m_usPort (0)
|
||||
, m_bPaused (FALSE)
|
||||
, m_bConnected (FALSE)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_dwDetectFails (0)
|
||||
, m_pExtra (nullptr)
|
||||
, m_pReserved (nullptr)
|
||||
, m_enReusePolicy (RAP_ADDR_ONLY)
|
||||
, m_dwMaxDatagramSize (DEFAULT_UDP_MAX_DATAGRAM_SIZE)
|
||||
, m_dwFreeBufferPoolSize(DEFAULT_CLIENT_FREE_BUFFER_POOL_SIZE)
|
||||
, m_dwFreeBufferPoolHold(DEFAULT_CLIENT_FREE_BUFFER_POOL_HOLD)
|
||||
, m_dwDetectAttempts (DEFAULT_UDP_DETECT_ATTEMPTS)
|
||||
, m_dwDetectInterval (DEFAULT_UDP_DETECT_INTERVAL)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CUdpClient()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
IUdpClientListener* m_pListener;
|
||||
TClientCloseContext m_ccContext;
|
||||
|
||||
SOCKET m_soClient;
|
||||
SHORT m_nEvents;
|
||||
CONNID m_dwConnID;
|
||||
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
DWORD m_dwMaxDatagramSize;
|
||||
DWORD m_dwFreeBufferPoolSize;
|
||||
DWORD m_dwFreeBufferPoolHold;
|
||||
DWORD m_dwDetectAttempts;
|
||||
DWORD m_dwDetectInterval;
|
||||
|
||||
EnSocketError m_enLastError;
|
||||
volatile BOOL m_bConnected;
|
||||
volatile EnServiceState m_enState;
|
||||
|
||||
PVOID m_pExtra;
|
||||
PVOID m_pReserved;
|
||||
|
||||
CBufferPtr m_rcBuffer;
|
||||
|
||||
protected:
|
||||
CStringA m_strHost;
|
||||
USHORT m_usPort;
|
||||
|
||||
CItemPool m_itPool;
|
||||
|
||||
private:
|
||||
CSpinGuard m_csState;
|
||||
|
||||
CCriSec m_csSend;
|
||||
TItemListExV m_lsSend;
|
||||
|
||||
CEvt m_evSend;
|
||||
CEvt m_evRecv;
|
||||
CEvt m_evStop;
|
||||
|
||||
DWORD m_dwDetectFails;
|
||||
volatile BOOL m_bPaused;
|
||||
|
||||
CThread<CUdpClient, VOID, UINT> m_thWorker;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,758 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 11
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#endif
|
||||
|
||||
#include "UdpNode.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
BOOL CUdpNode::Start(LPCTSTR lpszBindAddress, USHORT usPort, EnCastMode enCastMode, LPCTSTR lpszCastAddress)
|
||||
{
|
||||
m_enCastMode = enCastMode;
|
||||
|
||||
if(!CheckParams() || !CheckStarting())
|
||||
return FALSE;
|
||||
|
||||
PrepareStart();
|
||||
|
||||
HP_SOCKADDR bindAddr(AF_UNSPEC, TRUE);
|
||||
|
||||
if(ParseBindAddr(lpszBindAddress, usPort, lpszCastAddress, bindAddr))
|
||||
if(CreateListenSocket(bindAddr))
|
||||
if(CreateWorkerThreads())
|
||||
if(StartAccept())
|
||||
{
|
||||
m_enState = SS_STARTED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EXECUTE_RESTORE_ERROR(Stop());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::CheckParams()
|
||||
{
|
||||
if (((int)m_dwFreeBufferPoolSize >= 0) &&
|
||||
((int)m_dwFreeBufferPoolHold >= 0) &&
|
||||
((int)m_dwPostReceiveCount > 0) &&
|
||||
((int)m_dwWorkerThreadCount > 0 && m_dwWorkerThreadCount <= MAX_WORKER_THREAD_COUNT) &&
|
||||
(m_enCastMode >= CM_UNICAST && m_enCastMode <= CM_BROADCAST) &&
|
||||
(m_iMCTtl >= 0 && m_iMCTtl <= 255) &&
|
||||
(m_bMCLoop == TRUE || m_bMCLoop == FALSE) &&
|
||||
((int)m_dwMaxDatagramSize > 0 && m_dwMaxDatagramSize <= MAXIMUM_UDP_MAX_DATAGRAM_SIZE) )
|
||||
return TRUE;
|
||||
|
||||
SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::CheckStarting()
|
||||
{
|
||||
CReentrantWriteLock locallock(m_lcState);
|
||||
|
||||
if(m_enState == SS_STOPPED)
|
||||
m_enState = SS_STARTING;
|
||||
else
|
||||
{
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CUdpNode::PrepareStart()
|
||||
{
|
||||
m_bfObjPool.SetItemCapacity(m_dwMaxDatagramSize);
|
||||
m_bfObjPool.SetPoolSize(m_dwFreeBufferPoolSize);
|
||||
m_bfObjPool.SetPoolHold(m_dwFreeBufferPoolHold);
|
||||
|
||||
m_bfObjPool.Prepare();
|
||||
|
||||
TNodeBufferObjList* pBufferObjList = (TNodeBufferObjList*)malloc(m_dwWorkerThreadCount * sizeof(TNodeBufferObjList));
|
||||
|
||||
for(int i = 0; i < (int)m_dwWorkerThreadCount; i++)
|
||||
new (pBufferObjList + i) TNodeBufferObjList(m_bfObjPool);
|
||||
|
||||
m_sndBuffs.reset(pBufferObjList);
|
||||
|
||||
m_csSends = make_unique<CCriSec[]>(m_dwWorkerThreadCount);
|
||||
|
||||
m_rcBuffers = make_unique<CBufferPtr[]>(m_dwWorkerThreadCount);
|
||||
for_each(m_rcBuffers.get(), m_rcBuffers.get() + m_dwWorkerThreadCount, [this](CBufferPtr& buff) {buff.Malloc(m_dwMaxDatagramSize);});
|
||||
|
||||
m_soListens = make_unique<SOCKET[]>(m_dwWorkerThreadCount);
|
||||
for_each(m_soListens.get(), m_soListens.get() + m_dwWorkerThreadCount, [](SOCKET& sock) {sock = INVALID_FD;});
|
||||
}
|
||||
|
||||
BOOL CUdpNode::ParseBindAddr(LPCTSTR lpszBindAddress, USHORT usPort, LPCTSTR lpszCastAddress, HP_SOCKADDR& bindAddr)
|
||||
{
|
||||
if(::IsStrEmpty(lpszCastAddress))
|
||||
{
|
||||
if(m_enCastMode == CM_BROADCAST)
|
||||
lpszCastAddress = DEFAULT_IPV4_BROAD_CAST_ADDRESS;
|
||||
else if(m_enCastMode == CM_MULTICAST)
|
||||
{
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ERROR_ADDRNOTAVAIL);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_enCastMode != CM_UNICAST && !::sockaddr_A_2_IN(lpszCastAddress, usPort, m_castAddr))
|
||||
{
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(::IsStrEmpty(lpszBindAddress))
|
||||
{
|
||||
bindAddr.family = (m_enCastMode != CM_UNICAST) ? m_castAddr.family : AF_INET;
|
||||
bindAddr.SetPort(usPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!::sockaddr_A_2_IN(lpszBindAddress, usPort, bindAddr))
|
||||
{
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_enCastMode == CM_BROADCAST && bindAddr.IsIPv6())
|
||||
{
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ERROR_PFNOSUPPORT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(m_enCastMode != CM_UNICAST && m_castAddr.family != bindAddr.family)
|
||||
{
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ERROR_AFNOSUPPORT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::CreateListenSocket(const HP_SOCKADDR& bindAddr)
|
||||
{
|
||||
for(DWORD i = 0; i < m_dwWorkerThreadCount; i++)
|
||||
{
|
||||
m_soListens[i] = socket(bindAddr.family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
SOCKET soListen = m_soListens[i];
|
||||
|
||||
if(IS_INVALID_FD(soListen))
|
||||
{
|
||||
SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
::fcntl_SETFL(soListen, O_NOATIME | O_NONBLOCK | O_CLOEXEC);
|
||||
VERIFY(IS_NO_ERROR(::SSO_ReuseAddress(soListen, m_enReusePolicy)));
|
||||
VERIFY(bindAddr.IsIPv4() || IS_NO_ERROR(::SSO_DualStack(soListen, m_bDualStack)));
|
||||
|
||||
if(IS_HAS_ERROR(::bind(soListen, bindAddr.Addr(), bindAddr.AddrSize())))
|
||||
{
|
||||
SetLastError(SE_SOCKET_BIND, __FUNCTION__, ::WSAGetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
socklen_t dwAddrLen = (socklen_t)bindAddr.AddrSize();
|
||||
ENSURE(IS_NO_ERROR(::getsockname(soListen, m_localAddr.Addr(), &dwAddrLen)));
|
||||
}
|
||||
|
||||
if(m_enCastMode == CM_MULTICAST)
|
||||
{
|
||||
if(!::SetMultiCastSocketOptions(soListen, bindAddr, m_castAddr, m_iMCTtl, m_bMCLoop))
|
||||
{
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ::WSAGetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if(m_enCastMode == CM_BROADCAST)
|
||||
{
|
||||
ASSERT(m_castAddr.IsIPv4());
|
||||
|
||||
BOOL bSet = TRUE;
|
||||
if(IS_HAS_ERROR(::SSO_SetSocketOption(soListen, SOL_SOCKET, SO_BROADCAST, &bSet, sizeof(BOOL))))
|
||||
{
|
||||
SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ::WSAGetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(TRIGGER(FirePrepareListen(soListen)) == HR_ERROR)
|
||||
{
|
||||
SetLastError(SE_SOCKET_PREPARE, __FUNCTION__, ENSURE_ERROR_CANCELLED);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::CreateWorkerThreads()
|
||||
{
|
||||
return m_ioDispatcher.Start(this, m_dwPostReceiveCount, m_dwWorkerThreadCount);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::StartAccept()
|
||||
{
|
||||
for(int i = 0; i < (int)m_dwWorkerThreadCount; i++)
|
||||
{
|
||||
SOCKET& soListen = m_soListens[i];
|
||||
|
||||
if(!m_ioDispatcher.AddFD(i, soListen, EPOLLIN | EPOLLOUT | EPOLLET, TO_PVOID(&soListen)))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::Stop()
|
||||
{
|
||||
if(!CheckStoping())
|
||||
return FALSE;
|
||||
|
||||
CloseListenSocket();
|
||||
|
||||
WaitForWorkerThreadEnd();
|
||||
|
||||
FireShutdown();
|
||||
|
||||
ReleaseFreeBuffer();
|
||||
|
||||
Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::CheckStoping()
|
||||
{
|
||||
if(m_enState != SS_STOPPED)
|
||||
{
|
||||
CReentrantWriteLock locallock(m_lcState);
|
||||
|
||||
if(HasStarted())
|
||||
{
|
||||
m_enState = SS_STOPPING;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_STATE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CUdpNode::CloseListenSocket()
|
||||
{
|
||||
if(m_soListens)
|
||||
{
|
||||
for_each(m_soListens.get(), m_soListens.get() + m_dwWorkerThreadCount, [](SOCKET& sock)
|
||||
{
|
||||
if(sock != INVALID_FD)
|
||||
{
|
||||
::ManualCloseSocket(sock);
|
||||
sock = INVALID_FD;
|
||||
}
|
||||
});
|
||||
|
||||
::WaitFor(100);
|
||||
}
|
||||
}
|
||||
|
||||
void CUdpNode::WaitForWorkerThreadEnd()
|
||||
{
|
||||
m_ioDispatcher.Stop();
|
||||
}
|
||||
|
||||
void CUdpNode::ReleaseFreeBuffer()
|
||||
{
|
||||
for_each(m_sndBuffs.get(), m_sndBuffs.get() + m_dwWorkerThreadCount, [](TNodeBufferObjList& sndBuff)
|
||||
{
|
||||
sndBuff.Clear();
|
||||
sndBuff.~TNodeBufferObjList();
|
||||
});
|
||||
|
||||
free(m_sndBuffs.release());
|
||||
|
||||
m_csSends = nullptr;
|
||||
|
||||
m_bfObjPool.Clear();
|
||||
}
|
||||
|
||||
void CUdpNode::Reset()
|
||||
{
|
||||
m_castAddr.Reset();
|
||||
m_localAddr.Reset();
|
||||
|
||||
m_soListens = nullptr;
|
||||
m_rcBuffers = nullptr;
|
||||
|
||||
m_iSending = 0;
|
||||
m_enState = SS_STOPPED;
|
||||
|
||||
m_evWait.SyncNotifyAll();
|
||||
}
|
||||
|
||||
int CUdpNode::GenerateBufferIndex(const HP_SOCKADDR& addrRemote)
|
||||
{
|
||||
return (int)(addrRemote.Hash() % m_dwWorkerThreadCount);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::Send(LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
HP_SOCKADDR addrRemote;
|
||||
|
||||
if(!::GetSockAddrByHostName(lpszRemoteAddress, usRemotePort, addrRemote))
|
||||
return FALSE;
|
||||
|
||||
return DoSend(addrRemote, pBuffer, iLength, iOffset);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::SendPackets(LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
HP_SOCKADDR addrRemote;
|
||||
|
||||
if(!::GetSockAddrByHostName(lpszRemoteAddress, usRemotePort, addrRemote))
|
||||
return FALSE;
|
||||
|
||||
return DoSendPackets(addrRemote, pBuffers, iCount);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::SendCast(const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
if(m_enCastMode == CM_UNICAST)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return DoSend(m_castAddr, pBuffer, iLength, iOffset);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::SendCastPackets(const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
if(m_enCastMode == CM_UNICAST)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_OPERATION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return DoSendPackets(m_castAddr, pBuffers, iCount);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::DoSend(const HP_SOCKADDR& addrRemote, const BYTE* pBuffer, int iLength, int iOffset)
|
||||
{
|
||||
ASSERT(pBuffer && iLength >= 0 && iLength <= (int)m_dwMaxDatagramSize);
|
||||
|
||||
int result = NO_ERROR;
|
||||
|
||||
if(IsValid())
|
||||
{
|
||||
if(addrRemote.family == m_localAddr.family)
|
||||
{
|
||||
if(pBuffer && iLength >= 0 && iLength <= (int)m_dwMaxDatagramSize)
|
||||
{
|
||||
if(iOffset != 0) pBuffer += iOffset;
|
||||
|
||||
TNodeBufferObjPtr bufPtr(m_bfObjPool, m_bfObjPool.PickFreeItem());
|
||||
bufPtr->Cat(pBuffer, iLength);
|
||||
|
||||
result = SendInternal(addrRemote, bufPtr);
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
result = ERROR_AFNOSUPPORT;
|
||||
}
|
||||
else
|
||||
result = ERROR_INVALID_STATE;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::DoSendPackets(const HP_SOCKADDR& addrRemote, const WSABUF pBuffers[], int iCount)
|
||||
{
|
||||
ASSERT(pBuffers && iCount > 0);
|
||||
|
||||
if(!pBuffers || iCount <= 0)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(!IsValid())
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(addrRemote.family != m_localAddr.family)
|
||||
{
|
||||
::SetLastError(ERROR_AFNOSUPPORT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int result = NO_ERROR;
|
||||
int iLength = 0;
|
||||
int iMaxLen = (int)m_dwMaxDatagramSize;
|
||||
|
||||
TNodeBufferObjPtr bufPtr(m_bfObjPool, m_bfObjPool.PickFreeItem());
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
int iBufLen = pBuffers[i].len;
|
||||
|
||||
if(iBufLen > 0)
|
||||
{
|
||||
BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
|
||||
ASSERT(pBuffer);
|
||||
|
||||
iLength += iBufLen;
|
||||
|
||||
if(iLength <= iMaxLen)
|
||||
bufPtr->Cat(pBuffer, iBufLen);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(iLength > 0 && iLength <= iMaxLen)
|
||||
result = SendInternal(addrRemote, bufPtr);
|
||||
else
|
||||
result = ERROR_INCORRECT_SIZE;
|
||||
|
||||
if(result != NO_ERROR)
|
||||
::SetLastError(result);
|
||||
|
||||
return (result == NO_ERROR);
|
||||
}
|
||||
|
||||
int CUdpNode::SendInternal(const HP_SOCKADDR& addrRemote, TNodeBufferObjPtr& bufPtr)
|
||||
{
|
||||
BOOL bPending;
|
||||
int iBufferSize = bufPtr->Size();
|
||||
int idx = GenerateBufferIndex(addrRemote);
|
||||
|
||||
addrRemote.Copy(bufPtr->remoteAddr);
|
||||
|
||||
{
|
||||
CReentrantReadLock locallock(m_lcState);
|
||||
|
||||
if(!IsValid())
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
TNodeBufferObjList& sndBuff = m_sndBuffs[idx];
|
||||
|
||||
CCriSecLock locallock2(m_csSends[idx]);
|
||||
|
||||
bPending = IsPending(idx);
|
||||
sndBuff.PushBack(bufPtr.Detach());
|
||||
|
||||
if(iBufferSize == 0) sndBuff.IncreaseLength(1);
|
||||
|
||||
ASSERT(sndBuff.Length() > 0);
|
||||
}
|
||||
|
||||
if(!bPending && IsPending(idx))
|
||||
VERIFY(m_ioDispatcher.SendCommandByIndex(idx, DISP_CMD_SEND));
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
ASSERT(pv == &m_soListens[pContext->GetIndex()]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID CUdpNode::OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VOID CUdpNode::OnCommand(const TDispContext* pContext, TDispCommand* pCmd)
|
||||
{
|
||||
int idx = pContext->GetIndex();
|
||||
int flag = (int)(pCmd->wParam);
|
||||
|
||||
switch(pCmd->type)
|
||||
{
|
||||
case DISP_CMD_SEND:
|
||||
HandleCmdSend(idx, flag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CUdpNode::OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
return HandleReceive(pContext, RETRIVE_EVENT_FLAG_H(events));
|
||||
}
|
||||
|
||||
BOOL CUdpNode::OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
return HandleSend(pContext, RETRIVE_EVENT_FLAG_H(events), RETRIVE_EVENT_FLAG_R(events));
|
||||
}
|
||||
|
||||
BOOL CUdpNode::OnHungUp(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
return HandleClose(pContext->GetIndex(), nullptr, SO_CLOSE, 0);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::OnError(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
return HandleClose(pContext->GetIndex(), nullptr, SO_CLOSE, -1);
|
||||
}
|
||||
|
||||
VOID CUdpNode::OnDispatchThreadStart(THR_ID tid)
|
||||
{
|
||||
OnWorkerThreadStart(tid);
|
||||
}
|
||||
|
||||
VOID CUdpNode::OnDispatchThreadEnd(THR_ID tid)
|
||||
{
|
||||
OnWorkerThreadEnd(tid);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::HandleClose(int idx, TNodeBufferObj* pBufferObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
if(!HasStarted())
|
||||
return FALSE;
|
||||
|
||||
if(iErrorCode == -1)
|
||||
iErrorCode = ::SSO_GetError(m_soListens[idx]);
|
||||
|
||||
if(pBufferObj != nullptr)
|
||||
TRIGGER(FireError(&pBufferObj->remoteAddr, pBufferObj->Ptr(), pBufferObj->Size(), enOperation, iErrorCode));
|
||||
else
|
||||
TRIGGER(FireError(nullptr, nullptr, 0, enOperation, iErrorCode));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::HandleReceive(const TDispContext* pContext, int flag)
|
||||
{
|
||||
int idx = pContext->GetIndex();
|
||||
CBufferPtr& buffer = m_rcBuffers[idx];
|
||||
int iBufferLen = (int)buffer.Size();
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
HP_SOCKADDR addr;
|
||||
socklen_t dwAddrLen = (socklen_t)addr.AddrSize();
|
||||
|
||||
int rc = (int)recvfrom(m_soListens[idx], buffer.Ptr(), iBufferLen, MSG_TRUNC, addr.Addr(), &dwAddrLen);
|
||||
|
||||
if(rc >= 0)
|
||||
{
|
||||
if(rc > iBufferLen)
|
||||
{
|
||||
TRIGGER(FireError(&addr, buffer.Ptr(), iBufferLen, SO_RECEIVE, ERROR_BAD_LENGTH));
|
||||
continue;
|
||||
}
|
||||
|
||||
TRIGGER(FireReceive(&addr, buffer.Ptr(), rc));
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
break;
|
||||
else if(!HandleClose(idx, nullptr, SO_RECEIVE, code))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::HandleSend(const TDispContext* pContext, int flag, int rd)
|
||||
{
|
||||
HandleCmdSend(pContext->GetIndex(), flag);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID CUdpNode::HandleCmdSend(int idx, int flag)
|
||||
{
|
||||
BOOL bBlocked = FALSE;
|
||||
TNodeBufferObjList& sndBuff = m_sndBuffs[idx];
|
||||
|
||||
TNodeBufferObjPtr bufPtr(m_bfObjPool);
|
||||
|
||||
while(IsPending(idx))
|
||||
{
|
||||
{
|
||||
CCriSecLock locallock(m_csSends[idx]);
|
||||
bufPtr = sndBuff.PopFront();
|
||||
}
|
||||
|
||||
if(!bufPtr.IsValid())
|
||||
break;
|
||||
|
||||
if(!SendItem(idx, sndBuff, bufPtr, bBlocked))
|
||||
return;
|
||||
|
||||
if(bBlocked)
|
||||
{
|
||||
{
|
||||
CCriSecLock locallock(m_csSends[idx]);
|
||||
sndBuff.PushFront(bufPtr.Detach());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!bBlocked && IsPending(idx))
|
||||
VERIFY(m_ioDispatcher.SendCommandByIndex(idx, DISP_CMD_SEND));
|
||||
}
|
||||
|
||||
BOOL CUdpNode::SendItem(int idx, TNodeBufferObjList& sndBuff, TNodeBufferObj* pBufferObj, BOOL& bBlocked)
|
||||
{
|
||||
int rc = (int)sendto(m_soListens[idx], pBufferObj->Ptr(), pBufferObj->Size(), 0, pBufferObj->remoteAddr.Addr(), pBufferObj->remoteAddr.AddrSize());
|
||||
|
||||
if(rc >= 0)
|
||||
{
|
||||
ASSERT(rc == pBufferObj->Size());
|
||||
|
||||
if(rc == 0)
|
||||
{
|
||||
CCriSecLock locallock(m_csSends[idx]);
|
||||
sndBuff.ReduceLength(1);
|
||||
}
|
||||
|
||||
TRIGGER(FireSend(pBufferObj));
|
||||
}
|
||||
else if(rc == SOCKET_ERROR)
|
||||
{
|
||||
int code = ::WSAGetLastError();
|
||||
|
||||
if(code == ERROR_WOULDBLOCK)
|
||||
bBlocked = TRUE;
|
||||
else if(!HandleClose(idx, pBufferObj, SO_SEND, code))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CUdpNode::GetLocalAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
ADDRESS_FAMILY usFamily;
|
||||
return ::sockaddr_IN_2_A(m_localAddr, usFamily, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::GetCastAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
|
||||
{
|
||||
ADDRESS_FAMILY usFamily;
|
||||
return ::sockaddr_IN_2_A(m_castAddr, usFamily, lpszAddress, iAddressLen, usPort);
|
||||
}
|
||||
|
||||
void CUdpNode::SetLastError(EnSocketError code, LPCSTR func, int ec)
|
||||
{
|
||||
m_enLastError = code;
|
||||
::SetLastError(ec);
|
||||
}
|
||||
|
||||
BOOL CUdpNode::GetPendingDataLength(int& iPending)
|
||||
{
|
||||
iPending = 0;
|
||||
|
||||
{
|
||||
CReentrantReadLock locallock(m_lcState);
|
||||
|
||||
if(!IsValid())
|
||||
return FALSE;
|
||||
|
||||
for_each(m_sndBuffs.get(), m_sndBuffs.get() + m_dwWorkerThreadCount, [&iPending](TNodeBufferObjList& sndBuff) { iPending += sndBuff.Length(); });
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EnHandleResult CUdpNode::FireSend(TNodeBufferObj* pBufferObj)
|
||||
{
|
||||
TCHAR szAddress[60];
|
||||
int iAddressLen = ARRAY_SIZE(szAddress);
|
||||
ADDRESS_FAMILY usFamily;
|
||||
USHORT usPort;
|
||||
|
||||
::sockaddr_IN_2_A(pBufferObj->remoteAddr, usFamily, szAddress, iAddressLen, usPort);
|
||||
|
||||
return m_pListener->OnSend(this, szAddress, usPort, pBufferObj->Ptr(), pBufferObj->Size());
|
||||
}
|
||||
|
||||
EnHandleResult CUdpNode::FireReceive(const HP_SOCKADDR* pRemoteAddr, const BYTE* pData, int iLength)
|
||||
{
|
||||
TCHAR szAddress[60];
|
||||
int iAddressLen = ARRAY_SIZE(szAddress);
|
||||
ADDRESS_FAMILY usFamily;
|
||||
USHORT usPort;
|
||||
|
||||
::sockaddr_IN_2_A(*pRemoteAddr, usFamily, szAddress, iAddressLen, usPort);
|
||||
return m_pListener->OnReceive(this, szAddress, usPort, pData, iLength);
|
||||
}
|
||||
|
||||
EnHandleResult CUdpNode::FireError(const HP_SOCKADDR* pRemoteAddr, const BYTE* pData, int iLength, EnSocketOperation enOperation, int iErrorCode)
|
||||
{
|
||||
TCHAR szAddress[60];
|
||||
int iAddressLen = ARRAY_SIZE(szAddress);
|
||||
ADDRESS_FAMILY usFamily;
|
||||
USHORT usPort;
|
||||
|
||||
if(pRemoteAddr == nullptr)
|
||||
{
|
||||
::sockaddr_IN_2_A(m_localAddr, usFamily, szAddress, iAddressLen, usPort);
|
||||
return m_pListener->OnError(this, enOperation, iErrorCode, szAddress, usPort, nullptr, 0);
|
||||
}
|
||||
|
||||
::sockaddr_IN_2_A(*pRemoteAddr, usFamily, szAddress, iAddressLen, usPort);
|
||||
return m_pListener->OnError(this, enOperation, iErrorCode, szAddress, usPort, pData, iLength);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 11
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
#include "./common/IODispatcher.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
class CUdpNode : public IUdpNode, private CIOHandler
|
||||
{
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszBindAddress = nullptr, USHORT usPort = 0, EnCastMode enCastMode = CM_UNICAST, LPCTSTR lpszCastAddress = nullptr);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Send (LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendPackets (LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const WSABUF pBuffers[], int iCount);
|
||||
virtual BOOL SendCast (const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendCastPackets(const WSABUF pBuffers[], int iCount);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual BOOL GetLocalAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetCastAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
virtual BOOL GetPendingDataLength (int& iPending);
|
||||
|
||||
private:
|
||||
virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) override;
|
||||
virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) override;
|
||||
virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnDispatchThreadStart(THR_ID tid) override;
|
||||
virtual VOID OnDispatchThreadEnd(THR_ID tid) override;
|
||||
|
||||
public:
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy){ENSURE_HAS_STOPPED(); ASSERT(m_enReusePolicy == enReusePolicy);}
|
||||
virtual void SetWorkerThreadCount (DWORD dwWorkerThreadCount) {ENSURE_HAS_STOPPED(); m_dwWorkerThreadCount = dwWorkerThreadCount;}
|
||||
virtual void SetFreeBufferPoolSize (DWORD dwFreeBufferPoolSize) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolSize = dwFreeBufferPoolSize;}
|
||||
virtual void SetFreeBufferPoolHold (DWORD dwFreeBufferPoolHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferPoolHold = dwFreeBufferPoolHold;}
|
||||
virtual void SetPostReceiveCount (DWORD dwPostReceiveCount) {ENSURE_HAS_STOPPED(); m_dwPostReceiveCount = dwPostReceiveCount;}
|
||||
virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) {ENSURE_HAS_STOPPED(); m_dwMaxDatagramSize = dwMaxDatagramSize;}
|
||||
virtual void SetMultiCastTtl (int iMCTtl) {ENSURE_HAS_STOPPED(); m_iMCTtl = iMCTtl;}
|
||||
virtual void SetMultiCastLoop (BOOL bMCLoop) {ENSURE_HAS_STOPPED(); m_bMCLoop = bMCLoop;}
|
||||
virtual void SetDualStack (BOOL bDualStack) {ENSURE_HAS_STOPPED(); m_bDualStack = bDualStack;}
|
||||
virtual void SetExtra (PVOID pExtra) {m_pExtra = pExtra;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual DWORD GetWorkerThreadCount () {return m_dwWorkerThreadCount;}
|
||||
virtual DWORD GetFreeBufferPoolSize () {return m_dwFreeBufferPoolSize;}
|
||||
virtual DWORD GetFreeBufferPoolHold () {return m_dwFreeBufferPoolHold;}
|
||||
virtual DWORD GetPostReceiveCount () {return m_dwPostReceiveCount;}
|
||||
virtual DWORD GetMaxDatagramSize () {return m_dwMaxDatagramSize;}
|
||||
virtual EnCastMode GetCastMode () {return m_enCastMode;}
|
||||
virtual int GetMultiCastTtl () {return m_iMCTtl;}
|
||||
virtual BOOL IsMultiCastLoop () {return m_bMCLoop;}
|
||||
virtual BOOL IsDualStack () {return m_bDualStack;}
|
||||
virtual PVOID GetExtra () {return m_pExtra;}
|
||||
|
||||
protected:
|
||||
EnHandleResult FirePrepareListen(SOCKET soListen)
|
||||
{return m_pListener->OnPrepareListen(this, soListen);}
|
||||
EnHandleResult FireShutdown()
|
||||
{return m_pListener->OnShutdown(this);}
|
||||
|
||||
EnHandleResult FireSend(TNodeBufferObj* pBufferObj);
|
||||
EnHandleResult FireReceive(const HP_SOCKADDR* pRemoteAddr, const BYTE* pData, int iLength);
|
||||
EnHandleResult FireError(const HP_SOCKADDR* pRemoteAddr, const BYTE* pData, int iLength, EnSocketOperation enOperation, int iErrorCode);
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID dwThreadID) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID dwThreadID) {}
|
||||
|
||||
BOOL DoSend(const HP_SOCKADDR& addrRemote, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
BOOL DoSendPackets(const HP_SOCKADDR& addrRemote, const WSABUF pBuffers[], int iCount);
|
||||
int SendInternal(const HP_SOCKADDR& addrRemote, TNodeBufferObjPtr& bufPtr);
|
||||
|
||||
private:
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL ParseBindAddr(LPCTSTR lpszBindAddress, USHORT usPort, LPCTSTR lpszCastAddress, HP_SOCKADDR& bindAddr);
|
||||
BOOL CreateListenSocket(const HP_SOCKADDR& bindAddr);
|
||||
BOOL CreateWorkerThreads();
|
||||
BOOL StartAccept();
|
||||
|
||||
void CloseListenSocket();
|
||||
void WaitForWorkerThreadEnd();
|
||||
void ReleaseFreeBuffer();
|
||||
|
||||
int GenerateBufferIndex(const HP_SOCKADDR& addrRemote);
|
||||
|
||||
private:
|
||||
BOOL HandleReceive(const TDispContext* pContext, int flag = 0);
|
||||
BOOL HandleSend(const TDispContext* pContext, int flag = 0, int rd = 0);
|
||||
BOOL HandleClose(int idx, TNodeBufferObj* pBufferObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
|
||||
VOID HandleCmdSend(int idx, int flag);
|
||||
|
||||
BOOL SendItem(int idx, TNodeBufferObjList& sndBuff, TNodeBufferObj* pBufferObj, BOOL& bBlocked);
|
||||
|
||||
private:
|
||||
BOOL IsValid () {return m_enState == SS_STARTED;}
|
||||
BOOL IsPending (int idx) {return m_sndBuffs[idx].Length() > 0;}
|
||||
|
||||
public:
|
||||
CUdpNode(IUdpNodeListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_iSending (0)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_enReusePolicy (RAP_ADDR_AND_PORT)
|
||||
, m_dwWorkerThreadCount (DEFAULT_WORKER_THREAD_COUNT)
|
||||
, m_dwFreeBufferPoolSize (DEFAULT_FREE_BUFFEROBJ_POOL)
|
||||
, m_dwFreeBufferPoolHold (DEFAULT_FREE_BUFFEROBJ_HOLD)
|
||||
, m_dwPostReceiveCount (DEFAULT_UDP_POST_RECEIVE_COUNT)
|
||||
, m_dwMaxDatagramSize (DEFAULT_UDP_MAX_DATAGRAM_SIZE)
|
||||
, m_pExtra (nullptr)
|
||||
, m_iMCTtl (1)
|
||||
, m_bMCLoop (FALSE)
|
||||
, m_enCastMode (CM_UNICAST)
|
||||
, m_bDualStack (TRUE)
|
||||
, m_castAddr (AF_UNSPEC, TRUE)
|
||||
, m_localAddr (AF_UNSPEC, TRUE)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CUdpNode()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
DWORD m_dwWorkerThreadCount;
|
||||
DWORD m_dwFreeBufferPoolSize;
|
||||
DWORD m_dwFreeBufferPoolHold;
|
||||
DWORD m_dwPostReceiveCount;
|
||||
DWORD m_dwMaxDatagramSize;
|
||||
PVOID m_pExtra;
|
||||
|
||||
int m_iMCTtl;
|
||||
BOOL m_bMCLoop;
|
||||
EnCastMode m_enCastMode;
|
||||
BOOL m_bDualStack;
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
HP_SOCKADDR m_castAddr;
|
||||
HP_SOCKADDR m_localAddr;
|
||||
|
||||
CNodeBufferObjPool m_bfObjPool;
|
||||
CNodeCriSecs m_csSends;
|
||||
TNodeBufferObjLists m_sndBuffs;
|
||||
|
||||
IUdpNodeListener* m_pListener;
|
||||
ListenSocketsPtr m_soListens;
|
||||
EnServiceState m_enState;
|
||||
EnSocketError m_enLastError;
|
||||
|
||||
CReceiveBuffersPtr m_rcBuffers;
|
||||
|
||||
CRWLock m_lcState;
|
||||
|
||||
volatile long m_iSending;
|
||||
|
||||
CIODispatcher m_ioDispatcher;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketHelper.h"
|
||||
#include "./common/GeneralHelper.h"
|
||||
#include "./common/IODispatcher.h"
|
||||
|
||||
#ifdef _UDP_SUPPORT
|
||||
|
||||
class CUdpServer : public IUdpServer, private CIOHandler
|
||||
{
|
||||
using CWorkerThread = CThread<CUdpServer, VOID, UINT>;
|
||||
using CSendQueue = CCASSimpleQueue<CONNID>;
|
||||
using CSendQueuesPtr = unique_ptr<CSendQueue[]>;
|
||||
using CGCThread = CGCThreadT<CUdpServer>;
|
||||
|
||||
friend class CGCThreadT<CUdpServer>;
|
||||
|
||||
public:
|
||||
virtual BOOL Start (LPCTSTR lpszBindAddress, USHORT usPort);
|
||||
virtual BOOL Stop ();
|
||||
virtual BOOL Send (CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
virtual BOOL SendPackets (CONNID dwConnID, const WSABUF pBuffers[], int iCount);
|
||||
virtual BOOL PauseReceive (CONNID dwConnID, BOOL bPause = TRUE);
|
||||
virtual BOOL Wait (DWORD dwMilliseconds = INFINITE) {return m_evWait.WaitFor(dwMilliseconds, WAIT_FOR_STOP_PREDICATE);}
|
||||
virtual BOOL HasStarted () {return m_enState == SS_STARTED || m_enState == SS_STARTING;}
|
||||
virtual EnServiceState GetState () {return m_enState;}
|
||||
virtual BOOL Disconnect (CONNID dwConnID, BOOL bForce = TRUE);
|
||||
virtual BOOL DisconnectLongConnections (DWORD dwPeriod, BOOL bForce = TRUE);
|
||||
virtual BOOL DisconnectSilenceConnections(DWORD dwPeriod, BOOL bForce = TRUE);
|
||||
virtual BOOL GetListenAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetLocalAddress (CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
virtual BOOL GetRemoteAddress (CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort);
|
||||
|
||||
virtual BOOL IsConnected (CONNID dwConnID);
|
||||
virtual BOOL IsPauseReceive (CONNID dwConnID, BOOL& bPaused);
|
||||
virtual BOOL GetPendingDataLength (CONNID dwConnID, int& iPending);
|
||||
virtual DWORD GetConnectionCount ();
|
||||
virtual BOOL GetAllConnectionIDs (CONNID pIDs[], DWORD& dwCount);
|
||||
virtual BOOL GetConnectPeriod (CONNID dwConnID, DWORD& dwPeriod);
|
||||
virtual BOOL GetSilencePeriod (CONNID dwConnID, DWORD& dwPeriod);
|
||||
virtual EnSocketError GetLastError () {return m_enLastError;}
|
||||
virtual LPCTSTR GetLastErrorDesc () {return ::GetSocketErrorDesc(m_enLastError);}
|
||||
|
||||
private:
|
||||
virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) override;
|
||||
virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) override;
|
||||
virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) override;
|
||||
virtual VOID OnDispatchThreadStart(THR_ID tid) override;
|
||||
virtual VOID OnDispatchThreadEnd(THR_ID tid) override;
|
||||
|
||||
public:
|
||||
virtual BOOL IsSecure () {return FALSE;}
|
||||
|
||||
virtual BOOL SetConnectionExtra(CONNID dwConnID, PVOID pExtra);
|
||||
virtual BOOL GetConnectionExtra(CONNID dwConnID, PVOID* ppExtra);
|
||||
|
||||
virtual void SetReuseAddressPolicy (EnReuseAddressPolicy enReusePolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enReusePolicy == enReusePolicy);}
|
||||
virtual void SetSendPolicy (EnSendPolicy enSendPolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enSendPolicy == enSendPolicy);}
|
||||
virtual void SetOnSendSyncPolicy (EnOnSendSyncPolicy enOnSendSyncPolicy) {ENSURE_HAS_STOPPED(); ASSERT(m_enOnSendSyncPolicy == enOnSendSyncPolicy);}
|
||||
virtual void SetMaxConnectionCount (DWORD dwMaxConnectionCount) {ENSURE_HAS_STOPPED(); m_dwMaxConnectionCount = dwMaxConnectionCount;}
|
||||
virtual void SetWorkerThreadCount (DWORD dwWorkerThreadCount) {ENSURE_HAS_STOPPED(); m_dwWorkerThreadCount = dwWorkerThreadCount;}
|
||||
virtual void SetFreeSocketObjLockTime (DWORD dwFreeSocketObjLockTime) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjLockTime = dwFreeSocketObjLockTime;}
|
||||
virtual void SetFreeSocketObjPool (DWORD dwFreeSocketObjPool) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjPool = dwFreeSocketObjPool;}
|
||||
virtual void SetFreeBufferObjPool (DWORD dwFreeBufferObjPool) {ENSURE_HAS_STOPPED(); m_dwFreeBufferObjPool = dwFreeBufferObjPool;}
|
||||
virtual void SetFreeSocketObjHold (DWORD dwFreeSocketObjHold) {ENSURE_HAS_STOPPED(); m_dwFreeSocketObjHold = dwFreeSocketObjHold;}
|
||||
virtual void SetFreeBufferObjHold (DWORD dwFreeBufferObjHold) {ENSURE_HAS_STOPPED(); m_dwFreeBufferObjHold = dwFreeBufferObjHold;}
|
||||
virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) {ENSURE_HAS_STOPPED(); m_dwMaxDatagramSize = dwMaxDatagramSize;}
|
||||
virtual void SetPostReceiveCount (DWORD dwPostReceiveCount) {ENSURE_HAS_STOPPED(); m_dwPostReceiveCount = dwPostReceiveCount;}
|
||||
virtual void SetDetectAttempts (DWORD dwDetectAttempts) {ENSURE_HAS_STOPPED(); m_dwDetectAttempts = dwDetectAttempts;}
|
||||
virtual void SetDetectInterval (DWORD dwDetectInterval) {ENSURE_HAS_STOPPED(); m_dwDetectInterval = dwDetectInterval;}
|
||||
virtual void SetMarkSilence (BOOL bMarkSilence) {ENSURE_HAS_STOPPED(); m_bMarkSilence = bMarkSilence;}
|
||||
virtual void SetDualStack (BOOL bDualStack) {ENSURE_HAS_STOPPED(); m_bDualStack = bDualStack;}
|
||||
|
||||
virtual EnReuseAddressPolicy GetReuseAddressPolicy () {return m_enReusePolicy;}
|
||||
virtual EnSendPolicy GetSendPolicy () {return m_enSendPolicy;}
|
||||
virtual EnOnSendSyncPolicy GetOnSendSyncPolicy () {return m_enOnSendSyncPolicy;}
|
||||
virtual DWORD GetMaxConnectionCount () {return m_dwMaxConnectionCount;}
|
||||
virtual DWORD GetWorkerThreadCount () {return m_dwWorkerThreadCount;}
|
||||
virtual DWORD GetFreeSocketObjLockTime () {return m_dwFreeSocketObjLockTime;}
|
||||
virtual DWORD GetFreeSocketObjPool () {return m_dwFreeSocketObjPool;}
|
||||
virtual DWORD GetFreeBufferObjPool () {return m_dwFreeBufferObjPool;}
|
||||
virtual DWORD GetFreeSocketObjHold () {return m_dwFreeSocketObjHold;}
|
||||
virtual DWORD GetFreeBufferObjHold () {return m_dwFreeBufferObjHold;}
|
||||
virtual DWORD GetMaxDatagramSize () {return m_dwMaxDatagramSize;}
|
||||
virtual DWORD GetPostReceiveCount () {return m_dwPostReceiveCount;}
|
||||
virtual DWORD GetDetectAttempts () {return m_dwDetectAttempts;}
|
||||
virtual DWORD GetDetectInterval () {return m_dwDetectInterval;}
|
||||
virtual BOOL IsMarkSilence () {return m_bMarkSilence;}
|
||||
virtual BOOL IsDualStack () {return m_bDualStack;}
|
||||
|
||||
protected:
|
||||
virtual EnHandleResult FirePrepareListen(SOCKET soListen)
|
||||
{return DoFirePrepareListen(soListen);}
|
||||
virtual EnHandleResult FireAccept(TUdpSocketObj* pSocketObj)
|
||||
{
|
||||
EnHandleResult rs = DoFireAccept(pSocketObj);
|
||||
if(rs != HR_ERROR) rs = FireHandShake(pSocketObj);
|
||||
return rs;
|
||||
}
|
||||
virtual EnHandleResult FireHandShake(TUdpSocketObj* pSocketObj)
|
||||
{return DoFireHandShake(pSocketObj);}
|
||||
virtual EnHandleResult FireReceive(TUdpSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return DoFireReceive(pSocketObj, pData, iLength);}
|
||||
virtual EnHandleResult FireReceive(TUdpSocketObj* pSocketObj, int iLength)
|
||||
{return DoFireReceive(pSocketObj, iLength);}
|
||||
virtual EnHandleResult FireSend(TUdpSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return DoFireSend(pSocketObj, pData, iLength);}
|
||||
virtual EnHandleResult FireClose(TUdpSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return DoFireClose(pSocketObj, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult FireShutdown()
|
||||
{return DoFireShutdown();}
|
||||
|
||||
virtual EnHandleResult DoFirePrepareListen(SOCKET soListen)
|
||||
{return m_pListener->OnPrepareListen(this, soListen);}
|
||||
virtual EnHandleResult DoFireAccept(TUdpSocketObj* pSocketObj)
|
||||
{return m_pListener->OnAccept(this, pSocketObj->connID, (UINT_PTR)(&pSocketObj->remoteAddr));}
|
||||
virtual EnHandleResult DoFireHandShake(TUdpSocketObj* pSocketObj)
|
||||
{return m_pListener->OnHandShake(this, pSocketObj->connID);}
|
||||
virtual EnHandleResult DoFireReceive(TUdpSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnReceive(this, pSocketObj->connID, pData, iLength);}
|
||||
virtual EnHandleResult DoFireReceive(TUdpSocketObj* pSocketObj, int iLength)
|
||||
{return m_pListener->OnReceive(this, pSocketObj->connID, iLength);}
|
||||
virtual EnHandleResult DoFireSend(TUdpSocketObj* pSocketObj, const BYTE* pData, int iLength)
|
||||
{return m_pListener->OnSend(this, pSocketObj->connID, pData, iLength);}
|
||||
virtual EnHandleResult DoFireClose(TUdpSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
|
||||
{return m_pListener->OnClose(this, pSocketObj->connID, enOperation, iErrorCode);}
|
||||
virtual EnHandleResult DoFireShutdown()
|
||||
{return m_pListener->OnShutdown(this);}
|
||||
|
||||
void SetLastError(EnSocketError code, LPCSTR func, int ec);
|
||||
virtual BOOL CheckParams();
|
||||
virtual void PrepareStart();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void OnWorkerThreadStart(THR_ID tid) {}
|
||||
virtual void OnWorkerThreadEnd(THR_ID tid) {}
|
||||
|
||||
virtual void ReleaseGCSocketObj(BOOL bForce = FALSE);
|
||||
|
||||
TUdpSocketObj* FindSocketObj(CONNID dwConnID);
|
||||
int SendInternal(TUdpSocketObj* pSocketObj, TItemPtr& itPtr);
|
||||
|
||||
BOOL DoSend(TUdpSocketObj* pSocketObj, const BYTE* pBuffer, int iLength, int iOffset = 0);
|
||||
|
||||
protected:
|
||||
BOOL SetConnectionExtra(TUdpSocketObj* pSocketObj, PVOID pExtra);
|
||||
BOOL GetConnectionExtra(TUdpSocketObj* pSocketObj, PVOID* ppExtra);
|
||||
BOOL SetConnectionReserved(CONNID dwConnID, PVOID pReserved);
|
||||
BOOL GetConnectionReserved(CONNID dwConnID, PVOID* ppReserved);
|
||||
BOOL SetConnectionReserved(TUdpSocketObj* pSocketObj, PVOID pReserved);
|
||||
BOOL GetConnectionReserved(TUdpSocketObj* pSocketObj, PVOID* ppReserved);
|
||||
BOOL SetConnectionReserved2(CONNID dwConnID, PVOID pReserved2);
|
||||
BOOL GetConnectionReserved2(CONNID dwConnID, PVOID* ppReserved2);
|
||||
BOOL SetConnectionReserved2(TUdpSocketObj* pSocketObj, PVOID pReserved2);
|
||||
BOOL GetConnectionReserved2(TUdpSocketObj* pSocketObj, PVOID* ppReserved2);
|
||||
|
||||
private:
|
||||
BOOL CheckStarting();
|
||||
BOOL CheckStoping();
|
||||
BOOL CreateListenSocket(LPCTSTR lpszBindAddress, USHORT usPort);
|
||||
BOOL CreateWorkerThreads();
|
||||
BOOL StartAccept();
|
||||
|
||||
void SendCloseNotify();
|
||||
void CloseListenSocket();
|
||||
void DisconnectClientSocket();
|
||||
void WaitForClientSocketClose();
|
||||
void ReleaseClientSocket();
|
||||
void ReleaseFreeSocket();
|
||||
void ClearSendQueues();
|
||||
void WaitForWorkerThreadEnd();
|
||||
|
||||
TUdpSocketObj* GetFreeSocketObj(CONNID dwConnID);
|
||||
TUdpSocketObj* CreateSocketObj();
|
||||
CONNID FindConnectionID(const HP_SOCKADDR* pAddr);
|
||||
void AddFreeSocketObj(TUdpSocketObj* pSocketObj, EnSocketCloseFlag enFlag = SCF_NONE, EnSocketOperation enOperation = SO_UNKNOWN, int iErrorCode = 0, BOOL bNotify = TRUE);
|
||||
void DeleteSocketObj(TUdpSocketObj* pSocketObj);
|
||||
BOOL InvalidSocketObj(TUdpSocketObj* pSocketObj);
|
||||
void AddClientSocketObj(int idx, CONNID dwConnID, TUdpSocketObj* pSocketObj, const HP_SOCKADDR& remoteAddr);
|
||||
void CloseClientSocketObj(TUdpSocketObj* pSocketObj, EnSocketCloseFlag enFlag = SCF_NONE, EnSocketOperation enOperation = SO_UNKNOWN, int iErrorCode = 0, BOOL bNotify = TRUE);
|
||||
|
||||
EnHandleResult TriggerFireAccept(TUdpSocketObj* pSocketObj);
|
||||
|
||||
private:
|
||||
VOID HandleCmdSend (CONNID dwConnID, int flag);
|
||||
VOID HandleCmdDisconnect(CONNID dwConnID, BOOL bForce);
|
||||
VOID HandleCmdTimeout (CONNID dwConnID);
|
||||
|
||||
CONNID HandleAccept (const TDispContext* pContext, HP_SOCKADDR& addr);
|
||||
BOOL HandleReceive (const TDispContext* pContext, int flag = 0);
|
||||
BOOL HandleSend (const TDispContext* pContext, int flag = 0);
|
||||
BOOL HandleClose (TUdpSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode);
|
||||
void HandleZeroBytes (TUdpSocketObj* pSocketObj);
|
||||
|
||||
BOOL SendItem (TUdpSocketObj* pSocketObj, TItem* pItem, BOOL& bBlocked);
|
||||
|
||||
void DetectConnection (PVOID pv);
|
||||
BOOL IsNeedDetectConnection () const {return m_dwDetectAttempts > 0 && m_dwDetectInterval > 0;}
|
||||
|
||||
public:
|
||||
CUdpServer(IUdpServerListener* pListener)
|
||||
: m_pListener (pListener)
|
||||
, m_enLastError (SE_OK)
|
||||
, m_enState (SS_STOPPED)
|
||||
, m_enSendPolicy (SP_PACK)
|
||||
, m_enOnSendSyncPolicy (OSSP_RECEIVE)
|
||||
, m_enReusePolicy (RAP_ADDR_AND_PORT)
|
||||
, m_dwMaxConnectionCount (DEFAULT_CONNECTION_COUNT)
|
||||
, m_dwWorkerThreadCount (DEFAULT_WORKER_THREAD_COUNT)
|
||||
, m_dwFreeSocketObjLockTime (DEFAULT_FREE_SOCKETOBJ_LOCK_TIME)
|
||||
, m_dwFreeSocketObjPool (DEFAULT_FREE_SOCKETOBJ_POOL)
|
||||
, m_dwFreeBufferObjPool (DEFAULT_FREE_BUFFEROBJ_POOL)
|
||||
, m_dwFreeSocketObjHold (DEFAULT_FREE_SOCKETOBJ_HOLD)
|
||||
, m_dwFreeBufferObjHold (DEFAULT_FREE_BUFFEROBJ_HOLD)
|
||||
, m_dwMaxDatagramSize (DEFAULT_UDP_MAX_DATAGRAM_SIZE)
|
||||
, m_dwPostReceiveCount (DEFAULT_UDP_POST_RECEIVE_COUNT)
|
||||
, m_dwDetectAttempts (DEFAULT_UDP_DETECT_ATTEMPTS)
|
||||
, m_dwDetectInterval (DEFAULT_UDP_DETECT_INTERVAL)
|
||||
, m_bMarkSilence (TRUE)
|
||||
, m_bDualStack (TRUE)
|
||||
, m_thGC (this)
|
||||
{
|
||||
ASSERT(m_pListener);
|
||||
}
|
||||
|
||||
virtual ~CUdpServer()
|
||||
{
|
||||
ENSURE_STOP();
|
||||
}
|
||||
|
||||
private:
|
||||
EnReuseAddressPolicy m_enReusePolicy;
|
||||
EnSendPolicy m_enSendPolicy;
|
||||
EnOnSendSyncPolicy m_enOnSendSyncPolicy;
|
||||
DWORD m_dwMaxConnectionCount;
|
||||
DWORD m_dwWorkerThreadCount;
|
||||
DWORD m_dwFreeSocketObjLockTime;
|
||||
DWORD m_dwFreeSocketObjPool;
|
||||
DWORD m_dwFreeBufferObjPool;
|
||||
DWORD m_dwFreeSocketObjHold;
|
||||
DWORD m_dwFreeBufferObjHold;
|
||||
DWORD m_dwMaxDatagramSize;
|
||||
DWORD m_dwPostReceiveCount;
|
||||
DWORD m_dwDetectAttempts;
|
||||
DWORD m_dwDetectInterval;
|
||||
BOOL m_bMarkSilence;
|
||||
BOOL m_bDualStack;
|
||||
|
||||
protected:
|
||||
CBufferObjPool m_bfObjPool;
|
||||
|
||||
private:
|
||||
CSEM m_evWait;
|
||||
|
||||
IUdpServerListener* m_pListener;
|
||||
ListenSocketsPtr m_soListens;
|
||||
EnServiceState m_enState;
|
||||
EnSocketError m_enLastError;
|
||||
|
||||
CReceiveBuffersPtr m_rcBuffers;
|
||||
|
||||
CPrivateHeap m_phSocket;
|
||||
|
||||
CSpinGuard m_csState;
|
||||
|
||||
CGCThread m_thGC;
|
||||
|
||||
TUdpSocketObjPtrPool m_bfActiveSockets;
|
||||
|
||||
CSimpleRWLock m_csClientSocket;
|
||||
TSockAddrMap m_mpClientAddr;
|
||||
|
||||
TUdpSocketObjPtrList m_lsFreeSocket;
|
||||
TUdpSocketObjPtrQueue m_lsGCSocket;
|
||||
|
||||
CSendQueuesPtr m_quSends;
|
||||
|
||||
CIODispatcher m_ioDispatcher;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "BufferPool.h"
|
||||
#include "FuncHelper.h"
|
||||
|
||||
const DWORD TItem::DEFAULT_ITEM_CAPACITY = DEFAULT_BUFFER_CACHE_CAPACITY;
|
||||
const DWORD CBufferPool::DEFAULT_MAX_CACHE_SIZE = 0;
|
||||
const DWORD CBufferPool::DEFAULT_ITEM_CAPACITY = CItemPool::DEFAULT_ITEM_CAPACITY;
|
||||
const DWORD CBufferPool::DEFAULT_ITEM_POOL_SIZE = CItemPool::DEFAULT_POOL_SIZE;
|
||||
const DWORD CBufferPool::DEFAULT_ITEM_POOL_HOLD = CItemPool::DEFAULT_POOL_HOLD;
|
||||
const DWORD CBufferPool::DEFAULT_BUFFER_LOCK_TIME = DEFAULT_OBJECT_CACHE_LOCK_TIME;
|
||||
const DWORD CBufferPool::DEFAULT_BUFFER_POOL_SIZE = DEFAULT_OBJECT_CACHE_POOL_SIZE;
|
||||
const DWORD CBufferPool::DEFAULT_BUFFER_POOL_HOLD = DEFAULT_OBJECT_CACHE_POOL_HOLD;
|
||||
|
||||
int TItem::Cat(const BYTE* pData, int length)
|
||||
{
|
||||
ASSERT(pData != nullptr && length >= 0);
|
||||
|
||||
int cat = MIN(Remain(), length);
|
||||
|
||||
if(cat > 0)
|
||||
{
|
||||
memcpy(end, pData, cat);
|
||||
end += cat;
|
||||
}
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
int TItem::Cat(const TItem& other)
|
||||
{
|
||||
ASSERT(this != &other);
|
||||
return Cat(other.Ptr(), other.Size());
|
||||
}
|
||||
|
||||
int TItem::Fetch(BYTE* pData, int length)
|
||||
{
|
||||
ASSERT(pData != nullptr && length > 0);
|
||||
|
||||
int fetch = MIN(Size(), length);
|
||||
memcpy(pData, begin, fetch);
|
||||
begin += fetch;
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
int TItem::Peek(BYTE* pData, int length)
|
||||
{
|
||||
ASSERT(pData != nullptr && length > 0);
|
||||
|
||||
int peek = MIN(Size(), length);
|
||||
memcpy(pData, begin, peek);
|
||||
|
||||
return peek;
|
||||
}
|
||||
|
||||
int TItem::Increase(int length)
|
||||
{
|
||||
ASSERT(length >= 0);
|
||||
|
||||
int increase = MIN(Remain(), length);
|
||||
end += increase;
|
||||
|
||||
return increase;
|
||||
}
|
||||
|
||||
int TItem::Reduce(int length)
|
||||
{
|
||||
ASSERT(length >= 0);
|
||||
|
||||
int reduce = MIN(Size(), length);
|
||||
begin += reduce;
|
||||
|
||||
return reduce;
|
||||
}
|
||||
|
||||
void TItem::Reset(int first, int last)
|
||||
{
|
||||
ASSERT(first >= -1 && first <= capacity);
|
||||
ASSERT(last >= -1 && last <= capacity);
|
||||
|
||||
if(first >= 0) begin = head + MIN(first, capacity);
|
||||
if(last >= 0) end = head + MIN(last, capacity);
|
||||
}
|
||||
|
||||
TBuffer* TBuffer::Construct(CBufferPool& pool, ULONG_PTR dwID)
|
||||
{
|
||||
ASSERT(dwID != 0);
|
||||
|
||||
CPrivateHeap& heap = pool.GetPrivateHeap();
|
||||
TBuffer* pBuffer = (TBuffer*)heap.Alloc(sizeof(TBuffer));
|
||||
|
||||
return ::ConstructObject(pBuffer, heap, pool.GetItemPool(), dwID);
|
||||
}
|
||||
|
||||
void TBuffer::Destruct(TBuffer* pBuffer)
|
||||
{
|
||||
ASSERT(pBuffer != nullptr);
|
||||
|
||||
CPrivateHeap& heap = pBuffer->heap;
|
||||
::DestructObject(pBuffer);
|
||||
heap.Free(pBuffer);
|
||||
}
|
||||
|
||||
void TBuffer::Reset()
|
||||
{
|
||||
id = 0;
|
||||
length = 0;
|
||||
freeTime = ::TimeGetTime();
|
||||
}
|
||||
|
||||
int TBuffer::Cat(const BYTE* pData, int len)
|
||||
{
|
||||
items.Cat(pData, len);
|
||||
return IncreaseLength(len);
|
||||
}
|
||||
|
||||
int TBuffer::Cat(const TItem* pItem)
|
||||
{
|
||||
items.Cat(pItem);
|
||||
return IncreaseLength(pItem->Size());
|
||||
}
|
||||
|
||||
int TBuffer::Cat(const TItemList& other)
|
||||
{
|
||||
ASSERT(&items != &other);
|
||||
|
||||
for(TItem* pItem = other.Front(); pItem != nullptr; pItem = pItem->next)
|
||||
Cat(pItem);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int TBuffer::Fetch(BYTE* pData, int len)
|
||||
{
|
||||
int fetch = items.Fetch(pData, len);
|
||||
DecreaseLength(fetch);
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
int TBuffer::Peek(BYTE* pData, int len)
|
||||
{
|
||||
return items.Peek(pData, len);
|
||||
}
|
||||
|
||||
int TBuffer::Reduce(int len)
|
||||
{
|
||||
int reduce = items.Reduce(len);
|
||||
DecreaseLength(reduce);
|
||||
|
||||
return reduce;
|
||||
}
|
||||
|
||||
void CBufferPool::PutFreeBuffer(ULONG_PTR dwID)
|
||||
{
|
||||
ASSERT(dwID != 0);
|
||||
|
||||
TBuffer* pBuffer = FindCacheBuffer(dwID);
|
||||
|
||||
if(pBuffer != nullptr)
|
||||
PutFreeBuffer(pBuffer);
|
||||
}
|
||||
|
||||
void CBufferPool::PutFreeBuffer(TBuffer* pBuffer)
|
||||
{
|
||||
ASSERT(pBuffer != nullptr);
|
||||
|
||||
if(!pBuffer->IsValid())
|
||||
return;
|
||||
|
||||
m_bfCache.RemoveEx(pBuffer->ID());
|
||||
|
||||
BOOL bOK = FALSE;
|
||||
|
||||
{
|
||||
CCriSecLock locallock(pBuffer->cs);
|
||||
|
||||
if(pBuffer->IsValid())
|
||||
{
|
||||
pBuffer->Reset();
|
||||
bOK = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(bOK)
|
||||
{
|
||||
m_itPool.PutFreeItem(pBuffer->items);
|
||||
|
||||
#ifndef USE_EXTERNAL_GC
|
||||
ReleaseGCBuffer();
|
||||
#endif
|
||||
if(!m_lsFreeBuffer.TryPut(pBuffer))
|
||||
m_lsGCBuffer.PushBack(pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CBufferPool::ReleaseGCBuffer(BOOL bForce)
|
||||
{
|
||||
::ReleaseGCObj(m_lsGCBuffer, m_dwBufferLockTime, bForce);
|
||||
}
|
||||
|
||||
TBuffer* CBufferPool::PutCacheBuffer(ULONG_PTR dwID)
|
||||
{
|
||||
ASSERT(dwID != 0);
|
||||
|
||||
TBuffer* pBuffer = PickFreeBuffer(dwID);
|
||||
m_bfCache.SetEx(dwID, pBuffer);
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
TBuffer* CBufferPool::PickFreeBuffer(ULONG_PTR dwID)
|
||||
{
|
||||
ASSERT( dwID != 0);
|
||||
|
||||
DWORD dwIndex;
|
||||
TBuffer* pBuffer = nullptr;
|
||||
|
||||
if(m_lsFreeBuffer.TryLock(&pBuffer, dwIndex))
|
||||
{
|
||||
if(::GetTimeGap32(pBuffer->freeTime) >= m_dwBufferLockTime)
|
||||
VERIFY(m_lsFreeBuffer.ReleaseLock(nullptr, dwIndex));
|
||||
else
|
||||
{
|
||||
VERIFY(m_lsFreeBuffer.ReleaseLock(pBuffer, dwIndex));
|
||||
pBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(pBuffer) pBuffer->id = dwID;
|
||||
else pBuffer = TBuffer::Construct(*this, dwID);
|
||||
|
||||
ASSERT(pBuffer);
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
TBuffer* CBufferPool::FindCacheBuffer(ULONG_PTR dwID)
|
||||
{
|
||||
ASSERT(dwID != 0);
|
||||
|
||||
TBuffer* pBuffer = nullptr;
|
||||
|
||||
if(m_bfCache.GetEx(dwID, &pBuffer) != TBufferCache::GR_VALID)
|
||||
pBuffer = nullptr;
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
void CBufferPool::Prepare()
|
||||
{
|
||||
m_itPool.Prepare();
|
||||
|
||||
m_bfCache.Reset(m_dwMaxCacheSize);
|
||||
m_lsFreeBuffer.Reset(m_dwBufferPoolSize);
|
||||
}
|
||||
|
||||
void CBufferPool::Clear()
|
||||
{
|
||||
TBufferCache::IndexSet& indexes = m_bfCache.Indexes();
|
||||
|
||||
for(auto it = indexes.begin(), end = indexes.end(); it != end; ++it)
|
||||
{
|
||||
TBuffer* pBuffer = FindCacheBuffer(*it);
|
||||
if(pBuffer) TBuffer::Destruct(pBuffer);
|
||||
}
|
||||
|
||||
m_bfCache.Reset();
|
||||
|
||||
m_lsFreeBuffer.Clear();
|
||||
|
||||
ReleaseGCBuffer(TRUE);
|
||||
VERIFY(m_lsGCBuffer.IsEmpty());
|
||||
|
||||
m_itPool.Clear();
|
||||
m_heap.Reset();
|
||||
}
|
||||
|
|
@ -0,0 +1,869 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "Singleton.h"
|
||||
#include "STLHelper.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "PrivateHeap.h"
|
||||
#include "CriSec.h"
|
||||
|
||||
template<class T> T* ConstructItemT(T*, CPrivateHeap& heap, int capacity, BYTE* pData, int length)
|
||||
{
|
||||
ASSERT(capacity > 0);
|
||||
|
||||
int item_size = sizeof(T);
|
||||
T* pItem = (T*)heap.Alloc(item_size + capacity);
|
||||
BYTE* pHead = (BYTE*)pItem + item_size;
|
||||
|
||||
return ::ConstructObject(pItem, heap, pHead, capacity, pData, length);
|
||||
}
|
||||
|
||||
template<class T> void DestructItemT(T* pItem)
|
||||
{
|
||||
ASSERT(pItem != nullptr);
|
||||
|
||||
CPrivateHeap& heap = pItem->GetPrivateHeap();
|
||||
|
||||
::DestructObject(pItem);
|
||||
heap.Free(pItem);
|
||||
}
|
||||
|
||||
struct TItem
|
||||
{
|
||||
template<typename T> friend struct TSimpleList;
|
||||
template<typename T> friend class CNodePoolT;
|
||||
template<typename T> friend struct TItemListT;
|
||||
|
||||
friend struct TBuffer;
|
||||
|
||||
public:
|
||||
int Cat (const BYTE* pData, int length);
|
||||
int Cat (const TItem& other);
|
||||
int Fetch (BYTE* pData, int length);
|
||||
int Peek (BYTE* pData, int length);
|
||||
int Increase(int length);
|
||||
int Reduce (int length);
|
||||
void Reset (int first = 0, int last = 0);
|
||||
|
||||
BYTE* Ptr () {return begin;}
|
||||
const BYTE* Ptr () const {return begin;}
|
||||
int Size () const {return (int)(end - begin);}
|
||||
int Remain () const {return capacity - (int)(end - head);}
|
||||
int Capacity() const {return capacity;}
|
||||
bool IsEmpty () const {return Size() == 0;}
|
||||
bool IsFull () const {return Remain() == 0;}
|
||||
CPrivateHeap& GetPrivateHeap() {return heap;}
|
||||
|
||||
operator BYTE* () {return Ptr();}
|
||||
operator const BYTE* () const {return Ptr();}
|
||||
|
||||
public:
|
||||
static TItem* Construct(CPrivateHeap& heap,
|
||||
int capacity = DEFAULT_ITEM_CAPACITY,
|
||||
BYTE* pData = nullptr,
|
||||
int length = 0)
|
||||
{
|
||||
return ::ConstructItemT((TItem*)(nullptr), heap, capacity, pData, length);
|
||||
}
|
||||
|
||||
static void Destruct(TItem* pItem)
|
||||
{
|
||||
::DestructItemT(pItem);
|
||||
}
|
||||
|
||||
TItem(CPrivateHeap& hp, BYTE* pHead, int cap = DEFAULT_ITEM_CAPACITY, BYTE* pData = nullptr, int length = 0)
|
||||
: heap(hp), head(pHead), begin(pHead), end(pHead), capacity(cap), next(nullptr), last(nullptr)
|
||||
{
|
||||
if(pData != nullptr && length != 0)
|
||||
Cat(pData, length);
|
||||
}
|
||||
|
||||
~TItem() {}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(TItem)
|
||||
|
||||
public:
|
||||
static const DWORD DEFAULT_ITEM_CAPACITY;
|
||||
|
||||
private:
|
||||
CPrivateHeap& heap;
|
||||
|
||||
private:
|
||||
TItem* next;
|
||||
TItem* last;
|
||||
|
||||
int capacity;
|
||||
BYTE* head;
|
||||
BYTE* begin;
|
||||
BYTE* end;
|
||||
};
|
||||
|
||||
template<class T> struct TSimpleList
|
||||
{
|
||||
public:
|
||||
T* PushFront(T* pItem)
|
||||
{
|
||||
if(pFront != nullptr)
|
||||
{
|
||||
pFront->last = pItem;
|
||||
pItem->next = pFront;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem->last = nullptr;
|
||||
pItem->next = nullptr;
|
||||
pBack = pItem;
|
||||
}
|
||||
|
||||
pFront = pItem;
|
||||
++size;
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
T* PushBack(T* pItem)
|
||||
{
|
||||
if(pBack != nullptr)
|
||||
{
|
||||
pBack->next = pItem;
|
||||
pItem->last = pBack;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem->last = nullptr;
|
||||
pItem->next = nullptr;
|
||||
pFront = pItem;
|
||||
}
|
||||
|
||||
pBack = pItem;
|
||||
++size;
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
T* PopFront()
|
||||
{
|
||||
T* pItem = pFront;
|
||||
|
||||
if(pFront != pBack)
|
||||
{
|
||||
pFront = (T*)pFront->next;
|
||||
pFront->last = nullptr;
|
||||
}
|
||||
else if(pFront != nullptr)
|
||||
{
|
||||
pFront = nullptr;
|
||||
pBack = nullptr;
|
||||
}
|
||||
|
||||
if(pItem != nullptr)
|
||||
{
|
||||
pItem->next = nullptr;
|
||||
pItem->last = nullptr;
|
||||
|
||||
--size;
|
||||
}
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
T* PopBack()
|
||||
{
|
||||
T* pItem = pBack;
|
||||
|
||||
if(pFront != pBack)
|
||||
{
|
||||
pBack = (T*)pBack->last;
|
||||
pBack->next = nullptr;
|
||||
}
|
||||
else if(pBack != nullptr)
|
||||
{
|
||||
pFront = nullptr;
|
||||
pBack = nullptr;
|
||||
}
|
||||
|
||||
if(pItem != nullptr)
|
||||
{
|
||||
pItem->next = nullptr;
|
||||
pItem->last = nullptr;
|
||||
|
||||
--size;
|
||||
}
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
TSimpleList<T>& Shift(TSimpleList<T>& other)
|
||||
{
|
||||
if(&other != this && other.size > 0)
|
||||
{
|
||||
if(size > 0)
|
||||
{
|
||||
pBack->next = other.pFront;
|
||||
other.pFront->last = pBack;
|
||||
}
|
||||
else
|
||||
{
|
||||
pFront = other.pFront;
|
||||
}
|
||||
|
||||
pBack = other.pBack;
|
||||
size += other.size;
|
||||
|
||||
other.Reset();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
if(size > 0)
|
||||
{
|
||||
T* pItem;
|
||||
while((pItem = PopFront()) != nullptr)
|
||||
T::Destruct(pItem);
|
||||
}
|
||||
}
|
||||
|
||||
T* Front () const {return pFront;}
|
||||
T* Back () const {return pBack;}
|
||||
int Size () const {return size;}
|
||||
bool IsEmpty () const {return size == 0;}
|
||||
|
||||
public:
|
||||
TSimpleList() {Reset();}
|
||||
~TSimpleList() {Clear();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(TSimpleList<T>)
|
||||
|
||||
private:
|
||||
void Reset()
|
||||
{
|
||||
pFront = nullptr;
|
||||
pBack = nullptr;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int size;
|
||||
T* pFront;
|
||||
T* pBack;
|
||||
};
|
||||
|
||||
template<class T> class CNodePoolT
|
||||
{
|
||||
public:
|
||||
void PutFreeItem(T* pItem)
|
||||
{
|
||||
ASSERT(pItem != nullptr);
|
||||
|
||||
if(!m_lsFreeItem.TryPut(pItem))
|
||||
T::Destruct(pItem);
|
||||
}
|
||||
|
||||
void PutFreeItem(TSimpleList<T>& lsItem)
|
||||
{
|
||||
if(lsItem.IsEmpty())
|
||||
return;
|
||||
|
||||
T* pItem;
|
||||
while((pItem = lsItem.PopFront()) != nullptr)
|
||||
PutFreeItem(pItem);
|
||||
}
|
||||
|
||||
T* PickFreeItem()
|
||||
{
|
||||
T* pItem = nullptr;
|
||||
|
||||
if(!m_lsFreeItem.TryGet(&pItem))
|
||||
pItem = T::Construct(m_heap, m_dwItemCapacity);
|
||||
|
||||
ASSERT(pItem);
|
||||
pItem->Reset();
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
void Prepare()
|
||||
{
|
||||
m_lsFreeItem.Reset(m_dwPoolSize);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_lsFreeItem.Clear();
|
||||
|
||||
m_heap.Reset();
|
||||
}
|
||||
|
||||
public:
|
||||
void SetItemCapacity(DWORD dwItemCapacity) {m_dwItemCapacity = dwItemCapacity;}
|
||||
void SetPoolSize (DWORD dwPoolSize) {m_dwPoolSize = dwPoolSize;}
|
||||
void SetPoolHold (DWORD dwPoolHold) {m_dwPoolHold = dwPoolHold;}
|
||||
DWORD GetItemCapacity () {return m_dwItemCapacity;}
|
||||
DWORD GetPoolSize () {return m_dwPoolSize;}
|
||||
DWORD GetPoolHold () {return m_dwPoolHold;}
|
||||
|
||||
CPrivateHeap& GetPrivateHeap() {return m_heap;}
|
||||
|
||||
public:
|
||||
CNodePoolT( DWORD dwPoolSize = DEFAULT_POOL_SIZE,
|
||||
DWORD dwPoolHold = DEFAULT_POOL_HOLD,
|
||||
DWORD dwItemCapacity = DEFAULT_ITEM_CAPACITY)
|
||||
: m_dwPoolSize(dwPoolSize)
|
||||
, m_dwPoolHold(dwPoolHold)
|
||||
, m_dwItemCapacity(dwItemCapacity)
|
||||
{
|
||||
}
|
||||
|
||||
~CNodePoolT() {Clear();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CNodePoolT)
|
||||
|
||||
public:
|
||||
static const DWORD DEFAULT_ITEM_CAPACITY;
|
||||
static const DWORD DEFAULT_POOL_SIZE;
|
||||
static const DWORD DEFAULT_POOL_HOLD;
|
||||
|
||||
private:
|
||||
CPrivateHeap m_heap;
|
||||
|
||||
DWORD m_dwItemCapacity;
|
||||
DWORD m_dwPoolSize;
|
||||
DWORD m_dwPoolHold;
|
||||
|
||||
CRingPool<T> m_lsFreeItem;
|
||||
};
|
||||
|
||||
template<class T> const DWORD CNodePoolT<T>::DEFAULT_ITEM_CAPACITY = TItem::DEFAULT_ITEM_CAPACITY;
|
||||
template<class T> const DWORD CNodePoolT<T>::DEFAULT_POOL_SIZE = DEFAULT_BUFFER_CACHE_POOL_SIZE;
|
||||
template<class T> const DWORD CNodePoolT<T>::DEFAULT_POOL_HOLD = DEFAULT_BUFFER_CACHE_POOL_HOLD;
|
||||
|
||||
using CItemPool = CNodePoolT<TItem>;
|
||||
|
||||
template<class T> struct TItemListT : public TSimpleList<T>
|
||||
{
|
||||
using __super = TSimpleList<T>;
|
||||
|
||||
public:
|
||||
int PushTail(const BYTE* pData, int length)
|
||||
{
|
||||
ASSERT(length <= (int)itPool.GetItemCapacity());
|
||||
|
||||
if(length > (int)itPool.GetItemCapacity())
|
||||
return 0;
|
||||
|
||||
T* pItem = __super::PushBack(itPool.PickFreeItem());
|
||||
return pItem->Cat(pData, length);
|
||||
}
|
||||
|
||||
int Cat(const BYTE* pData, int length)
|
||||
{
|
||||
int remain = length;
|
||||
|
||||
while(remain > 0)
|
||||
{
|
||||
T* pItem = __super::Back();
|
||||
|
||||
if(pItem == nullptr || pItem->IsFull())
|
||||
pItem = __super::PushBack(itPool.PickFreeItem());
|
||||
|
||||
int cat = pItem->Cat(pData, remain);
|
||||
|
||||
pData += cat;
|
||||
remain -= cat;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int Cat(const T* pItem)
|
||||
{
|
||||
return Cat(pItem->Ptr(), pItem->Size());
|
||||
}
|
||||
|
||||
int Cat(const TItemListT<T>& other)
|
||||
{
|
||||
ASSERT(this != &other);
|
||||
|
||||
int length = 0;
|
||||
|
||||
for(T* pItem = other.Front(); pItem != nullptr; pItem = pItem->next)
|
||||
length += Cat(pItem);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int Fetch(BYTE* pData, int length)
|
||||
{
|
||||
int remain = length;
|
||||
|
||||
while(remain > 0 && __super::Size() > 0)
|
||||
{
|
||||
T* pItem = __super::Front();
|
||||
int fetch = pItem->Fetch(pData, remain);
|
||||
|
||||
pData += fetch;
|
||||
remain -= fetch;
|
||||
|
||||
if(pItem->IsEmpty())
|
||||
itPool.PutFreeItem(__super::PopFront());
|
||||
}
|
||||
|
||||
return length - remain;
|
||||
}
|
||||
|
||||
int Peek(BYTE* pData, int length)
|
||||
{
|
||||
int remain = length;
|
||||
T* pItem = __super::Front();
|
||||
|
||||
while(remain > 0 && pItem != nullptr)
|
||||
{
|
||||
int peek = pItem->Peek(pData, remain);
|
||||
|
||||
pData += peek;
|
||||
remain -= peek;
|
||||
pItem = pItem->next;
|
||||
}
|
||||
|
||||
return length - remain;
|
||||
}
|
||||
|
||||
int Increase(int length)
|
||||
{
|
||||
int remain = length;
|
||||
|
||||
while(remain > 0)
|
||||
{
|
||||
T* pItem = __super::Back();
|
||||
|
||||
if(pItem == nullptr || pItem->IsFull())
|
||||
{
|
||||
pItem = itPool.PickFreeItem();
|
||||
__super::PushBack(pItem);
|
||||
}
|
||||
|
||||
remain -= pItem->Increase(remain);
|
||||
}
|
||||
|
||||
return length - remain;
|
||||
}
|
||||
|
||||
int Reduce(int length)
|
||||
{
|
||||
int remain = length;
|
||||
|
||||
while(remain > 0 && __super::Size() > 0)
|
||||
{
|
||||
T* pItem = __super::Front();
|
||||
remain -= pItem->Reduce(remain);
|
||||
|
||||
if(pItem->IsEmpty())
|
||||
itPool.PutFreeItem(__super::PopFront());
|
||||
}
|
||||
|
||||
return length - remain;
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
itPool.PutFreeItem(*this);
|
||||
}
|
||||
|
||||
CNodePoolT<T>& GetItemPool() {return itPool;}
|
||||
|
||||
public:
|
||||
TItemListT(CNodePoolT<T>& pool) : itPool(pool)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
CNodePoolT<T>& itPool;
|
||||
};
|
||||
|
||||
using TItemList = TItemListT<TItem>;
|
||||
|
||||
template<class T, class length_t = int, typename = enable_if_t<is_integral<typename decay<length_t>::type>::value>>
|
||||
struct TItemListExT : public TItemListT<T>
|
||||
{
|
||||
using __super = TItemListT<T>;
|
||||
|
||||
public:
|
||||
T* PushFront(T* pItem)
|
||||
{
|
||||
length += pItem->Size();
|
||||
return __super::PushFront(pItem);
|
||||
}
|
||||
|
||||
T* PushBack(T* pItem)
|
||||
{
|
||||
length += pItem->Size();
|
||||
return __super::PushBack(pItem);
|
||||
}
|
||||
|
||||
T* PopFront()
|
||||
{
|
||||
T* pItem = __super::PopFront();
|
||||
|
||||
if(pItem != nullptr)
|
||||
length -= pItem->Size();
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
T* PopBack()
|
||||
{
|
||||
T* pItem = __super::PopBack();
|
||||
|
||||
if(pItem != nullptr)
|
||||
length -= pItem->Size();
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
TItemListExT& Shift(TItemListExT<T>& other)
|
||||
{
|
||||
if(&other != this && other.length > 0)
|
||||
{
|
||||
length += other.length;
|
||||
other.length = 0;
|
||||
|
||||
__super::Shift(other);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
__super::Clear();
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
__super::Release();
|
||||
length = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
int PushTail(const BYTE* pData, int length)
|
||||
{
|
||||
int cat = __super::PushTail(pData, length);
|
||||
this->length += cat;
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
int Cat(const BYTE* pData, int length)
|
||||
{
|
||||
int cat = __super::Cat(pData, length);
|
||||
this->length += cat;
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
int Cat(const T* pItem)
|
||||
{
|
||||
int cat = __super::Cat(pItem->Ptr(), pItem->Size());
|
||||
this->length += cat;
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
int Cat(const TItemListT<T>& other)
|
||||
{
|
||||
int cat = __super::Cat(other);
|
||||
this->length += cat;
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
int Fetch(BYTE* pData, int length)
|
||||
{
|
||||
int fetch = __super::Fetch(pData, length);
|
||||
this->length -= fetch;
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
int Increase(int length)
|
||||
{
|
||||
int increase = __super::Increase(length);
|
||||
this->length += increase;
|
||||
|
||||
return increase;
|
||||
}
|
||||
|
||||
int Reduce(int length)
|
||||
{
|
||||
int reduce = __super::Reduce(length);
|
||||
this->length -= reduce;
|
||||
|
||||
return reduce;
|
||||
}
|
||||
|
||||
typename decay<length_t>::type Length() const {return length;}
|
||||
|
||||
int IncreaseLength (int length) {return (this->length += length);}
|
||||
int ReduceLength (int length) {return (this->length -= length);}
|
||||
|
||||
public:
|
||||
TItemListExT(CNodePoolT<T>& pool) : TItemListT<T>(pool), length(0)
|
||||
{
|
||||
}
|
||||
|
||||
~TItemListExT()
|
||||
{
|
||||
ASSERT(length >= 0);
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(TItemListExT)
|
||||
|
||||
private:
|
||||
length_t length;
|
||||
};
|
||||
|
||||
using TItemListEx = TItemListExT<TItem>;
|
||||
using TItemListExV = TItemListExT<TItem, volatile int>;
|
||||
|
||||
template<class T> struct TItemPtrT
|
||||
{
|
||||
public:
|
||||
T* Reset(T* pItem = nullptr)
|
||||
{
|
||||
if(m_pItem != nullptr)
|
||||
itPool.PutFreeItem(m_pItem);
|
||||
|
||||
m_pItem = pItem;
|
||||
|
||||
return m_pItem;
|
||||
}
|
||||
|
||||
T* Attach(T* pItem)
|
||||
{
|
||||
return Reset(pItem);
|
||||
}
|
||||
|
||||
T* Detach()
|
||||
{
|
||||
T* pItem = m_pItem;
|
||||
m_pItem = nullptr;
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
T* New()
|
||||
{
|
||||
return Attach(itPool.PickFreeItem());
|
||||
}
|
||||
|
||||
bool IsValid () {return m_pItem != nullptr;}
|
||||
T* operator -> () {return m_pItem;}
|
||||
T* operator = (T* pItem) {return Reset(pItem);}
|
||||
operator T* () {return m_pItem;}
|
||||
T*& PtrRef () {return m_pItem;}
|
||||
T* Ptr () {return m_pItem;}
|
||||
const T* Ptr () const {return m_pItem;}
|
||||
operator const T* () const {return m_pItem;}
|
||||
|
||||
public:
|
||||
TItemPtrT(CNodePoolT<T>& pool, T* pItem = nullptr)
|
||||
: itPool(pool), m_pItem(pItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TItemPtrT(TItemListT<T>& ls, T* pItem = nullptr)
|
||||
: itPool(ls.GetItemPool()), m_pItem(pItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~TItemPtrT()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(TItemPtrT)
|
||||
|
||||
private:
|
||||
CNodePoolT<T>& itPool;
|
||||
T* m_pItem;
|
||||
};
|
||||
|
||||
using TItemPtr = TItemPtrT<TItem>;
|
||||
|
||||
class CBufferPool;
|
||||
|
||||
struct TBuffer
|
||||
{
|
||||
template<typename T> friend struct TSimpleList;
|
||||
friend class CBufferPool;
|
||||
|
||||
public:
|
||||
static TBuffer* Construct(CBufferPool& pool, ULONG_PTR dwID);
|
||||
static void Destruct(TBuffer* pBuffer);
|
||||
|
||||
public:
|
||||
int Cat (const BYTE* pData, int len);
|
||||
int Cat (const TItem* pItem);
|
||||
int Cat (const TItemList& other);
|
||||
int Fetch (BYTE* pData, int length);
|
||||
int Peek (BYTE* pData, int length);
|
||||
int Reduce (int len);
|
||||
|
||||
public:
|
||||
CCriSec& CriSec () {return cs;}
|
||||
TItemList& ItemList() {return items;}
|
||||
|
||||
ULONG_PTR ID () const {return id;}
|
||||
int Length () const {return length;}
|
||||
bool IsValid () const {return id != 0;}
|
||||
|
||||
DWORD GetFreeTime () const {return freeTime;}
|
||||
int GetCount () const {return 0;}
|
||||
|
||||
private:
|
||||
int IncreaseLength (int len) {return (length += len);}
|
||||
int DecreaseLength (int len) {return (length -= len);}
|
||||
|
||||
void Reset ();
|
||||
|
||||
private:
|
||||
friend TBuffer* ConstructObject<>(TBuffer*, CPrivateHeap&, CItemPool&, ULONG_PTR&);
|
||||
friend void DestructObject<>(TBuffer*);
|
||||
|
||||
TBuffer(CPrivateHeap& hp, CItemPool& itPool, ULONG_PTR dwID = 0)
|
||||
: heap(hp), items(itPool), id(dwID), length(0)
|
||||
{
|
||||
}
|
||||
|
||||
~TBuffer() {}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(TBuffer)
|
||||
|
||||
private:
|
||||
CPrivateHeap& heap;
|
||||
|
||||
private:
|
||||
ULONG_PTR id;
|
||||
int length;
|
||||
DWORD freeTime;
|
||||
|
||||
private:
|
||||
TBuffer* next;
|
||||
TBuffer* last;
|
||||
|
||||
CCriSec cs;
|
||||
TItemList items;
|
||||
};
|
||||
|
||||
class CBufferPool
|
||||
{
|
||||
using TBufferList = CRingPool<TBuffer>;
|
||||
using TBufferQueue = CCASQueue<TBuffer>;
|
||||
using TBufferCache = CRingCache<TBuffer, ULONG_PTR, true>;
|
||||
|
||||
public:
|
||||
void PutFreeBuffer (ULONG_PTR dwID);
|
||||
TBuffer* PutCacheBuffer (ULONG_PTR dwID);
|
||||
TBuffer* FindCacheBuffer (ULONG_PTR dwID);
|
||||
TBuffer* PickFreeBuffer (ULONG_PTR dwID);
|
||||
void PutFreeBuffer (TBuffer* pBuffer);
|
||||
|
||||
void Prepare ();
|
||||
void Clear ();
|
||||
|
||||
void ReleaseGCBuffer (BOOL bForce = FALSE);
|
||||
|
||||
public:
|
||||
void SetItemCapacity (DWORD dwItemCapacity) {m_itPool.SetItemCapacity(dwItemCapacity);}
|
||||
void SetItemPoolSize (DWORD dwItemPoolSize) {m_itPool.SetPoolSize(dwItemPoolSize);}
|
||||
void SetItemPoolHold (DWORD dwItemPoolHold) {m_itPool.SetPoolHold(dwItemPoolHold);}
|
||||
|
||||
void SetMaxCacheSize (DWORD dwMaxCacheSize) {m_dwMaxCacheSize = dwMaxCacheSize;}
|
||||
void SetBufferLockTime (DWORD dwBufferLockTime) {m_dwBufferLockTime = dwBufferLockTime;}
|
||||
void SetBufferPoolSize (DWORD dwBufferPoolSize) {m_dwBufferPoolSize = dwBufferPoolSize;}
|
||||
void SetBufferPoolHold (DWORD dwBufferPoolHold) {m_dwBufferPoolHold = dwBufferPoolHold;}
|
||||
|
||||
DWORD GetItemCapacity () {return m_itPool.GetItemCapacity();}
|
||||
DWORD GetItemPoolSize () {return m_itPool.GetPoolSize();}
|
||||
DWORD GetItemPoolHold () {return m_itPool.GetPoolHold();}
|
||||
|
||||
DWORD GetMaxCacheSize () {return m_dwMaxCacheSize;}
|
||||
DWORD GetBufferLockTime () {return m_dwBufferLockTime;}
|
||||
DWORD GetBufferPoolSize () {return m_dwBufferPoolSize;}
|
||||
DWORD GetBufferPoolHold () {return m_dwBufferPoolHold;}
|
||||
|
||||
TBuffer* operator [] (ULONG_PTR dwID) {return FindCacheBuffer(dwID);}
|
||||
|
||||
public:
|
||||
CBufferPool(DWORD dwPoolSize = DEFAULT_BUFFER_POOL_SIZE,
|
||||
DWORD dwPoolHold = DEFAULT_BUFFER_POOL_HOLD,
|
||||
DWORD dwLockTime = DEFAULT_BUFFER_LOCK_TIME,
|
||||
DWORD dwMaxCacheSize = DEFAULT_MAX_CACHE_SIZE)
|
||||
: m_dwBufferPoolSize(dwPoolSize)
|
||||
, m_dwBufferPoolHold(dwPoolHold)
|
||||
, m_dwBufferLockTime(dwLockTime)
|
||||
, m_dwMaxCacheSize(dwMaxCacheSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CBufferPool() {Clear();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CBufferPool)
|
||||
|
||||
public:
|
||||
CPrivateHeap& GetPrivateHeap() {return m_heap;}
|
||||
CItemPool& GetItemPool() {return m_itPool;}
|
||||
|
||||
public:
|
||||
static const DWORD DEFAULT_MAX_CACHE_SIZE;
|
||||
static const DWORD DEFAULT_ITEM_CAPACITY;
|
||||
static const DWORD DEFAULT_ITEM_POOL_SIZE;
|
||||
static const DWORD DEFAULT_ITEM_POOL_HOLD;
|
||||
static const DWORD DEFAULT_BUFFER_LOCK_TIME;
|
||||
static const DWORD DEFAULT_BUFFER_POOL_SIZE;
|
||||
static const DWORD DEFAULT_BUFFER_POOL_HOLD;
|
||||
|
||||
private:
|
||||
DWORD m_dwMaxCacheSize;
|
||||
DWORD m_dwBufferLockTime;
|
||||
DWORD m_dwBufferPoolSize;
|
||||
DWORD m_dwBufferPoolHold;
|
||||
|
||||
CPrivateHeap m_heap;
|
||||
CItemPool m_itPool;
|
||||
|
||||
TBufferCache m_bfCache;
|
||||
|
||||
TBufferList m_lsFreeBuffer;
|
||||
TBufferQueue m_lsGCBuffer;
|
||||
};
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
|
||||
#include <memory.h>
|
||||
#include <malloc.h>
|
||||
|
||||
template<class T, size_t MAX_CACHE_SIZE = 0>
|
||||
class CBufferPtrT
|
||||
{
|
||||
public:
|
||||
explicit CBufferPtrT(size_t size = 0, bool zero = false) {Reset(); Malloc(size, zero);}
|
||||
explicit CBufferPtrT(const T* pch, size_t size) {Reset(); Copy(pch, size);}
|
||||
CBufferPtrT(const CBufferPtrT& other) {Reset(); Copy(other);}
|
||||
template<size_t S> CBufferPtrT(const CBufferPtrT<T, S>& other) {Reset(); Copy(other);}
|
||||
|
||||
~CBufferPtrT() {Free();}
|
||||
|
||||
T* Malloc(size_t size = 1, bool zero = false)
|
||||
{
|
||||
Free();
|
||||
return Alloc(size, zero, false);
|
||||
}
|
||||
|
||||
T* Realloc(size_t size, bool zero = false)
|
||||
{
|
||||
return Alloc(size, zero, true);
|
||||
}
|
||||
|
||||
void Free()
|
||||
{
|
||||
if(m_pch)
|
||||
{
|
||||
free(m_pch);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t S> CBufferPtrT& Copy(const CBufferPtrT<T, S>& other)
|
||||
{
|
||||
if((void*)&other != (void*)this)
|
||||
Copy(other.Ptr(), other.Size());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBufferPtrT& Copy(const T* pch, size_t size)
|
||||
{
|
||||
Malloc(size);
|
||||
|
||||
if(m_pch)
|
||||
memcpy(m_pch, pch, size * sizeof(T));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<size_t S> CBufferPtrT& Cat(const CBufferPtrT<T, S>& other)
|
||||
{
|
||||
if((void*)&other != (void*)this)
|
||||
Cat(other.Ptr(), other.Size());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBufferPtrT& Cat(const T* pch, size_t size = 1)
|
||||
{
|
||||
size_t pre_size = m_size;
|
||||
Realloc(m_size + size);
|
||||
|
||||
if(m_pch)
|
||||
memcpy(m_pch + pre_size, pch, size * sizeof(T));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<size_t S> bool Equal(const CBufferPtrT<T, S>& other) const
|
||||
{
|
||||
if((void*)&other == (void*)this)
|
||||
return true;
|
||||
else if(m_size != other.Size())
|
||||
return false;
|
||||
else if(m_size == 0)
|
||||
return true;
|
||||
else
|
||||
return (memcmp(m_pch, other.Ptr(), m_size * sizeof(T)) == 0);
|
||||
}
|
||||
|
||||
bool Equal(T* pch) const
|
||||
{
|
||||
if(m_pch == pch)
|
||||
return true;
|
||||
else if(!m_pch || !pch)
|
||||
return false;
|
||||
else
|
||||
return (memcmp(m_pch, pch, m_size * sizeof(T)) == 0);
|
||||
}
|
||||
|
||||
size_t SetSize(size_t size)
|
||||
{
|
||||
if(size < 0 || size > m_capacity)
|
||||
size = m_capacity;
|
||||
|
||||
return (m_size = size);
|
||||
}
|
||||
|
||||
T* Ptr() {return m_pch;}
|
||||
const T* Ptr() const {return m_pch;}
|
||||
T& Get(int i) {return *(m_pch + i);}
|
||||
const T& Get(int i) const {return *(m_pch + i);}
|
||||
size_t Size() const {return m_size;}
|
||||
size_t Capacity() const {return m_capacity;}
|
||||
bool IsValid() const {return m_pch != 0;}
|
||||
|
||||
operator T* () {return Ptr();}
|
||||
operator const T* () const {return Ptr();}
|
||||
T& operator [] (int i) {return Get(i);}
|
||||
const T& operator [] (int i) const {return Get(i);}
|
||||
bool operator == (T* pv) const {return Equal(pv);}
|
||||
template<size_t S> bool operator == (const CBufferPtrT<T, S>& other) {return Equal(other);}
|
||||
CBufferPtrT& operator = (const CBufferPtrT& other) {return Copy(other);}
|
||||
template<size_t S> CBufferPtrT& operator = (const CBufferPtrT<T, S>& other) {return Copy(other);}
|
||||
|
||||
private:
|
||||
void Reset() {m_pch = 0; m_size = 0; m_capacity = 0;}
|
||||
size_t GetAllocSize(size_t size) {return MAX(size, MIN(size * 2, m_size + MAX_CACHE_SIZE));}
|
||||
|
||||
T* Alloc(size_t size, bool zero = false, bool is_realloc = false)
|
||||
{
|
||||
if(size != m_size)
|
||||
{
|
||||
size_t rsize = GetAllocSize(size);
|
||||
if(size > m_capacity || rsize < m_size)
|
||||
{
|
||||
T* pch = is_realloc ?
|
||||
(T*)realloc(m_pch, rsize * sizeof(T)) :
|
||||
(T*)malloc(rsize * sizeof(T)) ;
|
||||
|
||||
if(pch || rsize == 0)
|
||||
{
|
||||
m_pch = pch;
|
||||
m_size = size;
|
||||
m_capacity = rsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
Free();
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
if(zero && m_pch)
|
||||
memset(m_pch, 0, m_size * sizeof(T));
|
||||
|
||||
return m_pch;
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_pch;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
};
|
||||
|
||||
typedef CBufferPtrT<char> CCharBufferPtr;
|
||||
typedef CBufferPtrT<wchar_t> CWCharBufferPtr;
|
||||
typedef CBufferPtrT<unsigned char> CByteBufferPtr;
|
||||
typedef CByteBufferPtr CBufferPtr;
|
||||
|
||||
#ifdef _UNICODE
|
||||
typedef CWCharBufferPtr CTCharBufferPtr;
|
||||
#else
|
||||
typedef CCharBufferPtr CTCharBufferPtr;
|
||||
#endif
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "Singleton.h"
|
||||
#include "FuncHelper.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CSpinGuard
|
||||
{
|
||||
public:
|
||||
CSpinGuard() : m_atFlag(FALSE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CSpinGuard()
|
||||
{
|
||||
ASSERT(!m_atFlag);
|
||||
}
|
||||
|
||||
void Lock(BOOL bWeek = TRUE, memory_order m = memory_order_acquire)
|
||||
{
|
||||
for(UINT i = 0; !TryLock(bWeek, m); ++i)
|
||||
YieldThread(i);
|
||||
}
|
||||
|
||||
BOOL TryLock(BOOL bWeek = FALSE, memory_order m = memory_order_acquire)
|
||||
{
|
||||
BOOL bExpect = FALSE;
|
||||
|
||||
return bWeek
|
||||
? m_atFlag.compare_exchange_weak(bExpect, TRUE, m)
|
||||
: m_atFlag.compare_exchange_strong(bExpect, TRUE, m);
|
||||
}
|
||||
|
||||
void Unlock(memory_order m = memory_order_release)
|
||||
{
|
||||
ASSERT(m_atFlag);
|
||||
m_atFlag.store(FALSE, m);
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CSpinGuard)
|
||||
|
||||
private:
|
||||
atomic<BOOL> m_atFlag;
|
||||
};
|
||||
|
||||
class CReentrantSpinGuard
|
||||
{
|
||||
public:
|
||||
CReentrantSpinGuard()
|
||||
: m_atThreadID (0)
|
||||
, m_iCount (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CReentrantSpinGuard()
|
||||
{
|
||||
ASSERT(m_atThreadID == 0);
|
||||
ASSERT(m_iCount == 0);
|
||||
}
|
||||
|
||||
void Lock(BOOL bWeek = TRUE, memory_order m = memory_order_acquire)
|
||||
{
|
||||
for(UINT i = 0; !_TryLock(i == 0, bWeek, m); ++i)
|
||||
YieldThread(i);
|
||||
}
|
||||
|
||||
BOOL TryLock(BOOL bWeek = FALSE, memory_order m = memory_order_acquire)
|
||||
{
|
||||
return _TryLock(TRUE, bWeek, m);
|
||||
}
|
||||
|
||||
void Unlock(memory_order m = memory_order_release)
|
||||
{
|
||||
ASSERT(::IsSelfThread(m_atThreadID));
|
||||
|
||||
if((--m_iCount) == 0)
|
||||
m_atThreadID.store(0, m);
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL _TryLock(BOOL bFirst, BOOL bWeek = FALSE, memory_order m = memory_order_acquire)
|
||||
{
|
||||
THR_ID dwCurrentThreadID = SELF_THREAD_ID;
|
||||
|
||||
if(bFirst && ::IsSameThread(m_atThreadID, dwCurrentThreadID))
|
||||
{
|
||||
++m_iCount;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
THR_ID ulExpect = 0;
|
||||
|
||||
BOOL isOK = bWeek
|
||||
? m_atThreadID.compare_exchange_weak(ulExpect, dwCurrentThreadID, m)
|
||||
: m_atThreadID.compare_exchange_strong(ulExpect, dwCurrentThreadID, m);
|
||||
|
||||
|
||||
if(isOK)
|
||||
{
|
||||
ASSERT(m_iCount == 0);
|
||||
|
||||
m_iCount = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CReentrantSpinGuard)
|
||||
|
||||
private:
|
||||
atomic_tid m_atThreadID;
|
||||
int m_iCount;
|
||||
};
|
||||
|
||||
class CFakeGuard
|
||||
{
|
||||
public:
|
||||
void Lock() {}
|
||||
void Unlock() {}
|
||||
BOOL TryLock() {return TRUE;}
|
||||
};
|
||||
|
||||
template<class CLockObj> class CLocalLock
|
||||
{
|
||||
public:
|
||||
CLocalLock(CLockObj& obj) : m_lock(obj) {m_lock.Lock();}
|
||||
~CLocalLock() {m_lock.Unlock();}
|
||||
private:
|
||||
CLockObj& m_lock;
|
||||
};
|
||||
|
||||
template<class CLockObj> class CLocalTryLock
|
||||
{
|
||||
public:
|
||||
CLocalTryLock(CLockObj& obj) : m_lock(obj) {m_bValid = m_lock.TryLock();}
|
||||
~CLocalTryLock() {if(m_bValid) m_lock.Unlock();}
|
||||
|
||||
BOOL IsValid() {return m_bValid;}
|
||||
|
||||
private:
|
||||
CLockObj& m_lock;
|
||||
BOOL m_bValid;
|
||||
};
|
||||
|
||||
template<class CMTXObj> class CMTXTryLock
|
||||
{
|
||||
public:
|
||||
CMTXTryLock(CMTXObj& obj) : m_lock(obj) {m_bValid = m_lock.try_lock();}
|
||||
~CMTXTryLock() {if(m_bValid) m_lock.unlock();}
|
||||
|
||||
BOOL IsValid() {return m_bValid;}
|
||||
|
||||
private:
|
||||
CMTXObj& m_lock;
|
||||
BOOL m_bValid;
|
||||
};
|
||||
|
||||
using CSpinLock = CLocalLock<CSpinGuard>;
|
||||
using CReentrantSpinLock = CLocalLock<CReentrantSpinGuard>;
|
||||
using CFakeLock = CLocalLock<CFakeGuard>;
|
||||
|
||||
using CCriSec = mutex;
|
||||
using CCriSecLock = lock_guard<mutex>;
|
||||
using CCriSecLock2 = unique_lock<mutex>;
|
||||
using CCriSecTryLock = CMTXTryLock<mutex>;
|
||||
|
||||
using CMTX = CCriSec;
|
||||
using CMutexLock = CCriSecLock;
|
||||
using CMutexLock2 = CCriSecLock2;
|
||||
using CMutexTryLock = CCriSecTryLock;
|
||||
|
||||
using CReentrantCriSec = recursive_mutex;
|
||||
using CReentrantCriSecLock = lock_guard<recursive_mutex>;
|
||||
using CReentrantCriSecLock2 = unique_lock<recursive_mutex>;
|
||||
using CReentrantCriSecTryLock = CMTXTryLock<recursive_mutex>;
|
||||
|
||||
using CReentrantMTX = CReentrantCriSec;
|
||||
using CReentrantMutexLock = CReentrantCriSecLock;
|
||||
using CReentrantMutexLock2 = CReentrantCriSecLock2;
|
||||
using CReentrantMutexTryLock = CReentrantCriSecTryLock;
|
||||
|
||||
template<typename T, typename = enable_if_t<is_arithmetic<T>::value>> class CSafeCounterT
|
||||
{
|
||||
public:
|
||||
T Increment() {return ::InterlockedIncrement(&m_iCount);}
|
||||
T Decrement() {return ::InterlockedDecrement(&m_iCount);}
|
||||
T AddFetch(T iCount) {return ::InterlockedAdd(&m_iCount, iCount);}
|
||||
T SubFetch(T iCount) {return ::InterlockedSub(&m_iCount, iCount);}
|
||||
T FetchAdd(T iCount) {return ::InterlockedExchangeAdd(&m_iCount, iCount);}
|
||||
T FetchSub(T iCount) {return ::InterlockedExchangeSub(&m_iCount, iCount);}
|
||||
|
||||
T SetCount(T iCount) {return (m_iCount = iCount);}
|
||||
T ResetCount(T iCount = 0) {return SetCount(iCount);}
|
||||
T GetCount() {return m_iCount;}
|
||||
|
||||
T operator ++ () {return Increment();}
|
||||
T operator -- () {return Decrement();}
|
||||
T operator ++ (int) {return FetchAdd(1);}
|
||||
T operator -- (int) {return FetchSub(1);}
|
||||
T operator += (T iCount) {return AddFetch(iCount);}
|
||||
T operator -= (T iCount) {return SubFetch(iCount);}
|
||||
T operator = (T iCount) {return SetCount(iCount);}
|
||||
operator T () {return GetCount();}
|
||||
|
||||
public:
|
||||
CSafeCounterT(T iCount = 0) : m_iCount(iCount) {}
|
||||
|
||||
protected:
|
||||
volatile T m_iCount;
|
||||
};
|
||||
|
||||
template<typename T, typename = enable_if_t<is_arithmetic<T>::value>> class CUnsafeCounterT
|
||||
{
|
||||
public:
|
||||
T Increment() {return ++m_iCount;}
|
||||
T Decrement() {return --m_iCount;}
|
||||
T AddFetch(T iCount) {return m_iCount += iCount;}
|
||||
T SubFetch(T iCount) {return m_iCount -= iCount;}
|
||||
T FetchAdd(T iCount) {T rs = m_iCount; m_iCount += iCount; return rs;}
|
||||
T FetchSub(T iCount) {T rs = m_iCount; m_iCount -= iCount; return rs;}
|
||||
|
||||
T SetCount(T iCount) {return (m_iCount = iCount);}
|
||||
T ResetCount(T iCount = 0) {return SetCount(iCount);}
|
||||
T GetCount() {return m_iCount;}
|
||||
|
||||
T operator ++ () {return Increment();}
|
||||
T operator -- () {return Decrement();}
|
||||
T operator ++ (int) {return FetchAdd(1);}
|
||||
T operator -- (int) {return FetchSub(1);}
|
||||
T operator += (T iCount) {return AddFetch(iCount);}
|
||||
T operator -= (T iCount) {return SubFetch(iCount);}
|
||||
T operator = (T iCount) {return SetCount(iCount);}
|
||||
operator T () {return GetCount();}
|
||||
|
||||
public:
|
||||
CUnsafeCounterT(T iCount = 0) : m_iCount(iCount) {}
|
||||
|
||||
protected:
|
||||
T m_iCount;
|
||||
};
|
||||
|
||||
template<class CCounter> class CLocalCounter
|
||||
{
|
||||
public:
|
||||
CLocalCounter(CCounter& obj) : m_counter(obj) {m_counter.Increment();}
|
||||
~CLocalCounter() {m_counter.Decrement();}
|
||||
private:
|
||||
CCounter& m_counter;
|
||||
};
|
||||
|
||||
using CSafeCounter = CSafeCounterT<INT>;
|
||||
using CSafeBigCounter = CSafeCounterT<LONGLONG>;
|
||||
using CUnsafeCounter = CUnsafeCounterT<INT>;
|
||||
using CUnsafeBigCounter = CUnsafeCounterT<LONGLONG>;
|
||||
|
||||
using CLocalSafeCounter = CLocalCounter<CSafeCounter>;
|
||||
using CLocalSafeBigCounter = CLocalCounter<CSafeBigCounter>;
|
||||
using CLocalUnsafeCounter = CLocalCounter<CUnsafeCounter>;
|
||||
using CLocalUnsafeBigCounter = CLocalCounter<CUnsafeBigCounter>;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Event.h"
|
||||
|
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "Singleton.h"
|
||||
#include "FuncHelper.h"
|
||||
#include "PollHelper.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
class CPipeEvent
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
EVT_1 = 0x01,
|
||||
EVT_WAKEUP = EVT_1,
|
||||
EVT_EXIT = 0x7F,
|
||||
EVT_SIG_0 = 0x80,
|
||||
EVT_SIG_MAX = EVT_SIG_0 + _NSIG,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
int Wait(long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr)
|
||||
{
|
||||
pollfd pfd = {m_fd[0], POLLIN};
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
int rs = (int)::PollForSingleObject(pfd, lTimeout, pSigSet);
|
||||
|
||||
if(rs <= TIMEOUT) return rs;
|
||||
|
||||
if(pfd.revents & POLLIN)
|
||||
{
|
||||
BYTE v;
|
||||
|
||||
if(!Get(v))
|
||||
return HAS_ERROR;
|
||||
|
||||
if(v == 0)
|
||||
continue;
|
||||
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
if(pfd.revents & _POLL_ALL_ERROR_EVENTS)
|
||||
{
|
||||
::SetLastError(ERROR_BROKEN_PIPE);
|
||||
return HAS_ERROR;
|
||||
}
|
||||
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Set(BYTE bVal = EVT_WAKEUP)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(bVal != 0);
|
||||
|
||||
return VERIFY(write(m_fd[1], &bVal, 1) > 0);
|
||||
}
|
||||
|
||||
BOOL Get(BYTE& v)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
int rs = (int)read(m_fd[0], &v, 1);
|
||||
|
||||
if(IS_HAS_ERROR(rs))
|
||||
{
|
||||
if(IS_WOULDBLOCK_ERROR())
|
||||
v = 0;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
else if(rs == 0)
|
||||
{
|
||||
::SetLastError(ERROR_BROKEN_PIPE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Reset()
|
||||
{
|
||||
BYTE v;
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
if(!Get(v))
|
||||
return FALSE;
|
||||
|
||||
if(v == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL SetSignal(BYTE bSigVal)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(bSigVal > 0 && bSigVal < _NSIG);
|
||||
|
||||
return Set((BYTE)(EVT_SIG_0 + bSigVal));
|
||||
}
|
||||
|
||||
static inline BYTE ToSignalValue(int iWaitResult)
|
||||
{
|
||||
if(iWaitResult <= EVT_SIG_0 || iWaitResult >= EVT_SIG_MAX)
|
||||
return 0;
|
||||
|
||||
return (BYTE)(iWaitResult - EVT_SIG_0);
|
||||
}
|
||||
|
||||
BOOL IsValid() {return IS_VALID_FD(m_fd[0]) && IS_VALID_FD(m_fd[1]);}
|
||||
|
||||
operator FD () {return m_fd[0];}
|
||||
FD GetFD () {return m_fd[0];}
|
||||
|
||||
public:
|
||||
CPipeEvent()
|
||||
{
|
||||
VERIFY_IS_NO_ERROR(pipe2(m_fd, O_NONBLOCK | O_CLOEXEC));
|
||||
VERIFY(::fcntl_SETFL(m_fd[0], O_NOATIME));
|
||||
VERIFY(::fcntl_SETFL(m_fd[1], O_NOATIME));
|
||||
}
|
||||
|
||||
~CPipeEvent()
|
||||
{
|
||||
close(m_fd[1]);
|
||||
close(m_fd[0]);
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CPipeEvent)
|
||||
|
||||
private:
|
||||
FD m_fd[2] = {INVALID_FD, INVALID_FD};
|
||||
};
|
||||
|
||||
template<bool is_sem_mode = false> class CCounterEvent
|
||||
{
|
||||
public:
|
||||
|
||||
eventfd_t Wait(long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr)
|
||||
{
|
||||
pollfd pfd = {m_evt, POLLIN};
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
long rs = ::PollForSingleObject(pfd, lTimeout, pSigSet);
|
||||
|
||||
if(rs <= TIMEOUT) return (eventfd_t)rs;
|
||||
|
||||
if(pfd.revents & POLLIN)
|
||||
{
|
||||
eventfd_t v;
|
||||
|
||||
if(!Get(v))
|
||||
return HAS_ERROR;
|
||||
|
||||
if(v == 0)
|
||||
continue;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
if(pfd.revents & _POLL_ALL_ERROR_EVENTS)
|
||||
{
|
||||
::SetLastError(ERROR_HANDLES_CLOSED);
|
||||
return HAS_ERROR;
|
||||
}
|
||||
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Set(eventfd_t val = 1)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(val > 0);
|
||||
|
||||
int rs = eventfd_write(m_evt, val);
|
||||
return VERIFY_IS_NO_ERROR(rs);
|
||||
}
|
||||
|
||||
BOOL Get(eventfd_t& v)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
if(IS_HAS_ERROR(eventfd_read(m_evt, &v)))
|
||||
{
|
||||
if(IS_WOULDBLOCK_ERROR())
|
||||
v = 0;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Reset()
|
||||
{
|
||||
eventfd_t v;
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
if(!Get(v))
|
||||
return FALSE;
|
||||
|
||||
if(v == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL IsValid() {return IS_VALID_FD(m_evt);}
|
||||
|
||||
operator FD () {return m_evt;}
|
||||
FD GetFD () {return m_evt;}
|
||||
|
||||
public:
|
||||
CCounterEvent(int iInitCount = 0)
|
||||
{
|
||||
int iFlag = EFD_NONBLOCK | EFD_CLOEXEC | (is_sem_mode ? EFD_SEMAPHORE : 0);
|
||||
m_evt = eventfd(iInitCount, iFlag);
|
||||
|
||||
VERIFY(IsValid());
|
||||
}
|
||||
|
||||
~CCounterEvent()
|
||||
{
|
||||
if(IsValid()) close(m_evt);
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CCounterEvent)
|
||||
|
||||
private:
|
||||
FD m_evt = INVALID_FD;
|
||||
};
|
||||
|
||||
using CSimpleEvent = CCounterEvent<false>;
|
||||
using CSemaphoreEvent = CCounterEvent<true>;
|
||||
using CEvt = CSimpleEvent;
|
||||
|
||||
class CTimerEvent
|
||||
{
|
||||
public:
|
||||
|
||||
ULLONG Wait(long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr)
|
||||
{
|
||||
pollfd pfd = {m_tmr, POLLIN};
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
SSIZE_T rs = ::PollForSingleObject(pfd, lTimeout, pSigSet);
|
||||
|
||||
if(rs <= TIMEOUT) return (ULLONG)rs;
|
||||
|
||||
if(pfd.revents & POLLIN)
|
||||
{
|
||||
BOOL ok;
|
||||
ULLONG v;
|
||||
|
||||
if(!Get(v, ok))
|
||||
return HAS_ERROR;
|
||||
|
||||
if(!ok)
|
||||
continue;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
if(pfd.revents & _POLL_ALL_ERROR_EVENTS)
|
||||
{
|
||||
::SetLastError(ERROR_HANDLES_CLOSED);
|
||||
return HAS_ERROR;
|
||||
}
|
||||
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Set(LLONG llInterval, LLONG llStart = -1)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(llInterval >= 0L);
|
||||
|
||||
if(llStart < 0)
|
||||
llStart = llInterval;
|
||||
|
||||
itimerspec its;
|
||||
|
||||
::MillisecondToTimespec(llStart, its.it_value);
|
||||
::MillisecondToTimespec(llInterval, its.it_interval);
|
||||
|
||||
int rs = timerfd_settime(m_tmr, 0, &its, nullptr);
|
||||
return VERIFY_IS_NO_ERROR(rs);
|
||||
}
|
||||
|
||||
BOOL Get(ULLONG &v, BOOL& ok)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
return ::ReadTimer(m_tmr, &v, &ok);
|
||||
}
|
||||
|
||||
BOOL Reset()
|
||||
{
|
||||
BOOL ok;
|
||||
ULLONG v;
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
if(!Get(v, ok))
|
||||
return FALSE;
|
||||
|
||||
if(!ok)
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL GetTime(LLONG& lStart, LLONG& lInterval)
|
||||
{
|
||||
itimerspec its;
|
||||
|
||||
if(IS_HAS_ERROR(timerfd_gettime(m_tmr, &its)))
|
||||
return FALSE;
|
||||
|
||||
lStart = ::TimespecToMillisecond(its.it_value);
|
||||
lInterval = ::TimespecToMillisecond(its.it_interval);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL IsValid() {return IS_VALID_FD(m_tmr);}
|
||||
|
||||
operator FD () {return m_tmr;}
|
||||
FD GetFD () {return m_tmr;}
|
||||
|
||||
public:
|
||||
CTimerEvent(bool bRealTimeClock = FALSE)
|
||||
{
|
||||
int iCID = (bRealTimeClock ? CLOCK_REALTIME : CLOCK_MONOTONIC);
|
||||
m_tmr = timerfd_create(iCID, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
|
||||
VERIFY(IsValid());
|
||||
}
|
||||
|
||||
~CTimerEvent()
|
||||
{
|
||||
if(IsValid()) close(m_tmr);
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CTimerEvent)
|
||||
|
||||
private:
|
||||
FD m_tmr = INVALID_FD;
|
||||
};
|
||||
|
||||
class CSignalEvent
|
||||
{
|
||||
public:
|
||||
|
||||
int Wait(signalfd_siginfo& sgInfo, long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr)
|
||||
{
|
||||
m_dwTID = SELF_THREAD_ID;
|
||||
pollfd pfd = {m_sig, POLLIN};
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
long rs = ::PollForSingleObject(pfd, lTimeout, pSigSet);
|
||||
|
||||
if(rs <= TIMEOUT) return (int)rs;
|
||||
|
||||
if(pfd.revents & POLLIN)
|
||||
{
|
||||
BOOL ok;
|
||||
|
||||
if(!Get(sgInfo, ok))
|
||||
return HAS_ERROR;
|
||||
|
||||
if(!ok)
|
||||
continue;
|
||||
|
||||
return sgInfo.ssi_signo;
|
||||
}
|
||||
|
||||
if(pfd.revents & _POLL_ALL_ERROR_EVENTS)
|
||||
{
|
||||
::SetLastError(ERROR_HANDLES_CLOSED);
|
||||
return HAS_ERROR;
|
||||
}
|
||||
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
m_dwTID = 0;
|
||||
}
|
||||
|
||||
BOOL Set(int iSig, const sigval sgVal, THR_ID dwTID = 0)
|
||||
{
|
||||
if(dwTID == 0)
|
||||
{
|
||||
dwTID = m_dwTID;
|
||||
|
||||
if(dwTID == 0)
|
||||
{
|
||||
::SetLastError(ERROR_INVALID_STATE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
int rs = pthread_sigqueue(dwTID, iSig, sgVal);
|
||||
#else
|
||||
int rs = pthread_kill(dwTID, iSig);
|
||||
#endif
|
||||
|
||||
return IS_NO_ERROR(rs);
|
||||
}
|
||||
|
||||
BOOL Get(signalfd_siginfo& v, BOOL& ok)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
static const SSIZE_T SIZE = sizeof(signalfd_siginfo);
|
||||
|
||||
if(read(m_sig, &v, SIZE) == SIZE)
|
||||
ok = TRUE;
|
||||
{
|
||||
if(IS_WOULDBLOCK_ERROR())
|
||||
ok = FALSE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
BOOL Reset()
|
||||
{
|
||||
BOOL ok;
|
||||
signalfd_siginfo v;
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
if(!Get(v, ok))
|
||||
return FALSE;
|
||||
|
||||
if(!ok)
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Mask(const sigset_t* pSigMask)
|
||||
{
|
||||
if(!pSigMask)
|
||||
{
|
||||
if(!IsValid()) return TRUE;
|
||||
return IS_NO_ERROR(close(m_sig));
|
||||
}
|
||||
|
||||
FD sig = signalfd(m_sig, pSigMask, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
|
||||
if(IS_VALID_FD(sig))
|
||||
{
|
||||
m_sig = sig;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL IsValid() {return IS_VALID_FD(m_sig);}
|
||||
|
||||
operator FD () {return m_sig;}
|
||||
FD GetFD () {return m_sig;}
|
||||
|
||||
public:
|
||||
CSignalEvent(const sigset_t* pSigMask = nullptr)
|
||||
{
|
||||
if(pSigMask) VERIFY(Mask(pSigMask));
|
||||
}
|
||||
|
||||
~CSignalEvent()
|
||||
{
|
||||
if(IsValid()) close(m_sig);
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CSignalEvent)
|
||||
|
||||
private:
|
||||
FD m_sig = INVALID_FD;
|
||||
THR_ID m_dwTID = 0;
|
||||
};
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FileHelper.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
CString GetCurrentDirectory()
|
||||
{
|
||||
char szPath[MAX_PATH];
|
||||
|
||||
if(getcwd(szPath, sizeof(szPath) - 1) == nullptr)
|
||||
szPath[0] = 0;
|
||||
|
||||
return szPath;
|
||||
}
|
||||
|
||||
CString GetModuleFileName(pid_t pid)
|
||||
{
|
||||
if(pid == 0)
|
||||
pid = SELF_PROCESS_ID;
|
||||
|
||||
char szLink[MAX_PATH];
|
||||
char szPath[MAX_PATH];
|
||||
|
||||
sprintf(szLink, "/proc/%d/exe", pid);
|
||||
|
||||
SSIZE_T rs = readlink(szLink, szPath, sizeof(szPath) - 1);
|
||||
|
||||
if(rs < 0) rs = 0;
|
||||
szPath[rs] = 0;
|
||||
|
||||
return szPath;
|
||||
}
|
||||
|
||||
BOOL SetCurrentPathToModulePath(pid_t pid)
|
||||
{
|
||||
CString strPath = GetModuleFileName(pid);
|
||||
|
||||
if(strPath.IsEmpty())
|
||||
return FALSE;
|
||||
|
||||
CString::size_type pos = strPath.rfind('/');
|
||||
|
||||
if(pos == CString::npos)
|
||||
return FALSE;
|
||||
|
||||
return IS_NO_ERROR(chdir(strPath.substr(0, pos + 1)));
|
||||
}
|
||||
|
||||
BOOL CFile::Open(LPCTSTR lpszFilePath, int iFlag, mode_t iMode)
|
||||
{
|
||||
CHECK_ERROR(!IsValid(), ERROR_INVALID_STATE);
|
||||
|
||||
m_fd = open(lpszFilePath, iFlag, iMode);
|
||||
|
||||
return IS_VALID_FD(m_fd);
|
||||
}
|
||||
|
||||
BOOL CFile::Close()
|
||||
{
|
||||
CHECK_ERROR(IsValid(), ERROR_INVALID_STATE);
|
||||
|
||||
if(IS_NO_ERROR(close(m_fd)))
|
||||
{
|
||||
m_fd = INVALID_FD;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CFile::Stat(struct stat& st)
|
||||
{
|
||||
CHECK_ERROR_INVOKE(fstat(m_fd, &st));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CFile::GetSize(SIZE_T& dwSize)
|
||||
{
|
||||
struct stat st;
|
||||
CHECK_IS_OK(Stat(st));
|
||||
|
||||
dwSize = st.st_size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CFile::IsDirectory()
|
||||
{
|
||||
struct stat st;
|
||||
CHECK_IS_OK(Stat(st));
|
||||
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
BOOL CFile::IsFile()
|
||||
{
|
||||
struct stat st;
|
||||
CHECK_IS_OK(Stat(st));
|
||||
|
||||
return S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
BOOL CFile::IsExist(LPCTSTR lpszFilePath)
|
||||
{
|
||||
return IS_NO_ERROR(access(lpszFilePath, F_OK));
|
||||
}
|
||||
|
||||
BOOL CFile::IsDirectory(LPCTSTR lpszFilePath)
|
||||
{
|
||||
struct stat st;
|
||||
CHECK_ERROR_INVOKE(stat(lpszFilePath, &st));
|
||||
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
BOOL CFile::IsFile(LPCTSTR lpszFilePath)
|
||||
{
|
||||
struct stat st;
|
||||
CHECK_ERROR_INVOKE(stat(lpszFilePath, &st));
|
||||
|
||||
return S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
BOOL CFile::IsLink(LPCTSTR lpszFilePath)
|
||||
{
|
||||
struct stat st;
|
||||
CHECK_ERROR_INVOKE(lstat(lpszFilePath, &st));
|
||||
|
||||
return S_ISLNK(st.st_mode);
|
||||
}
|
||||
|
||||
BOOL CFileMapping::Map(LPCTSTR lpszFilePath, SIZE_T dwSize, SIZE_T dwOffset, int iProtected, int iFlag)
|
||||
{
|
||||
CHECK_ERROR(!IsValid(), ERROR_INVALID_STATE);
|
||||
|
||||
FD fd = INVALID_FD;
|
||||
|
||||
if(lpszFilePath != nullptr)
|
||||
{
|
||||
int iFileFlag = O_RDONLY;
|
||||
|
||||
if(iProtected & PROT_WRITE)
|
||||
{
|
||||
if(iProtected & PROT_READ)
|
||||
iFileFlag = O_RDWR;
|
||||
else
|
||||
iFileFlag = O_WRONLY;
|
||||
}
|
||||
|
||||
fd = open(lpszFilePath, iFileFlag);
|
||||
CHECK_ERROR_FD(fd);
|
||||
}
|
||||
|
||||
BOOL isOK = Map(fd, dwSize, dwOffset, iProtected, iFlag);
|
||||
|
||||
if(IS_VALID_FD(fd)) EXECUTE_RESTORE_ERROR(close(fd));
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CFileMapping::Map(FD fd, SIZE_T dwSize, SIZE_T dwOffset, int iProtected, int iFlag)
|
||||
{
|
||||
CHECK_ERROR(!IsValid(), ERROR_INVALID_STATE);
|
||||
|
||||
if(IS_INVALID_FD(fd))
|
||||
{
|
||||
CHECK_EINVAL((iFlag & MAP_ANONYMOUS) && (dwSize > 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EINVAL((iFlag & MAP_ANONYMOUS) == 0);
|
||||
|
||||
struct stat st;
|
||||
CHECK_ERROR_INVOKE(fstat(fd, &st));
|
||||
|
||||
CHECK_ERROR(S_ISREG(st.st_mode), ERROR_BAD_FILE_TYPE);
|
||||
|
||||
if(dwSize == 0)
|
||||
dwSize = st.st_size;
|
||||
}
|
||||
|
||||
m_pv = (PBYTE)mmap(nullptr, dwSize, iProtected, iFlag, fd, dwOffset);
|
||||
|
||||
if(IsValid())
|
||||
{
|
||||
m_dwSize = dwSize;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CFileMapping::Unmap()
|
||||
{
|
||||
CHECK_ERROR(IsValid(), ERROR_INVALID_STATE);
|
||||
|
||||
if(IS_NO_ERROR(munmap(m_pv, m_dwSize)))
|
||||
{
|
||||
m_pv = INVALID_MAP_ADDR;
|
||||
m_dwSize = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CFileMapping::MSync(int iFlag, SIZE_T dwSize)
|
||||
{
|
||||
CHECK_ERROR(IsValid(), ERROR_INVALID_STATE);
|
||||
|
||||
if(dwSize == 0) dwSize = m_dwSize;
|
||||
|
||||
return IS_NO_ERROR(msync(m_pv, dwSize, iFlag));
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FuncHelper.h"
|
||||
#include "StringT.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define INVALID_MAP_ADDR ((PBYTE)(MAP_FAILED))
|
||||
|
||||
CString GetCurrentDirectory();
|
||||
CString GetModuleFileName(pid_t pid = 0);
|
||||
BOOL SetCurrentPathToModulePath(pid_t pid = 0);
|
||||
|
||||
class CFile
|
||||
{
|
||||
public:
|
||||
BOOL Open(LPCTSTR lpszFilePath, int iFlag, mode_t iMode = 0);
|
||||
BOOL Close();
|
||||
BOOL Stat(struct stat& st);
|
||||
BOOL GetSize(SIZE_T& dwSize);
|
||||
|
||||
SSIZE_T Read(PVOID pBuffer, SIZE_T dwCount)
|
||||
{return read(m_fd, pBuffer, dwCount);}
|
||||
SSIZE_T Write(PVOID pBuffer, SIZE_T dwCount)
|
||||
{return write(m_fd, pBuffer, dwCount);}
|
||||
SSIZE_T PRead(PVOID pBuffer, SIZE_T dwCount, SIZE_T dwOffset)
|
||||
{return pread(m_fd, pBuffer, dwCount, dwOffset);}
|
||||
SSIZE_T PWrite(PVOID pBuffer, SIZE_T dwCount, SIZE_T dwOffset)
|
||||
{return pwrite(m_fd, pBuffer, dwCount, dwOffset);}
|
||||
SSIZE_T ReadV(const iovec* pVec, int iVecCount)
|
||||
{return readv(m_fd, pVec, iVecCount);}
|
||||
SSIZE_T WriteV(const iovec* pVec, int iVecCount)
|
||||
{return writev(m_fd, pVec, iVecCount);}
|
||||
SSIZE_T Seek(SSIZE_T lOffset, int iWhence)
|
||||
{return lseek(m_fd, lOffset, iWhence);}
|
||||
|
||||
BOOL IsValid() {return IS_VALID_FD(m_fd);}
|
||||
operator FD () {return m_fd;}
|
||||
|
||||
BOOL IsExist() {return IsValid();}
|
||||
|
||||
BOOL IsDirectory();
|
||||
BOOL IsFile();
|
||||
|
||||
static BOOL IsExist(LPCTSTR lpszFilePath);
|
||||
static BOOL IsDirectory(LPCTSTR lpszFilePath);
|
||||
static BOOL IsFile(LPCTSTR lpszFilePath);
|
||||
static BOOL IsLink(LPCTSTR lpszFilePath);
|
||||
|
||||
public:
|
||||
CFile(LPCTSTR lpszFilePath = nullptr, int iFlag = O_RDONLY, mode_t iMode = 0)
|
||||
: m_fd(INVALID_FD)
|
||||
{
|
||||
if(lpszFilePath != nullptr)
|
||||
Open(lpszFilePath, iFlag, iMode);
|
||||
}
|
||||
|
||||
~CFile()
|
||||
{
|
||||
if(IsValid())
|
||||
Close();
|
||||
}
|
||||
|
||||
private:
|
||||
FD m_fd;
|
||||
};
|
||||
|
||||
class CFileMapping
|
||||
{
|
||||
public:
|
||||
BOOL Map(LPCTSTR lpszFilePath, SIZE_T dwSize = 0, SIZE_T dwOffset = 0, int iProtected = PROT_READ, int iFlag = MAP_PRIVATE);
|
||||
BOOL Map(FD fd, SIZE_T dwSize = 0, SIZE_T dwOffset = 0, int iProtected = PROT_READ, int iFlag = MAP_PRIVATE);
|
||||
BOOL Unmap();
|
||||
BOOL MSync(int iFlag = MS_SYNC, SIZE_T dwSize = 0);
|
||||
|
||||
BOOL IsValid () {return m_pv != INVALID_MAP_ADDR;}
|
||||
SIZE_T Size () {return m_dwSize;}
|
||||
LPBYTE Ptr () {return m_pv;}
|
||||
operator LPBYTE () {return Ptr();}
|
||||
|
||||
public:
|
||||
CFileMapping()
|
||||
: m_pv(INVALID_MAP_ADDR)
|
||||
, m_dwSize(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CFileMapping()
|
||||
{
|
||||
if(IsValid())
|
||||
Unmap();
|
||||
}
|
||||
|
||||
private:
|
||||
PBYTE m_pv;
|
||||
SIZE_T m_dwSize;
|
||||
};
|
||||
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FuncHelper.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#include <sys/timeb.h>
|
||||
#include <execinfo.h>
|
||||
#ifdef __GNUC__
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
INT WaitFor(DWORD dwMillSecond, DWORD dwSecond, BOOL bExceptThreadInterrupted)
|
||||
{
|
||||
timeval tv {(time_t)dwSecond, (suseconds_t)(dwMillSecond * 1000)};
|
||||
|
||||
if(bExceptThreadInterrupted)
|
||||
return NO_EINTR_EXCEPT_THR_INTR_INT(select(0, nullptr, nullptr, nullptr, &tv));
|
||||
|
||||
return NO_EINTR_INT(select(0, nullptr, nullptr, nullptr, &tv));
|
||||
}
|
||||
|
||||
INT Sleep(DWORD dwMillSecond, DWORD dwSecond, BOOL bExceptThreadInterrupted)
|
||||
{
|
||||
timespec ts_req = {(time_t)dwSecond, (long)(dwMillSecond * 1000000)};
|
||||
timespec ts_rem = ts_req;
|
||||
INT rs = NO_ERROR;
|
||||
|
||||
while(IS_HAS_ERROR(rs = nanosleep(&ts_req, &ts_rem)))
|
||||
{
|
||||
if(!IS_INTR_ERROR())
|
||||
break;
|
||||
else
|
||||
{
|
||||
if(bExceptThreadInterrupted && ::IsThreadInterrupted())
|
||||
break;
|
||||
}
|
||||
|
||||
ts_req = ts_rem;
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
__time64_t _time64(time_t* ptm)
|
||||
{
|
||||
return (__time64_t)time(ptm);
|
||||
}
|
||||
|
||||
__time64_t _mkgmtime64(tm* ptm)
|
||||
{
|
||||
return (__time64_t)timegm(ptm);
|
||||
}
|
||||
|
||||
tm* _gmtime64(tm* ptm, __time64_t* pt)
|
||||
{
|
||||
time_t t = (time_t)(*pt);
|
||||
|
||||
return gmtime_r(&t, ptm);
|
||||
}
|
||||
|
||||
DWORD TimeGetTime()
|
||||
{
|
||||
return (DWORD)TimeGetTime64();
|
||||
}
|
||||
|
||||
ULLONG TimeGetTime64()
|
||||
{
|
||||
#if !defined(__ANDROID__)
|
||||
|
||||
timeb tb;
|
||||
|
||||
if(ftime(&tb) == NO_ERROR)
|
||||
return (((ULLONG)(tb.time)) * 1000 + tb.millitm);
|
||||
|
||||
#else
|
||||
|
||||
timespec ts;
|
||||
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) == NO_ERROR)
|
||||
return (((ULLONG)(ts.tv_sec)) * 1000 + ts.tv_nsec / 1000000);
|
||||
|
||||
#endif
|
||||
|
||||
return 0ull;
|
||||
}
|
||||
|
||||
DWORD GetTimeGap32(DWORD dwOriginal, DWORD dwCurrent)
|
||||
{
|
||||
if(dwCurrent == 0)
|
||||
dwCurrent = ::TimeGetTime();
|
||||
|
||||
return dwCurrent - dwOriginal;
|
||||
}
|
||||
|
||||
ULLONG GetTimeGap64(ULLONG ullOriginal, ULONGLONG ullCurrent)
|
||||
{
|
||||
if(ullCurrent == 0)
|
||||
ullCurrent = ::TimeGetTime64();
|
||||
|
||||
return ullCurrent - ullOriginal;
|
||||
}
|
||||
|
||||
LLONG TimevalToMillisecond(const timeval& tv)
|
||||
{
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
timeval& MillisecondToTimeval(LLONG ms, timeval& tv)
|
||||
{
|
||||
tv.tv_sec = (time_t)(ms / 1000);
|
||||
tv.tv_usec = (suseconds_t)((ms % 1000) * 1000);
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
LLONG TimespecToMillisecond(const timespec& ts)
|
||||
{
|
||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
timespec& MillisecondToTimespec(LLONG ms, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = (time_t)(ms / 1000);
|
||||
ts.tv_nsec = (long)((ms % 1000) * 1000000);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
timeval& GetFutureTimeval(LLONG ms, timeval& tv, struct timezone* ptz)
|
||||
{
|
||||
gettimeofday(&tv, ptz);
|
||||
|
||||
tv.tv_sec += (time_t)(ms / 1000);
|
||||
tv.tv_usec += (suseconds_t)((ms % 1000) * 1000);
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
timespec& GetFutureTimespec(LLONG ms, timespec& ts, clockid_t clkid)
|
||||
{
|
||||
clock_gettime(clkid, &ts);
|
||||
|
||||
ts.tv_sec += (time_t)(ms / 1000);
|
||||
ts.tv_nsec += (long)((ms % 1000) * 1000000);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
FD CreateTimer(LLONG llInterval, LLONG llStart, BOOL bRealTimeClock)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(llInterval >= 0L);
|
||||
|
||||
if(llStart < 0)
|
||||
llStart = llInterval;
|
||||
|
||||
FD fdTimer = timerfd_create((bRealTimeClock ? CLOCK_REALTIME : CLOCK_MONOTONIC), TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
|
||||
itimerspec its;
|
||||
|
||||
::MillisecondToTimespec(llStart, its.it_value);
|
||||
::MillisecondToTimespec(llInterval, its.it_interval);
|
||||
|
||||
if(IS_HAS_ERROR(timerfd_settime(fdTimer, 0, &its, nullptr)))
|
||||
{
|
||||
close(fdTimer);
|
||||
fdTimer = INVALID_FD;
|
||||
}
|
||||
|
||||
return fdTimer;
|
||||
}
|
||||
|
||||
BOOL ReadTimer(FD tmr, ULLONG* pVal, BOOL* pRs)
|
||||
{
|
||||
static const SSIZE_T SIZE = sizeof(ULLONG);
|
||||
|
||||
if(pVal == nullptr)
|
||||
pVal = CreateLocalObject(ULLONG);
|
||||
if(pRs == nullptr)
|
||||
pRs = CreateLocalObject(BOOL);
|
||||
|
||||
if(read(tmr, pVal, SIZE) == SIZE)
|
||||
*pRs = TRUE;
|
||||
else
|
||||
{
|
||||
*pRs = FALSE;
|
||||
|
||||
if(!IS_WOULDBLOCK_ERROR())
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL fcntl_SETFL(FD fd, INT fl, BOOL bSet)
|
||||
{
|
||||
int val = fcntl(fd, F_GETFL);
|
||||
|
||||
if(IS_HAS_ERROR(val))
|
||||
return FALSE;
|
||||
|
||||
val = bSet ? (val | fl) : (val & (~fl));
|
||||
|
||||
return IS_NO_ERROR(fcntl(fd, F_SETFL , val));
|
||||
}
|
||||
|
||||
void PrintStackTrace()
|
||||
{
|
||||
#if !defined(__ANDROID__)
|
||||
|
||||
const int MAX_SIZE = 51;
|
||||
void* arr[MAX_SIZE];
|
||||
|
||||
int size = backtrace(arr, MAX_SIZE);
|
||||
char** messages = backtrace_symbols(arr, size);
|
||||
|
||||
for(int i = 1; i < size && messages != nullptr; i++)
|
||||
{
|
||||
char* mangled_name = nullptr;
|
||||
char* offset_end = nullptr;
|
||||
const char* offset_begin = nullptr;
|
||||
|
||||
for(char* p = messages[i]; *p; ++p)
|
||||
{
|
||||
if(*p == '(')
|
||||
{
|
||||
mangled_name = p;
|
||||
}
|
||||
else if(*p == '+')
|
||||
{
|
||||
offset_begin = p;
|
||||
}
|
||||
else if(*p == ')')
|
||||
{
|
||||
offset_end = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(mangled_name && offset_end && mangled_name < offset_end)
|
||||
{
|
||||
*mangled_name++ = 0;
|
||||
*offset_end++ = 0;
|
||||
|
||||
if(offset_begin == nullptr)
|
||||
offset_begin = "";
|
||||
else
|
||||
*(char*)offset_begin++ = 0;
|
||||
|
||||
while(*offset_end == ' ')
|
||||
++offset_end;
|
||||
|
||||
#ifdef __GNUC__
|
||||
int status;
|
||||
char* real_name = abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status);
|
||||
|
||||
if(status == 0)
|
||||
FPRINTLN(stderr, " -> [%02d] %s : (%s+%s) %s", i, messages[i], real_name, offset_begin, offset_end);
|
||||
else
|
||||
FPRINTLN(stderr, " -> [%02d] %s : (%s+%s) %s", i, messages[i], mangled_name, offset_begin, offset_end);
|
||||
|
||||
if(real_name != nullptr)
|
||||
free(real_name);
|
||||
#else
|
||||
FPRINTLN(stderr, " -> [%02d] %s : (%s+%s) %s", i, messages[i], mangled_name, offset_begin, offset_end);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FPRINTLN(stderr, " -> [%02d] %s", i, messages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(messages);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void __EXIT_FN_(void (*fn)(int), LPCSTR lpszFnName, int* lpiExitCode, int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
|
||||
{
|
||||
if(iErrno >= 0)
|
||||
SetLastError(iErrno);
|
||||
else
|
||||
iErrno = GetLastError();
|
||||
|
||||
if(!lpszTitle)
|
||||
{
|
||||
lpszTitle = CreateLocalObjects(char, 64);
|
||||
|
||||
if(lpiExitCode)
|
||||
sprintf((LPSTR)lpszTitle, "(#%d, 0x%zX) > %s(%d) [%d]", SELF_PROCESS_ID, (SIZE_T)SELF_THREAD_ID, lpszFnName, *lpiExitCode, iErrno);
|
||||
else
|
||||
sprintf((LPSTR)lpszTitle, "(#%d, 0x%zX) > %s() [%d]", SELF_PROCESS_ID, (SIZE_T)SELF_THREAD_ID, lpszFnName, iErrno);
|
||||
}
|
||||
|
||||
if(lpszFile && iLine > 0)
|
||||
FPRINTLN(stderr, "%s : %s\n => %s (%d) : %s", lpszTitle, strerror(iErrno), lpszFile, iLine, lpszFunc ? lpszFunc : "");
|
||||
else
|
||||
FPRINTLN(stderr, "%s : %s", lpszTitle, strerror(iErrno));
|
||||
|
||||
if(lpiExitCode)
|
||||
fn(*lpiExitCode);
|
||||
else
|
||||
((void (*)())fn)();
|
||||
}
|
||||
|
||||
void EXIT(int iExitCode, int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
|
||||
{
|
||||
__EXIT_FN_(exit, "exit", &iExitCode, iErrno, lpszFile, iLine, lpszFunc, lpszTitle);
|
||||
}
|
||||
|
||||
void _EXIT(int iExitCode, int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
|
||||
{
|
||||
__EXIT_FN_(_exit, "_exit", &iExitCode, iErrno, lpszFile, iLine, lpszFunc, lpszTitle);
|
||||
}
|
||||
|
||||
void ABORT(int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
|
||||
{
|
||||
__EXIT_FN_((void (*)(int))abort, "abort", nullptr, iErrno, lpszFile, iLine, lpszFunc, lpszTitle);
|
||||
}
|
||||
|
||||
BOOL SetSequenceThreadName(THR_ID tid, LPCTSTR lpszPrefix, volatile UINT& vuiSeq)
|
||||
{
|
||||
UINT uiSequence = InterlockedIncrement(&vuiSeq);
|
||||
return SetThreadName(tid, lpszPrefix, uiSequence);
|
||||
}
|
||||
|
||||
BOOL SetThreadName(THR_ID tid, LPCTSTR lpszPrefix, UINT uiSequence)
|
||||
{
|
||||
int iMaxSeqLength = (int)(MAX_THREAD_NAME_LENGTH - lstrlen(lpszPrefix));
|
||||
|
||||
ASSERT(iMaxSeqLength > 0);
|
||||
|
||||
if(iMaxSeqLength <= 0)
|
||||
{
|
||||
::SetLastError(ERROR_OUT_OF_RANGE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ULONGLONG uiDiv = 1;
|
||||
|
||||
for(int i = 0; i < iMaxSeqLength; i++)
|
||||
uiDiv *= 10;
|
||||
|
||||
uiSequence = (UINT)(uiSequence % uiDiv);
|
||||
|
||||
CString strName;
|
||||
strName.Format(_T("%s%u"), lpszPrefix, uiSequence);
|
||||
|
||||
return SetThreadName(tid, strName);
|
||||
}
|
||||
|
||||
BOOL SetThreadName(THR_ID tid, LPCTSTR lpszName)
|
||||
{
|
||||
ASSERT(lstrlen(lpszName) <= MAX_THREAD_NAME_LENGTH);
|
||||
|
||||
if(tid == 0)
|
||||
tid = SELF_THREAD_ID;
|
||||
|
||||
int rs = pthread_setname_np(tid, CT2A(lpszName));
|
||||
|
||||
CHECK_ERROR_CODE(rs)
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "../../include/hpsocket/GlobalErrno.h"
|
||||
#include "SysHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <alloca.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
typedef atomic_ulong atomic_tid;
|
||||
|
||||
#define FPRINTLN(fd, fmt, ...) fprintf((fd), fmt "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
typedef atomic_long atomic_tid;
|
||||
|
||||
#if defined(stdout)
|
||||
#undef stdout
|
||||
#endif
|
||||
|
||||
#if defined(stderr)
|
||||
#undef stderr
|
||||
#endif
|
||||
|
||||
#define stdout nullptr
|
||||
#define stderr nullptr
|
||||
|
||||
#define FPRINTLN(fd, fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define PRINTLN(fmt, ...) FPRINTLN(stdout, fmt, ##__VA_ARGS__)
|
||||
|
||||
#if defined(DEBUG) && defined(DEBUG_TRACE)
|
||||
#define TRACE(fmt, ...) PRINTLN("> TRC (0x%zX, %d) " fmt, (SIZE_T)SELF_THREAD_ID, SELF_NATIVE_THREAD_ID, ##__VA_ARGS__)
|
||||
#define ASSERT(expr) ((expr) ? TRUE : (::PrintStackTrace(), assert(FALSE), FALSE))
|
||||
#else
|
||||
#define TRACE(fmt, ...)
|
||||
#define ASSERT(expr) assert(expr)
|
||||
#endif
|
||||
|
||||
#define VERIFY(expr) ((expr) ? TRUE : (::PrintStackTrace(), ERROR_ABORT2(ERROR_VERIFY_CHECK), FALSE))
|
||||
#define ASSERT_IS_NO_ERROR(expr) ASSERT(IS_NO_ERROR(expr))
|
||||
#define VERIFY_IS_NO_ERROR(expr) VERIFY(IS_NO_ERROR(expr))
|
||||
#define ENSURE(expr) VERIFY(expr)
|
||||
#define ENSURE_IS_NO_ERROR(expr) VERIFY_IS_NO_ERROR(expr)
|
||||
|
||||
#define TEMP_FAILURE_RETRY_INT(exp) ((int)TEMP_FAILURE_RETRY(exp))
|
||||
|
||||
#define NO_EINTR TEMP_FAILURE_RETRY
|
||||
#define NO_EINTR_INT TEMP_FAILURE_RETRY_INT
|
||||
|
||||
#define CHECK_IS_OK(expr) {if(IS_NOT_OK(expr)) return FALSE;}
|
||||
#define CHECK_ERROR_FD(fd) {if(IS_INVALID_FD(fd)) return FALSE;}
|
||||
#define CHECK_ERROR_INVOKE(expr) {if(!IS_NO_ERROR(expr)) return FALSE;}
|
||||
#define CHECK_ERROR_CODE(rs) {if(!IS_NO_ERROR(rs)) {::SetLastError(rs); return FALSE;}}
|
||||
#define CHECK_ERROR(expr, code) {if(!(expr)) {::SetLastError(code); return FALSE;}}
|
||||
#define CHECK_EINVAL(expr) CHECK_ERROR(expr, ERROR_INVALID_PARAMETER)
|
||||
#define ASSERT_CHECK_ERROR(expr, code) {ASSERT(expr); CHECK_ERROR(expr, code);}
|
||||
#define ASSERT_CHECK_EINVAL(expr) {ASSERT(expr); CHECK_EINVAL(expr);}
|
||||
|
||||
#define SUCCEEDED(rs) IS_NO_ERROR(rs)
|
||||
#define FAILED(rs) (!SUCCEEDED(rs))
|
||||
#define IS_OK(rs) ((BOOL)(rs))
|
||||
#define IS_NOT_OK(rs) (!IS_OK(rs))
|
||||
|
||||
#define IS_ERROR(code) (::GetLastError() == (code))
|
||||
#define CONTINUE_IF_ERROR(code) {if(IS_ERROR(code)) continue;}
|
||||
#define BREAK_IF_ERROR(code) {if(IS_ERROR(code)) break;}
|
||||
|
||||
#define IS_WOULDBLOCK_ERROR() IS_ERROR(ERROR_WOULDBLOCK)
|
||||
#define CONTINUE_WOULDBLOCK_ERROR() CONTINUE_IF_ERROR(ERROR_WOULDBLOCK)
|
||||
#define BREAK_WOULDBLOCK_ERROR() BREAK_IF_ERROR(ERROR_WOULDBLOCK)
|
||||
#define IS_IO_PENDING_ERROR() IS_ERROR(ERROR_IO_PENDING)
|
||||
#define CONTINUE_IO_PENDING_ERROR() CONTINUE_IF_ERROR(ERROR_IO_PENDING)
|
||||
#define BREAK_IO_PENDING_ERROR() BREAK_IF_ERROR(ERROR_IO_PENDING)
|
||||
#define IS_INTR_ERROR() IS_ERROR(ERROR_INTR)
|
||||
#define CONTINUE_INTR_ERROR() CONTINUE_IF_ERROR(ERROR_INTR)
|
||||
#define BREAK_INTR_ERROR() BREAK_IF_ERROR(ERROR_INTR)
|
||||
|
||||
#define EqualMemory(dest, src, len) (!memcmp((dest), (src), (len)))
|
||||
#define MoveMemory(dest, src, len) memmove((dest), (src), (len))
|
||||
#define CopyMemory(dest, src, len) memcpy((dest), (src), (len))
|
||||
#define FillMemory(dest, len, ch) memset((dest), (ch), (len))
|
||||
#define ZeroMemory(dest, len) FillMemory((dest), (len), 0)
|
||||
#define ZeroObject(obj) ZeroMemory((&(obj)), sizeof(obj))
|
||||
|
||||
inline void SetLastError(int code) {errno = code;}
|
||||
inline int GetLastError() {return errno;}
|
||||
inline LPCSTR GetErrorStr(int code) {return strerror(code);}
|
||||
inline LPCSTR GetLastErrorStr() {return GetErrorStr(errno);}
|
||||
inline void PrintError(LPCSTR subject) {perror(subject);}
|
||||
|
||||
#define EXECUTE_RESET_ERROR(expr) (::SetLastError(0), (expr))
|
||||
#define EXECUTE_RESTORE_ERROR(expr) {int __le_ = ::GetLastError(); (expr); ::SetLastError(__le_);}
|
||||
#define EXECUTE_RESTORE_ERROR_RT(T, expr)\
|
||||
({int __le_ = ::GetLastError(); T __rs_ = (expr); ::SetLastError(__le_); __rs_;})
|
||||
#define ENSURE_ERROR(def_code) ({int __le_ = ::GetLastError(); if(__le_ == NO_ERROR) __le_ = (def_code); __le_;})
|
||||
#define ENSURE_ERROR_CANCELLED ENSURE_ERROR(ERROR_CANCELLED)
|
||||
#define TRIGGER(expr) EXECUTE_RESET_ERROR((expr))
|
||||
|
||||
#define _msize(p) malloc_usable_size(p)
|
||||
#define CreateLocalObjects(T, n) ((T*)alloca(sizeof(T) * (n)))
|
||||
#define CreateLocalObject(T) CreateLocalObjects(T, 1)
|
||||
#define CallocObjects(T, n) ((T*)calloc((n), sizeof(T)))
|
||||
|
||||
#define MALLOC(T, n) ((T*)malloc(sizeof(T) * (n)))
|
||||
#define REALLOC(T, p, n) ((T*)realloc((PVOID)(p), sizeof(T) * (n)))
|
||||
#define FREE(p) free((PVOID)(p))
|
||||
#define CALLOC(n, s) calloc((n), (s))
|
||||
|
||||
#define InterlockedExchangeAdd(p, n) __atomic_fetch_add((p), (n), memory_order_seq_cst)
|
||||
#define InterlockedExchangeSub(p, n) __atomic_fetch_sub((p), (n), memory_order_seq_cst)
|
||||
#define InterlockedAdd(p, n) __atomic_add_fetch((p), (n), memory_order_seq_cst)
|
||||
#define InterlockedSub(p, n) __atomic_sub_fetch((p), (n), memory_order_seq_cst)
|
||||
#define InterlockedIncrement(p) InterlockedAdd((p), 1)
|
||||
#define InterlockedDecrement(p) InterlockedSub((p), 1)
|
||||
|
||||
#define ERROR_EXIT2(code, err) EXIT((code), (err), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define ERROR__EXIT2(code, err) _EXIT((code), (err), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define ERROR_ABORT2(err) ABORT((err), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
#define ERROR_EXIT(code) ERROR_EXIT2((code), -1)
|
||||
#define ERROR__EXIT(code) ERROR__EXIT2((code), -1)
|
||||
#define ERROR_ABORT() ERROR_ABORT2(-1)
|
||||
|
||||
#define IS_VALID_FD(fd) ((fd) != INVALID_FD)
|
||||
#define IS_INVALID_FD(fd) (!IS_VALID_FD(fd))
|
||||
|
||||
#define IS_VALID_PVOID(pv) ((pv) != INVALID_PVOID)
|
||||
#define IS_INVALID_PVOID(pv) (!IS_VALID_PVOID(pv))
|
||||
|
||||
#define TO_PVOID(v) ((PVOID)(UINT_PTR)(v))
|
||||
#define FROM_PVOID(T, pv) ((T)(UINT_PTR)(pv))
|
||||
|
||||
#define IS_NULL(v) ((v) == nullptr)
|
||||
#define IS_NOT_NULL(v) (!IS_NULL(v))
|
||||
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#define wcsicmp wcscasecmp
|
||||
#define wcsnicmp wcsncasecmp
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define tstrchr wcschr
|
||||
#define tstrrchr wcsrchr
|
||||
#define tstrstr wcsstr
|
||||
#define tstrpbrk wcspbrk
|
||||
#define tstrtok wcstok
|
||||
|
||||
#define stscanf swscanf
|
||||
#define tstrlen wcslen
|
||||
#define tstrcpy wcscpy
|
||||
#define tstrcmp wcscmp
|
||||
#define tstricmp wcsicmp
|
||||
#define tstrncpy wcsncpy
|
||||
#define tstrncmp wcsncmp
|
||||
#define tstrnicmp wcsnicmp
|
||||
#define tstrspn wcsspn
|
||||
#define tstrcspn wcscspn
|
||||
#define wsprintf swprintf
|
||||
#else
|
||||
#define tstrchr strchr
|
||||
#define tstrrchr strrchr
|
||||
#define tstrstr strstr
|
||||
#define tstrpbrk strpbrk
|
||||
#define tstrtok strtok_r
|
||||
|
||||
#define stscanf sscanf
|
||||
#define tstrlen strlen
|
||||
#define tstrcpy strcpy
|
||||
#define tstrcmp strcmp
|
||||
#define tstricmp stricmp
|
||||
#define tstrncpy strncpy
|
||||
#define tstrncmp strncmp
|
||||
#define tstrnicmp strnicmp
|
||||
#define tstrspn strspn
|
||||
#define tstrcspn strcspn
|
||||
#define wsprintf sprintf
|
||||
#endif
|
||||
|
||||
inline const char* StrChr(const char* s, char c) {return strchr(s, c);}
|
||||
inline const char* StrRChr(const char* s, char c) {return strrchr(s, c);}
|
||||
inline const char* StrStr(const char* h, const char* n) {return strstr(h, n);}
|
||||
inline const char* StrPBrk(const char* s, const char* a) {return strpbrk(s, a);}
|
||||
inline const wchar_t* StrChr(const wchar_t* s, wchar_t c) {return wcschr(s, c);}
|
||||
inline const wchar_t* StrRChr(const wchar_t* s, wchar_t c) {return wcsrchr(s, c);}
|
||||
inline const wchar_t* StrStr(const wchar_t* h, const wchar_t* n) {return wcsstr(h, n);}
|
||||
inline const wchar_t* StrPBrk(const wchar_t* s, const wchar_t* a) {return wcspbrk(s, a);}
|
||||
inline LPSTR StrSep2(LPSTR* lpStr, LPCSTR lpDelim = " \t\r\n") {LPSTR lpTok; while((lpTok = strsep(lpStr, lpDelim)) != nullptr && lpTok[0] == 0); return lpTok;}
|
||||
inline LPSTR TrimLeft(LPSTR* lpStr, LPCSTR lpDelim = " \t\r\n") {while((*lpStr)[0] != 0 && ::StrChr(lpDelim, (*lpStr)[0]) != nullptr) ++(*lpStr); return (*lpStr);}
|
||||
inline LPSTR TrimRitht(LPSTR* lpStr, LPCSTR lpDelim = " \t\r\n")
|
||||
{
|
||||
LPSTR lpEnd = (*lpStr) + strlen(*lpStr) - 1;
|
||||
LPSTR lpCur = lpEnd;
|
||||
|
||||
while(lpCur >= (*lpStr) && ::StrChr(lpDelim, lpCur[0]) != nullptr)
|
||||
--lpCur;
|
||||
|
||||
if(lpCur != lpEnd)
|
||||
lpCur[1] = 0;
|
||||
|
||||
return (*lpStr);
|
||||
}
|
||||
|
||||
inline BOOL IsStrEmptyA(LPCSTR lpsz) {return (lpsz == nullptr || lpsz[0] == 0);}
|
||||
inline BOOL IsStrEmptyW(LPCWSTR lpsz) {return (lpsz == nullptr || lpsz[0] == 0);}
|
||||
inline BOOL IsStrNotEmptyA(LPCSTR lpsz) {return !IsStrEmptyA(lpsz);}
|
||||
inline BOOL IsStrNotEmptyW(LPCWSTR lpsz){return !IsStrEmptyW(lpsz);}
|
||||
inline LPCSTR SafeStrA(LPCSTR lpsz) {return (lpsz != nullptr) ? lpsz : "";}
|
||||
inline LPCWSTR SafeStrW(LPCWSTR lpsz) {return (lpsz != nullptr) ? lpsz : L"";}
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define IsStrEmpty(lpsz) IsStrEmptyW(lpsz)
|
||||
#define IsStrNotEmpty(lpsz) IsStrNotEmptyW(lpsz)
|
||||
#define SafeStr(lpsz) SafeStrW(lpsz)
|
||||
#else
|
||||
#define IsStrEmpty(lpsz) IsStrEmptyA(lpsz)
|
||||
#define IsStrNotEmpty(lpsz) IsStrNotEmptyA(lpsz)
|
||||
#define SafeStr(lpsz) SafeStrA(lpsz)
|
||||
#endif
|
||||
|
||||
inline int lstrlen(LPCTSTR p) {return (int)tstrlen(p);}
|
||||
inline LPTSTR lstrcpy(LPTSTR d, LPCTSTR s) {return tstrcpy(d, s);}
|
||||
inline LPTSTR lstrncpy(LPTSTR d, LPCTSTR s, size_t n) {return tstrncpy(d, s, n);}
|
||||
inline int lstrcmp(LPCTSTR s1, LPCTSTR s2) {return tstrcmp(s1, s2);}
|
||||
inline int lstrncmp(LPCTSTR s1, LPCTSTR s2, size_t n) {return tstrncmp(s1, s2, n);}
|
||||
inline int lstricmp(LPCTSTR s1, LPCTSTR s2) {return tstricmp(s1, s2);}
|
||||
inline int lstrnicmp(LPCTSTR s1, LPCTSTR s2, size_t n) {return tstrnicmp(s1, s2, n);}
|
||||
inline int lstrspn(LPCTSTR s, LPCTSTR accept) {return (int)tstrspn(s, accept);}
|
||||
inline int lstrcspn(LPCTSTR s, LPCTSTR accept) {return (int)tstrcspn(s, accept);}
|
||||
|
||||
template <typename T, size_t N> char (&_ArraySizeHelper(T(&arr)[N]))[N];
|
||||
template <typename T, size_t N> char (&_ArraySizeHelper(const T(&arr)[N]))[N];
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(_ArraySizeHelper(arr)))
|
||||
|
||||
#ifndef _countof
|
||||
#define _countof(arr) ARRAY_SIZE(arr)
|
||||
#endif
|
||||
|
||||
#ifndef __countof
|
||||
#define __countof(arr) ARRAY_SIZE(arr)
|
||||
#endif
|
||||
|
||||
#define THREAD_YIELD_CYCLE 63
|
||||
#define THREAD_SWITCH_CYCLE 4095
|
||||
|
||||
inline void YieldThread(UINT i = THREAD_YIELD_CYCLE)
|
||||
{
|
||||
if((i & THREAD_SWITCH_CYCLE) == THREAD_SWITCH_CYCLE)
|
||||
::SwitchToThread();
|
||||
else if((i & THREAD_YIELD_CYCLE) == THREAD_YIELD_CYCLE)
|
||||
::YieldProcessor();
|
||||
}
|
||||
|
||||
INT WaitFor(DWORD dwMillSecond, DWORD dwSecond = 0, BOOL bExceptThreadInterrupted = FALSE);
|
||||
INT Sleep(DWORD dwMillSecond, DWORD dwSecond = 0, BOOL bExceptThreadInterrupted = FALSE);
|
||||
|
||||
__time64_t _time64(time_t* ptm = nullptr);
|
||||
__time64_t _mkgmtime64(tm* ptm);
|
||||
tm* _gmtime64(tm* ptm, __time64_t* pt);
|
||||
|
||||
DWORD TimeGetTime();
|
||||
ULLONG TimeGetTime64();
|
||||
DWORD GetTimeGap32(DWORD dwOriginal, DWORD dwCurrent = 0);
|
||||
ULLONG GetTimeGap64(ULLONG ullOriginal, ULONGLONG ullCurrent = 0);
|
||||
LLONG TimevalToMillisecond(const timeval& tv);
|
||||
timeval& MillisecondToTimeval(LLONG ms, timeval& tv);
|
||||
LLONG TimespecToMillisecond(const timespec& ts);
|
||||
timespec& MillisecondToTimespec(LLONG ms, timespec& ts);
|
||||
timeval& GetFutureTimeval(LLONG ms, timeval& tv, struct timezone* ptz = nullptr);
|
||||
timespec& GetFutureTimespec(LLONG ms, timespec& ts, clockid_t clkid = CLOCK_MONOTONIC);
|
||||
|
||||
FD CreateTimer(LLONG llInterval, LLONG llStart = -1, BOOL bRealTimeClock = FALSE);
|
||||
BOOL ReadTimer(FD tmr, ULLONG* pVal = nullptr, BOOL* pRs = nullptr);
|
||||
|
||||
BOOL fcntl_SETFL(FD fd, INT fl, BOOL bSet = TRUE);
|
||||
|
||||
void PrintStackTrace();
|
||||
void EXIT(int iExitCode = 0, int iErrno = -1, LPCSTR lpszFile = nullptr, int iLine = 0, LPCSTR lpszFunc = nullptr, LPCSTR lpszTitle = nullptr);
|
||||
void _EXIT(int iExitCode = 0, int iErrno = -1, LPCSTR lpszFile = nullptr, int iLine = 0, LPCSTR lpszFunc = nullptr, LPCSTR lpszTitle = nullptr);
|
||||
void ABORT(int iErrno = -1, LPCSTR lpszFile = nullptr, int iLine = 0, LPCSTR lpszFunc = nullptr, LPCSTR lpszTitle = nullptr);
|
||||
|
||||
/* ¹¤×÷Ïß³ÌÃû³Æ×î´ó³¤¶È */
|
||||
#define MAX_THREAD_NAME_LENGTH 15
|
||||
|
||||
BOOL SetSequenceThreadName(THR_ID tid, LPCTSTR lpszPrefix, volatile UINT& vuiSeq);
|
||||
BOOL SetThreadName(THR_ID tid, LPCTSTR lpszPrefix, UINT uiSequence);
|
||||
BOOL SetThreadName(THR_ID tid, LPCTSTR lpszName);
|
||||
|
||||
template<typename T, typename = enable_if_t<is_integral<T>::value>>
|
||||
inline bool IS_INFINITE(T v)
|
||||
{
|
||||
return v == (T)INFINITE;
|
||||
}
|
||||
|
||||
template<typename T, typename = enable_if_t<is_integral<T>::value>>
|
||||
inline bool IS_HAS_ERROR(T v)
|
||||
{
|
||||
return v == (T)HAS_ERROR;
|
||||
}
|
||||
|
||||
template<typename T, typename = enable_if_t<is_integral<T>::value>>
|
||||
inline bool IS_NO_ERROR(T v)
|
||||
{
|
||||
return v == (T)NO_ERROR;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T InterlockedCompareExchange(volatile T* _Tgt, T _Value, T _Exp, BOOL _bWeek = FALSE, memory_order m1 = memory_order_seq_cst, memory_order m2 = memory_order_seq_cst)
|
||||
{
|
||||
__atomic_compare_exchange_n(_Tgt, &_Exp, _Value, _bWeek, m1, m2);
|
||||
return _Exp;
|
||||
}
|
||||
|
||||
template<typename T, typename V, typename E, typename = enable_if_t<is_same<decay_t<T>, decay_t<V>>::value && is_same<decay_t<V>, decay_t<E>>::value>>
|
||||
inline V* InterlockedCompareExchangePointer(volatile T** _Tgt, V* _Value, E* _Exp, BOOL _bWeek = FALSE, memory_order m1 = memory_order_seq_cst, memory_order m2 = memory_order_seq_cst)
|
||||
{
|
||||
return (V*)(ULONG_PTR)InterlockedCompareExchange((volatile ULONG_PTR*)(volatile PVOID*)_Tgt, (ULONG_PTR)(PVOID)_Value, (ULONG_PTR)(PVOID)_Exp, _bWeek, m1, m2);
|
||||
}
|
||||
|
||||
template<typename T, typename ... A>
|
||||
inline T* ConstructObject(T* p, A&& ... args)
|
||||
{
|
||||
return new (p) T(forward<A>(args) ...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void DestructObject(T* p)
|
||||
{
|
||||
p->T::~T();
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename = enable_if_t<is_same<decay_t<T1>, decay_t<T2>>::value>>
|
||||
inline void CopyPlainObject(T1* p1, const T2* p2)
|
||||
{
|
||||
CopyMemory(p1, p2, sizeof(T1));
|
||||
}
|
||||
|
||||
template<typename T, typename C, typename = enable_if_t<is_integral<T>::value && (is_same<C, char>::value || is_same<C, wchar_t>::value)>>
|
||||
C* _n_2_c(T value, C* lpszDest, int radix)
|
||||
{
|
||||
static const C* dig = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
bool neg = false;
|
||||
|
||||
if(is_signed<T>::value && value < 0)
|
||||
{
|
||||
value = -value;
|
||||
neg = true;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
|
||||
do
|
||||
{
|
||||
lpszDest[n++] = dig[value % radix];
|
||||
value /= radix;
|
||||
} while(value);
|
||||
|
||||
if(neg) lpszDest[n++] = '-';
|
||||
lpszDest[n] = 0;
|
||||
|
||||
C c, *p, *q;
|
||||
for(p = lpszDest, q = p + n - 1; p < q; ++p, --q)
|
||||
c = *p, *p = *q, *q = c;
|
||||
|
||||
return lpszDest;
|
||||
}
|
||||
|
||||
#define itoa(v, p, r) _n_2_c<INT, char>((v), (p), (r))
|
||||
#define ltoa(v, p, r) _n_2_c<LONG, char>((v), (p), (r))
|
||||
#define lltoa(v, p, r) _n_2_c<LLONG, char>((v), (p), (r))
|
||||
#define uitoa(v, p, r) _n_2_c<UINT, char>((v), (p), (r))
|
||||
#define ultoa(v, p, r) _n_2_c<ULONG, char>((v), (p), (r))
|
||||
#define ulltoa(v, p, r) _n_2_c<ULLONG, char>((v), (p), (r))
|
||||
#define itow(v, p, r) _n_2_c<INT, wchar_t>((v), (p), (r))
|
||||
#define ltow(v, p, r) _n_2_c<LONG, wchar_t>((v), (p), (r))
|
||||
#define lltow(v, p, r) _n_2_c<LLONG, wchar_t>((v), (p), (r))
|
||||
#define uitow(v, p, r) _n_2_c<UINT, wchar_t>((v), (p), (r))
|
||||
#define ultow(v, p, r) _n_2_c<ULONG, wchar_t>((v), (p), (r))
|
||||
#define ulltow(v, p, r) _n_2_c<ULLONG, wchar_t>((v), (p), (r))
|
||||
|
||||
#define HEX_CHAR_TO_VALUE(c) (c <= '9' ? c - '0' : (c <= 'F' ? c - 'A' + 0x0A : c - 'a' + 0X0A))
|
||||
#define HEX_DOUBLE_CHAR_TO_VALUE(pc) ((BYTE)(((HEX_CHAR_TO_VALUE(*(pc))) << 4) | (HEX_CHAR_TO_VALUE(*((pc) + 1)))))
|
||||
#define HEX_VALUE_TO_CHAR(n) (n <= 9 ? n + '0' : (n <= 'F' ? n + 'A' - 0X0A : n + 'a' - 0X0A))
|
||||
#define HEX_VALUE_TO_DOUBLE_CHAR(pc, n) {*(pc) = (BYTE)HEX_VALUE_TO_CHAR((n >> 4)); *((pc) + 1) = (BYTE)HEX_VALUE_TO_CHAR((n & 0X0F));}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "../../include/hpsocket/GlobalErrno.h"
|
||||
#include "Singleton.h"
|
||||
#include "STLHelper.h"
|
||||
#include "FuncHelper.h"
|
||||
#include "StringT.h"
|
||||
#include "SysHelper.h"
|
||||
#include "PrivateHeap.h"
|
||||
#include "Semaphore.h"
|
||||
#include "RWLock.h"
|
||||
#include "BufferPtr.h"
|
||||
#include "Event.h"
|
||||
#include "CriSec.h"
|
||||
#include "Thread.h"
|
||||
#include "SignalHandler.h"
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "IODispatcher.h"
|
||||
#include "FuncHelper.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
volatile UINT CIODispatcher::sm_uiNum = MAXUINT;
|
||||
LPCTSTR CIODispatcher::WORKER_THREAD_PREFIX = _T("io-disp-");
|
||||
|
||||
BOOL CIODispatcher::Start(IIOHandler* pHandler, int iWorkerMaxEvents, int iWorkers)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(pHandler && iWorkerMaxEvents >= 0 && iWorkers >= 0);
|
||||
CHECK_ERROR(!HasStarted(), ERROR_INVALID_STATE);
|
||||
|
||||
if(iWorkerMaxEvents == 0) iWorkerMaxEvents = DEF_WORKER_MAX_EVENTS;
|
||||
if(iWorkers == 0) iWorkers = DEFAULT_WORKER_THREAD_COUNT;
|
||||
|
||||
m_iMaxEvents = iWorkerMaxEvents;
|
||||
m_iWorkers = iWorkers;
|
||||
m_pHandler = pHandler;
|
||||
|
||||
m_evExit = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE);
|
||||
|
||||
if(IS_INVALID_FD(m_evExit))
|
||||
goto START_ERROR;
|
||||
|
||||
m_pContexts = make_unique<TDispContext[]>(m_iWorkers);
|
||||
|
||||
for(int i = 0; i < m_iWorkers; i++)
|
||||
{
|
||||
TDispContext& ctx = m_pContexts[i];
|
||||
|
||||
ctx.m_iIndex = i;
|
||||
|
||||
ctx.m_epoll = epoll_create1(EPOLL_CLOEXEC);
|
||||
CHECK_ERROR_FD(ctx.m_epoll);
|
||||
|
||||
ctx.m_evCmd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
|
||||
if(IS_INVALID_FD(ctx.m_evCmd))
|
||||
goto START_ERROR;
|
||||
|
||||
if(!VERIFY(AddFD(i, ctx.m_evCmd, EPOLLIN | EPOLLET, &ctx.m_evCmd)))
|
||||
goto START_ERROR;
|
||||
|
||||
if(!VERIFY(AddFD(i, m_evExit, EPOLLIN, &m_evExit)))
|
||||
goto START_ERROR;
|
||||
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGPIPE);
|
||||
|
||||
VERIFY_IS_NO_ERROR(pthread_sigmask(SIG_BLOCK, &ss, nullptr));
|
||||
|
||||
ctx.m_pWorker = make_unique<CWorkerThread>();
|
||||
|
||||
if(!VERIFY(ctx.m_pWorker->Start(this, &CIODispatcher::WorkerProc, &ctx)))
|
||||
goto START_ERROR;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
START_ERROR:
|
||||
EXECUTE_RESTORE_ERROR(Stop(FALSE));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::Stop(BOOL bCheck)
|
||||
{
|
||||
if(bCheck) CHECK_ERROR(HasStarted(), ERROR_INVALID_STATE);
|
||||
|
||||
BOOL isOK = TRUE;
|
||||
|
||||
if(m_pContexts)
|
||||
{
|
||||
isOK &= IS_NO_ERROR(eventfd_write(m_evExit, m_iWorkers));
|
||||
|
||||
for(int i = 0; i < m_iWorkers; i++)
|
||||
{
|
||||
TDispContext& ctx = m_pContexts[i];
|
||||
|
||||
if(ctx.m_pWorker)
|
||||
isOK &= ctx.m_pWorker->Join();
|
||||
|
||||
if(!ctx.m_queue.IsEmpty())
|
||||
{
|
||||
TDispCommand* pCmd = nullptr;
|
||||
|
||||
while(ctx.m_queue.PopFront(&pCmd))
|
||||
TDispCommand::Destruct(pCmd);
|
||||
|
||||
VERIFY(ctx.m_queue.IsEmpty());
|
||||
}
|
||||
|
||||
if(IS_VALID_FD(ctx.m_evCmd))
|
||||
isOK &= IS_NO_ERROR(close(ctx.m_evCmd));
|
||||
|
||||
if(IS_VALID_FD(ctx.m_epoll))
|
||||
isOK &= IS_NO_ERROR(close(ctx.m_epoll));
|
||||
}
|
||||
}
|
||||
|
||||
if(IS_VALID_FD(m_evExit))
|
||||
isOK &= IS_NO_ERROR(close(m_evExit));
|
||||
|
||||
Reset();
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
VOID CIODispatcher::Reset()
|
||||
{
|
||||
m_uiSeq = MAXUINT;
|
||||
m_iWorkers = 0;
|
||||
m_iMaxEvents= 0;
|
||||
m_evExit = INVALID_FD;
|
||||
m_pHandler = nullptr;
|
||||
m_pContexts = nullptr;
|
||||
}
|
||||
|
||||
VOID CIODispatcher::MakePrefix()
|
||||
{
|
||||
UINT uiNumber = ::InterlockedIncrement(&sm_uiNum);
|
||||
|
||||
m_strPrefix.Format(_T("%s%u-"), WORKER_THREAD_PREFIX, uiNumber);
|
||||
}
|
||||
|
||||
TDispContext& CIODispatcher::GetContext(int idx, FD fd)
|
||||
{
|
||||
if(idx < 0) idx = fd;
|
||||
ASSERT(idx >= 0);
|
||||
|
||||
if(idx >= m_iWorkers)
|
||||
idx %= m_iWorkers;
|
||||
|
||||
return m_pContexts[idx];
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByIndex(int idx, USHORT t, UINT_PTR wp, UINT_PTR lp)
|
||||
{
|
||||
return SendCommandByIndex(idx, TDispCommand::Construct(t, wp, lp));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByIndex(int idx, TDispCommand* pCmd)
|
||||
{
|
||||
TDispContext& ctx = GetContextByIndex(idx);
|
||||
return SendCommand(ctx, pCmd);
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByFD(FD fd, USHORT t, UINT_PTR wp, UINT_PTR lp)
|
||||
{
|
||||
return SendCommandByFD(fd, TDispCommand::Construct(t, wp, lp));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByFD(FD fd, TDispCommand* pCmd)
|
||||
{
|
||||
TDispContext& ctx = GetContextByFD(fd);
|
||||
return SendCommand(ctx, pCmd);
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommand(TDispContext& ctx, TDispCommand* pCmd)
|
||||
{
|
||||
ctx.m_queue.PushBack(pCmd);
|
||||
return VERIFY_IS_NO_ERROR(eventfd_write(ctx.m_evCmd, 1));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::CtlFD(int idx, FD fd, int op, UINT mask, PVOID pv)
|
||||
{
|
||||
const TDispContext& ctx = GetContext(idx, fd);
|
||||
|
||||
epoll_event evt = {mask, pv};
|
||||
return IS_NO_ERROR(epoll_ctl(ctx.m_epoll, op, fd, &evt));
|
||||
}
|
||||
|
||||
int CIODispatcher::WorkerProc(TDispContext* pContext)
|
||||
{
|
||||
::SetSequenceThreadName(SELF_THREAD_ID, m_strPrefix, m_uiSeq);
|
||||
|
||||
m_pHandler->OnDispatchThreadStart(SELF_THREAD_ID);
|
||||
|
||||
BOOL bRun = TRUE;
|
||||
unique_ptr<epoll_event[]> pEvents = make_unique<epoll_event[]>(m_iMaxEvents);
|
||||
|
||||
while(bRun)
|
||||
{
|
||||
int rs = NO_EINTR_INT(epoll_pwait(pContext->m_epoll, pEvents.get(), m_iMaxEvents, INFINITE, nullptr));
|
||||
|
||||
if(rs <= TIMEOUT)
|
||||
ERROR_ABORT();
|
||||
|
||||
for(int i = 0; i < rs; i++)
|
||||
{
|
||||
UINT events = pEvents[i].events;
|
||||
PVOID ptr = pEvents[i].data.ptr;
|
||||
|
||||
if(ptr == &pContext->m_evCmd)
|
||||
ProcessCommand(pContext, events);
|
||||
else if(ptr == &m_evExit)
|
||||
bRun = ProcessExit(pContext, events);
|
||||
else
|
||||
ProcessIo(pContext, ptr, events);
|
||||
}
|
||||
}
|
||||
|
||||
m_pHandler->OnDispatchThreadEnd(SELF_THREAD_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessCommand(TDispContext* pContext, UINT events)
|
||||
{
|
||||
if(events & _EPOLL_ALL_ERROR_EVENTS)
|
||||
ERROR_ABORT();
|
||||
|
||||
if(!(events & EPOLLIN))
|
||||
return FALSE;
|
||||
|
||||
BOOL isOK = TRUE;
|
||||
|
||||
eventfd_t v;
|
||||
|
||||
int rs = eventfd_read(pContext->m_evCmd, &v);
|
||||
|
||||
if(IS_NO_ERROR(rs))
|
||||
{
|
||||
ASSERT(v > 0);
|
||||
|
||||
TDispCommand* pCmd = nullptr;
|
||||
|
||||
while(pContext->m_queue.PopFront(&pCmd))
|
||||
{
|
||||
m_pHandler->OnCommand(pContext, pCmd);
|
||||
TDispCommand::Destruct(pCmd);
|
||||
}
|
||||
}
|
||||
else if(IS_HAS_ERROR(rs))
|
||||
{
|
||||
ASSERT(IS_WOULDBLOCK_ERROR());
|
||||
|
||||
isOK = FALSE;
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessExit(const TDispContext* pContext, UINT events)
|
||||
{
|
||||
if(events & _EPOLL_ALL_ERROR_EVENTS)
|
||||
ERROR_ABORT();
|
||||
|
||||
if(!(events & EPOLLIN))
|
||||
return TRUE;
|
||||
|
||||
BOOL bRun = TRUE;
|
||||
|
||||
eventfd_t v;
|
||||
|
||||
int rs = eventfd_read(m_evExit, &v);
|
||||
|
||||
if(IS_HAS_ERROR(rs))
|
||||
ASSERT(IS_WOULDBLOCK_ERROR());
|
||||
else
|
||||
{
|
||||
ASSERT(v == 1);
|
||||
bRun = FALSE;
|
||||
}
|
||||
|
||||
return bRun;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessIo(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
if(!m_pHandler->OnBeforeProcessIo(pContext, pv, events))
|
||||
return FALSE;
|
||||
|
||||
BOOL rs = DoProcessIo(pContext, pv, events);
|
||||
m_pHandler->OnAfterProcessIo(pContext, pv, events, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::DoProcessIo(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
{
|
||||
if(events & EPOLLERR)
|
||||
return m_pHandler->OnError(pContext, pv, events);
|
||||
if((events & EPOLLPRI) && !m_pHandler->OnReadyPrivilege(pContext, pv, events))
|
||||
return FALSE;
|
||||
if((events & EPOLLIN) && !m_pHandler->OnReadyRead(pContext, pv, events))
|
||||
return FALSE;
|
||||
if((events & EPOLLOUT) && !m_pHandler->OnReadyWrite(pContext, pv, events))
|
||||
return FALSE;
|
||||
if((events & (_EPOLL_HUNGUP_EVENTS)) && !m_pHandler->OnHungUp(pContext, pv, events))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FD CIODispatcher::AddTimer(int idx, LLONG llInterval, PVOID pv)
|
||||
{
|
||||
FD fdTimer = ::CreateTimer(llInterval);
|
||||
|
||||
if(IS_VALID_FD(fdTimer))
|
||||
{
|
||||
if(!AddFD(idx, fdTimer, EPOLLIN | EPOLLET, pv))
|
||||
{
|
||||
close(fdTimer);
|
||||
fdTimer = INVALID_FD;
|
||||
}
|
||||
}
|
||||
|
||||
return fdTimer;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::DelTimer(int idx, FD fdTimer)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
if(IS_VALID_FD(fdTimer))
|
||||
{
|
||||
if(DelFD(idx, fdTimer))
|
||||
isOK = TRUE;
|
||||
|
||||
close(fdTimer);
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "Singleton.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define _EPOLL_READ_PRI_EVENTS (EPOLLPRI | EPOLLRDHUP)
|
||||
#define _EPOLL_READ_EVENTS (EPOLLIN | EPOLLRDHUP)
|
||||
#define _EPOLL_ALL_READ_EVENTS (_EPOLL_READ_EVENTS | _EPOLL_READ_PRI_EVENTS)
|
||||
#define _EPOLL_WRITE_EVENTS (EPOLLOUT)
|
||||
#define _EPOLL_NORMAL_RW_EVENTS (_EPOLL_READ_EVENTS | _EPOLL_WRITE_EVENTS)
|
||||
#define _EPOLL_ALL_RW_EVENTS (_EPOLL_ALL_READ_EVENTS | _EPOLL_WRITE_EVENTS)
|
||||
#define _EPOLL_ERROR_EVENTS (EPOLLERR)
|
||||
#define _EPOLL_HUNGUP_EVENTS (EPOLLHUP | EPOLLRDHUP)
|
||||
#define _EPOLL_ALL_ERROR_EVENTS (_EPOLL_ERROR_EVENTS | _EPOLL_HUNGUP_EVENTS)
|
||||
#define _EPOLL_ALL_NORMAL_EVENTS (_EPOLL_NORMAL_RW_EVENTS | _EPOLL_ALL_ERROR_EVENTS)
|
||||
#define _EPOLL_ALL_EVENTS (_EPOLL_ALL_RW_EVENTS | _EPOLL_ALL_ERROR_EVENTS)
|
||||
|
||||
#define DISP_EVENT_FLAG_R 0x1
|
||||
#define DISP_EVENT_FLAG_W 0x2
|
||||
#define DISP_EVENT_FLAG_H 0x4
|
||||
|
||||
#define RETRIVE_EVENT_FLAG_R(evt) ((evt) & (_EPOLL_ALL_READ_EVENTS) ? DISP_EVENT_FLAG_R : 0)
|
||||
#define RETRIVE_EVENT_FLAG_W(evt) ((evt) & (_EPOLL_WRITE_EVENTS) ? DISP_EVENT_FLAG_W : 0)
|
||||
#define RETRIVE_EVENT_FLAG_RW(evt) (RETRIVE_EVENT_FLAG_R(evt) | RETRIVE_EVENT_FLAG_W(evt))
|
||||
#define RETRIVE_EVENT_FLAG_H(evt) ((evt) & (_EPOLL_HUNGUP_EVENTS) ? DISP_EVENT_FLAG_H : 0)
|
||||
|
||||
#ifndef EPOLLEXCLUSIVE
|
||||
#define EPOLLEXCLUSIVE (1u << 28)
|
||||
#endif
|
||||
|
||||
#define MAYBE_EPOLLEXCLUSIVE (::IsKernelVersionAbove(4, 5, 0) ? EPOLLEXCLUSIVE : 0)
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
struct TDispCommand;
|
||||
class CIODispatcher;
|
||||
|
||||
struct TDispContext
|
||||
{
|
||||
friend class CIODispatcher;
|
||||
|
||||
using CCommandQueue = CCASQueue<TDispCommand>;
|
||||
using CWorkerThread = CThread<CIODispatcher, TDispContext, int>;
|
||||
|
||||
public:
|
||||
int GetIndex() const {return m_iIndex;}
|
||||
THR_ID GetThreadId() const {return m_pWorker != nullptr ? m_pWorker->GetThreadID() : 0;}
|
||||
|
||||
public:
|
||||
TDispContext() {Reset();}
|
||||
~TDispContext() = default;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(TDispContext)
|
||||
|
||||
private:
|
||||
VOID Reset()
|
||||
{
|
||||
m_iIndex = -1;
|
||||
m_epoll = INVALID_FD;
|
||||
m_evCmd = INVALID_FD;
|
||||
m_pWorker = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_iIndex;
|
||||
FD m_epoll;
|
||||
FD m_evCmd;
|
||||
|
||||
CCommandQueue m_queue;
|
||||
unique_ptr<CWorkerThread> m_pWorker;
|
||||
};
|
||||
|
||||
struct TDispCommand
|
||||
{
|
||||
USHORT type;
|
||||
UINT_PTR wParam;
|
||||
UINT_PTR lParam;
|
||||
|
||||
static TDispCommand* Construct(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0)
|
||||
{return new TDispCommand(t, wp, lp);}
|
||||
|
||||
static VOID Destruct(TDispCommand* p)
|
||||
{if(p) delete p;}
|
||||
|
||||
private:
|
||||
TDispCommand(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0)
|
||||
: type(t), wParam(wp), lParam(lp)
|
||||
{
|
||||
}
|
||||
|
||||
~TDispCommand() = default;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
class IIOHandler
|
||||
{
|
||||
public:
|
||||
virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) = 0;
|
||||
|
||||
virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) = 0;
|
||||
virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) = 0;
|
||||
virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) = 0;
|
||||
virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) = 0;
|
||||
virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) = 0;
|
||||
virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) = 0;
|
||||
virtual BOOL OnReadyPrivilege(const TDispContext* pContext, PVOID pv, UINT events) = 0;
|
||||
|
||||
virtual VOID OnDispatchThreadStart(THR_ID tid) = 0;
|
||||
virtual VOID OnDispatchThreadEnd(THR_ID tid) = 0;
|
||||
|
||||
public:
|
||||
virtual ~IIOHandler() = default;
|
||||
};
|
||||
|
||||
class CIOHandler : public IIOHandler
|
||||
{
|
||||
public:
|
||||
virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) override {}
|
||||
|
||||
virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
|
||||
virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) override {}
|
||||
virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
|
||||
virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
|
||||
virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
|
||||
virtual BOOL OnReadyPrivilege(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
|
||||
|
||||
virtual VOID OnDispatchThreadStart(THR_ID tid) override {}
|
||||
virtual VOID OnDispatchThreadEnd(THR_ID tid) override {}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------------------------------- //
|
||||
|
||||
class CIODispatcher
|
||||
{
|
||||
public:
|
||||
static const int DEF_WORKER_MAX_EVENTS = 64;
|
||||
|
||||
using CCommandQueue = TDispContext::CCommandQueue;
|
||||
using CWorkerThread = TDispContext::CWorkerThread;
|
||||
|
||||
public:
|
||||
BOOL Start(IIOHandler* pHandler, int iWorkerMaxEvents = DEF_WORKER_MAX_EVENTS, int iWorkers = 0);
|
||||
BOOL Stop(BOOL bCheck = TRUE);
|
||||
|
||||
BOOL SendCommandByIndex(int idx, TDispCommand* pCmd);
|
||||
BOOL SendCommandByIndex(int idx, USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0);
|
||||
BOOL SendCommandByFD(FD fd, TDispCommand* pCmd);
|
||||
BOOL SendCommandByFD(FD fd, USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0);
|
||||
BOOL SendCommand(TDispContext& ctx, TDispCommand* pCmd);
|
||||
|
||||
template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
|
||||
BOOL SendCommandsByIndex(int idx, const _List& cmds)
|
||||
{
|
||||
TDispContext& ctx = GetContextByIndex(idx);
|
||||
return SendCommands(ctx, cmds);
|
||||
}
|
||||
|
||||
template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
|
||||
BOOL SendCommandsByFD(FD fd, const _List& cmds)
|
||||
{
|
||||
TDispContext& ctx = GetContextByFD(fd);
|
||||
return SendCommands(ctx, cmds);
|
||||
}
|
||||
|
||||
template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
|
||||
BOOL SendCommands(TDispContext& ctx, const _List& cmds)
|
||||
{
|
||||
size_t size = cmds.size();
|
||||
if(size == 0) return FALSE;
|
||||
|
||||
for(auto it = cmds.begin(), end = cmds.end(); it != end; ++it)
|
||||
ctx.m_queue.PushBack(*it);
|
||||
|
||||
return VERIFY_IS_NO_ERROR(eventfd_write(ctx.m_evCmd, size));
|
||||
}
|
||||
|
||||
BOOL AddFD(int idx, FD fd, UINT mask, PVOID pv) {return CtlFD(idx, fd, EPOLL_CTL_ADD, mask, pv);}
|
||||
BOOL ModFD(int idx, FD fd, UINT mask, PVOID pv) {return CtlFD(idx, fd, EPOLL_CTL_MOD, mask, pv);}
|
||||
BOOL DelFD(int idx, FD fd) {return CtlFD(idx, fd, EPOLL_CTL_DEL, 0, nullptr);}
|
||||
BOOL CtlFD(int idx, FD fd, int op, UINT mask, PVOID pv);
|
||||
|
||||
|
||||
BOOL AddFD(FD fd, UINT mask, PVOID pv) {return CtlFD(-1, fd, EPOLL_CTL_ADD, mask, pv);}
|
||||
BOOL ModFD(FD fd, UINT mask, PVOID pv) {return CtlFD(-1, fd, EPOLL_CTL_MOD, mask, pv);}
|
||||
BOOL DelFD(FD fd) {return CtlFD(-1, fd, EPOLL_CTL_DEL, 0, nullptr);}
|
||||
BOOL CtlFD(FD fd, int op, UINT mask, PVOID pv) {return CtlFD(-1, fd, op, mask, pv);}
|
||||
|
||||
BOOL ProcessIo(const TDispContext* pContext, PVOID pv, UINT events);
|
||||
|
||||
FD AddTimer (int idx, LLONG llInterval, PVOID pv);
|
||||
BOOL DelTimer (int idx, FD fdTimer);
|
||||
|
||||
FD AddTimer (LLONG llInterval, PVOID pv) {return AddTimer(-1, llInterval, pv);}
|
||||
BOOL DelTimer (FD fdTimer) {return DelTimer(-1, fdTimer);}
|
||||
|
||||
private:
|
||||
int WorkerProc(TDispContext* pContext);
|
||||
BOOL ProcessExit(const TDispContext* pContext, UINT events);
|
||||
BOOL ProcessCommand(TDispContext* pContext, UINT events);
|
||||
BOOL DoProcessIo(const TDispContext* pContext, PVOID pv, UINT events);
|
||||
|
||||
VOID Reset();
|
||||
VOID MakePrefix();
|
||||
|
||||
TDispContext& GetContextByIndex(int idx) {return GetContext(idx, -1);}
|
||||
TDispContext& GetContextByFD(FD fd) {return GetContext(-1, fd);}
|
||||
TDispContext& GetContext(int idx, FD fd);
|
||||
|
||||
public:
|
||||
const TDispContext& GetContextRefByIndex(int idx) {return GetContextByIndex(idx);}
|
||||
const TDispContext& GetContextRefByFD(FD fd) {return GetContextByFD(fd);}
|
||||
const TDispContext& GetContextRef(int idx, FD fd) {return GetContext(idx, fd);}
|
||||
|
||||
BOOL HasStarted() {return m_pHandler && m_pContexts;}
|
||||
int GetWorkers() {return m_iWorkers;}
|
||||
const TDispContext* GetContexts() {return m_pContexts.get();}
|
||||
|
||||
CIODispatcher() {MakePrefix(); Reset();}
|
||||
~CIODispatcher() {if(HasStarted()) Stop();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CIODispatcher)
|
||||
|
||||
private:
|
||||
static LPCTSTR WORKER_THREAD_PREFIX;
|
||||
static volatile UINT sm_uiNum;
|
||||
|
||||
volatile UINT m_uiSeq;
|
||||
CString m_strPrefix;
|
||||
|
||||
private:
|
||||
int m_iWorkers;
|
||||
int m_iMaxEvents;
|
||||
|
||||
FD m_evExit;
|
||||
|
||||
IIOHandler* m_pHandler;
|
||||
unique_ptr<TDispContext[]> m_pContexts;
|
||||
};
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PollHelper.h"
|
||||
#include "FuncHelper.h"
|
||||
|
||||
long PollForSingleObject(pollfd& pfd, long lTimeout, const sigset_t* pSigSet)
|
||||
{
|
||||
return PollForMultipleObjects(&pfd, 1, lTimeout, pSigSet);
|
||||
}
|
||||
|
||||
long PollForMultipleObjects(pollfd pfds[], int iCount, long lTimeout, const sigset_t* pSigSet)
|
||||
{
|
||||
ASSERT(iCount > 0 && iCount < (int)(sizeof(LONG) * 8));
|
||||
|
||||
timespec* pts = nullptr;
|
||||
|
||||
if(!IS_INFINITE(lTimeout))
|
||||
{
|
||||
pts = CreateLocalObject(timespec);
|
||||
::MillisecondToTimespec(lTimeout, *pts);
|
||||
}
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
int rs = NO_EINTR_INT(ppoll(pfds, iCount, pts, pSigSet));
|
||||
|
||||
if(rs <= TIMEOUT) return rs;
|
||||
|
||||
LONG lValue = 0L;
|
||||
|
||||
for(int i = 0; i < iCount; i++)
|
||||
{
|
||||
pollfd& pfd = pfds[i];
|
||||
|
||||
if(pfd.revents & _POLL_ALL_EVENTS)
|
||||
lValue |= (1 << i);
|
||||
}
|
||||
|
||||
return lValue;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if __USE_GNU
|
||||
#define _POLL_READ_PRI_EVENTS (POLLPRI | POLLRDHUP)
|
||||
#define _POLL_READ_EVENTS (POLLIN | POLLRDHUP)
|
||||
#define _POLL_HUNGUP_EVENTS (POLLHUP | POLLRDHUP)
|
||||
#else
|
||||
#define _POLL_READ_PRI_EVENTS (POLLPRI)
|
||||
#define _POLL_READ_EVENTS (POLLIN)
|
||||
#define _POLL_HUNGUP_EVENTS (POLLHUP)
|
||||
#endif
|
||||
|
||||
#define _POLL_ALL_READ_EVENTS (_POLL_READ_EVENTS | _POLL_READ_PRI_EVENTS)
|
||||
#define _POLL_WRITE_EVENTS (POLLOUT)
|
||||
#define _POLL_NORMAL_RW_EVENTS (_POLL_READ_EVENTS | _POLL_WRITE_EVENTS)
|
||||
#define _POLL_ALL_RW_EVENTS (_POLL_ALL_READ_EVENTS | _POLL_WRITE_EVENTS)
|
||||
#define _POLL_ERROR_EVENTS (POLLERR | POLLNVAL)
|
||||
#define _POLL_ALL_ERROR_EVENTS (_POLL_ERROR_EVENTS | _POLL_HUNGUP_EVENTS)
|
||||
#define _POLL_ALL_NORMAL_EVENTS (_POLL_NORMAL_RW_EVENTS | _POLL_ALL_ERROR_EVENTS)
|
||||
#define _POLL_ALL_EVENTS (_POLL_ALL_RW_EVENTS | _POLL_ALL_ERROR_EVENTS)
|
||||
|
||||
long PollForSingleObject(pollfd& pfd, long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr);
|
||||
long PollForMultipleObjects(pollfd pfds[], int iCount, long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr);
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#define HEAP_ZERO_MEMORY 0x08
|
||||
|
||||
class CGlobalHeapImpl
|
||||
{
|
||||
public:
|
||||
PVOID Alloc(SIZE_T dwSize, DWORD dwFlags = 0)
|
||||
{
|
||||
PVOID pv = malloc(dwSize);
|
||||
|
||||
if(!pv)
|
||||
throw std::bad_alloc();
|
||||
|
||||
if(dwFlags & HEAP_ZERO_MEMORY)
|
||||
ZeroMemory(pv, dwSize);
|
||||
|
||||
return pv;
|
||||
}
|
||||
|
||||
PVOID ReAlloc(PVOID pvMemory, SIZE_T dwSize, DWORD dwFlags = 0)
|
||||
{
|
||||
PVOID pv = realloc(pvMemory, dwSize);
|
||||
|
||||
if(!pv)
|
||||
{
|
||||
if(pvMemory)
|
||||
free(pvMemory);
|
||||
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
if(dwFlags & HEAP_ZERO_MEMORY)
|
||||
ZeroMemory(pv, dwSize);
|
||||
|
||||
return pv;
|
||||
}
|
||||
|
||||
BOOL Free(PVOID pvMemory, DWORD dwFlags = 0)
|
||||
{
|
||||
if(pvMemory)
|
||||
{
|
||||
free(pvMemory);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SIZE_T Compact (DWORD dwFlags = 0) {return -1;}
|
||||
SIZE_T Size (PVOID pvMemory, DWORD dwFlags = 0) {return _msize(pvMemory);}
|
||||
|
||||
BOOL IsValid() {return TRUE;}
|
||||
BOOL Reset() {return TRUE;}
|
||||
|
||||
public:
|
||||
CGlobalHeapImpl (DWORD dwOptions = 0, SIZE_T dwInitSize = 0, SIZE_T dwMaxSize = 0) {}
|
||||
~CGlobalHeapImpl() {}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CGlobalHeapImpl)
|
||||
};
|
||||
|
||||
#if !defined (_USE_CUSTOM_PRIVATE_HEAP)
|
||||
using CPrivateHeap = CGlobalHeapImpl;
|
||||
#endif
|
||||
|
||||
template<class T> class CPrivateHeapBuffer
|
||||
{
|
||||
public:
|
||||
CPrivateHeapBuffer(CPrivateHeap& hpPrivate, SIZE_T dwSize = 0)
|
||||
: m_hpPrivate (hpPrivate)
|
||||
, m_pvMemory (nullptr)
|
||||
{
|
||||
ASSERT(m_hpPrivate.IsValid());
|
||||
Alloc(dwSize);
|
||||
}
|
||||
|
||||
~CPrivateHeapBuffer() {Free();}
|
||||
|
||||
public:
|
||||
|
||||
T* Alloc(SIZE_T dwSize, DWORD dwFlags = 0)
|
||||
{
|
||||
if(IsValid())
|
||||
Free();
|
||||
|
||||
if(dwSize > 0)
|
||||
m_pvMemory = (T*)m_hpPrivate.Alloc(dwSize * sizeof(T), dwFlags);
|
||||
|
||||
return m_pvMemory;
|
||||
}
|
||||
|
||||
T* ReAlloc(SIZE_T dwSize, DWORD dwFlags = 0)
|
||||
{return m_pvMemory = (T*)m_hpPrivate.ReAlloc(m_pvMemory, dwSize * sizeof(T), dwFlags);}
|
||||
|
||||
SIZE_T Size(DWORD dwFlags = 0)
|
||||
{return m_hpPrivate.Size(m_pvMemory, dwFlags) / sizeof(T);}
|
||||
|
||||
BOOL Free(DWORD dwFlags = 0)
|
||||
{
|
||||
BOOL isOK = TRUE;
|
||||
|
||||
if(IsValid())
|
||||
{
|
||||
isOK = m_hpPrivate.Free(m_pvMemory, dwFlags);
|
||||
m_pvMemory = nullptr;
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL IsValid() {return m_pvMemory != nullptr;}
|
||||
operator T* () const {return m_pvMemory;}
|
||||
T& operator [] (int i) const {return *(m_pvMemory + i);}
|
||||
|
||||
private:
|
||||
CPrivateHeap& m_hpPrivate;
|
||||
T* m_pvMemory;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CPrivateHeapBuffer)
|
||||
};
|
||||
|
||||
using CPrivateHeapByteBuffer = CPrivateHeapBuffer<BYTE>;
|
||||
using CPrivateHeapStrBuffer = CPrivateHeapBuffer<TCHAR>;
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "RWLock.h"
|
||||
|
||||
CMutexRWLock::CMutexRWLock()
|
||||
: m_nActive (0)
|
||||
, m_dwWriterTID (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CMutexRWLock::~CMutexRWLock()
|
||||
{
|
||||
ASSERT(m_nActive == 0);
|
||||
ASSERT(m_dwWriterTID == 0);
|
||||
}
|
||||
|
||||
VOID CMutexRWLock::WaitToRead()
|
||||
{
|
||||
BOOL bWait = FALSE;
|
||||
|
||||
{
|
||||
CSpinLock locallock(m_cs);
|
||||
|
||||
if(m_nActive > 0)
|
||||
++m_nActive;
|
||||
else if(m_nActive == 0)
|
||||
{
|
||||
if(m_mtx.try_lock_shared())
|
||||
++m_nActive;
|
||||
else
|
||||
bWait = TRUE;
|
||||
}
|
||||
else if(!IsOwner())
|
||||
bWait = TRUE;
|
||||
}
|
||||
|
||||
if(bWait)
|
||||
{
|
||||
m_mtx.lock_shared();
|
||||
|
||||
CSpinLock locallock(m_cs);
|
||||
++m_nActive;
|
||||
}
|
||||
}
|
||||
|
||||
VOID CMutexRWLock::WaitToWrite()
|
||||
{
|
||||
BOOL bWait = FALSE;
|
||||
|
||||
{
|
||||
CSpinLock locallock(m_cs);
|
||||
|
||||
if(m_nActive > 0)
|
||||
bWait = TRUE;
|
||||
else if(m_nActive == 0)
|
||||
{
|
||||
if(m_mtx.try_lock())
|
||||
{
|
||||
SetOwner();
|
||||
--m_nActive;
|
||||
}
|
||||
else
|
||||
bWait = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IsOwner())
|
||||
--m_nActive;
|
||||
else
|
||||
bWait = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(bWait)
|
||||
{
|
||||
m_mtx.lock();
|
||||
|
||||
SetOwner();
|
||||
--m_nActive;
|
||||
}
|
||||
}
|
||||
|
||||
VOID CMutexRWLock::ReadDone()
|
||||
{
|
||||
ASSERT(m_nActive != 0);
|
||||
|
||||
if(m_nActive > 0)
|
||||
{
|
||||
{
|
||||
CSpinLock locallock(m_cs);
|
||||
--m_nActive;
|
||||
}
|
||||
|
||||
m_mtx.unlock_shared();
|
||||
}
|
||||
else
|
||||
ASSERT(IsOwner());
|
||||
}
|
||||
|
||||
VOID CMutexRWLock::WriteDone()
|
||||
{
|
||||
ASSERT(IsOwner());
|
||||
ASSERT(m_nActive < 0);
|
||||
|
||||
BOOL bDone;
|
||||
|
||||
{
|
||||
CSpinLock locallock(m_cs);
|
||||
bDone = (++m_nActive == 0);
|
||||
}
|
||||
|
||||
if(bDone)
|
||||
{
|
||||
DetachOwner();
|
||||
m_mtx.unlock();
|
||||
}
|
||||
else
|
||||
ASSERT(IsOwner());
|
||||
}
|
||||
|
||||
CSEMRWLock::CSEMRWLock()
|
||||
: m_nWaitingReaders (0)
|
||||
, m_nWaitingWriters (0)
|
||||
, m_nActive (0)
|
||||
, m_dwWriterTID (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSEMRWLock::~CSEMRWLock()
|
||||
{
|
||||
ASSERT(m_nActive == 0);
|
||||
ASSERT(m_dwWriterTID == 0);
|
||||
}
|
||||
|
||||
VOID CSEMRWLock::WaitToRead()
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
if(IsOwner())
|
||||
return;
|
||||
|
||||
++m_nWaitingReaders;
|
||||
|
||||
m_cvRead.wait(lock, [=]() -> BOOL
|
||||
{
|
||||
return m_nActive >= 0 && m_nWaitingWriters == 0;
|
||||
});
|
||||
|
||||
--m_nWaitingReaders;
|
||||
++m_nActive;
|
||||
}
|
||||
|
||||
VOID CSEMRWLock::WaitToWrite()
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
if(IsOwner())
|
||||
{
|
||||
--m_nActive;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
++m_nWaitingWriters;
|
||||
|
||||
m_cvWrite.wait(lock, [=]() -> BOOL
|
||||
{
|
||||
return m_nActive == 0;
|
||||
});
|
||||
|
||||
--m_nWaitingWriters;
|
||||
--m_nActive;
|
||||
|
||||
SetOwner();
|
||||
}
|
||||
|
||||
VOID CSEMRWLock::ReadDone()
|
||||
{
|
||||
CMutexLock2 locallock(m_mtx);
|
||||
|
||||
if(IsOwner())
|
||||
return;
|
||||
|
||||
ASSERT(m_nActive > 0);
|
||||
|
||||
if(--m_nActive == 0 && m_nWaitingWriters > 0)
|
||||
m_cvWrite.notify_one();
|
||||
}
|
||||
|
||||
VOID CSEMRWLock::WriteDone()
|
||||
{
|
||||
ASSERT(IsOwner());
|
||||
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
if(++m_nActive == 0)
|
||||
{
|
||||
DetachOwner();
|
||||
|
||||
if(m_nWaitingWriters > 0)
|
||||
m_cvWrite.notify_one();
|
||||
else if(m_nWaitingReaders > 0)
|
||||
m_cvRead.notify_all();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "CriSec.h"
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CMutexRWLock
|
||||
{
|
||||
public:
|
||||
VOID WaitToRead();
|
||||
VOID WaitToWrite();
|
||||
VOID ReadDone();
|
||||
VOID WriteDone();
|
||||
|
||||
private:
|
||||
BOOL IsOwner() {return ::IsSelfThread(m_dwWriterTID);}
|
||||
VOID SetOwner() {m_dwWriterTID = SELF_THREAD_ID;}
|
||||
VOID DetachOwner() {m_dwWriterTID = 0;}
|
||||
|
||||
public:
|
||||
CMutexRWLock();
|
||||
~CMutexRWLock();
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CMutexRWLock)
|
||||
|
||||
private:
|
||||
int m_nActive;
|
||||
THR_ID m_dwWriterTID;
|
||||
|
||||
CSpinGuard m_cs;
|
||||
shared_timed_mutex m_mtx;
|
||||
};
|
||||
|
||||
class CSEMRWLock
|
||||
{
|
||||
public:
|
||||
VOID WaitToRead();
|
||||
VOID WaitToWrite();
|
||||
VOID ReadDone();
|
||||
VOID WriteDone();
|
||||
|
||||
private:
|
||||
BOOL IsOwner() {BOOL bOwner = ::IsSelfThread(m_dwWriterTID); ASSERT(!bOwner || m_nActive < 0); return bOwner;}
|
||||
VOID SetOwner() {m_dwWriterTID = SELF_THREAD_ID;}
|
||||
VOID DetachOwner() {m_dwWriterTID = 0;}
|
||||
|
||||
public:
|
||||
CSEMRWLock();
|
||||
~CSEMRWLock();
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CSEMRWLock)
|
||||
|
||||
private:
|
||||
int m_nWaitingReaders;
|
||||
int m_nWaitingWriters;
|
||||
int m_nActive;
|
||||
THR_ID m_dwWriterTID;
|
||||
|
||||
CMTX m_mtx;
|
||||
condition_variable m_cvRead;
|
||||
condition_variable m_cvWrite;
|
||||
};
|
||||
|
||||
template<class CLockObj> class CLocalReadLock
|
||||
{
|
||||
public:
|
||||
CLocalReadLock(CLockObj& obj) : m_wait(obj) {m_wait.WaitToRead();}
|
||||
~CLocalReadLock() {m_wait.ReadDone();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CLocalReadLock)
|
||||
|
||||
private:
|
||||
CLockObj& m_wait;
|
||||
};
|
||||
|
||||
template<class CLockObj> class CLocalWriteLock
|
||||
{
|
||||
public:
|
||||
CLocalWriteLock(CLockObj& obj) : m_wait(obj) {m_wait.WaitToWrite();}
|
||||
~CLocalWriteLock() {m_wait.WriteDone();}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CLocalWriteLock)
|
||||
|
||||
private:
|
||||
CLockObj& m_wait;
|
||||
};
|
||||
|
||||
|
||||
using CSimpleRWLock = shared_timed_mutex;
|
||||
using CReadLock = shared_lock<shared_timed_mutex>;
|
||||
using CWriteLock = lock_guard<shared_timed_mutex>;
|
||||
using CWriteLock2 = unique_lock<shared_timed_mutex>;
|
||||
|
||||
#if !defined(_USE_MUTEX_RW_LOCK)
|
||||
using CRWLock = CSEMRWLock;
|
||||
#else
|
||||
using CRWLock = CMutexRWLock;
|
||||
#endif
|
||||
|
||||
using CReentrantReadLock = CLocalReadLock<CRWLock>;
|
||||
using CReentrantWriteLock = CLocalWriteLock<CRWLock>;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "CriSec.h"
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CSEM
|
||||
{
|
||||
public:
|
||||
void Wait()
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
m_cv.wait(lock);
|
||||
}
|
||||
|
||||
template<typename _Predicate>
|
||||
void Wait(_Predicate p)
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
m_cv.wait(lock, p);
|
||||
}
|
||||
|
||||
template<typename _Rep, typename _Period>
|
||||
cv_status WaitFor(const chrono::duration<_Rep, _Period>& t)
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
return m_cv.wait_for(lock, t);
|
||||
}
|
||||
|
||||
cv_status WaitFor(DWORD dwMilliseconds)
|
||||
{
|
||||
return WaitFor(chrono::milliseconds(dwMilliseconds));
|
||||
}
|
||||
|
||||
template<typename _Rep, typename _Period, typename _Predicate>
|
||||
bool WaitFor(const chrono::duration<_Rep, _Period>& t, _Predicate p)
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
return m_cv.wait_for(lock, t, p);
|
||||
}
|
||||
|
||||
template<typename _Predicate>
|
||||
bool WaitFor(DWORD dwMilliseconds, _Predicate p)
|
||||
{
|
||||
if(IS_INFINITE(dwMilliseconds))
|
||||
{
|
||||
Wait(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
return WaitFor(chrono::milliseconds(dwMilliseconds), p);
|
||||
|
||||
}
|
||||
|
||||
void NotifyOne()
|
||||
{
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
void NotifyAll()
|
||||
{
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void SyncNotifyOne()
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
NotifyOne();
|
||||
}
|
||||
|
||||
void SyncNotifyAll()
|
||||
{
|
||||
CMutexLock2 lock(m_mtx);
|
||||
|
||||
NotifyAll();
|
||||
}
|
||||
|
||||
private:
|
||||
CMTX m_mtx;
|
||||
condition_variable m_cv;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CSEM)
|
||||
DECLARE_PUBLIC_DEFAULT_CONSTRUCTOR(CSEM)
|
||||
};
|
||||
|
||||
using CCVLock = CSEM;
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||||
*
|
||||
* Author : Bruce Liang
|
||||
* Website : https://github.com/ldcsaa
|
||||
* Project : https://github.com/ldcsaa/HP-Socket
|
||||
* Blog : http://www.cnblogs.com/ldcsaa
|
||||
* Wiki : http://www.oschina.net/p/hp-socket
|
||||
* QQ Group : 44636872, 75375912
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../include/hpsocket/GlobalDef.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class T> class CSignalHandler
|
||||
{
|
||||
public:
|
||||
using MT = CSignalHandler<T>;
|
||||
using SI = siginfo_t;
|
||||
using SS = sigset_t;
|
||||
using CHandlerThread = CThread<MT, const SS, VOID>;
|
||||
using F = VOID (T::*)(const SI*);
|
||||
using SF = VOID (*)(const SI*);
|
||||
using SSPTR = unique_ptr<SS>;
|
||||
friend CHandlerThread;
|
||||
|
||||
public:
|
||||
|
||||
BOOL Setup(SF pFunc, const SS* pSigSet, BOOL bRestorOnCancel = TRUE)
|
||||
{
|
||||
return Setup((__CFakeRunnerClass_*)nullptr, *(F*)&pFunc, pSigSet, bRestorOnCancel);
|
||||
}
|
||||
|
||||
BOOL Setup(T* pRunner, F pFunc, const SS* pSigSet, BOOL bRestorOnCancel = TRUE)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(pSigSet != nullptr);
|
||||
|
||||
m_pssPre = make_unique<SS>();
|
||||
int rs = pthread_sigmask(SIG_BLOCK, pSigSet, m_pssPre.get());
|
||||
|
||||
if(rs != NO_ERROR)
|
||||
{
|
||||
m_pssPre = nullptr;
|
||||
::SetLastError(rs);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_pRunner = pRunner;
|
||||
m_pFunc = pFunc;
|
||||
m_pssCur = make_unique<SS>();
|
||||
|
||||
::CopyPlainObject(m_pssCur.get(), pSigSet);
|
||||
|
||||
BOOL isOK = m_thHandler.Start(this, &MT::ThreadFunc, m_pssCur.get());
|
||||
|
||||
if(isOK && !bRestorOnCancel)
|
||||
m_pssPre = nullptr;
|
||||
else if(!isOK)
|
||||
EXECUTE_RESTORE_ERROR(Reset());
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL Cancel()
|
||||
{
|
||||
BOOL isOK = m_thHandler.IsRunning();
|
||||
|
||||
if(isOK)
|
||||
{
|
||||
isOK = m_thHandler.Interrupt();
|
||||
isOK &= m_thHandler.Join();
|
||||
}
|
||||
|
||||
isOK &= Reset();
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL IsRunning () {return m_thHandler.IsRunning();}
|
||||
T* GetRunner () {return m_pRunner;}
|
||||
F GetFunc () {return m_pFunc;}
|
||||
SF GetSFunc () {return *(SF*)&m_pFunc;}
|
||||
THR_ID GetThreadID () {return m_thHandler.GetThreadID();}
|
||||
NTHR_ID GetNativeID () {return m_thHandler.GetNativeID();}
|
||||
|
||||
|
||||
private:
|
||||
VOID ThreadFunc(const SS* pSigSet)
|
||||
{
|
||||
ASSERT(pSigSet == m_pssCur.get());
|
||||
|
||||
SI si;
|
||||
|
||||
ZeroObject(si);
|
||||
|
||||
while(!::IsThreadInterrupted())
|
||||
{
|
||||
#if !defined(__ANDROID__)
|
||||
int rs = NO_EINTR_EXCEPT_THR_INTR_INT(sigwaitinfo(pSigSet, &si));
|
||||
#else
|
||||
int rs = NO_EINTR_EXCEPT_THR_INTR_INT(sigwait(pSigSet, &si.si_signo));
|
||||
#endif
|
||||
|
||||
if(IS_HAS_ERROR(rs))
|
||||
{
|
||||
if(IS_ERROR(EINTR))
|
||||
{
|
||||
ASSERT(::IsThreadInterrupted());
|
||||
break;
|
||||
}
|
||||
|
||||
ERROR_ABORT();
|
||||
}
|
||||
|
||||
Run((T*)nullptr, &si);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T_, typename = enable_if_t<!is_same<T_, __CFakeRunnerClass_>::value>>
|
||||
VOID Run(T_*, const SI* pSigSet) {(m_pRunner->*m_pFunc)(pSigSet);}
|
||||
|
||||
VOID Run(__CFakeRunnerClass_*, const SI* pSigSet) {(*(SF*)&m_pFunc)(pSigSet);}
|
||||
|
||||
|
||||
BOOL Reset()
|
||||
{
|
||||
BOOL isOK = TRUE;
|
||||
|
||||
if(m_pssPre)
|
||||
{
|
||||
isOK = (pthread_sigmask(SIG_SETMASK, m_pssPre.get(), nullptr) == NO_ERROR);
|
||||
m_pssPre = nullptr;
|
||||
}
|
||||
|
||||
m_pssCur = nullptr;
|
||||
m_pRunner = nullptr;
|
||||
m_pFunc = nullptr;
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
public:
|
||||
CSignalHandler()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CSignalHandler()
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CSignalHandler)
|
||||
|
||||
private:
|
||||
T* m_pRunner;
|
||||
F m_pFunc;
|
||||
SSPTR m_pssCur;
|
||||
SSPTR m_pssPre;
|
||||
CHandlerThread m_thHandler;
|
||||
};
|
||||
|
||||
using CStaticSignalHandler = CSignalHandler<__CFakeRunnerClass_>;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue