瀏覽代碼

HP-Socket 第三方网络库

Flynn 8 年之前
當前提交
4735767381

+ 328 - 0
HP-Socket/Src/HPTypeDef.h

@@ -0,0 +1,328 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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
+
+/*****************************************************************************************************************************************************/
+/**************************************************************** Base Type Definitions **************************************************************/
+/*****************************************************************************************************************************************************/
+
+typedef const BYTE*	LPCBYTE, PCBYTE;
+
+/************************************************************************
+名称:连接 ID 数据类型
+描述:应用程序可以把 CONNID 定义为自身需要的类型(如:ULONG / ULONGLONG)
+************************************************************************/
+typedef ULONG_PTR	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;
+
+/************************************************************************
+名称:操作结果代码
+描述:组件 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,		// 数据发送失败
+
+	/***** SSL Socket 扩展操作结果代码 *****/
+	SE_SSL_ENV_NOT_READY		= 101,		// SSL 环境未就绪
+} En_HP_SocketError;
+
+/************************************************************************
+名称:播送模式
+描述:UDP 组件的播送模式(组播或广播)
+************************************************************************/
+typedef enum EnCastMode
+{
+	CM_MULTICAST	= 0,	// 组播
+	CM_BROADCAST	= 1,	// 广播
+} En_HP_CastMode;
+
+
+/*****************************************************************************************************************************************************/
+/**************************************************************** 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;
+
+/************************************************************************
+名称:SNI 服务名称回调函数
+描述:根据服务器名称选择 SSL 证书
+参数:	
+		lpszServerName -- 服务器名称(域名)
+
+返回值:
+		0	 -- 成功,使用默认 SSL 证书
+		正数	 -- 成功,使用返回值对应的 SNI 主机证书
+		负数	 -- 失败,中断 SSL 握手
+
+************************************************************************/
+typedef int (CALLBACK *Fn_SNI_ServerNameCallback)(LPCTSTR lpszServerName);
+typedef Fn_SNI_ServerNameCallback	HP_Fn_SNI_ServerNameCallback;
+
+#endif
+
+/*****************************************************************************************************************************************************/
+/**************************************************************** HTTP Type Definitions **************************************************************/
+/*****************************************************************************************************************************************************/
+
+/************************************************************************
+名称: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_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_IM_USED							= 226,
+
+	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_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	= 431,
+	HSC_UNAVAILABLE_FOR_LEGAL_REASONS	= 451,
+	HSC_RETRY_WITH						= 449,
+
+	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_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;

+ 832 - 0
HP-Socket/Src/HttpHelper.cpp

@@ -0,0 +1,832 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "HttpHelper.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult)
+{
+	strResult.Format("HTTP/%d.%d", LOBYTE(enVersion), HIBYTE(enVersion));
+	return strResult;
+}
+
+CStringA& AdjustRequestPath(LPCSTR lpszPath, CStringA& strPath)
+{
+	strPath = lpszPath;
+
+	if(strPath.IsEmpty() || 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_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_IM_USED						: return "IM Used";
+
+	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_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: return "Request Header Fields Too Large";
+	case HSC_UNAVAILABLE_FOR_LEGAL_REASONS	: return "Unavailable For Legal Reasons";
+	case HSC_RETRY_WITH						: return "Retry With";
+
+	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_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", 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_hash_func::hash, str_hash_func::equal_to> szHeaderNames;
+
+	if(iHeaderCount > 0)
+	{
+		ASSERT(lpHeaders);
+
+		for(int i = 0; i < iHeaderCount; i++)
+		{
+			const THeader& header = lpHeaders[i];
+
+			if(header.name != nullptr)
+			{
+				ASSERT(strlen(header.name) > 0);
+
+				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 && lpszDefaultHost && lpszDefaultHost[0] != 0			&&
+		(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 = (LPSTR)(LPCSTR)strHeader;
+	szBuffer[0].len = strHeader.GetLength();
+	szBuffer[1].buf = (LPSTR)(LPCSTR)pBody;
+	szBuffer[1].len = iLength;
+}
+
+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 = (LPSTR)(LPCSTR)szHeader;
+	szBuffer[0].len = iHeaderLen;
+	szBuffer[1].buf = (LPSTR)(LPCSTR)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);
+	CStringA strSchema	= strUrl.Left(iSchemaLength);
+
+	strSchema.MakeLower();
+
+	if(strSchema.Compare(HTTP_SCHEMA) == 0)
+		bHttps = FALSE;
+	else
+	{
+		iSchemaLength	= (int)strlen(HTTPS_SCHEMA);
+		strSchema		= strUrl.Left(iSchemaLength);
+
+		strSchema.MakeLower();
+
+		if(strSchema.Compare(HTTPS_SCHEMA) == 0)
+			bHttps = TRUE;
+		else
+			return FALSE;
+	}
+
+	int i = strUrl.Find(HTTP_PATH_SEPARATOR_CHAR, iSchemaLength);
+
+	if(i > 0)
+	{
+		strHost = strUrl.Mid(iSchemaLength, i - iSchemaLength);
+		strPath = strUrl.Mid(i);
+	}
+	else
+	{
+		strHost = strUrl.Mid(iSchemaLength);
+		strPath = HTTP_PATH_SEPARATOR;
+	}
+
+	if(strHost.IsEmpty() || !::isalnum(strHost.GetAt(0)))
+		return FALSE;
+
+	i = strHost.Find(HTTP_PORT_SEPARATOR_CHAR);
+
+	if(i > 0)
+	{
+		CStringA strPort = strHost.Mid(i + 1);
+		int iLength		 = strPort.GetLength();
+
+		if(iLength == 0)
+			return FALSE;
+
+		for(int j = 0; j < iLength; j++)
+		{
+			if(!::isdigit(strPort.GetAt(j)))
+				return FALSE;
+		}
+
+		usPort	= (USHORT)::atoi(strPort);
+		strHost = strHost.Mid(0, i);
+	}
+	else
+	{
+		usPort = bHttps ? HTTPS_DEFAULT_PORT : HTTP_DEFAULT_PORT;
+	}
+
+	return TRUE;
+}
+
+BOOL CodePageToUnicode(int iCodePage, const char szSrc[], WCHAR szDest[], int& iDestLength)
+{
+	ASSERT(szSrc);
+
+	int iSize = ::MultiByteToWideChar(iCodePage, 0, szSrc, -1, nullptr, 0);
+
+	if(iSize == 0 || iSize > iDestLength || !szDest || iDestLength == 0)
+	{
+		iDestLength = iSize;
+		return FALSE;
+	}
+
+	if(::MultiByteToWideChar(iCodePage, 0, szSrc, -1, szDest, iSize) != 0)
+		iDestLength = iSize;
+	else
+		iDestLength = 0;
+
+	return iDestLength != 0;
+}
+
+BOOL UnicodeToCodePage(int iCodePage, const WCHAR szSrc[], char szDest[], int& iDestLength)
+{
+	ASSERT(szSrc);
+
+	int iSize = ::WideCharToMultiByte(iCodePage, 0, szSrc, -1, nullptr, 0, nullptr, nullptr);
+
+	if(iSize == 0 || iSize > iDestLength || !szDest || iDestLength == 0)
+	{
+		iDestLength = iSize;
+		return FALSE;
+	}
+
+	if(::WideCharToMultiByte(iCodePage, 0, szSrc, -1, szDest, iSize, nullptr, nullptr) != 0)
+		iDestLength = iSize;
+	else
+		iDestLength = 0;
+
+	return iDestLength != 0;
+}
+
+BOOL GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
+{
+	return CodePageToUnicode(CP_ACP, szSrc, szDest, iDestLength);
+}
+
+BOOL UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
+{
+	return UnicodeToCodePage(CP_ACP, szSrc, szDest, iDestLength);
+}
+
+BOOL Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
+{
+	return CodePageToUnicode(CP_UTF8, szSrc, szDest, iDestLength);
+}
+
+BOOL UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
+{
+	return UnicodeToCodePage(CP_UTF8, szSrc, szDest, iDestLength);
+}
+
+BOOL GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
+{
+	int iMiddleLength = 0;
+	GbkToUnicode(szSrc, nullptr, iMiddleLength);
+
+	if(iMiddleLength == 0)
+	{
+		iDestLength = 0;
+		return FALSE;
+	}
+
+	unique_ptr<WCHAR[]> p(new WCHAR[iMiddleLength]);
+	VERIFY(GbkToUnicode(szSrc, p.get(), iMiddleLength));
+
+	return UnicodeToUtf8(p.get(), szDest, iDestLength);
+}
+
+BOOL Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
+{
+	int iMiddleLength = 0;
+	Utf8ToUnicode(szSrc, nullptr, iMiddleLength);
+
+	if(iMiddleLength == 0)
+	{
+		iDestLength = 0;
+		return FALSE;
+	}
+
+	unique_ptr<WCHAR[]> p(new WCHAR[iMiddleLength]);
+	VERIFY(Utf8ToUnicode(szSrc, p.get(), iMiddleLength));
+
+	return UnicodeToGbk(p.get(), szDest, iDestLength);
+}
+
+int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
+}
+
+int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel, int iMethod, int iWindowBits, int iMemLevel, int iStrategy)
+{
+	z_stream stream;
+
+	stream.next_in	 = (z_const Bytef*)lpszSrc;
+	stream.avail_in	 = dwSrcLen;
+	stream.next_out	 = lpszDest;
+	stream.avail_out = dwDestLen;
+	stream.zalloc	 = nullptr;
+	stream.zfree	 = nullptr;
+	stream.opaque	 = nullptr;
+
+	int err = ::deflateInit2(&stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy);
+
+	if(err != Z_OK) return err;
+
+	err = ::deflate(&stream, Z_FINISH);
+
+	if(err != Z_STREAM_END)
+	{
+		::deflateEnd(&stream);
+		return err == Z_OK ? Z_BUF_ERROR : err;
+	}
+
+	if(dwDestLen > stream.total_out)
+	{
+		lpszDest[stream.total_out]	= 0;
+		dwDestLen					= stream.total_out;
+	}
+
+	return ::deflateEnd(&stream);
+}
+
+int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
+}
+
+int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits)
+{
+	z_stream stream;
+
+	stream.next_in	 = (z_const Bytef*)lpszSrc;
+	stream.avail_in	 = (uInt)dwSrcLen;
+	stream.next_out	 = lpszDest;
+	stream.avail_out = dwDestLen;
+	stream.zalloc	 = nullptr;
+	stream.zfree	 = nullptr;
+
+	int err = ::inflateInit2(&stream, iWindowBits);
+
+	if(err != Z_OK) return err;
+
+	err = ::inflate(&stream, Z_FINISH);
+
+	if(err != Z_STREAM_END)
+	{
+		::inflateEnd(&stream);
+		return (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) ? Z_DATA_ERROR : err;
+	}
+
+	if(dwDestLen > stream.total_out)
+	{
+		lpszDest[stream.total_out]	= 0;
+		dwDestLen					= stream.total_out;
+	}
+
+	return inflateEnd(&stream);
+}
+
+DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip)
+{
+	DWORD dwBound = ::compressBound(dwSrcLen);
+	
+	if(bGZip) dwBound += 11;
+
+	return dwBound;
+}
+
+int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16);
+}
+
+int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, MAX_WBITS + 32);
+}
+
+DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen)
+{
+	if(dwSrcLen < 20 || *(USHORT*)lpszSrc != 0x8B1F)
+		return 0;
+
+	return *(DWORD*)(lpszSrc + dwSrcLen - 4);
+}
+
+DWORD GuessBase64EncodeBound(DWORD dwSrcLen)
+{
+	return 4 * ((dwSrcLen + 2) / 3);
+}
+
+DWORD GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
+{
+	if(dwSrcLen < 2)
+		return 0;
+
+	if(lpszSrc[dwSrcLen - 2] == '=')
+		dwSrcLen -= 2;
+	else if(lpszSrc[dwSrcLen - 1] == '=')
+			--dwSrcLen;
+
+	DWORD dwMod = dwSrcLen % 4;
+	DWORD dwAdd = dwMod == 2 ? 1 : (dwMod == 3 ? 2 : 0);
+
+	return 3 * (dwSrcLen / 4) + dwAdd;
+}
+
+int Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	static const BYTE CODES[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+	DWORD dwRealLen = GuessBase64EncodeBound(dwSrcLen);
+
+	if(lpszDest == nullptr || dwDestLen < dwRealLen)
+	{
+		dwDestLen = dwRealLen;
+		return -5;
+	}
+
+	BYTE* p		= lpszDest;
+	DWORD leven	= 3 * (dwSrcLen / 3);
+	DWORD i		= 0;
+
+	for (; i < leven; i += 3)
+	{
+		*p++ = CODES[lpszSrc[0] >> 2];
+		*p++ = CODES[((lpszSrc[0] & 3) << 4) + (lpszSrc[1] >> 4)];
+		*p++ = CODES[((lpszSrc[1] & 0xf) << 2) + (lpszSrc[2] >> 6)];
+		*p++ = CODES[lpszSrc[2] & 0x3f];
+
+		lpszSrc += 3;
+	}
+
+	if(i < dwSrcLen)
+	{
+		BYTE a = lpszSrc[0];
+		BYTE b = (i + 1 < dwSrcLen) ? lpszSrc[1] : 0;
+
+		*p++ = CODES[a >> 2];
+		*p++ = CODES[((a & 3) << 4) + (b >> 4)];
+		*p++ = (i + 1 < dwSrcLen) ? CODES[((b & 0xf) << 2)] : '=';
+		*p++ = '=';
+	}  
+
+	ASSERT(dwRealLen == p - lpszDest);
+
+	if(dwDestLen > dwRealLen)
+	{
+		*p			= 0;
+		dwDestLen	= dwRealLen;
+	}
+
+	return 0;  
+}
+
+int Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	static const BYTE MAP[256]	=
+	{ 
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
+		255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
+		 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+		255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
+		  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
+		 19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
+		255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
+		 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+		 49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		255, 255, 255, 255
+	};
+
+	DWORD dwRealLen = GuessBase64DecodeBound(lpszSrc, dwSrcLen);
+
+	if(lpszDest == nullptr || dwDestLen < dwRealLen)
+	{
+		dwDestLen = dwRealLen;
+		return -5;
+	}
+
+	BYTE c;
+	int g = 3;
+	DWORD i, x, y, z;
+
+	for(i = x = y = z = 0; i < dwSrcLen || x != 0;)
+	{
+		c = i < dwSrcLen ? MAP[lpszSrc[i++]] : 254;
+
+		if(c == 255) {dwDestLen = 0; return -3;}
+		else if(c == 254) {c = 0; g--;}
+		else if(c == 253) continue;
+
+		z = (z << 6) | c;
+
+		if(++x == 4)
+		{
+			lpszDest[y++] = (BYTE)((z >> 16) & 255);
+			if (g > 1) lpszDest[y++] = (BYTE)((z >> 8) & 255);
+			if (g > 2) lpszDest[y++] = (BYTE)(z & 255);
+
+			x = z = 0;
+		}
+	}
+
+	BOOL isOK = (y == dwRealLen);
+
+	if(!isOK)
+		dwDestLen = 0;
+	else
+	{
+		if(dwDestLen > dwRealLen)
+		{
+			lpszDest[dwRealLen]	= 0;
+			dwDestLen			= dwRealLen;
+		}
+	}
+
+	return isOK ? 0 : -3;
+}
+
+DWORD GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
+{
+	DWORD dwAdd = 0;
+
+	for(DWORD i = 0; i < dwSrcLen; i++)
+	{
+		BYTE c	= lpszSrc[i];
+
+		if(!(isalnum(c) || c == ' ' || c == '.' || c == '-' || c == '_' || c == '*'))
+			dwAdd += 2;
+	}
+
+	return dwSrcLen + dwAdd;
+}
+
+DWORD GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
+{
+	DWORD dwPercent = 0;
+
+	for(DWORD i = 0; i < dwSrcLen; i++)
+	{
+		if(lpszSrc[i] == '%')
+		{
+			++dwPercent;
+			i += 2;
+		}
+	}
+
+	DWORD dwSub = dwPercent * 2;
+
+	if(dwSrcLen < dwSub)
+		return 0;
+
+	return dwSrcLen - dwSub;
+}
+
+#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)	(((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) = HEX_VALUE_TO_CHAR((n >> 4)); *((pc) + 1) = HEX_VALUE_TO_CHAR((n & 0X0F));}
+
+int UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	if(lpszDest == nullptr || dwDestLen == 0)
+		goto ERROR_DEST_LEN;
+
+	BYTE c;
+	DWORD j = 0;
+
+	for(DWORD i = 0; i < dwSrcLen; i++)
+	{
+		if(j >= dwDestLen)
+			goto ERROR_DEST_LEN;
+
+		c = lpszSrc[i];
+
+		if (isalnum(c) || c == '.' || c == '-' || c == '_' || c == '*')
+			lpszDest[j++] = c;
+		else if(c == ' ')
+			lpszDest[j++] = '+';
+		else
+		{
+			if(j + 3 >= dwDestLen)
+				goto ERROR_DEST_LEN;
+
+			lpszDest[j++] = '%';
+			HEX_VALUE_TO_DOUBLE_CHAR(lpszDest + j, c);
+			j += 2;
+			
+		}
+	}
+
+	if(dwDestLen > j)
+	{
+		lpszDest[j]	= 0;
+		dwDestLen	= j;
+	}
+
+	return 0;
+
+ERROR_DEST_LEN:
+	dwDestLen = GuessUrlEncodeBound(lpszSrc, dwSrcLen);
+	return -5;
+}
+
+int UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
+{
+	if(lpszDest == nullptr || dwDestLen == 0)
+		goto ERROR_DEST_LEN;
+
+	char c;
+	DWORD j = 0;
+
+	for(DWORD i = 0; i < dwSrcLen; i++)
+	{
+		if(j >= dwDestLen)
+			goto ERROR_DEST_LEN;
+
+		c = lpszSrc[i];
+
+		if(c == '+')
+			lpszDest[j++] = ' ';
+		else if(c != '%')
+			lpszDest[j++] = c;
+		else
+		{
+			if(i + 2 >= dwSrcLen)
+				goto ERROR_SRC_DATA;
+
+			lpszDest[j++] = HEX_DOUBLE_CHAR_TO_VALUE(lpszSrc + i + 1);
+			i += 2;
+		}
+	}
+
+	if(dwDestLen > j)
+	{
+		lpszDest[j]	= 0;
+		dwDestLen	= j;
+	}
+
+	return 0;
+
+ERROR_SRC_DATA:
+	dwDestLen = 0;
+	return -3;
+
+ERROR_DEST_LEN:
+	dwDestLen = GuessUrlDecodeBound(lpszSrc, dwSrcLen);
+	return -5;
+}

+ 1352 - 0
HP-Socket/Src/HttpHelper.h

@@ -0,0 +1,1352 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "HttpCookie.h"
+
+#include "../../Common/Src/http/http_parser.h"
+#include "../../Common/Src/zlib/zutil.h"
+
+/************************************************************************
+名称:HTTP 全局常量
+描述:声明 HTTP 组件的公共全局常量
+************************************************************************/
+
+#define HTTP_DEFAULT_PORT					80
+#define HTTPS_DEFAULT_PORT					443
+
+#define HTTP_SCHEMA							"http://"
+#define HTTPS_SCHEMA						"https://"
+
+#define HTTP_CRLF							"\r\n"
+#define HTTP_PORT_SEPARATOR_CHAR			':'
+#define HTTP_PATH_SEPARATOR_CHAR			'/'
+#define HTTP_PATH_SEPARATOR					"/"
+#define HTTP_HEADER_SEPARATOR				": "
+#define HTTP_COOKIE_SEPARATOR				"; "
+#define HTTP_1_0_STR						"HTTP/1.0"
+#define HTTP_1_1_STR						"HTTP/1.1"
+
+#define HTTP_HEADER_HOST					"Host"
+#define HTTP_HEADER_COOKIE					"Cookie"
+#define HTTP_HEADER_SET_COOKIE				"Set-Cookie"
+#define HTTP_HEADER_CONTENT_TYPE			"Content-Type"
+#define HTTP_HEADER_CONTENT_LENGTH			"Content-Length"
+#define HTTP_HEADER_CONTENT_ENCODING		"Content-Encoding"
+#define HTTP_HEADER_TRANSFER_ENCODING		"Transfer-Encoding"
+#define HTTP_HEADER_CONNECTION				"Connection"
+#define HTTP_HEADER_UPGRADE					"Upgrade"
+#define HTTP_HEADER_VALUE_WEB_SOCKET		"WebSocket"
+
+#define HTTP_CONNECTION_CLOSE_VALUE			"close"
+#define HTTP_CONNECTION_KEEPALIVE_VALUE		"keep-alive"
+
+#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_MIN_WS_HEADER_LEN				2
+#define HTTP_MAX_WS_HEADER_LEN				14
+
+#define MIN_HTTP_RELEASE_CHECK_INTERVAL		1000
+#define MIN_HTTP_RELEASE_DELAY				100
+#define MAX_HTTP_RELEASE_DELAY				(60 * 1000)
+#define DEFAULT_HTTP_RELEASE_DELAY			(3 * 1000)
+#define DEFAULT_HTTP_VERSION				HV_1_1
+
+#define DEFAULT_HTTP_SYNC_CONNECT_TIMEOUT	5000
+#define DEFAULT_HTTP_SYNC_REQUEST_TIMEOUT	10000
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+enum EnHttpSyncRequestProgress
+{
+	HSRP_DONE,
+	HSRP_WAITING,
+	HSRP_ERROR,
+	HSRP_CLOSE
+};
+
+struct TDyingConnection
+{
+	CONNID			connID;
+	DWORD			killTime;
+
+	TDyingConnection(CONNID id, DWORD kt = 0)
+	: connID		(id)
+	, killTime		(kt == 0 ? ::TimeGetTime() : kt)
+	{
+
+	}
+
+	static TDyingConnection* Construct(CONNID id, DWORD kt = 0)	{return new TDyingConnection(id, kt);}
+	static void Destruct(TDyingConnection* pObj)				{if(pObj) delete pObj;}
+
+};
+
+typedef unordered_multimap<CStringA, CStringA,
+		cstringa_hash_func::hash, cstringa_hash_func::equal_to>	THeaderMap;
+typedef THeaderMap::const_iterator								THeaderMapCI;
+typedef THeaderMap::iterator									THeaderMapI;
+
+typedef unordered_map<CStringA, CStringA,
+		cstringa_hash_func::hash, cstringa_hash_func::equal_to>	TCookieMap;
+typedef TCookieMap::const_iterator								TCookieMapCI;
+typedef TCookieMap::iterator									TCookieMapI;
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+struct TBaseWSHeader
+{
+public:
+	BOOL fin()
+	{
+		return (data >> 7) & 0x1;
+	}
+
+	void set_fin(BOOL v)
+	{
+		data |= ((v ? 1 : 0) << 7);
+	}
+
+	BYTE rsv()
+	{
+		return (data >> 4) & 0x7;
+	}
+
+	void set_rsv(BYTE v)
+	{
+		data |= ((v & 0x7) << 4);
+	}
+
+	BYTE code()
+	{
+		return data & 0xF;
+	}
+
+	void set_code(BYTE v)
+	{
+		data |= (v & 0xF);
+	}
+
+	BOOL mask()
+	{
+		return (data >> 15) & 0x1;
+	}
+
+	void set_mask(BOOL v)
+	{
+		data |= ((v ? 1 : 0) << 15);
+	}
+
+	BYTE len()
+	{
+		return (data >> 8) & 0x7F;
+	}
+
+	void set_len(BYTE v)
+	{
+		data |= ((v & 0x7F) << 8);
+	}
+
+	USHORT extlen()
+	{
+		return ntohs(data >> 16);
+	}
+
+	void set_extlen(USHORT v)
+	{
+		data |= (htons(v) << 16);
+	}
+
+	TBaseWSHeader(const BYTE* p, BOOL bZero = FALSE)
+	: data(*(UINT*)p)
+	{
+		if(bZero) data = 0;
+	}
+
+private:
+	UINT& data;
+};
+
+template<class T> struct TWSContext
+{
+public:
+	EnHandleResult Parse(const BYTE* pData, int iLength)
+	{
+		ASSERT(pData != nullptr && iLength > 0);
+
+		EnHandleResult hr	= HR_OK;
+		BYTE* pTemp			= (BYTE*)pData;
+		int iRemain			= iLength;
+		int iMin			= 0;
+
+		while(iRemain > 0)
+		{
+			if(m_bHeader)
+			{
+				iMin = min(m_iHeaderRemain, iRemain);
+				memcpy(m_szHeader + m_iHeaderLen - m_iHeaderRemain, pTemp, iMin);
+
+				m_iHeaderRemain	-= iMin;
+
+				if(m_iHeaderRemain == 0)
+				{
+					TBaseWSHeader bh(m_szHeader);
+
+					int iLen			= bh.len();
+					int iExtLen			= iLen < 126 ? 0 : (iLen == 126 ? 2 : 8);
+					int iMaskLen		= bh.mask() ? 4 : 0;
+					int iRealHeaderLen	= HTTP_MIN_WS_HEADER_LEN + iExtLen + iMaskLen;
+
+					if(m_iHeaderLen < iRealHeaderLen)
+					{
+						m_iHeaderRemain	= iRealHeaderLen - m_iHeaderLen;
+						m_iHeaderLen	= iRealHeaderLen;
+					}
+					else
+					{
+						m_ullBodyLen	= iExtLen == 0 ? iLen : (iExtLen == 2 ? bh.extlen() : NToH64(*(ULONGLONG*)(m_szHeader + HTTP_MIN_WS_HEADER_LEN)));
+						m_ullBodyRemain	= m_ullBodyLen;
+						m_lpszMask		= iMaskLen > 0 ? m_szHeader + HTTP_MIN_WS_HEADER_LEN + iExtLen : nullptr;
+
+						hr = m_pHttpObj->on_ws_message_header(bh.fin(), bh.rsv(), bh.code(), m_lpszMask, m_ullBodyLen);
+
+						if(hr == HR_ERROR)
+							break;
+
+						if(m_ullBodyLen > 0)
+							m_bHeader = FALSE;
+						else
+						{
+							hr = CompleteMessage();
+
+							if(hr == HR_ERROR)
+								break;
+						}
+					}
+				}
+			}
+			else
+			{
+				iMin = (int)min(m_ullBodyRemain, (ULONGLONG)iRemain);
+
+				if(m_lpszMask)
+				{
+					int iFactor = (m_ullBodyLen - m_ullBodyRemain) & 0x03;
+
+					for(int i = 0; i < iMin; i++)
+						pTemp[i] = pTemp[i] ^ m_lpszMask[(i + iFactor) & 0x03];
+				}
+
+				m_ullBodyRemain	-= iMin;
+
+				EnHandleResult hr = m_pHttpObj->on_ws_message_body(pTemp, iMin);
+
+				if(hr == HR_ERROR)
+					break;
+
+				if(m_ullBodyRemain == 0)
+				{
+					hr = CompleteMessage();
+
+					if(hr == HR_ERROR)
+						break;
+				}
+			}
+
+			pTemp	+= iMin;
+			iRemain	-= iMin;
+		}
+
+		return HR_OK;
+	}
+
+	BOOL GetMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
+	{
+		TBaseWSHeader bh(m_szHeader);
+
+		if(lpbFinal)			*lpbFinal			= bh.fin();
+		if(lpiReserved)			*lpiReserved		= bh.rsv();
+		if(lpiOperationCode)	*lpiOperationCode	= bh.code();
+		if(lpszMask)			*lpszMask			= m_lpszMask;
+		if(lpullBodyLen)		*lpullBodyLen		= m_ullBodyLen;
+		if(lpullBodyRemain)		*lpullBodyRemain	= m_ullBodyRemain;
+
+		return TRUE;
+	}
+
+	BOOL CopyData(const TWSContext& src)
+	{
+		if(&src == this)
+			return FALSE;
+
+		memcpy(m_szHeader, src.m_szHeader, HTTP_MAX_WS_HEADER_LEN);
+
+		if(src.m_lpszMask)
+			m_lpszMask = m_szHeader + (src.m_lpszMask - src.m_szHeader);
+		else
+			m_lpszMask = nullptr;
+
+		m_ullBodyLen	= src.m_ullBodyLen;
+		m_ullBodyRemain	= src.m_ullBodyRemain;
+
+		return TRUE;
+	}
+
+public:
+	TWSContext(T* pHttpObj) : m_pHttpObj(pHttpObj)
+	{
+		Reset();
+	}
+
+private:
+	EnHandleResult CompleteMessage()
+	{
+		EnHandleResult hr = m_pHttpObj->on_ws_message_complete();
+
+		Reset();
+
+		return hr;
+	}
+
+	void Reset()
+	{
+		m_bHeader		= TRUE;
+		m_lpszMask		= nullptr;
+		m_iHeaderLen	= HTTP_MIN_WS_HEADER_LEN;
+		m_iHeaderRemain	= HTTP_MIN_WS_HEADER_LEN;
+		m_ullBodyLen	= 0;
+		m_ullBodyRemain	= 0;
+	}
+
+private:
+	T* m_pHttpObj;
+
+	BYTE m_szHeader[HTTP_MAX_WS_HEADER_LEN];
+	const BYTE* m_lpszMask;
+
+	BOOL m_bHeader;
+	int m_iHeaderLen;
+	int m_iHeaderRemain;
+	ULONGLONG m_ullBodyLen;
+	ULONGLONG m_ullBodyRemain;
+};
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+/* Http 上下文结构 */
+template<class T, class S> struct THttpObjT
+{
+public:
+	EnHandleResult Execute(const BYTE* pData, int iLength)
+	{
+		ASSERT(pData != nullptr && iLength > 0);
+
+		if(m_parser.upgrade)
+		{
+			if(m_enUpgrade == HUT_WEB_SOCKET)
+				return m_pwsContext->Parse(pData, iLength);
+			else
+				return m_pContext->DoFireSuperReceive(m_pSocket, pData, iLength);
+		}
+
+		EnHandleResult hr = HR_OK;
+		int iPased		  = (int)::http_parser_execute(&m_parser, &sm_settings, (LPCSTR)pData, iLength);
+
+		if(m_parser.upgrade)
+			hr = Upgrade(pData, iLength, iPased);
+		else if(m_parser.http_errno != HPE_OK)
+		{
+			m_pContext->FireParseError(m_pSocket, m_parser.http_errno, ::http_errno_description(HTTP_PARSER_ERRNO(&m_parser)));
+			hr = HR_ERROR;
+		}
+		else
+			ASSERT(iPased == iLength);
+
+		return hr;
+	}
+
+	static int on_message_begin(http_parser* p)
+	{
+		THttpObjT* pSelf = Self(p);
+
+		pSelf->ResetHeaderState(FALSE, FALSE);
+
+		return pSelf->m_pContext->FireMessageBegin(pSelf->m_pSocket);
+	}
+
+	static int on_url(http_parser* p, const char* at, size_t length)
+	{
+		EnHttpParseResult hpr	= HPR_OK;
+		THttpObjT* pSelf		= Self(p);
+
+		pSelf->AppendBuffer(at, length);
+
+		if(p->state != s_req_http_start)
+			return hpr;
+
+		hpr = pSelf->ParseUrl();
+
+		if(hpr == HPR_OK)
+			hpr = pSelf->m_pContext->FireRequestLine(pSelf->m_pSocket, ::http_method_str((http_method)p->method), pSelf->GetBuffer());
+
+		pSelf->ResetBuffer();
+
+		return hpr;
+	}
+
+	static int on_status(http_parser* p, const char* at, size_t length)
+	{
+		EnHttpParseResult hpr	= HPR_OK;
+		THttpObjT* pSelf		= Self(p);
+
+		pSelf->AppendBuffer(at, length);
+
+		if(p->state != s_res_line_almost_done)
+			return hpr;
+
+		hpr = pSelf->m_pContext->FireStatusLine(pSelf->m_pSocket, p->status_code, pSelf->GetBuffer());
+		pSelf->ResetBuffer();
+
+		return hpr;
+	}
+
+	static int on_header_field(http_parser* p, const char* at, size_t length)
+	{
+		EnHttpParseResult hpr	= HPR_OK;
+		THttpObjT* pSelf		= Self(p);
+
+		pSelf->AppendBuffer(at, length);
+
+		if(p->state != s_header_value_discard_ws)
+			return hpr;
+
+		pSelf->m_strCurHeader = pSelf->GetBuffer();
+		pSelf->ResetBuffer();
+
+		return hpr;
+	}
+
+	static int on_header_value(http_parser* p, const char* at, size_t length)
+	{
+		EnHttpParseResult hpr	= HPR_OK;
+		THttpObjT* pSelf		= Self(p);
+
+		pSelf->AppendBuffer(at, length);
+
+		if(p->state != s_header_almost_done && p->state != s_header_field_start)
+			return hpr;
+
+		pSelf->m_headers.emplace(move(THeaderMap::value_type(pSelf->m_strCurHeader, pSelf->GetBuffer())));
+		hpr = pSelf->m_pContext->FireHeader(pSelf->m_pSocket, pSelf->m_strCurHeader, pSelf->GetBuffer());
+
+		if(hpr != HPR_ERROR)
+		{
+			if(pSelf->m_bRequest && pSelf->m_strCurHeader == HTTP_HEADER_COOKIE)
+				hpr = pSelf->ParseCookie();
+			else if(!pSelf->m_bRequest && pSelf->m_strCurHeader == HTTP_HEADER_SET_COOKIE)
+				hpr = pSelf->ParseSetCookie();
+		}
+
+		pSelf->ResetBuffer();
+
+		return hpr;
+	}
+
+	static int on_headers_complete(http_parser* p)
+	{
+		THttpObjT* pSelf = Self(p);
+
+		pSelf->CheckUpgrade();
+		pSelf->ResetHeaderBuffer();
+
+		return pSelf->m_pContext->FireHeadersComplete(pSelf->m_pSocket);
+	}
+
+	static int on_body(http_parser* p, const char* at, size_t length)
+	{
+		THttpObjT* pSelf = Self(p);
+
+		return pSelf->m_pContext->FireBody(pSelf->m_pSocket, (const BYTE*)at, (int)length);
+	}
+
+	static int on_chunk_header(http_parser* p)
+	{
+		THttpObjT* pSelf = Self(p);
+
+		if(p->state == s_chunk_data || p->state == s_header_field_start)
+			return pSelf->m_pContext->FireChunkHeader(pSelf->m_pSocket, (int)p->content_length);
+
+		return HPR_OK;
+	}
+
+	static int on_chunk_complete(http_parser* p)
+	{
+		THttpObjT* pSelf = Self(p);
+
+		if(p->state == s_headers_done || p->state == s_message_done)
+			return pSelf->m_pContext->FireChunkComplete(pSelf->m_pSocket);
+
+		return HPR_OK;
+	}
+
+	static int on_message_complete(http_parser* p)
+	{
+		THttpObjT* pSelf		= Self(p);
+		EnHttpParseResult hpr	= pSelf->m_pContext->FireMessageComplete(pSelf->m_pSocket);
+
+		return hpr;
+	}
+
+	EnHandleResult on_ws_message_header(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
+	{
+		return m_pContext->FireWSMessageHeader(m_pSocket, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);
+	}
+
+	EnHandleResult on_ws_message_body(const BYTE* pData, int iLength)
+	{
+		return m_pContext->FireWSMessageBody(m_pSocket, pData, iLength);
+	}
+
+	EnHandleResult on_ws_message_complete()
+	{
+		return m_pContext->FireWSMessageComplete(m_pSocket);
+	}
+
+private:
+
+	EnHandleResult Upgrade(const BYTE* pData, int iLength, int iPased)
+	{
+		ASSERT(m_parser.upgrade);
+
+		if(m_pContext->FireUpgrade(m_pSocket, m_enUpgrade) != HPR_OK)
+			return HR_ERROR;
+
+		ResetHeaderState();
+
+		if(m_enUpgrade == HUT_WEB_SOCKET)
+			m_pwsContext = new TWSContext<THttpObjT<T, S>>(this);
+
+		if(iPased < iLength)
+			return Execute(pData + iPased, iLength - iPased);
+
+		return HR_OK;
+	}
+
+	void CheckUpgrade()
+	{
+		if(!m_parser.upgrade)
+			return;
+
+		if(m_bRequest && m_parser.method == HTTP_CONNECT)
+			m_enUpgrade = HUT_HTTP_TUNNEL;
+		else
+		{
+			LPCSTR lpszValue;
+			if(GetHeader(HTTP_HEADER_UPGRADE, &lpszValue) && _stricmp(HTTP_HEADER_VALUE_WEB_SOCKET, lpszValue) == 0)
+				m_enUpgrade = HUT_WEB_SOCKET;
+			else
+				m_enUpgrade = HUT_UNKNOWN;
+		}
+	}
+
+	EnHttpParseResult ParseUrl()
+	{
+		http_parser_url url = {0};
+
+		BOOL isConnect	= m_parser.method == HTTP_CONNECT;
+		int rs			= ::http_parser_parse_url(m_strBuffer, m_strBuffer.GetLength(), isConnect, &url);
+
+		if(rs != HPE_OK)
+		{
+			m_parser.http_errno = HPE_INVALID_URL;
+			return HPR_ERROR;
+		}
+
+		m_usUrlFieldSet		= url.field_set;
+		LPCSTR lpszBuffer	= m_strBuffer;
+
+		for(int i = 0; i < UF_MAX; i++)
+		{
+			if((url.field_set & (1 << i)) != 0)
+				m_pstrUrlFileds[i].SetString((lpszBuffer + url.field_data[i].off), url.field_data[i].len);
+		}
+
+		return HPR_OK;
+	}
+
+	EnHttpParseResult ParseCookie()
+	{
+		int i = 0;
+
+		do 
+		{
+			CStringA tk = m_strBuffer.Tokenize(COOKIE_FIELD_SEP, i);
+
+			if(i == -1)
+				break;
+
+			int j = tk.Trim().Find(COOKIE_KV_SEP_CHAR);
+
+			if(j <= 0)
+				continue;
+			/*
+			{
+				m_parser.http_errno = HPE_INVALID_HEADER_TOKEN;
+				return HPR_ERROR;
+			}
+			*/
+
+			AddCookie(tk.Left(j), tk.Mid(j + 1));
+
+		} while(TRUE);
+
+		return HPR_OK;
+	}
+
+	EnHttpParseResult ParseSetCookie()
+	{
+		CCookieMgr* pCookieMgr = m_pContext->GetCookieMgr();
+
+		if(pCookieMgr == nullptr)
+			return HPR_OK;
+
+		LPCSTR lpszDomain	= GetDomain();
+		LPCSTR lpszPath		= GetPath();
+
+		unique_ptr<CCookie> pCookie(CCookie::FromString(m_strBuffer, lpszDomain, lpszPath));
+
+		if(pCookie == nullptr)
+			return HPR_ERROR;
+
+		if(pCookie->Match(lpszDomain, lpszPath, TRUE, m_pContext->IsSecure()))
+		{
+			if(pCookie->IsExpired())
+				DeleteCookie(pCookie->name);
+			else
+				AddCookie(pCookie->name, pCookie->value);
+		}
+
+		if(pCookieMgr->IsEnableThirdPartyCookie() || pCookie->IsSameDomain(lpszDomain))
+			pCookieMgr->SetCookie(*pCookie);
+
+		return HPR_OK;
+	}
+
+public:
+	DWORD GetFreeTime() const		{return m_dwFreeTime;}
+	void SetFree()					{m_dwFreeTime = ::TimeGetTime();}
+
+	BOOL IsUpgrade()				{return m_parser.upgrade;}
+	BOOL IsKeepAlive()				{return ::http_should_keep_alive(&m_parser);}
+	USHORT GetVersion()				{return MAKEWORD(m_parser.http_major, m_parser.http_minor);}
+	ULONGLONG GetContentLength()	{return m_parser.content_length;}
+
+	LPCSTR GetMethod()				{return ::http_method_str((http_method)(m_parser.method));}
+	USHORT GetUrlFieldSet()			{return m_usUrlFieldSet;}
+	USHORT GetStatusCode()			{return m_parser.status_code;}
+
+	EnHttpUpgradeType GetUpgradeType()	{return m_enUpgrade;}
+
+	THeaderMap& GetHeaderMap()		{return m_headers;}
+	TCookieMap& GetCookieMap()		{return m_cookies;}
+
+	BOOL HasReleased()				{return m_bReleased;}
+	void Release()					{m_bReleased = TRUE;}
+
+	LPCSTR GetContentType()
+	{
+		LPCSTR lpszValue = nullptr;
+		GetHeader(HTTP_HEADER_CONTENT_TYPE, &lpszValue);
+
+		return lpszValue;
+	}
+
+	LPCSTR GetContentEncoding()
+	{
+		LPCSTR lpszValue = nullptr;
+		GetHeader(HTTP_HEADER_CONTENT_ENCODING, &lpszValue);
+
+		return lpszValue;
+	}
+
+	LPCSTR GetTransferEncoding()
+	{
+		LPCSTR lpszValue = nullptr;
+		GetHeader(HTTP_HEADER_TRANSFER_ENCODING, &lpszValue);
+
+		return lpszValue;
+	}
+
+	LPCSTR GetHost()
+	{
+		LPCSTR lpszValue = nullptr;
+		GetHeader(HTTP_HEADER_HOST, &lpszValue);
+
+		return lpszValue;
+	}
+
+	USHORT GetParseErrorCode(LPCSTR* lpszErrorDesc = nullptr)
+	{
+		if(lpszErrorDesc)
+			*lpszErrorDesc = ::http_errno_description(HTTP_PARSER_ERRNO(&m_parser));
+
+		return m_parser.http_errno;
+	}
+
+	LPCSTR GetUrlField(EnHttpUrlField enField)
+	{
+		ASSERT(m_bRequest && enField < HUF_MAX);
+
+		if(!m_bRequest || enField >= HUF_MAX)
+			return nullptr;
+
+		return m_pstrUrlFileds[enField];
+	}
+
+	LPCSTR GetPath()
+	{
+		if(m_bRequest)
+			return GetUrlField(HUF_PATH);
+		else
+			return *m_pstrRequestPath;
+	}
+
+	LPCSTR GetDomain()
+	{
+		ASSERT(!m_bRequest);
+
+		return m_pContext->GetRemoteDomain(m_pSocket);
+	}
+
+	LPCSTR GetRequestPath()
+	{
+		if(m_bRequest)
+			return nullptr;
+
+		return *m_pstrRequestPath;
+	}
+
+	void SetRequestPath(LPCSTR lpszPath)
+	{
+		ASSERT(!m_bRequest);
+
+		if(!m_bRequest)
+			*m_pstrRequestPath = lpszPath;
+	}
+
+	BOOL GetHeader(LPCSTR lpszName, LPCSTR* lpszValue)
+	{
+		ASSERT(lpszName);
+
+		BOOL isOK		= FALSE;
+		THeaderMapCI it = m_headers.find(lpszName);
+
+		if(it != m_headers.end())
+		{
+			*lpszValue	= it->second;
+			isOK		= TRUE;
+		}
+
+		return isOK;
+	}
+
+	BOOL GetHeaders(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
+	{
+		ASSERT(lpszName);
+
+		if(lpszValue == nullptr || dwCount == 0)
+		{
+			dwCount = (DWORD)m_headers.count(lpszName);
+			return FALSE;
+		}
+
+		pair<THeaderMapCI, THeaderMapCI> range = m_headers.equal_range(lpszName);
+
+		THeaderMapCI it	= range.first;
+		DWORD dwIndex	= 0;
+
+		while(it != range.second)
+		{
+			if(dwIndex < dwCount)
+				lpszValue[dwIndex] = it->second;
+
+			++dwIndex;
+			++it;
+		}
+
+		BOOL isOK	= (dwIndex > 0 && dwIndex <= dwCount);
+		dwCount		= dwIndex;
+
+		return isOK;
+	}
+
+	BOOL GetAllHeaders(THeader lpHeaders[], DWORD& dwCount)
+	{
+		DWORD dwSize = (DWORD)m_headers.size();
+
+		if(lpHeaders == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
+		{
+			dwCount = dwSize;
+			return FALSE;
+		}
+
+		DWORD dwIndex = 0;
+
+		for(THeaderMapCI it = m_headers.begin(), end = m_headers.end(); it != end; ++it, ++dwIndex)
+		{
+			lpHeaders[dwIndex].name  = it->first;
+			lpHeaders[dwIndex].value = it->second;
+		}
+
+		dwCount = dwSize;
+		return TRUE;
+	}
+
+	BOOL GetAllHeaderNames(LPCSTR lpszName[], DWORD& dwCount)
+	{
+		DWORD dwSize = (DWORD)m_headers.size();
+
+		if(lpszName == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
+		{
+			dwCount = dwSize;
+			return FALSE;
+		}
+
+		DWORD dwIndex = 0;
+
+		for(THeaderMapCI it = m_headers.begin(), end = m_headers.end(); it != end; ++it, ++dwIndex)
+			lpszName[dwIndex] = it->first;
+
+		dwCount = dwSize;
+		return TRUE;
+	}
+
+	BOOL AddCookie(LPCSTR lpszName, LPCSTR lpszValue, BOOL bRelpace = TRUE)
+	{
+		ASSERT(lpszName);
+
+		TCookieMapI it = m_cookies.find(lpszName);
+
+		if(it == m_cookies.end())
+			return m_cookies.emplace(move(TCookieMap::value_type(lpszName, lpszValue))).second;
+
+		BOOL isOK = FALSE;
+
+		if(bRelpace)
+		{
+			it->second	= lpszValue;
+			isOK		= TRUE;
+		}
+
+		return isOK;
+	}
+
+	BOOL DeleteCookie(LPCSTR lpszName)
+	{
+		ASSERT(lpszName);
+
+		return m_cookies.erase(lpszName) > 0;
+	}
+
+	void DeleteAllCookies()
+	{
+		m_cookies.clear();
+	}
+
+	BOOL GetCookie(LPCSTR lpszName, LPCSTR* lpszValue)
+	{
+		ASSERT(lpszName);
+
+		BOOL isOK		= FALSE;
+		TCookieMapCI it = m_cookies.find(lpszName);
+
+		if(it != m_cookies.end())
+		{
+			*lpszValue	= it->second;
+			isOK		= TRUE;
+		}
+
+		return isOK;
+	}
+
+	BOOL GetAllCookies(TCookie lpCookies[], DWORD& dwCount)
+	{
+		DWORD dwSize = (DWORD)m_cookies.size();
+
+		if(lpCookies == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
+		{
+			dwCount = dwSize;
+			return FALSE;
+		}
+
+		DWORD dwIndex = 0;
+
+		for(TCookieMapCI it = m_cookies.begin(), end = m_cookies.end(); it != end; ++it, ++dwIndex)
+		{
+			lpCookies[dwIndex].name  = it->first;
+			lpCookies[dwIndex].value = it->second;
+		}
+
+		dwCount = dwSize;
+		return TRUE;
+	}
+
+	BOOL ReloadCookies()
+	{
+		CCookieMgr* pCookieMgr = m_pContext->GetCookieMgr();
+
+		if(pCookieMgr == nullptr)
+			return TRUE;
+
+		DeleteAllCookies();
+
+		CCookieSet cookies;
+
+		if(!pCookieMgr->GetCookies(cookies, GetDomain(), GetPath(), TRUE, m_pContext->IsSecure()))
+			return FALSE;
+
+		for(CCookieSetCI it = cookies.begin(), end = cookies.end(); it != end; ++it)
+			AddCookie(it->name, it->value);
+
+		return TRUE;
+	}
+
+	BOOL GetWSMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
+	{
+		if(!m_pwsContext)
+			return FALSE;
+
+		return m_pwsContext->GetMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);
+	}
+
+public:
+	THttpObjT			(BOOL bRequest, T* pContext, S* pSocket)
+	: m_pContext		(pContext)
+	, m_pSocket			(pSocket)
+	, m_bRequest		(bRequest)
+	, m_bReleased		(FALSE)
+	, m_dwFreeTime		(0)
+	, m_usUrlFieldSet	(0)
+	, m_pstrUrlFileds	(nullptr)
+	, m_enUpgrade		(HUT_NONE)
+	, m_pwsContext		(nullptr)
+	{
+		if(m_bRequest)
+			m_pstrUrlFileds	  = new CStringA[HUF_MAX];
+		else
+			m_pstrRequestPath = new CStringA;
+
+		ResetParser();
+	}
+
+	~THttpObjT()
+	{
+		if(m_bRequest)
+			delete[] m_pstrUrlFileds;
+		else
+			delete m_pstrRequestPath;
+
+		ReleaseWSContext();
+	}
+
+	static THttpObjT* Construct(BOOL bRequest, T* pContext, S* pSocket)
+		{return new THttpObjT(bRequest, pContext, pSocket);}
+
+	static void Destruct(THttpObjT* pHttpObj)
+		{if(pHttpObj) delete pHttpObj;}
+
+	void Reset()
+	{
+		ResetParser();
+		ResetHeaderState();
+		ReleaseWSContext();
+
+		m_bReleased  = FALSE;
+		m_enUpgrade  = HUT_NONE;
+		m_dwFreeTime = 0;
+	}
+
+	void Renew(T* pContext, S* pSocket)
+	{
+		m_pContext	= pContext;
+		m_pSocket	= pSocket;
+
+		Reset();
+	}
+
+	BOOL CopyData(const THttpObjT& src)
+	{
+		if(&src == this)
+			return FALSE;
+		if(m_bRequest != src.m_bRequest)
+			return FALSE;
+
+		void* p			= m_parser.data;
+		m_parser		= src.m_parser;
+		m_parser.data	= p;
+
+		m_headers = src.m_headers;
+		m_cookies = src.m_cookies;
+
+		if(m_bRequest)
+		{
+			m_usUrlFieldSet = src.m_usUrlFieldSet;
+
+			for(int i = 0;i < HUF_MAX; i++)
+				m_pstrUrlFileds[i] = src.m_pstrUrlFileds[i];
+		}
+		else
+		{
+			*m_pstrRequestPath = *src.m_pstrRequestPath;
+		}
+
+		m_enUpgrade = src.m_enUpgrade;
+
+		return TRUE;
+	}
+
+	BOOL CopyWSContext(const THttpObjT& src)
+	{
+		if(&src == this)
+			return FALSE;
+		if(m_bRequest != src.m_bRequest)
+			return FALSE;
+
+		if(!src.m_pwsContext && !m_pwsContext)
+			;
+		else if(!src.m_pwsContext && m_pwsContext)
+		{
+			delete m_pwsContext;
+			m_pwsContext = nullptr;
+		}
+		else
+		{
+			if(!m_pwsContext)
+				m_pwsContext = new TWSContext<THttpObjT<T, S>>(this);
+
+			m_pwsContext->CopyData(*src.m_pwsContext);
+		}
+
+		return TRUE;
+	}
+
+private:
+
+	void ResetParser()
+	{
+		::http_parser_init(&m_parser, m_bRequest ? HTTP_REQUEST : HTTP_RESPONSE);
+		m_parser.data = this;		
+	}
+
+	void ResetHeaderState(BOOL bClearCookies = TRUE, BOOL bResetRequestPath = TRUE)
+	{
+		if(m_bRequest)
+		{
+			if(m_usUrlFieldSet != 0)
+			{
+				m_usUrlFieldSet = 0;
+
+				for(int i = 0; i < HUF_MAX; i++)
+					m_pstrUrlFileds[i].Empty();
+			}
+		}
+		else
+		{
+			if(bResetRequestPath)
+				m_pstrRequestPath->Empty();
+		}
+
+		if(m_bRequest || bClearCookies)
+			DeleteAllCookies();
+			
+		m_headers.clear();
+		ResetHeaderBuffer();
+	}
+
+	void ResetHeaderBuffer()
+	{
+		ResetBuffer();
+		m_strCurHeader.Empty();
+	}
+
+	void ReleaseWSContext()
+	{
+		if(m_pwsContext)
+		{
+			delete m_pwsContext;
+			m_pwsContext = nullptr;
+		}
+	}
+
+	void AppendBuffer(const char* at, size_t length)	{m_strBuffer.Append(at, (int)length);}
+	void ResetBuffer()									{m_strBuffer.Empty();}
+	LPCSTR GetBuffer()									{return m_strBuffer;}
+
+	static THttpObjT* Self(http_parser* p)				{return (THttpObjT*)(p->data);}
+	static T* SelfContext(http_parser* p)				{return Self(p)->m_pContext;}
+	static S* SelfSocketObj(http_parser* p)				{return Self(p)->m_pSocket;}
+
+private:
+	BOOL		m_bRequest;
+	BOOL		m_bReleased;
+	T*			m_pContext;
+	S*			m_pSocket;
+	http_parser	m_parser;
+	THeaderMap	m_headers;
+	TCookieMap	m_cookies;
+	CStringA	m_strBuffer;
+	CStringA	m_strCurHeader;
+
+	USHORT		m_usUrlFieldSet;
+
+	union
+	{
+		CStringA* m_pstrUrlFileds;
+		CStringA* m_pstrRequestPath;
+	};
+
+	EnHttpUpgradeType	m_enUpgrade;
+	DWORD				m_dwFreeTime;
+
+	TWSContext<THttpObjT<T, S>>* m_pwsContext;
+
+	static http_parser_settings sm_settings;
+};
+
+template<class T, class S> http_parser_settings THttpObjT<T, S>::sm_settings = 
+{
+	on_message_begin,
+	on_url,
+	on_status,
+	on_header_field,
+	on_header_value,
+	on_headers_complete,
+	on_body,
+	on_message_complete,
+	on_chunk_header,
+	on_chunk_complete
+};
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+template<BOOL is_request, class T, class S> class CHttpObjPoolT
+{
+	typedef THttpObjT<T, S>		THttpObj;
+	typedef CRingPool<THttpObj>	TSSLHttpObjList;
+	typedef CCASQueue<THttpObj>	TSSLHttpObjQueue;
+
+public:
+	THttpObj* PickFreeHttpObj(T* pContext, S* pSocket)
+	{
+		DWORD dwIndex;
+		THttpObj* pHttpObj = nullptr;
+
+		if(m_lsFreeHttpObj.TryLock(&pHttpObj, dwIndex))
+		{
+			if(::GetTimeGap32(pHttpObj->GetFreeTime()) >= m_dwHttpObjLockTime)
+				VERIFY(m_lsFreeHttpObj.ReleaseLock(nullptr, dwIndex));
+			else
+			{
+				VERIFY(m_lsFreeHttpObj.ReleaseLock(pHttpObj, dwIndex));
+				pHttpObj = nullptr;
+			}
+		}
+
+		if(pHttpObj)
+			pHttpObj->Renew(pContext, pSocket);
+		else
+		{
+			pHttpObj = THttpObj::Construct(is_request, pContext, pSocket);
+			ASSERT(pHttpObj);
+		}
+		
+		return pHttpObj;
+	}
+
+	void PutFreeHttpObj(THttpObj* pHttpObj)
+	{
+		pHttpObj->SetFree();
+
+		if(!m_lsFreeHttpObj.TryPut(pHttpObj))
+		{
+			m_lsGCHttpObj.PushBack(pHttpObj);
+
+			if(m_lsGCHttpObj.Size() > m_dwHttpObjPoolSize)
+				ReleaseGCHttpObj();
+		}
+	}
+
+	void Prepare()
+	{
+		m_lsFreeHttpObj.Reset(m_dwHttpObjPoolHold);
+	}
+
+	void Clear()
+	{
+		THttpObj* pHttpObj = nullptr;
+
+		while(m_lsFreeHttpObj.TryGet(&pHttpObj))
+			delete pHttpObj;
+
+		VERIFY(m_lsFreeHttpObj.IsEmpty());
+		m_lsFreeHttpObj.Reset();
+
+		ReleaseGCHttpObj(TRUE);
+		VERIFY(m_lsGCHttpObj.IsEmpty());
+	}
+
+private:
+	void ReleaseGCHttpObj(BOOL bForce = FALSE)
+	{
+		THttpObj* pHttpObj	= nullptr;
+		DWORD now			= ::TimeGetTime();
+
+		while(m_lsGCHttpObj.PopFront(&pHttpObj))
+		{
+			if(bForce || (int)(now - pHttpObj->GetFreeTime()) >= (int)m_dwHttpObjLockTime)
+				delete pHttpObj;
+			else
+			{
+				m_lsGCHttpObj.PushBack(pHttpObj);
+				break;
+			}
+		}
+	}
+
+public:
+	void SetHttpObjLockTime	(DWORD dwHttpObjLockTime)	{m_dwHttpObjLockTime = dwHttpObjLockTime;}
+	void SetHttpObjPoolSize	(DWORD dwHttpObjPoolSize)	{m_dwHttpObjPoolSize = dwHttpObjPoolSize;}
+	void SetHttpObjPoolHold	(DWORD dwHttpObjPoolHold)	{m_dwHttpObjPoolHold = dwHttpObjPoolHold;}
+
+	DWORD GetHttpObjLockTime()	{return m_dwHttpObjLockTime;}
+	DWORD GetHttpObjPoolSize()	{return m_dwHttpObjPoolSize;}
+	DWORD GetHttpObjPoolHold()	{return m_dwHttpObjPoolHold;}
+
+public:
+	CHttpObjPoolT(	DWORD dwPoolSize = DEFAULT_HTTPOBJ_POOL_SIZE,
+					DWORD dwPoolHold = DEFAULT_HTTPOBJ_POOL_HOLD,
+					DWORD dwLockTime = DEFAULT_HTTPOBJ_LOCK_TIME)
+	: m_dwHttpObjPoolSize(dwPoolSize)
+	, m_dwHttpObjPoolHold(dwPoolHold)
+	, m_dwHttpObjLockTime(dwLockTime)
+	{
+
+	}
+
+	~CHttpObjPoolT()	{Clear();}
+
+	DECLARE_NO_COPY_CLASS(CHttpObjPoolT)
+
+public:
+	static const DWORD DEFAULT_HTTPOBJ_LOCK_TIME;
+	static const DWORD DEFAULT_HTTPOBJ_POOL_SIZE;
+	static const DWORD DEFAULT_HTTPOBJ_POOL_HOLD;
+
+private:
+	DWORD				m_dwHttpObjLockTime;
+	DWORD				m_dwHttpObjPoolSize;
+	DWORD				m_dwHttpObjPoolHold;
+
+	TSSLHttpObjList		m_lsFreeHttpObj;
+	TSSLHttpObjQueue	m_lsGCHttpObj;
+};
+
+template<BOOL is_request, class T, class S> const DWORD CHttpObjPoolT<is_request, T, S>::DEFAULT_HTTPOBJ_LOCK_TIME	= 10 * 1000;
+template<BOOL is_request, class T, class S> const DWORD CHttpObjPoolT<is_request, T, S>::DEFAULT_HTTPOBJ_POOL_SIZE	= 150;
+template<BOOL is_request, class T, class S> const DWORD CHttpObjPoolT<is_request, T, S>::DEFAULT_HTTPOBJ_POOL_HOLD	= 600;
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+extern CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult);
+extern CStringA& AdjustRequestPath(LPCSTR lpszPath, CStringA& strPath);
+extern LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode);
+extern void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue);
+extern void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue);
+extern void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, const TCookieMap* pCookies, int iBodyLength, BOOL bRequest, int iConnFlag, LPCSTR lpszDefaultHost, USHORT usPort, CStringA& strValue);
+extern void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2]);
+extern 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]);
+extern BOOL ParseUrl(const CStringA& strUrl, BOOL& bHttps, CStringA& strHost, USHORT& usPort, CStringA& strPath);
+
+// CP_XXX -> UNICODE
+BOOL CodePageToUnicode(int iCodePage, const char szSrc[], WCHAR szDest[], int& iDestLength);
+// UNICODE -> CP_XXX
+BOOL UnicodeToCodePage(int iCodePage, const WCHAR szSrc[], char szDest[], int& iDestLength);
+// GBK -> UNICODE
+BOOL GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength);
+// UNICODE -> GBK
+BOOL UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength);
+// UTF8 -> UNICODE
+BOOL Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength);
+// UNICODE -> UTF8
+BOOL UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength);
+// GBK -> UTF8
+BOOL GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength);
+// UTF8 -> GBK
+BOOL Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength);
+
+// 普通压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+// 高级压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel = Z_DEFAULT_COMPRESSION, int iMethod = Z_DEFLATED, int iWindowBits = DEF_WBITS, int iMemLevel = DEF_MEM_LEVEL, int iStrategy = Z_DEFAULT_STRATEGY);
+// 普通解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+// 高级解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits = DEF_WBITS);
+// 推测压缩结果长度
+DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip = FALSE);
+
+// Gzip 压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+// Gzip 解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+// 推测 Gzip 解压结果长度(如果返回 0 或不合理值则说明输入内容并非有效的 Gzip 格式)
+DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen);
+
+// 计算 Base64 编码后长度
+DWORD GuessBase64EncodeBound(DWORD dwSrcLen);
+// 计算 Base64 解码后长度
+DWORD GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
+// Base64 编码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+// Base64 解码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+
+// 计算 URL 编码后长度
+DWORD GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
+// 计算 URL 解码后长度
+DWORD GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
+// URL 编码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
+// URL 解码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
+int UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);

+ 750 - 0
HP-Socket/Src/SocketHelper.cpp

@@ -0,0 +1,750 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "../../Common/Src/GeneralHelper.h"
+#include "../../Common/Src/SysHelper.h"
+#include "SocketHelper.h"
+
+#include <mstcpip.h>
+#pragma comment(lib, "ws2_32")
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+DWORD GetDefaultWorkerThreadCount()
+{
+	static DWORD s_dwtc = min((::SysGetNumberOfProcessors() * 2 + 2), MAX_WORKER_THREAD_COUNT);
+	return s_dwtc;
+}
+
+DWORD GetDefaultTcpSocketBufferSize()
+{
+	static DWORD s_dtsbs = ::SysGetPageSize();
+	return s_dtsbs;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ULONG GetIPv4InAddr(LPCTSTR lpszAddress)
+{
+	if (!lpszAddress || lpszAddress[0] == 0)
+		return INADDR_NONE;
+
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+	IN_ADDR addr;
+	if (::InetPton(AF_INET, lpszAddress, &addr.s_addr) == 1)
+		return addr.s_addr;
+
+	return INADDR_NONE;
+#else
+	return ::inet_addr(CT2A(lpszAddress));
+#endif
+}
+
+BOOL IsIPAddress(LPCTSTR lpszAddress)
+{
+	return GetIPv4InAddr(lpszAddress) != INADDR_NONE;
+}
+
+BOOL GetIPAddress(LPCTSTR lpszHost, LPTSTR lpszIP, int& iIPLen)
+{
+	BOOL isOK = TRUE;
+
+	if(IsIPAddress(lpszHost))
+	{
+		int iHostLen = lstrlen(lpszHost);
+		
+		if(iHostLen > 0)
+			++iHostLen;
+
+		if(iHostLen > 0 && iIPLen >= iHostLen)
+			lstrcpy(lpszIP, lpszHost);
+		else
+			isOK = FALSE;
+
+		iIPLen = iHostLen;
+	}
+	else
+	{
+		IN_ADDR addr;
+
+		if(GetOptimalIPByHostName(lpszHost, addr))
+			isOK = IN_ADDR_2_IP(addr, lpszIP, iIPLen);
+		else
+			isOK = FALSE;
+	}
+
+	return isOK;
+}
+
+BOOL GetOptimalIPByHostName(LPCTSTR lpszHost, IN_ADDR& addr)
+{
+	addr.s_addr	= 0;
+
+	addrinfo*	pInfo = nullptr;
+	addrinfo	hints = {0};
+
+	hints.ai_flags	= AI_ALL;
+	hints.ai_family	= AF_INET;
+
+	int rs = ::getaddrinfo((CT2A)lpszHost, nullptr, &hints, &pInfo);
+
+	if(rs == NO_ERROR)
+	{
+		IN_ADDR inAddr;
+		ULONG addrs[3]  = {0};
+		char** pptr		= nullptr;
+
+		for(addrinfo* pCur = pInfo; pCur != nullptr; pCur = pCur->ai_next)
+		{
+			if(pCur->ai_family == AF_INET)
+			{
+				inAddr	= ((SOCKADDR_IN*)(pCur->ai_addr))->sin_addr;
+				UCHAR a	= inAddr.s_net;
+				UCHAR b	= inAddr.s_host;
+
+				if(addrs[0] == 0 && a == 127)
+				{
+					addrs[0] = inAddr.s_addr;
+					break;
+				}
+				else if(	addrs[1] == 0							&& 
+							(
+								(a == 10)							||
+								(a == 172 && b >= 16 && b <= 31)	||
+								(a == 192 && b == 168)
+								)
+							)
+					addrs[1] = inAddr.s_addr;
+				else if(addrs[2] == 0)
+					addrs[2] = inAddr.s_addr;
+			}
+		}
+
+		::freeaddrinfo(pInfo);
+
+		for(int i = 0; i < 3; i++)
+		{
+			if(addrs[i] != 0)
+			{
+				addr.s_addr = addrs[i];
+				break;
+			}
+		}
+	}
+
+	return addr.s_addr != 0;
+}
+
+BOOL IN_ADDR_2_IP(const IN_ADDR& addr, LPTSTR lpszAddress, int& iAddressLen)
+{
+	BOOL isOK = TRUE;
+
+	TCHAR szAddr[16];
+	wsprintf(szAddr, _T("%hu.%hu.%hu.%hu"), addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
+
+	int iIPLen = lstrlen(szAddr) + 1;
+
+	if(iAddressLen >= iIPLen)
+		memcpy(lpszAddress, szAddr, iIPLen * sizeof(TCHAR));
+	else
+		isOK = FALSE;
+
+	iAddressLen = iIPLen;
+
+	return isOK;
+}
+
+BOOL sockaddr_IN_2_A(const SOCKADDR_IN& addr, ADDRESS_FAMILY& usFamily, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
+{
+	usFamily = addr.sin_family;
+	usPort	 = ntohs(addr.sin_port);
+
+	return IN_ADDR_2_IP(addr.sin_addr, lpszAddress, iAddressLen);
+}
+
+BOOL sockaddr_A_2_IN(ADDRESS_FAMILY usFamily, LPCTSTR lpszAddress, USHORT usPort, SOCKADDR_IN& addr)
+{
+	ASSERT(usFamily == AF_INET);
+
+	addr.sin_family			= usFamily;
+	addr.sin_port			= htons(usPort);
+	addr.sin_addr.s_addr	= GetIPv4InAddr(lpszAddress);
+
+	return addr.sin_addr.s_addr != INADDR_NONE;
+}
+
+BOOL GetSocketAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort, BOOL bLocal)
+{
+	sockaddr addr;
+
+	int addr_len = sizeof(addr);
+	int result	 = bLocal ? getsockname(socket, &addr, &addr_len) : getpeername(socket, &addr, &addr_len);
+
+	if(result == NO_ERROR)
+	{
+		ADDRESS_FAMILY usFamily;
+		return sockaddr_IN_2_A((sockaddr_in&)addr, usFamily, lpszAddress, iAddressLen, usPort);
+	}
+
+	return FALSE;
+}
+
+BOOL GetSocketLocalAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
+{
+	return GetSocketAddress(socket, lpszAddress, iAddressLen, usPort, TRUE);
+}
+
+BOOL GetSocketRemoteAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
+{
+	return GetSocketAddress(socket, lpszAddress, iAddressLen, usPort, FALSE);
+}
+
+ULONGLONG NToH64(ULONGLONG value)
+{
+	return (((ULONGLONG)ntohl((u_long)((value << 32) >> 32))) << 32) | ntohl((u_long)(value >> 32));
+}
+
+ULONGLONG HToN64(ULONGLONG value)
+{
+	return (((ULONGLONG)htonl((u_long)((value << 32) >> 32))) << 32) | htonl((u_long)(value >> 32));
+}
+
+PVOID GetExtensionFuncPtr(SOCKET sock, GUID guid)
+{
+	DWORD dwBytes;
+	PVOID pfn = nullptr;
+
+	::WSAIoctl	(
+					sock,
+					SIO_GET_EXTENSION_FUNCTION_POINTER,
+					&guid,
+					sizeof(guid),
+					&pfn,
+					sizeof(pfn),
+					&dwBytes,
+					nullptr,
+					nullptr
+				);
+
+	return pfn;
+}
+
+LPFN_ACCEPTEX Get_AcceptEx_FuncPtr(SOCKET sock)
+{
+	GUID guid = WSAID_ACCEPTEX;
+	return (LPFN_ACCEPTEX)GetExtensionFuncPtr(sock, guid);
+}
+
+LPFN_GETACCEPTEXSOCKADDRS Get_GetAcceptExSockaddrs_FuncPtr(SOCKET sock)
+{
+	GUID guid = WSAID_GETACCEPTEXSOCKADDRS;
+	return (LPFN_GETACCEPTEXSOCKADDRS)GetExtensionFuncPtr(sock, guid);
+}
+
+LPFN_CONNECTEX Get_ConnectEx_FuncPtr(SOCKET sock)
+{
+	GUID guid = WSAID_CONNECTEX;
+	return (LPFN_CONNECTEX)GetExtensionFuncPtr(sock, guid);
+}
+
+LPFN_TRANSMITFILE Get_TransmitFile_FuncPtr(SOCKET sock)
+{
+	GUID guid = WSAID_TRANSMITFILE;
+	return (LPFN_TRANSMITFILE)GetExtensionFuncPtr(sock, guid);
+}
+
+LPFN_DISCONNECTEX Get_DisconnectEx_FuncPtr	(SOCKET sock)
+{
+	GUID guid = WSAID_DISCONNECTEX;
+	return (LPFN_DISCONNECTEX)GetExtensionFuncPtr(sock, guid);
+}
+
+HRESULT ReadSmallFile(LPCTSTR lpszFileName, CAtlFile& file, CAtlFileMapping<>& fmap, DWORD dwMaxFileSize)
+{
+	ASSERT(lpszFileName != nullptr);
+
+	HRESULT hr = file.Create(lpszFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
+
+	if(SUCCEEDED(hr))
+	{
+		ULONGLONG ullLen;
+		hr = file.GetSize(ullLen);
+
+		if(SUCCEEDED(hr))
+		{
+			if(ullLen > 0 && ullLen <= dwMaxFileSize)
+				hr = fmap.MapFile(file);
+			else if(ullLen == 0)
+				hr = HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
+			else
+				hr = HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
+		}
+	}
+
+	return hr;
+}
+
+HRESULT MakeSmallFilePackage(LPCTSTR lpszFileName, CAtlFile& file, CAtlFileMapping<>& fmap, WSABUF szBuf[3], const LPWSABUF pHead, const LPWSABUF pTail)
+{
+	DWORD dwMaxFileSize = MAX_SMALL_FILE_SIZE - (pHead ? pHead->len : 0) - (pTail ? pTail->len : 0);
+	ASSERT(dwMaxFileSize <= MAX_SMALL_FILE_SIZE);
+
+	HRESULT hr = ReadSmallFile(lpszFileName, file, fmap, dwMaxFileSize);
+
+	if(SUCCEEDED(hr))
+	{
+		szBuf[1].len = (ULONG)fmap.GetMappingSize();
+		szBuf[1].buf = fmap;
+
+		if(pHead) memcpy(&szBuf[0], pHead, sizeof(WSABUF));
+		else	  memset(&szBuf[0], 0, sizeof(WSABUF));
+
+		if(pTail) memcpy(&szBuf[2], pTail, sizeof(WSABUF));
+		else	  memset(&szBuf[2], 0, sizeof(WSABUF));
+	}
+
+	return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL PostIocpCommand(HANDLE hIOCP, EnIocpCommand enCmd, ULONG_PTR ulParam)
+{
+	return ::PostQueuedCompletionStatus(hIOCP, enCmd, ulParam, nullptr);
+}
+
+BOOL PostIocpExit(HANDLE hIOCP)
+{
+	return PostIocpCommand(hIOCP, IOCP_CMD_EXIT, 0);
+}
+
+BOOL PostIocpAccept(HANDLE hIOCP)
+{
+	return PostIocpCommand(hIOCP, IOCP_CMD_ACCEPT, 0);
+}
+
+BOOL PostIocpDisconnect(HANDLE hIOCP, CONNID dwConnID)
+{
+	return PostIocpCommand(hIOCP, IOCP_CMD_DISCONNECT, dwConnID);
+}
+
+BOOL PostIocpSend(HANDLE hIOCP, CONNID dwConnID)
+{
+	return PostIocpCommand(hIOCP, IOCP_CMD_SEND, dwConnID);
+}
+
+BOOL PostIocpClose(HANDLE hIOCP, CONNID dwConnID, int iErrorCode)
+{
+	return PostIocpCommand(hIOCP, (EnIocpCommand)iErrorCode, dwConnID);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int SSO_SetSocketOption(SOCKET sock, int level, int name, LPVOID val, int len)
+{
+	return setsockopt(sock, level, name, (CHAR*)val, len);
+}
+
+int SSO_GetSocketOption(SOCKET sock, int level, int name, LPVOID val, int* len)
+{
+	return getsockopt(sock, level, name, (CHAR*)val, len);
+}
+
+int SSO_IoctlSocket(SOCKET sock, long cmd, u_long* arg)
+{
+	return ioctlsocket(sock, cmd, arg);
+}
+
+int SSO_WSAIoctl(SOCKET sock, DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned)
+{
+	return ::WSAIoctl(sock, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, nullptr, nullptr);
+}
+
+int SSO_UpdateAcceptContext(SOCKET soClient, SOCKET soBind)
+{
+	return setsockopt(soClient, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (CHAR*)&soBind, sizeof(SOCKET));
+}
+
+int SSO_UpdateConnectContext(SOCKET soClient, int iOption)
+{
+	return setsockopt(soClient, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, (CHAR*)&iOption, sizeof(int));
+}
+
+int SSO_NoDelay(SOCKET sock, BOOL bNoDelay)
+{
+	return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (CHAR*)&bNoDelay, sizeof(BOOL));
+}
+
+int SSO_DontLinger(SOCKET sock, BOOL bDont)
+{
+	return setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (CHAR*)&bDont, sizeof(BOOL));
+}
+
+int SSO_Linger(SOCKET sock, USHORT l_onoff, USHORT l_linger)
+{
+	linger ln = {l_onoff, l_linger};
+	return setsockopt(sock, SOL_SOCKET, SO_LINGER, (CHAR*)&ln, sizeof(linger));
+}
+
+int SSO_KeepAlive(SOCKET sock, BOOL bKeepAlive)
+{
+	return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (CHAR*)&bKeepAlive, sizeof(BOOL));
+}
+
+int SSO_KeepAliveVals(SOCKET sock, u_long onoff, u_long time, u_long interval)
+{
+	int result		 = NO_ERROR;
+	tcp_keepalive in = {onoff, time, interval};
+	DWORD dwBytes;
+
+	if(::WSAIoctl	(
+						sock, 
+						SIO_KEEPALIVE_VALS, 
+						(LPVOID)&in, 
+						sizeof(in), 
+						nullptr, 
+						0, 
+						&dwBytes, 
+						nullptr, 
+						nullptr
+					) == SOCKET_ERROR)
+	{
+		result = ::WSAGetLastError();
+		if(result == WSAEWOULDBLOCK)
+			result = NO_ERROR;
+	}
+
+	return result;
+}
+
+int SSO_RecvBuffSize(SOCKET sock, int size)
+{
+	return setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (CHAR*)&size, sizeof(int));
+}
+
+int SSO_SendBuffSize(SOCKET sock, int size)
+{
+	return setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (CHAR*)&size, sizeof(int));
+}
+
+int SSO_ReuseAddress(SOCKET sock, BOOL bReuse)
+{
+	return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&bReuse, sizeof(BOOL));
+}
+
+int SSO_UDP_ConnReset(SOCKET sock, BOOL bNewBehavior)
+{
+	int result = NO_ERROR;
+	DWORD dwBytes;
+
+	if(::WSAIoctl	(
+						sock, 
+						SIO_UDP_CONNRESET, 
+						(LPVOID)&bNewBehavior, 
+						sizeof(bNewBehavior), 
+						nullptr, 
+						0, 
+						&dwBytes, 
+						nullptr, 
+						nullptr
+					) == SOCKET_ERROR)
+	{
+		result = ::WSAGetLastError();
+		if(result == WSAEWOULDBLOCK)
+			result = NO_ERROR;
+	}
+
+	return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+CONNID GenerateConnectionID()
+{
+	static volatile CONNID s_dwConnID = 0;
+
+	CONNID dwConnID	= ::InterlockedIncrement(&s_dwConnID);
+	
+	if(dwConnID == 0)
+		dwConnID = ::InterlockedIncrement(&s_dwConnID);
+
+	return dwConnID;
+}
+
+int ManualCloseSocket(SOCKET sock, int iShutdownFlag, BOOL bGraceful, BOOL bReuseAddress)
+{
+	if(!bGraceful)
+		SSO_Linger(sock, 1, 0);
+
+	if(bReuseAddress)
+		SSO_ReuseAddress(sock, bReuseAddress);
+
+	if(iShutdownFlag != 0xFF)
+		shutdown(sock, iShutdownFlag);
+
+	return closesocket(sock);
+}
+
+int PostAccept(LPFN_ACCEPTEX pfnAcceptEx, SOCKET soListen, SOCKET soClient, TBufferObj* pBufferObj)
+{
+	int result = PostAcceptNotCheck(pfnAcceptEx, soListen, soClient, pBufferObj);
+
+	if(result == WSA_IO_PENDING)
+		result = NO_ERROR;
+
+	return result;
+}
+
+int PostAcceptNotCheck(LPFN_ACCEPTEX pfnAcceptEx, SOCKET soListen, SOCKET soClient, TBufferObj* pBufferObj)
+{
+	int result				= NO_ERROR;
+	pBufferObj->client		= soClient;
+	pBufferObj->operation	= SO_ACCEPT;
+
+	if(!pfnAcceptEx	(
+						soListen,
+						pBufferObj->client,
+						pBufferObj->buff.buf,
+						0,
+						sizeof(SOCKADDR_IN) + 16,
+						sizeof(SOCKADDR_IN) + 16,
+						nullptr,
+						&pBufferObj->ov
+					)
+	)
+	{
+		result = ::WSAGetLastError();
+	}
+
+	return result;
+}
+
+int PostConnect(LPFN_CONNECTEX pfnConnectEx, SOCKET soClient, SOCKADDR_IN& soAddrIN, TBufferObj* pBufferObj)
+{
+	int result = PostConnectNotCheck(pfnConnectEx, soClient, soAddrIN, pBufferObj);
+
+	if(result == WSA_IO_PENDING)
+		result = NO_ERROR;
+
+	return result;
+}
+
+int PostConnectNotCheck(LPFN_CONNECTEX pfnConnectEx, SOCKET soClient, SOCKADDR_IN& soAddrIN, TBufferObj* pBufferObj)
+{
+	int result				= NO_ERROR;
+	pBufferObj->client		= soClient;
+	pBufferObj->operation	= SO_CONNECT;
+
+	if(!pfnConnectEx	(
+							soClient,
+							(SOCKADDR*)&soAddrIN,
+							sizeof(SOCKADDR_IN),
+							nullptr,
+							0,
+							nullptr,
+							&pBufferObj->ov
+						)
+	)
+	{
+		result = ::WSAGetLastError();
+	}
+
+	return result;
+}
+
+int PostSend(TSocketObj* pSocketObj, TBufferObj* pBufferObj)
+{
+	int result = PostSendNotCheck(pSocketObj, pBufferObj);
+
+	if(result == WSA_IO_PENDING)
+		result = NO_ERROR;
+
+	return result;
+}
+
+int PostSendNotCheck(TSocketObj* pSocketObj, TBufferObj* pBufferObj)
+{
+	int result				= NO_ERROR;
+	DWORD dwBytes			= 0;
+	pBufferObj->client		= pSocketObj->socket;
+	pBufferObj->operation	= SO_SEND;
+
+	if(::WSASend(
+					pBufferObj->client,
+					&pBufferObj->buff,
+					1,
+					&dwBytes,
+					0,
+					&pBufferObj->ov,
+					nullptr
+				) == SOCKET_ERROR)
+	{
+		result = ::WSAGetLastError();
+	}
+
+	return result;
+}
+
+int PostReceive(TSocketObj* pSocketObj, TBufferObj* pBufferObj)
+{
+	int result = PostReceiveNotCheck(pSocketObj, pBufferObj);
+
+	if(result == WSA_IO_PENDING)
+		result = NO_ERROR;
+
+	return result;
+}
+
+int PostReceiveNotCheck(TSocketObj* pSocketObj, TBufferObj* pBufferObj)
+{
+	int result				= NO_ERROR;
+	DWORD dwFlag			= 0; 
+	DWORD dwBytes			= 0; 
+	pBufferObj->client		= pSocketObj->socket;
+	pBufferObj->operation	= SO_RECEIVE;
+
+	if(::WSARecv(
+					pBufferObj->client,
+					&pBufferObj->buff,
+					1,
+					&dwBytes,
+					&dwFlag,
+					&pBufferObj->ov,
+					nullptr
+				) == SOCKET_ERROR)
+	{
+		result = ::WSAGetLastError();
+	}
+
+	return result;
+}
+
+int PostSendTo(SOCKET sock, TUdpBufferObj* pBufferObj)
+{
+	int result = PostSendToNotCheck(sock, pBufferObj);
+
+	if(result == WSA_IO_PENDING)
+		result = NO_ERROR;
+
+	return result;
+}
+
+int PostSendToNotCheck(SOCKET sock, TUdpBufferObj* pBufferObj)
+{
+	int result				= NO_ERROR;
+	DWORD dwBytes			= 0;
+	pBufferObj->operation	= SO_SEND;
+	pBufferObj->addrLen		= sizeof(SOCKADDR_IN);
+
+	if(::WSASendTo	(
+						sock,
+						&pBufferObj->buff,
+						1,
+						&dwBytes,
+						0,
+						(sockaddr*)&pBufferObj->remoteAddr,
+						pBufferObj->addrLen,
+						&pBufferObj->ov,
+						nullptr
+					) == SOCKET_ERROR)
+	{
+		result = ::WSAGetLastError();
+	}
+
+	return result;
+}
+
+int PostReceiveFrom(SOCKET sock, TUdpBufferObj* pBufferObj)
+{
+	int result = PostReceiveFromNotCheck(sock, pBufferObj);
+
+	if(result == WSA_IO_PENDING)
+		result = NO_ERROR;
+
+	return result;
+}
+
+int PostReceiveFromNotCheck(SOCKET sock, TUdpBufferObj* pBufferObj)
+{
+	int result				= NO_ERROR;
+	DWORD dwFlag			= 0;
+	DWORD dwBytes			= 0;
+	pBufferObj->operation	= SO_RECEIVE;
+	pBufferObj->addrLen		= sizeof(SOCKADDR_IN);
+
+	::ZeroMemory(&pBufferObj->remoteAddr, pBufferObj->addrLen);
+
+	if(::WSARecvFrom(
+						sock,
+						&pBufferObj->buff,
+						1,
+						&dwBytes,
+						&dwFlag,
+						(sockaddr*)&pBufferObj->remoteAddr,
+						&pBufferObj->addrLen,
+						&pBufferObj->ov,
+						nullptr
+					) == SOCKET_ERROR)
+	{
+		result = ::WSAGetLastError();
+	}
+
+	return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+LPCTSTR GetSocketErrorDesc(EnSocketError enCode)
+{
+	switch(enCode)
+	{
+	case SE_OK:						return _T("SUCCESS");
+	case SE_ILLEGAL_STATE:			return _T("Illegal State");
+	case SE_INVALID_PARAM:			return _T("Invalid Parameter");
+	case SE_SOCKET_CREATE:			return _T("Create SOCKET Fail");
+	case SE_SOCKET_BIND:			return _T("Bind SOCKET Fail");
+	case SE_SOCKET_PREPARE:			return _T("Prepare SOCKET Fail");
+	case SE_SOCKET_LISTEN:			return _T("Listen SOCKET Fail");
+	case SE_CP_CREATE:				return _T("Create IOCP Fail");
+	case SE_WORKER_THREAD_CREATE:	return _T("Create Worker Thread Fail");
+	case SE_DETECT_THREAD_CREATE:	return _T("Create Detector Thread Fail");
+	case SE_SOCKE_ATTACH_TO_CP:		return _T("Attach SOCKET to IOCP Fail");
+	case SE_CONNECT_SERVER:			return _T("Connect to Server Fail");
+	case SE_NETWORK:				return _T("Network Error");
+	case SE_DATA_PROC:				return _T("Process Data Error");
+	case SE_DATA_SEND:				return _T("Send Data Fail");
+
+	case SE_SSL_ENV_NOT_READY:		return _T("SSL environment not ready");
+
+	default: ASSERT(FALSE);			return _T("UNKNOWN ERROR");
+	}
+}
+
+DWORD GetHPSocketVersion()
+{
+	static DWORD s_dwVersion = (HP_VERSION_MAJOR << 24) | (HP_VERSION_MINOR << 16) | (HP_VERSION_REVISE << 8) | HP_VERSION_BUILD;
+
+	return s_dwVersion;
+}

+ 628 - 0
HP-Socket/Src/SocketHelper.h

@@ -0,0 +1,628 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 <ws2tcpip.h>
+#include <mswsock.h>
+#include <malloc.h>
+
+#include <atlfile.h>
+
+#include "SocketInterface.h"
+#include "../../Common/Src/WaitFor.h"
+#include "../../Common/Src/bufferpool.h"
+#include "../../Common/Src/RingBuffer.h"
+
+/************************************************************************
+名称:全局常量
+描述:声明组件的公共全局常量
+************************************************************************/
+
+/* HP-Socket 版本号 */
+#define HP_VERSION_MAJOR						4
+#define HP_VERSION_MINOR						2
+#define HP_VERSION_REVISE						1
+#define HP_VERSION_BUILD						5
+
+/* IOCP 最大工作线程数 */
+#define MAX_WORKER_THREAD_COUNT					500
+/* IOCP Socket 缓冲区最小值 */
+#define MIN_SOCKET_BUFFER_SIZE					64
+/* 小文件最大字节数 */
+#define MAX_SMALL_FILE_SIZE						0x3FFFFF
+/* 最大连接时长 */
+#define MAX_CONNECTION_PERIOD					(MAXLONG / 2)
+
+/* Server/Agent 默认最大连接数 */
+#define DEFAULT_MAX_CONNECTION_COUNT			10000
+/* Server/Agent 默认 IOCP 工作线程数 */
+#define DEFAULT_WORKER_THREAD_COUNT				GetDefaultWorkerThreadCount()
+/* Server/Agent 默认 Socket 缓存对象锁定时间 */
+#define DEFAULT_FREE_SOCKETOBJ_LOCK_TIME		(10 * 1000)
+/* Server/Agent 默认 Socket 缓存池大小 */
+#define DEFAULT_FREE_SOCKETOBJ_POOL				150
+/* Server/Agent 默认 Socket 缓存池回收阀值 */
+#define DEFAULT_FREE_SOCKETOBJ_HOLD				600
+/* Server/Agent 默认内存块缓存池大小 */
+#define DEFAULT_FREE_BUFFEROBJ_POOL				300
+/* Server/Agent 默认内存块缓存池回收阀值 */
+#define DEFAULT_FREE_BUFFEROBJ_HOLD				1200
+/* Client 默认内存块缓存池大小 */
+#define DEFAULT_CLIENT_FREE_BUFFER_POOL_SIZE	10
+/* Client 默认内存块缓存池回收阀值 */
+#define DEFAULT_CLIENT_FREE_BUFFER_POOL_HOLD	40
+/* Agent 默认绑定地址 */
+#define  DEFAULT_BIND_ADDRESS					_T("0.0.0.0")
+
+/* TCP 默认通信数据缓冲区大小 */
+#define DEFAULT_TCP_SOCKET_BUFFER_SIZE			GetDefaultTcpSocketBufferSize()
+/* TCP 默认心跳包间隔 */
+#define DEFALUT_TCP_KEEPALIVE_TIME				(30 * 1000)
+/* TCP 默认心跳确认包检测间隔 */
+#define DEFALUT_TCP_KEEPALIVE_INTERVAL			(10 * 1000)
+/* TCP Server 默认 Listen 队列大小 */
+#define DEFAULT_TCP_SERVER_SOCKET_LISTEN_QUEUE	SOMAXCONN
+/* TCP Server 默认预投递 Accept 数量 */
+#define DEFAULT_TCP_SERVER_ACCEPT_SOCKET_COUNT	300
+
+/* UDP 默认数据报文最大长度 */
+#define DEFAULT_UDP_MAX_DATAGRAM_SIZE			1472
+/* UDP 默认 Receive 预投递数量 */
+#define DEFAULT_UDP_POST_RECEIVE_COUNT			300
+/* UDP 默认监测包尝试次数 */
+#define DEFAULT_UDP_DETECT_ATTEMPTS				3
+/* UDP 默认监测包发送间隔 */
+#define DEFAULT_UDP_DETECT_INTERVAL				20
+
+/* 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
+
+DWORD GetDefaultWorkerThreadCount();
+DWORD GetDefaultTcpSocketBufferSize();
+
+/************************************************************************
+名称:Windows Socket 组件初始化类
+描述:自动加载和卸载 Windows Socket 组件
+************************************************************************/
+class CInitSocket
+{
+public:
+	CInitSocket(LPWSADATA lpWSAData = nullptr, BYTE minorVersion = 2, BYTE majorVersion = 2)
+	{
+		LPWSADATA lpTemp = lpWSAData;
+		if(!lpTemp)
+			lpTemp	= (LPWSADATA)_alloca(sizeof(WSADATA));
+
+		m_iResult	= ::WSAStartup(MAKEWORD(majorVersion, minorVersion), lpTemp);
+	}
+
+	~CInitSocket()
+	{
+		if(IsValid())
+			::WSACleanup();
+	}
+
+	int		GetResult()	{return m_iResult;}
+	BOOL	IsValid()	{return m_iResult == 0;}
+
+private:
+	int		m_iResult;
+};
+
+/* Server 组件和 Agent 组件内部使用的事件处理结果常量 */
+
+// 连接已关闭
+#define HR_CLOSED	0xFF
+
+/* 关闭连接标识 */
+enum EnSocketCloseFlag
+{
+	SCF_NONE	= 0,	// 不触发事件
+	SCF_CLOSE	= 1,	// 触发 正常关闭 OnClose 事件
+	SCF_ERROR	= 2		// 触发 异常关闭 OnClose 事件
+};
+
+/* 数据缓冲区基础结构 */
+template<class T> struct TBufferObjBase
+{
+	WSAOVERLAPPED		ov;
+	EnSocketOperation	operation;
+	WSABUF				buff;
+
+	int					capacity;
+	CPrivateHeap&		heap;
+
+	T* next;
+	T* last;
+
+	static T* Construct(CPrivateHeap& heap, DWORD dwCapacity)
+	{
+		T* pBufferObj = (T*)heap.Alloc(sizeof(T) + dwCapacity);
+		ASSERT(pBufferObj);
+
+		ZeroMemory(pBufferObj, sizeof(T));
+		
+		pBufferObj->TBufferObjBase::TBufferObjBase(heap, dwCapacity);
+		pBufferObj->buff.buf = ((char*)pBufferObj) + sizeof(T);
+
+		return pBufferObj;
+	}
+
+	static void Destruct(T* pBufferObj)
+	{
+		ASSERT(pBufferObj);
+		pBufferObj->heap.Free(pBufferObj);
+	}
+
+	TBufferObjBase(CPrivateHeap& hp, DWORD dwCapacity)
+	: heap(hp)
+	, capacity((int)dwCapacity)
+	{
+		ASSERT(capacity > 0);
+	}
+
+	int Cat(const BYTE* pData, int length)
+	{
+		ASSERT(pData != nullptr && length > 0);
+
+		int cat = min(Remain(), length);
+
+		if(cat > 0)
+		{
+			memcpy(buff.buf + buff.len, pData, cat);
+			buff.len += cat;
+		}
+
+		return cat;
+	}
+
+	void Reset()	{buff.len = 0;}
+	int Remain()	{return capacity - buff.len;}
+	BOOL IsFull()	{return buff.len == capacity;}
+};
+
+/* 数据缓冲区结构 */
+struct TBufferObj : public TBufferObjBase<TBufferObj>
+{
+	SOCKET client;
+};
+
+/* UDP 数据缓冲区结构 */
+struct TUdpBufferObj : public TBufferObjBase<TUdpBufferObj>
+{
+	SOCKADDR_IN	remoteAddr;
+	int			addrLen;
+};
+
+/* 数据缓冲区链表模板 */
+template<class T> struct TBufferObjListT : public TSimpleList<T>
+{
+public:
+	int Cat(const BYTE* pData, int length)
+	{
+		ASSERT(pData != nullptr && length > 0);
+
+		int remain = length;
+
+		while(remain > 0)
+		{
+			T* pItem = Back();
+
+			if(pItem == nullptr || pItem->IsFull())
+				pItem = PushBack(bfPool.PickFreeItem());
+
+			int cat  = pItem->Cat(pData, remain);
+
+			pData	+= cat;
+			remain	-= cat;
+		}
+
+		return length;
+	}
+
+	T* PushTail(const BYTE* pData, int length)
+	{
+		ASSERT(pData != nullptr && length > 0 && length <= (int)bfPool.GetItemCapacity());
+
+		T* pItem = PushBack(bfPool.PickFreeItem());
+		pItem->Cat(pData, length);
+
+		return pItem;
+	}
+
+	void Release()
+	{
+		bfPool.PutFreeItem(*this);
+	}
+
+public:
+	TBufferObjListT(CNodePoolT<T>& pool) : bfPool(pool)
+	{
+	}
+
+private:
+	CNodePoolT<T>& bfPool;
+};
+
+/* 数据缓冲区对象池 */
+typedef CNodePoolT<TBufferObj>			CBufferObjPool;
+/* UDP 数据缓冲区对象池 */
+typedef CNodePoolT<TUdpBufferObj>		CUdpBufferObjPool;
+/* 数据缓冲区链表模板 */
+typedef TBufferObjListT<TBufferObj>		TBufferObjList;
+/* UDP 数据缓冲区链表模板 */
+typedef TBufferObjListT<TUdpBufferObj>	TUdpBufferObjList;
+
+/* 数据缓冲区结构链表 */
+typedef CRingPool<TBufferObj>		TBufferObjPtrList;
+
+/* Udp 数据缓冲区结构链表 */
+typedef CRingPool<TUdpBufferObj>	TUdpBufferObjPtrList;
+
+/* Socket 缓冲区基础结构 */
+struct TSocketObjBase
+{
+	CONNID		connID;
+	SOCKADDR_IN	remoteAddr;
+	PVOID		extra;
+	PVOID		reserved;
+	PVOID		reserved2;
+	BOOL		valid;
+
+	union
+	{
+		DWORD	freeTime;
+		DWORD	connTime;
+	};
+
+	DWORD		activeTime;
+
+	CCriSec		csSend;
+
+	volatile BOOL smooth;
+	volatile long pending;
+	volatile long sndCount;
+
+	CReentrantSpinGuard csRecv;
+
+	static BOOL IsExist(TSocketObjBase* pSocketObj)
+		{return pSocketObj != nullptr;}
+
+	static BOOL IsValid(TSocketObjBase* pSocketObj)
+		{return pSocketObj != nullptr && pSocketObj->valid;}
+
+	static void Invalid(TSocketObjBase* pSocketObj)
+		{ASSERT(IsExist(pSocketObj)); pSocketObj->valid = FALSE;}
+
+	static BOOL IsSmooth(TSocketObjBase* pSocketObj)
+		{ASSERT(IsExist(pSocketObj)); return pSocketObj->valid && pSocketObj->smooth;}
+
+	static BOOL IsPending(TSocketObjBase* pSocketObj)
+		{ASSERT(IsExist(pSocketObj)); return pSocketObj->valid && pSocketObj->pending > 0;}
+
+	static void Release(TSocketObjBase* pSocketObj)
+	{
+		ASSERT(IsExist(pSocketObj));
+
+		pSocketObj->freeTime = ::TimeGetTime();
+	}
+
+	int Pending() {return pending;}
+
+	void Reset(CONNID dwConnID)
+	{
+		connID	 = dwConnID;
+		valid	 = TRUE;
+		smooth	 = TRUE;
+		pending	 = 0;
+		sndCount = 0;
+		extra	 = nullptr;
+		reserved = nullptr;
+		reserved2= nullptr;
+	}
+};
+
+/* 数据缓冲区结构 */
+struct TSocketObj : public TSocketObjBase
+{
+	SOCKET			socket;
+	CStringA		host;
+	TBufferObjList	sndBuff;
+	
+	TSocketObj(CBufferObjPool& bfPool)
+	: sndBuff(bfPool)
+	{
+
+	}
+
+	static void Release(TSocketObj* pSocketObj)
+	{
+		__super::Release(pSocketObj);
+
+		pSocketObj->sndBuff.Release();
+	}
+
+	void Reset(CONNID dwConnID, SOCKET soClient)
+	{
+		__super::Reset(dwConnID);
+		
+		host.Empty();
+
+		socket = soClient;
+	}
+
+	BOOL GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort = nullptr)
+	{
+		*lpszHost = host;
+
+		if(pusPort)
+			*pusPort = ntohs(remoteAddr.sin_port);
+
+		return (*lpszHost != nullptr && (*lpszHost)[0] != 0);
+	}
+};
+
+/* UDP 数据缓冲区结构 */
+struct TUdpSocketObj : public TSocketObjBase
+{
+	TUdpBufferObjList	sndBuff;
+	volatile DWORD		detectFails;
+
+	TUdpSocketObj(CUdpBufferObjPool& bfPool)
+	: sndBuff(bfPool)
+	{
+
+	}
+
+	static void Release(TUdpSocketObj* pSocketObj)
+	{
+		__super::Release(pSocketObj);
+
+		pSocketObj->sndBuff.Release();
+	}
+
+	void Reset(CONNID dwConnID)
+	{
+		__super::Reset(dwConnID);
+		detectFails = 0;
+	}
+};
+
+/* 有效 TSocketObj 缓存 */
+typedef CRingCache2<TSocketObj, CONNID, true>		TSocketObjPtrPool;
+/* 失效 TSocketObj 缓存 */
+typedef CRingPool<TSocketObj>						TSocketObjPtrList;
+/* 失效 TSocketObj 垃圾回收结构链表 */
+typedef CCASQueue<TSocketObj>						TSocketObjPtrQueue;
+
+/* 有效 TUdpSocketObj 缓存 */
+typedef CRingCache2<TUdpSocketObj, CONNID, true>	TUdpSocketObjPtrPool;
+/* 失效 TUdpSocketObj 缓存 */
+typedef CRingPool<TUdpSocketObj>					TUdpSocketObjPtrList;
+/* 失效 TUdpSocketObj 垃圾回收结构链表 */
+typedef CCASQueue<TUdpSocketObj>					TUdpSocketObjPtrQueue;
+
+/* SOCKADDR_IN 比较器 */
+struct sockaddr_func
+{
+	struct hash
+	{
+		size_t operator() (const SOCKADDR_IN* pA) const
+		{
+			return ((pA->sin_family << 16) | ntohs(pA->sin_port)) ^ pA->sin_addr.s_addr;
+		}
+	};
+
+	struct equal_to
+	{
+		bool operator () (const SOCKADDR_IN* pA, const SOCKADDR_IN* pB) const
+		{
+			return memcmp(pA, pB, offsetof(SOCKADDR_IN, sin_zero)) == 0;
+		}
+	};
+
+};
+
+/* 地址-连接 ID 哈希表 */
+typedef unordered_map<SOCKADDR_IN*, CONNID, sockaddr_func::hash, sockaddr_func::equal_to>
+										TSockAddrMap;
+/* 地址-连接 ID 哈希表迭代器 */
+typedef TSockAddrMap::iterator			TSockAddrMapI;
+/* 地址-连接 ID 哈希表 const 迭代器 */
+typedef TSockAddrMap::const_iterator	TSockAddrMapCI;
+
+/* IClient 组件关闭上下文 */
+struct TClientCloseContext
+{
+	BOOL bFireOnClose;
+	EnSocketOperation enOperation;
+	int iErrorCode;
+
+	TClientCloseContext(BOOL bFire = TRUE, EnSocketOperation enOp = SO_CLOSE, int iCode = SE_OK)
+	{
+		Reset(bFire, enOp, iCode);
+	}
+
+	void Reset(BOOL bFire = TRUE, EnSocketOperation enOp = SO_CLOSE, int iCode = SE_OK)
+	{
+		bFireOnClose = bFire;
+		enOperation	 = enOp;
+		iErrorCode	 = iCode;
+	}
+
+};
+
+/*****************************************************************************************************/
+/******************************************** 公共帮助方法 ********************************************/
+/*****************************************************************************************************/
+
+// 获取 HPSocket 版本号(4 个字节分别为:主版本号,子版本号,修正版本号,构建编号)
+DWORD GetHPSocketVersion();
+
+/* 获取错误描述文本 */
+LPCTSTR GetSocketErrorDesc(EnSocketError enCode);
+/* IPv4 字符串地址转换为整数 */
+ULONG GetIPv4InAddr(LPCTSTR lpszAddress);
+/* 检查字符串是否符合 IP 地址格式 */
+BOOL IsIPAddress(LPCTSTR lpszAddress);
+/* 通过主机名获取 IP 地址 */
+BOOL GetIPAddress(LPCTSTR lpszHost, __out LPTSTR lpszIP, __inout int& iIPLenth);
+/* 通过主机名获取最优的 IP 地址 */
+BOOL GetOptimalIPByHostName(LPCTSTR lpszHost, __out IN_ADDR& addr);
+/* 获取 IN_ADDR 结构的 IP 地址 */
+BOOL IN_ADDR_2_IP(const IN_ADDR& addr, __out LPTSTR lpszAddress, __inout int& iAddressLen);
+/* 把 SOCKADDR_IN 结构转换为地址数据 */
+BOOL sockaddr_IN_2_A(const SOCKADDR_IN& addr, __out ADDRESS_FAMILY& usFamily, __out LPTSTR lpszAddress, __inout int& iAddressLen, __out USHORT& usPort);
+/* 把地址数据转换为 SOCKADDR_IN 结构 */
+BOOL sockaddr_A_2_IN(ADDRESS_FAMILY usFamily, LPCTSTR lpszAddress, USHORT usPort, __out SOCKADDR_IN& addr);
+/* 获取 Socket 的本地或远程地址信息 */
+BOOL GetSocketAddress(SOCKET socket, __out LPTSTR lpszAddress, __inout int& iAddressLen, __out USHORT& usPort, BOOL bLocal = TRUE);
+/* 获取 Socket 的本地地址信息 */
+BOOL GetSocketLocalAddress(SOCKET socket, __out LPTSTR lpszAddress, __inout int& iAddressLen, __out USHORT& usPort);
+/* 获取 Socket 的远程地址信息 */
+BOOL GetSocketRemoteAddress(SOCKET socket, __out LPTSTR lpszAddress, __inout int& iAddressLen, __out USHORT& usPort);
+
+/* 64 位网络字节序转主机字节序 */
+ULONGLONG NToH64(ULONGLONG value);
+/* 64 位主机字节序转网络字节序 */
+ULONGLONG HToN64(ULONGLONG value);
+
+/* 获取 Socket 的某个扩展函数的指针 */
+PVOID GetExtensionFuncPtr					(SOCKET sock, GUID guid);
+/* 获取 AcceptEx 扩展函数指针 */
+LPFN_ACCEPTEX Get_AcceptEx_FuncPtr			(SOCKET sock);
+/* 获取 GetAcceptExSockaddrs 扩展函数指针 */
+LPFN_GETACCEPTEXSOCKADDRS Get_GetAcceptExSockaddrs_FuncPtr(SOCKET sock);
+/* 获取 ConnectEx 扩展函数指针 */
+LPFN_CONNECTEX Get_ConnectEx_FuncPtr		(SOCKET sock);
+/* 获取 TransmitFile 扩展函数指针 */
+LPFN_TRANSMITFILE Get_TransmitFile_FuncPtr	(SOCKET sock);
+/* 获取 DisconnectEx 扩展函数指针 */
+LPFN_DISCONNECTEX Get_DisconnectEx_FuncPtr	(SOCKET sock);
+
+HRESULT ReadSmallFile(LPCTSTR lpszFileName, CAtlFile& file, CAtlFileMapping<>& fmap, DWORD dwMaxFileSize = MAX_SMALL_FILE_SIZE);
+HRESULT MakeSmallFilePackage(LPCTSTR lpszFileName, CAtlFile& file, CAtlFileMapping<>& fmap, WSABUF szBuf[3], const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr);
+
+/************************************************************************
+名称:IOCP 指令投递帮助方法
+描述:简化 IOCP 指令投递
+************************************************************************/
+
+/* IOCP 命令 */
+enum EnIocpCommand
+{
+	IOCP_CMD_EXIT		= 0x00000000,	// 退出程序
+	IOCP_CMD_ACCEPT		= 0xFFFFFFF1,	// 接受连接
+	IOCP_CMD_DISCONNECT	= 0xFFFFFFF2,	// 断开连接
+	IOCP_CMD_SEND		= 0xFFFFFFF3	// 发送数据
+};
+
+/* IOCP 命令处理动作 */
+enum EnIocpAction
+{
+	IOCP_ACT_GOON		= 0,	// 继续执行
+	IOCP_ACT_CONTINUE	= 1,	// 重新执行
+	IOCP_ACT_BREAK		= 2		// 中断执行
+};
+
+BOOL PostIocpCommand(HANDLE hIOCP, EnIocpCommand enCmd, ULONG_PTR ulParam);
+BOOL PostIocpExit(HANDLE hIOCP);
+BOOL PostIocpAccept(HANDLE hIOCP);
+BOOL PostIocpDisconnect(HANDLE hIOCP, CONNID dwConnID);
+BOOL PostIocpSend(HANDLE hIOCP, CONNID dwConnID);
+BOOL PostIocpClose(HANDLE hIOCP, CONNID dwConnID, int iErrorCode);
+
+/************************************************************************
+名称:setsockopt() 帮助方法
+描述:简化常用的 setsockopt() 调用
+************************************************************************/
+
+int SSO_SetSocketOption		(SOCKET sock, int level, int name, LPVOID val, int len);
+int SSO_GetSocketOption		(SOCKET sock, int level, int name, LPVOID val, int* len);
+int SSO_IoctlSocket			(SOCKET sock, long cmd, u_long* arg);
+int SSO_WSAIoctl			(SOCKET sock, DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned);
+
+int SSO_UpdateAcceptContext	(SOCKET soClient, SOCKET soBind);
+int SSO_UpdateConnectContext(SOCKET soClient, int iOption);
+int SSO_NoDelay				(SOCKET sock, BOOL bNoDelay = TRUE);
+int SSO_DontLinger			(SOCKET sock, BOOL bDont = TRUE);
+int SSO_Linger				(SOCKET sock, USHORT l_onoff, USHORT l_linger);
+int SSO_KeepAlive			(SOCKET sock, BOOL bKeepAlive = TRUE);
+int SSO_KeepAliveVals		(SOCKET sock, u_long onoff, u_long time, u_long interval);
+int SSO_RecvBuffSize		(SOCKET sock, int size);
+int SSO_SendBuffSize		(SOCKET sock, int size);
+int SSO_ReuseAddress		(SOCKET sock, BOOL bReuse = TRUE);
+int SSO_UDP_ConnReset		(SOCKET sock, BOOL bNewBehavior = TRUE);
+
+/************************************************************************
+名称:Socket 操作方法
+描述:Socket 操作包装方法
+************************************************************************/
+
+/* 检测 IOCP 操作返回值:NO_ERROR 则返回 TRUE */
+#define IOCP_NO_ERROR(result)	(result == NO_ERROR)
+/* 检测 IOCP 操作返回值:WSA_IO_PENDING 则返回 TRUE */
+#define IOCP_PENDING(result)	(result == WSA_IO_PENDING)
+/* 检测 IOCP 操作返回值:NO_ERROR 或 WSA_IO_PENDING 则返回 TRUE */
+#define IOCP_SUCCESS(result)	(IOCP_NO_ERROR(result) || IOCP_PENDING(result))
+
+/* 生成 Connection ID */
+CONNID GenerateConnectionID	();
+/* 关闭 Socket */
+int ManualCloseSocket		(SOCKET sock, int iShutdownFlag = 0xFF, BOOL bGraceful = TRUE, BOOL bReuseAddress = FALSE);
+/* 投递 AccceptEx(),并把 WSA_IO_PENDING 转换为 NO_ERROR */
+int PostAccept				(LPFN_ACCEPTEX pfnAcceptEx, SOCKET soListen, SOCKET soClient, TBufferObj* pBufferObj);
+/* 投递 AccceptEx() */
+int PostAcceptNotCheck		(LPFN_ACCEPTEX pfnAcceptEx, SOCKET soListen, SOCKET soClient, TBufferObj* pBufferObj);
+/* 投递 ConnectEx(),并把 WSA_IO_PENDING 转换为 NO_ERROR */
+int PostConnect				(LPFN_CONNECTEX pfnConnectEx, SOCKET soClient, SOCKADDR_IN& soAddrIN, TBufferObj* pBufferObj);
+/* 投递 ConnectEx() */
+int PostConnectNotCheck		(LPFN_CONNECTEX pfnConnectEx, SOCKET soClient, SOCKADDR_IN& soAddrIN, TBufferObj* pBufferObj);
+/* 投递 WSASend(),并把 WSA_IO_PENDING 转换为 NO_ERROR */
+int PostSend				(TSocketObj* pSocketObj, TBufferObj* pBufferObj);
+/* 投递 WSASend() */
+int PostSendNotCheck		(TSocketObj* pSocketObj, TBufferObj* pBufferObj);
+/* 投递 WSARecv() ,并把 WSA_IO_PENDING 转换为 NO_ERROR*/
+int PostReceive				(TSocketObj* pSocketObj, TBufferObj* pBufferObj);
+/* 投递 WSARecv() */
+int PostReceiveNotCheck		(TSocketObj* pSocketObj, TBufferObj* pBufferObj);
+/* 投递 WSASendTo() ,并把 WSA_IO_PENDING 转换为 NO_ERROR*/
+int PostSendTo				(SOCKET sock, TUdpBufferObj* pBufferObj);
+/* 投递 WSASendTo() */
+int PostSendToNotCheck		(SOCKET sock, TUdpBufferObj* pBufferObj);
+/* 投递 WSARecvFrom() ,并把 WSA_IO_PENDING 转换为 NO_ERROR*/
+int PostReceiveFrom			(SOCKET sock, TUdpBufferObj* pBufferObj);
+/* 投递 WSARecvFrom() */
+int PostReceiveFromNotCheck	(SOCKET sock, TUdpBufferObj* pBufferObj);

+ 1985 - 0
HP-Socket/Src/SocketInterface.h

@@ -0,0 +1,1985 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 <winsock2.h>
+
+#include "HPTypeDef.h"
+
+/*****************************************************************************************************************************************************/
+/***************************************************************** TCP/UDP Interfaces ****************************************************************/
+/*****************************************************************************************************************************************************/
+
+/************************************************************************
+名称:复合 Socket 组件接口
+描述:定义复合 Socket 组件的所有操作方法和属性访问方法,复合 Socket 组件同时管理多个 Socket 连接
+************************************************************************/
+class IComplexSocket
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:关闭通信组件
+	* 描述:关闭通信组件,关闭完成后断开所有连接并释放所有资源
+	*		
+	* 参数:	
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 GetLastError() 获取错误代码
+	*/
+	virtual BOOL Stop	()																		= 0;
+
+	/*
+	* 名称:发送数据
+	* 描述:向指定连接发送数据
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			pBuffer		-- 发送缓冲区
+	*			iLength		-- 发送缓冲区长度
+	*			iOffset		-- 发送缓冲区指针偏移量
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL Send	(CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset = 0)	= 0;
+
+	/*
+	* 名称:发送多组数据
+	* 描述:向指定连接发送多组数据
+	*		TCP - 顺序发送所有数据包 
+	*		UDP - 把所有数据包组合成一个数据包发送(数据包的总长度不能大于设置的 UDP 包最大长度) 
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			pBuffers	-- 发送缓冲区数组
+	*			iCount		-- 发送缓冲区数目
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount)	= 0;
+
+	/*
+	* 名称:断开连接
+	* 描述:断开某个连接
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			bForce		-- 是否强制断开连接
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败
+	*/
+	virtual BOOL Disconnect(CONNID dwConnID, BOOL bForce = TRUE)					= 0;
+
+	/*
+	* 名称:断开超时连接
+	* 描述:断开超过指定时长的连接
+	*		
+	* 参数:		dwPeriod	-- 时长(毫秒)
+	*			bForce		-- 是否强制断开连接
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败
+	*/
+	virtual BOOL DisconnectLongConnections(DWORD dwPeriod, BOOL bForce = TRUE)		= 0;
+
+	/*
+	* 名称:断开静默连接
+	* 描述:断开超过指定时长的静默连接
+	*		
+	* 参数:		dwPeriod	-- 时长(毫秒)
+	*			bForce		-- 是否强制断开连接
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败
+	*/
+	virtual BOOL DisconnectSilenceConnections(DWORD dwPeriod, BOOL bForce = TRUE)	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/*
+	* 名称:设置连接的附加数据
+	* 描述:是否为连接绑定附加数据或者绑定什么样的数据,均由应用程序自身决定
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			pv			-- 数据
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败(无效的连接 ID)
+	*/
+	virtual BOOL SetConnectionExtra		(CONNID dwConnID, PVOID pExtra)			= 0;
+
+	/*
+	* 名称:获取连接的附加数据
+	* 描述:是否为连接绑定附加数据或者绑定什么样的数据,均由应用程序自身决定
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			ppv			-- 数据指针
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败(无效的连接 ID)
+	*/
+	virtual BOOL GetConnectionExtra			(CONNID dwConnID, PVOID* ppExtra)	= 0;
+
+	/* 检测是否为安全连接(SSL/HTTPS) */
+	virtual BOOL IsSecure				()									= 0;
+	/* 检查通信组件是否已启动 */
+	virtual BOOL HasStarted				()									= 0;
+	/* 查看通信组件当前状态 */
+	virtual EnServiceState GetState		()									= 0;
+	/* 获取连接数 */
+	virtual DWORD GetConnectionCount	()									= 0;
+	/* 获取所有连接的 CONNID */
+	virtual BOOL GetAllConnectionIDs	(CONNID pIDs[], DWORD& dwCount)		= 0;
+	/* 获取某个连接时长(毫秒) */
+	virtual BOOL GetConnectPeriod		(CONNID dwConnID, DWORD& dwPeriod)	= 0;
+	/* 获取某个连接静默时间(毫秒) */
+	virtual BOOL GetSilencePeriod		(CONNID dwConnID, DWORD& dwPeriod)	= 0;
+	/* 获取某个连接的本地地址信息 */
+	virtual BOOL GetLocalAddress		(CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)	= 0;
+	/* 获取某个连接的远程地址信息 */
+	virtual BOOL GetRemoteAddress		(CONNID dwConnID, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)	= 0;
+	/* 获取最近一次失败操作的错误代码 */
+	virtual EnSocketError GetLastError	()									= 0;
+	/* 获取最近一次失败操作的错误描述 */
+	virtual LPCTSTR GetLastErrorDesc	()									= 0;
+	/* 获取连接中未发出数据的长度 */
+	virtual BOOL GetPendingDataLength	(CONNID dwConnID, int& iPending)	= 0;
+
+	/* 设置数据发送策略 */
+	virtual void SetSendPolicy				(EnSendPolicy enSendPolicy)		= 0;
+	/* 设置最大连接数(组件会根据设置值预分配内存,因此需要根据实际情况设置,不宜过大)*/
+	virtual void SetMaxConnectionCount		(DWORD dwMaxConnectionCount)	= 0;
+	/* 设置 Socket 缓存对象锁定时间(毫秒,在锁定期间该 Socket 缓存对象不能被获取使用) */
+	virtual void SetFreeSocketObjLockTime	(DWORD dwFreeSocketObjLockTime)	= 0;
+	/* 设置 Socket 缓存池大小(通常设置为平均并发连接数的 1/3 - 1/2) */
+	virtual void SetFreeSocketObjPool		(DWORD dwFreeSocketObjPool)		= 0;
+	/* 设置内存块缓存池大小(通常设置为 Socket 缓存池大小的 2 - 3 倍) */
+	virtual void SetFreeBufferObjPool		(DWORD dwFreeBufferObjPool)		= 0;
+	/* 设置 Socket 缓存池回收阀值(通常设置为 Socket 缓存池大小的 3 倍) */
+	virtual void SetFreeSocketObjHold		(DWORD dwFreeSocketObjHold)		= 0;
+	/* 设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍) */
+	virtual void SetFreeBufferObjHold		(DWORD dwFreeBufferObjHold)		= 0;
+	/* 设置工作线程数量(通常设置为 2 * CPU + 2) */
+	virtual void SetWorkerThreadCount		(DWORD dwWorkerThreadCount)		= 0;
+	/* 设置是否标记静默时间(设置为 TRUE 时 DisconnectSilenceConnections() 和 GetSilencePeriod() 才有效,默认:TRUE) */
+	virtual void SetMarkSilence				(BOOL bMarkSilence)				= 0;
+
+	/* 获取数据发送策略 */
+	virtual EnSendPolicy GetSendPolicy		()	= 0;
+	/* 获取最大连接数 */
+	virtual DWORD GetMaxConnectionCount		()	= 0;
+	/* 获取 Socket 缓存对象锁定时间 */
+	virtual DWORD GetFreeSocketObjLockTime	()	= 0;
+	/* 获取 Socket 缓存池大小 */
+	virtual DWORD GetFreeSocketObjPool		()	= 0;
+	/* 获取内存块缓存池大小 */
+	virtual DWORD GetFreeBufferObjPool		()	= 0;
+	/* 获取 Socket 缓存池回收阀值 */
+	virtual DWORD GetFreeSocketObjHold		()	= 0;
+	/* 获取内存块缓存池回收阀值 */
+	virtual DWORD GetFreeBufferObjHold		()	= 0;
+	/* 获取工作线程数量 */
+	virtual DWORD GetWorkerThreadCount		()	= 0;
+	/* 检测是否标记静默时间 */
+	virtual BOOL IsMarkSilence				()	= 0;
+
+public:
+	virtual ~IComplexSocket() {}
+};
+
+/************************************************************************
+名称:通信服务端组件接口
+描述:定义通信服务端组件的所有操作方法和属性访问方法
+************************************************************************/
+class IServer : public IComplexSocket
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:启动通信组件
+	* 描述:启动服务端通信组件,启动完成后可开始接收客户端连接并收发数据
+	*		
+	* 参数:		lpszBindAddress	-- 监听地址
+	*			usPort			-- 监听端口
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 GetLastError() 获取错误代码
+	*/
+	virtual BOOL Start	(LPCTSTR lpszBindAddress, USHORT usPort)							= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 获取监听 Socket 的地址信息 */
+	virtual BOOL GetListenAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)	= 0;
+};
+
+/************************************************************************
+名称:TCP 通信服务端组件接口
+描述:定义 TCP 通信服务端组件的所有操作方法和属性访问方法
+************************************************************************/
+class ITcpServer : public IServer
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送小文件
+	* 描述:向指定连接发送 4096 KB 以下的小文件
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			lpszFileName	-- 文件路径
+	*			pHead			-- 头部附加数据
+	*			pTail			-- 尾部附加数据
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL SendSmallFile(CONNID dwConnID, LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr)	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置 Accept 预投递数量(根据负载调整设置,Accept 预投递数量越大则支持的并发连接请求越多) */
+	virtual void SetAcceptSocketCount	(DWORD dwAcceptSocketCount)		= 0;
+	/* 设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为 1024 的倍数) */
+	virtual void SetSocketBufferSize	(DWORD dwSocketBufferSize)		= 0;
+	/* 设置监听 Socket 的等候队列大小(根据并发连接数量调整设置) */
+	virtual void SetSocketListenQueue	(DWORD dwSocketListenQueue)		= 0;
+	/* 设置正常心跳包间隔(毫秒,0 则不发送心跳包,默认:30 * 1000) */
+	virtual void SetKeepAliveTime		(DWORD dwKeepAliveTime)			= 0;
+	/* 设置异常心跳包间隔(毫秒,0 不发送心跳包,,默认:10 * 1000,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线) */
+	virtual void SetKeepAliveInterval	(DWORD dwKeepAliveInterval)		= 0;
+
+	/* 获取 Accept 预投递数量 */
+	virtual DWORD GetAcceptSocketCount	()	= 0;
+	/* 获取通信数据缓冲区大小 */
+	virtual DWORD GetSocketBufferSize	()	= 0;
+	/* 获取监听 Socket 的等候队列大小 */
+	virtual DWORD GetSocketListenQueue	()	= 0;
+	/* 获取正常心跳包间隔 */
+	virtual DWORD GetKeepAliveTime		()	= 0;
+	/* 获取异常心跳包间隔 */
+	virtual DWORD GetKeepAliveInterval	()	= 0;
+};
+
+/************************************************************************
+名称:UDP 通信服务端组件接口
+描述:定义 UDP 通信服务端组件的所有操作方法和属性访问方法
+************************************************************************/
+class IUdpServer : public IServer
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置数据报文最大长度(建议在局域网环境下不超过 1472 字节,在广域网环境下不超过 548 字节) */
+	virtual void SetMaxDatagramSize		(DWORD dwMaxDatagramSize)	= 0;
+	/* 获取数据报文最大长度 */
+	virtual DWORD GetMaxDatagramSize	()							= 0;
+
+	/* 设置 Receive 预投递数量(根据负载调整设置,Receive 预投递数量越大则丢包概率越小) */
+	virtual void SetPostReceiveCount	(DWORD dwPostReceiveCount)	= 0;
+	/* 获取 Receive 预投递数量 */
+	virtual DWORD GetPostReceiveCount	()							= 0;
+
+	/* 设置监测包尝试次数(0 则不发送监测跳包,如果超过最大尝试次数则认为已断线) */
+	virtual void SetDetectAttempts		(DWORD dwDetectAttempts)	= 0;
+	/* 设置监测包发送间隔(秒,0 不发送监测包) */
+	virtual void SetDetectInterval		(DWORD dwDetectInterval)	= 0;
+	/* 获取心跳检查次数 */
+	virtual DWORD GetDetectAttempts		()							= 0;
+	/* 获取心跳检查间隔 */
+	virtual DWORD GetDetectInterval		()							= 0;
+};
+
+/************************************************************************
+名称:通信代理组件接口
+描述:定义通信代理组件的所有操作方法和属性访问方法,代理组件本质是一个同时连接多个服务器的客户端组件
+************************************************************************/
+class IAgent : public IComplexSocket
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:启动通信组件
+	* 描述:启动通信代理组件,启动完成后可开始连接远程服务器
+	*		
+	* 参数:		lpszBindAddress	-- 绑定地址(默认:nullptr,绑定 0.0.0.0)
+	*			bAsyncConnect	-- 是否采用异步 Connect
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 GetLastError() 获取错误代码
+	*/
+	virtual BOOL Start			(LPCTSTR lpszBindAddress = nullptr, BOOL bAsyncConnect = TRUE)				= 0;
+
+	/*
+	* 名称:连接服务器
+	* 描述:连接服务器,连接成功后 IAgentListener 会接收到 OnConnect() / OnHandShake() 事件
+	*		
+	* 参数:		lpszRemoteAddress	-- 服务端地址
+	*			usPort				-- 服务端端口
+	*			pdwConnID			-- 连接 ID(默认:nullptr,不获取连接 ID)
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL Connect		(LPCTSTR lpszRemoteAddress, USHORT usPort, CONNID* pdwConnID = nullptr)		= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 获取某个连接的远程主机信息 */
+	virtual BOOL GetRemoteHost	(CONNID dwConnID, TCHAR lpszHost[], int& iHostLen, USHORT& usPort)			= 0;
+
+};
+
+/************************************************************************
+名称:TCP 通信代理组件接口
+描述:定义 TCP 通信代理组件的所有操作方法和属性访问方法
+************************************************************************/
+class ITcpAgent : public IAgent
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送小文件
+	* 描述:向指定连接发送 4096 KB 以下的小文件
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			lpszFileName	-- 文件路径
+	*			pHead			-- 头部附加数据
+	*			pTail			-- 尾部附加数据
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL SendSmallFile(CONNID dwConnID, LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr)	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置是否启用地址重用机制(默认:不启用) */
+	virtual void SetReuseAddress		(BOOL bReuseAddress)			= 0;
+	/* 检测是否启用地址重用机制 */
+	virtual BOOL IsReuseAddress			()								= 0;
+
+	/* 设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为 1024 的倍数) */
+	virtual void SetSocketBufferSize	(DWORD dwSocketBufferSize)		= 0;
+	/* 设置正常心跳包间隔(毫秒,0 则不发送心跳包,默认:30 * 1000) */
+	virtual void SetKeepAliveTime		(DWORD dwKeepAliveTime)			= 0;
+	/* 设置异常心跳包间隔(毫秒,0 不发送心跳包,,默认:10 * 1000,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线) */
+	virtual void SetKeepAliveInterval	(DWORD dwKeepAliveInterval)		= 0;
+
+	/* 获取通信数据缓冲区大小 */
+	virtual DWORD GetSocketBufferSize	()	= 0;
+	/* 获取正常心跳包间隔 */
+	virtual DWORD GetKeepAliveTime		()	= 0;
+	/* 获取异常心跳包间隔 */
+	virtual DWORD GetKeepAliveInterval	()	= 0;
+};
+
+/************************************************************************
+名称:通信客户端组件接口
+描述:定义通信客户端组件的所有操作方法和属性访问方法
+************************************************************************/
+class IClient
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:启动通信组件
+	* 描述:启动客户端通信组件并连接服务端,启动完成后可开始收发数据
+	*		
+	* 参数:		lpszRemoteAddress	-- 服务端地址
+	*			usPort				-- 服务端端口
+	*			bAsyncConnect		-- 是否采用异步 Connect
+	*			lpszBindAddress		-- 绑定地址(默认:nullptr,TcpClient/UdpClient -> 不执行绑定操作,UdpCast 绑定 -> 0.0.0.0)
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 GetLastError() 获取错误代码
+	*/
+	virtual BOOL Start	(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr)	= 0;
+
+	/*
+	* 名称:关闭通信组件
+	* 描述:关闭客户端通信组件,关闭完成后断开与服务端的连接并释放所有资源
+	*		
+	* 参数:	
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 GetLastError() 获取错误代码
+	*/
+	virtual BOOL Stop	()																		= 0;
+
+	/*
+	* 名称:发送数据
+	* 描述:向服务端发送数据
+	*		
+	* 参数:		pBuffer		-- 发送缓冲区
+	*			iLength		-- 发送缓冲区长度
+	*			iOffset		-- 发送缓冲区指针偏移量
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL Send	(const BYTE* pBuffer, int iLength, int iOffset = 0)						= 0;
+
+	/*
+	* 名称:发送多组数据
+	* 描述:向服务端发送多组数据
+	*		TCP - 顺序发送所有数据包 
+	*		UDP - 把所有数据包组合成一个数据包发送(数据包的总长度不能大于设置的 UDP 包最大长度) 
+	*		
+	* 参数:		pBuffers	-- 发送缓冲区数组
+	*			iCount		-- 发送缓冲区数目
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL SendPackets(const WSABUF pBuffers[], int iCount)								= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置连接的附加数据 */
+	virtual void SetExtra					(PVOID pExtra)										= 0;
+
+	/* 获取连接的附加数据 */
+	virtual PVOID GetExtra					()													= 0;
+
+	/* 检测是否为安全连接(SSL/HTTPS) */
+	virtual BOOL IsSecure					()													= 0;
+	/* 检查通信组件是否已启动 */
+	virtual BOOL HasStarted					()													= 0;
+	/* 查看通信组件当前状态 */
+	virtual EnServiceState	GetState		()													= 0;
+	/* 获取最近一次失败操作的错误代码 */
+	virtual EnSocketError	GetLastError	()													= 0;
+	/* 获取最近一次失败操作的错误描述 */
+	virtual LPCTSTR			GetLastErrorDesc()													= 0;
+	/* 获取该组件对象的连接 ID */
+	virtual CONNID			GetConnectionID	()													= 0;
+	/* 获取 Client Socket 的地址信息 */
+	virtual BOOL GetLocalAddress		(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)	= 0;
+	/* 获取连接的远程主机信息 */
+	virtual BOOL GetRemoteHost			(TCHAR lpszHost[], int& iHostLen, USHORT& usPort)		= 0;
+	/* 获取连接中未发出数据的长度 */
+	virtual BOOL GetPendingDataLength	(int& iPending)											= 0;
+
+	/* 设置内存块缓存池大小(通常设置为 -> PUSH 模型:5 - 10;PULL 模型:10 - 20 ) */
+	virtual void SetFreeBufferPoolSize		(DWORD dwFreeBufferPoolSize)						= 0;
+	/* 设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍) */
+	virtual void SetFreeBufferPoolHold		(DWORD dwFreeBufferPoolHold)						= 0;
+
+	/* 获取内存块缓存池大小 */
+	virtual DWORD GetFreeBufferPoolSize		()													= 0;
+	/* 获取内存块缓存池回收阀值 */
+	virtual DWORD GetFreeBufferPoolHold		()													= 0;
+
+public:
+	virtual ~IClient() {}
+};
+
+/************************************************************************
+名称:TCP 通信客户端组件接口
+描述:定义 TCP 通信客户端组件的所有操作方法和属性访问方法
+************************************************************************/
+class ITcpClient : public IClient
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送小文件
+	* 描述:向服务端发送 4096 KB 以下的小文件
+	*		
+	* 参数:		lpszFileName	-- 文件路径
+	*			pHead			-- 头部附加数据
+	*			pTail			-- 尾部附加数据
+	* 返回值:	TRUE	-- 成功
+	*			FALSE	-- 失败,可通过 Windows API 函数 ::GetLastError() 获取 Windows 错误代码
+	*/
+	virtual BOOL SendSmallFile(LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr)	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为:(N * 1024) - sizeof(TBufferObj)) */
+	virtual void SetSocketBufferSize	(DWORD dwSocketBufferSize)	= 0;
+	/* 设置正常心跳包间隔(毫秒,0 则不发送心跳包,默认:30 * 1000) */
+	virtual void SetKeepAliveTime		(DWORD dwKeepAliveTime)		= 0;
+	/* 设置异常心跳包间隔(毫秒,0 不发送心跳包,,默认:10 * 1000,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线) */
+	virtual void SetKeepAliveInterval	(DWORD dwKeepAliveInterval)	= 0;
+
+	/* 获取通信数据缓冲区大小 */
+	virtual DWORD GetSocketBufferSize	()	= 0;
+	/* 获取正常心跳包间隔 */
+	virtual DWORD GetKeepAliveTime		()	= 0;
+	/* 获取异常心跳包间隔 */
+	virtual DWORD GetKeepAliveInterval	()	= 0;
+};
+
+/************************************************************************
+名称:UDP 通信客户端组件接口
+描述:定义 UDP 通信客户端组件的所有操作方法和属性访问方法
+************************************************************************/
+class IUdpClient : public IClient
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置数据报文最大长度(建议在局域网环境下不超过 1472 字节,在广域网环境下不超过 548 字节) */
+	virtual void SetMaxDatagramSize	(DWORD dwMaxDatagramSize)	= 0;
+	/* 获取数据报文最大长度 */
+	virtual DWORD GetMaxDatagramSize()							= 0;
+
+	/* 设置监测包尝试次数(0 则不发送监测跳包,如果超过最大尝试次数则认为已断线) */
+	virtual void SetDetectAttempts	(DWORD dwDetectAttempts)	= 0;
+	/* 设置监测包发送间隔(秒,0 不发送监测包) */
+	virtual void SetDetectInterval	(DWORD dwDetectInterval)	= 0;
+	/* 获取心跳检查次数 */
+	virtual DWORD GetDetectAttempts	()							= 0;
+	/* 获取心跳检查间隔 */
+	virtual DWORD GetDetectInterval	()							= 0;
+};
+
+/************************************************************************
+名称:UDP 传播组件接口
+描述:定义 UDP 传播(组播或广播)组件的所有操作方法和属性访问方法
+************************************************************************/
+class IUdpCast : public IClient
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置数据报文最大长度(建议在局域网环境下不超过 1472 字节,在广域网环境下不超过 548 字节) */
+	virtual void SetMaxDatagramSize	(DWORD dwMaxDatagramSize)		= 0;
+	/* 获取数据报文最大长度 */
+	virtual DWORD GetMaxDatagramSize()								= 0;
+
+	/* 设置是否启用地址重用机制(默认:不启用) */
+	virtual void SetReuseAddress	(BOOL bReuseAddress)			= 0;
+	/* 检测是否启用地址重用机制 */
+	virtual BOOL IsReuseAddress		()								= 0;
+
+	/* 设置传播模式(组播或广播) */
+	virtual void SetCastMode		(EnCastMode enCastMode)			= 0;
+	/* 获取传播模式 */
+	virtual EnCastMode GetCastMode	()								= 0;
+
+	/* 设置组播报文的 TTL(0 - 255) */
+	virtual void SetMultiCastTtl	(int iMCTtl)					= 0;
+	/* 获取组播报文的 TTL */
+	virtual int GetMultiCastTtl		()								= 0;
+
+	/* 设置是否启用组播环路(TRUE or FALSE) */
+	virtual void SetMultiCastLoop	(BOOL bMCLoop)					= 0;
+	/* 检测是否启用组播环路 */
+	virtual BOOL IsMultiCastLoop	()								= 0;
+
+	/* 获取当前数据报的远程地址信息(通常在 OnReceive 事件中调用) */
+	virtual BOOL GetRemoteAddress	(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)	= 0;
+};
+
+/************************************************************************
+名称:双接口模版类
+描述:定义双接口转换方法
+************************************************************************/
+template<class F, class S> class DualInterface : public F, public S
+{
+public:
+
+	/* this 转换为 F* */
+	inline static F* ToF(DualInterface* pThis)
+	{
+		return (F*)(pThis);
+	}
+
+	/* F* 转换为 this */
+	inline static DualInterface* FromF(F* pF)
+	{
+		return (DualInterface*)(pF);
+	}
+
+	/* this 转换为 S* */
+	inline static S* ToS(DualInterface* pThis)
+	{
+		return (S*)(F2S(ToF(pThis)));
+	}
+
+	/* S* 转换为 this */
+	inline static DualInterface* FromS(S* pS)
+	{
+		return FromF(S2F(pS));
+	}
+
+	/* S* 转换为 F* */
+	inline static F* S2F(S* pS)
+	{
+		return (F*)((char*)pS - sizeof(F));
+	}
+
+	/* F* 转换为 S* */
+	inline static S* F2S(F* pF)
+	{
+		return (S*)((char*)pF + sizeof(F));
+	}
+
+public:
+	~DualInterface() {}
+};
+
+/************************************************************************
+名称:Server/Agent PULL 模型组件接口
+描述:定义 Server/Agent 组件的 PULL 模型组件的所有操作方法
+************************************************************************/
+class IPullSocket
+{
+public:
+
+	/*
+	* 名称:抓取数据
+	* 描述:用户通过该方法从 Socket 组件中抓取数据
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			pData		-- 抓取缓冲区
+	*			iLength		-- 抓取数据长度
+	* 返回值:	EnFetchResult
+	*/
+	virtual EnFetchResult Fetch	(CONNID dwConnID, BYTE* pData, int iLength)	= 0;
+
+	/*
+	* 名称:窥探数据(不会移除缓冲区数据)
+	* 描述:用户通过该方法从 Socket 组件中窥探数据
+	*		
+	* 参数:		dwConnID	-- 连接 ID
+	*			pData		-- 窥探缓冲区
+	*			iLength		-- 窥探数据长度
+	* 返回值:	EnFetchResult
+	*/
+	virtual EnFetchResult Peek	(CONNID dwConnID, BYTE* pData, int iLength)	= 0;
+
+public:
+	virtual ~IPullSocket() {}
+};
+
+/************************************************************************
+名称:Client PULL 模型组件接口
+描述:定义 Client 组件的 PULL 模型组件的所有操作方法
+************************************************************************/
+class IPullClient
+{
+public:
+
+	/*
+	* 名称:抓取数据
+	* 描述:用户通过该方法从 Socket 组件中抓取数据
+	*		
+	* 参数:		pData		-- 抓取缓冲区
+	*			iLength		-- 抓取数据长度
+	* 返回值:	EnFetchResult
+	*/
+	virtual EnFetchResult Fetch	(BYTE* pData, int iLength)	= 0;
+
+	/*
+	* 名称:窥探数据(不会移除缓冲区数据)
+	* 描述:用户通过该方法从 Socket 组件中窥探数据
+	*		
+	* 参数:		pData		-- 窥探缓冲区
+	*			iLength		-- 窥探数据长度
+	* 返回值:	EnFetchResult
+	*/
+	virtual EnFetchResult Peek	(BYTE* pData, int iLength)	= 0;
+
+public:
+	virtual ~IPullClient() {}
+};
+
+/************************************************************************
+名称:TCP PULL 模型组件接口
+描述:继承了 PULL 和 Socket 接口
+************************************************************************/
+typedef	DualInterface<IPullSocket, ITcpServer>	ITcpPullServer;
+typedef	DualInterface<IPullSocket, ITcpAgent>	ITcpPullAgent;
+typedef	DualInterface<IPullClient, ITcpClient>	ITcpPullClient;
+
+/************************************************************************
+名称:Server/Agent PACK 模型组件接口
+描述:定义 Server/Agent 组件的 PACK 模型组件的所有操作方法
+************************************************************************/
+class IPackSocket
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置数据包最大长度(有效数据包最大长度不能超过 4194303/0x3FFFFF 字节,默认:262144/0x40000) */
+	virtual void SetMaxPackSize		(DWORD dwMaxPackSize)			= 0;
+	/* 设置包头标识(有效包头标识取值范围 0 ~ 1023/0x3FF,当包头标识为 0 时不校验包头,默认:0) */
+	virtual void SetPackHeaderFlag	(USHORT usPackHeaderFlag)		= 0;
+
+	/* 获取数据包最大长度 */
+	virtual DWORD GetMaxPackSize	()								= 0;
+	/* 获取包头标识 */
+	virtual USHORT GetPackHeaderFlag()								= 0;
+
+public:
+	virtual ~IPackSocket() {}
+};
+
+/************************************************************************
+名称:Client PACK 模型组件接口
+描述:定义 Client 组件的 PACK 模型组件的所有操作方法
+************************************************************************/
+class IPackClient
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置数据包最大长度(有效数据包最大长度不能超过 4194303/0x3FFFFF 字节,默认:262144/0x40000) */
+	virtual void SetMaxPackSize		(DWORD dwMaxPackSize)			= 0;
+	/* 设置包头标识(有效包头标识取值范围 0 ~ 1023/0x3FF,当包头标识为 0 时不校验包头,默认:0) */
+	virtual void SetPackHeaderFlag	(USHORT usPackHeaderFlag)		= 0;
+
+	/* 获取数据包最大长度 */
+	virtual DWORD GetMaxPackSize	()								= 0;
+	/* 获取包头标识 */
+	virtual USHORT GetPackHeaderFlag()								= 0;
+
+public:
+	virtual ~IPackClient() {}
+};
+
+/************************************************************************
+名称:TCP PACK 模型组件接口
+描述:继承了 PACK 和 Socket 接口
+************************************************************************/
+typedef	DualInterface<IPackSocket, ITcpServer>	ITcpPackServer;
+typedef	DualInterface<IPackSocket, ITcpAgent>	ITcpPackAgent;
+typedef	DualInterface<IPackClient, ITcpClient>	ITcpPackClient;
+
+/************************************************************************
+名称:Socket 监听器基接口
+描述:定义组件监听器的公共方法
+************************************************************************/
+template<class T> class ISocketListenerT
+{
+public:
+
+	/*
+	* 名称:握手完成通知
+	* 描述:连接完成握手时,Socket 监听器将收到该通知,监听器接收到该通知后才能开始
+	*		数据收发操作
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHandleResult OnHandShake(T* pSender, CONNID dwConnID)												= 0;
+
+	/*
+	* 名称:已发送数据通知
+	* 描述:成功发送数据后,Socket 监听器将收到该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			pData		-- 已发送数据缓冲区
+	*			iLength		-- 已发送数据长度
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 该通知不允许返回 HR_ERROR(调试模式下引发断言错误)
+	*/
+	virtual EnHandleResult OnSend(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)					= 0;
+
+	/*
+	* 名称:数据到达通知(PUSH 模型)
+	* 描述:对于 PUSH 模型的 Socket 通信组件,成功接收数据后将向 Socket 监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			pData		-- 已接收数据缓冲区
+	*			iLength		-- 已接收数据长度
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)				= 0;
+
+	/*
+	* 名称:数据到达通知(PULL 模型)
+	* 描述:对于 PULL 模型的 Socket 通信组件,成功接收数据后将向 Socket 监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			iLength		-- 已接收数据长度
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHandleResult OnReceive(T* pSender, CONNID dwConnID, int iLength)									= 0;
+
+	/*
+	* 名称:通信错误通知
+	* 描述:通信发生错误后,Socket 监听器将收到该通知,并关闭连接
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			enOperation	-- Socket 操作类型
+	*			iErrorCode	-- 错误代码
+	* 返回值:	忽略返回值
+	*/
+	virtual EnHandleResult OnClose(T* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)	= 0;
+
+public:
+	virtual ~ISocketListenerT() {}
+};
+
+template<class T> class IComplexSocketListenerT : public ISocketListenerT<T>
+{
+public:
+
+	/*
+	* 名称:关闭通信组件通知
+	* 描述:通信组件关闭时,Socket 监听器将收到该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	* 返回值:忽略返回值
+	*/
+	virtual EnHandleResult OnShutdown(T* pSender)																= 0;
+
+};
+
+/************************************************************************
+名称:服务端 Socket 监听器接口
+描述:定义服务端 Socket 监听器的所有事件
+************************************************************************/
+template<class T> class IServerListenerT : public IComplexSocketListenerT<T>
+{
+public:
+
+	/*
+	* 名称:准备监听通知
+	* 描述:通信服务端组件启动时,在监听 Socket 创建完成并开始执行监听前,Socket 监听
+	*		器将收到该通知,监听器可以在通知处理方法中执行 Socket 选项设置等额外工作
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			soListen	-- 监听 Socket
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 终止启动通信服务组件
+	*/
+	virtual EnHandleResult OnPrepareListen(T* pSender, SOCKET soListen)						= 0;
+
+	/*
+	* 名称:接收连接通知
+	* 描述:接收到客户端连接请求时,Socket 监听器将收到该通知,监听器可以在通知处理方
+	*		法中执行 Socket 选项设置或拒绝客户端连接等额外工作
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			soClient	-- TCP: 客户端 Socket 句柄,UDP: 客户端 Socket SOCKADDR_IN 指针
+	* 返回值:	HR_OK / HR_IGNORE	-- 接受连接
+	*			HR_ERROR			-- 拒绝连接
+	*/
+	virtual EnHandleResult OnAccept(T* pSender, CONNID dwConnID, UINT_PTR soClient)			= 0;
+};
+
+/************************************************************************
+名称:TCP 服务端 Socket 监听器接口
+描述:定义 TCP 服务端 Socket 监听器的所有事件
+************************************************************************/
+class ITcpServerListener : public IServerListenerT<ITcpServer>
+{
+public:
+
+};
+
+/************************************************************************
+名称:PUSH 模型服务端 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CTcpServerListener : public ITcpServerListener
+{
+public:
+	virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen)							{return HR_IGNORE;}
+	virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient)				{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID)								{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength)						{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+	virtual EnHandleResult OnShutdown(ITcpServer* pSender)													{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:PULL 模型服务端 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CTcpPullServerListener : public CTcpServerListener
+{
+public:
+	virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength)						= 0;
+	virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)	{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:UDP 服务端 Socket 监听器接口
+描述:定义 UDP 服务端 Socket 监听器的所有事件
+************************************************************************/
+class IUdpServerListener : public IServerListenerT<IUdpServer>
+{
+public:
+
+};
+
+/************************************************************************
+名称:UDP 服务端 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CUdpServerListener : public IUdpServerListener
+{
+public:
+	virtual EnHandleResult OnPrepareListen(IUdpServer* pSender, SOCKET soListen)						{return HR_IGNORE;}
+	virtual EnHandleResult OnAccept(IUdpServer* pSender, CONNID dwConnID, UINT_PTR pSockAddr)			{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(IUdpServer* pSender, CONNID dwConnID)							{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(IUdpServer* pSender, CONNID dwConnID, int iLength)					{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(IUdpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)	{return HR_IGNORE;}
+	virtual EnHandleResult OnShutdown(IUdpServer* pSender)												{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:通信代理 Socket 监听器接口
+描述:定义 通信代理 Socket 监听器的所有事件
+************************************************************************/
+template<class T> class IAgentListenerT : public IComplexSocketListenerT<T>
+{
+public:
+
+	/*
+	* 名称:准备连接通知
+	* 描述:通信客户端组件启动时,在客户端 Socket 创建完成并开始执行连接前,Socket 监听
+	*		器将收到该通知,监听器可以在通知处理方法中执行 Socket 选项设置等额外工作
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			socket		-- 客户端 Socket
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 终止启动通信客户端组件
+	*/
+	virtual EnHandleResult OnPrepareConnect(T* pSender, CONNID dwConnID, SOCKET socket)		= 0;
+
+	/*
+	* 名称:连接完成通知
+	* 描述:与服务端成功建立连接时,Socket 监听器将收到该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 同步连接:终止启动通信客户端组件
+	*								   异步连接:关闭连接
+	*/
+	virtual EnHandleResult OnConnect(T* pSender, CONNID dwConnID)							= 0;
+};
+
+/************************************************************************
+名称:TCP 通信代理 Socket 监听器接口
+描述:定义 TCP 通信代理 Socket 监听器的所有事件
+************************************************************************/
+class ITcpAgentListener : public IAgentListenerT<ITcpAgent>
+{
+public:
+
+};
+
+/************************************************************************
+名称:PUSH 模型通信代理 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CTcpAgentListener : public ITcpAgentListener
+{
+public:
+	virtual EnHandleResult OnPrepareConnect(ITcpAgent* pSender, CONNID dwConnID, SOCKET socket)				{return HR_IGNORE;}
+	virtual EnHandleResult OnConnect(ITcpAgent* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(ITcpAgent* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, int iLength)						{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(ITcpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+	virtual EnHandleResult OnShutdown(ITcpAgent* pSender)													{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:PULL 通信代理 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CTcpPullAgentListener : public CTcpAgentListener
+{
+public:
+	virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, int iLength)						= 0;
+	virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)	{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:客户端 Socket 监听器接口
+描述:定义客户端 Socket 监听器的所有事件
+************************************************************************/
+
+template<class T> class IClientListenerT : public ISocketListenerT<T>
+{
+public:
+	
+	/*
+	* 名称:准备连接通知
+	* 描述:通信客户端组件启动时,在客户端 Socket 创建完成并开始执行连接前,Socket 监听
+	*		器将收到该通知,监听器可以在通知处理方法中执行 Socket 选项设置等额外工作
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			socket		-- 客户端 Socket
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 终止启动通信客户端组件
+	*/
+	virtual EnHandleResult OnPrepareConnect(T* pSender, CONNID dwConnID, SOCKET socket)						= 0;
+
+	/*
+	* 名称:连接完成通知
+	* 描述:与服务端成功建立连接时,Socket 监听器将收到该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 同步连接:终止启动通信客户端组件
+	*								   异步连接:关闭连接
+	*/
+	virtual EnHandleResult OnConnect(T* pSender, CONNID dwConnID)											= 0;
+};
+
+/************************************************************************
+名称:TCP 客户端 Socket 监听器接口
+描述:定义 TCP 客户端 Socket 监听器的所有事件
+************************************************************************/
+class ITcpClientListener : public IClientListenerT<ITcpClient>
+{
+public:
+
+};
+
+/************************************************************************
+名称:PUSH 模型客户端 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CTcpClientListener : public ITcpClientListener
+{
+public:
+	virtual EnHandleResult OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket)			{return HR_IGNORE;}
+	virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(ITcpClient* pSender, CONNID dwConnID)								{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, int iLength)						{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:PULL 客户端 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CTcpPullClientListener : public CTcpClientListener
+{
+public:
+	virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, int iLength)						= 0;
+	virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)	{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:UDP 客户端 Socket 监听器接口
+描述:定义 UDP 客户端 Socket 监听器的所有事件
+************************************************************************/
+class IUdpClientListener : public IClientListenerT<IUdpClient>
+{
+public:
+
+};
+
+/************************************************************************
+名称:UDP 户端 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CUdpClientListener : public IUdpClientListener
+{
+public:
+	virtual EnHandleResult OnPrepareConnect(IUdpClient* pSender, CONNID dwConnID, SOCKET socket)			{return HR_IGNORE;}
+	virtual EnHandleResult OnConnect(IUdpClient* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(IUdpClient* pSender, CONNID dwConnID)								{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(IUdpClient* pSender, CONNID dwConnID, int iLength)						{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(IUdpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:UDP 传播 Socket 监听器接口
+描述:定义 UDP 传播 Socket 监听器的所有事件
+************************************************************************/
+class IUdpCastListener : public IClientListenerT<IUdpCast>
+{
+public:
+
+};
+
+/************************************************************************
+名称:UDP 传播 Socket 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CUdpCastListener : public IUdpCastListener
+{
+public:
+	virtual EnHandleResult OnPrepareConnect(IUdpCast* pSender, CONNID dwConnID, SOCKET socket)				{return HR_IGNORE;}
+	virtual EnHandleResult OnConnect(IUdpCast* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(IUdpCast* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(IUdpCast* pSender, CONNID dwConnID, int iLength)						{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(IUdpCast* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+};
+
+/*****************************************************************************************************************************************************/
+/****************************************************************** HTTP Interfaces ******************************************************************/
+/*****************************************************************************************************************************************************/
+
+/************************************************************************
+名称:复合 Http 组件接口
+描述:定义复合 Http 组件的所有操作方法和属性访问方法,复合 Http 组件同时管理多个 Http 连接
+************************************************************************/
+class IComplexHttp
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送 WebSocket 消息
+	* 描述:向对端端发送 WebSocket 消息
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			bFinal			-- 是否结束帧
+	*			iReserved		-- RSV1/RSV2/RSV3 各 1 位
+	*			iOperationCode	-- 操作码:0x0 - 0xF
+	*			lpszMask		-- 掩码(nullptr 或 4 字节掩码,如果为 nullptr 则没有掩码)
+	*			pData			-- 消息体数据缓冲区
+	*			iLength			-- 消息体数据长度
+	*			ullBodyLen		-- 消息总长度
+	* 								ullBodyLen = 0		 -> 消息总长度为 iLength
+	* 								ullBodyLen = iLength -> 消息总长度为 ullBodyLen
+	* 								ullBodyLen > iLength -> 消息总长度为 ullBodyLen,后续消息体长度为 ullBOdyLen - iLength,后续消息体通过底层方法 Send() / SendPackets() 发送
+	* 								ullBodyLen < iLength -> 错误参数,发送失败
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4] = nullptr, BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0)	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置本地协议版本 */
+	virtual void SetLocalVersion(EnHttpVersion usVersion)								= 0;
+	/* 获取本地协议版本 */
+	virtual EnHttpVersion GetLocalVersion()												= 0;
+
+	/* 检查是否升级协议 */
+	virtual BOOL IsUpgrade(CONNID dwConnID)												= 0;
+	/* 检查是否有 Keep-Alive 标识 */
+	virtual BOOL IsKeepAlive(CONNID dwConnID)											= 0;
+	/* 获取协议版本 */
+	virtual USHORT GetVersion(CONNID dwConnID)											= 0;
+	/* 获取内容长度 */
+	virtual ULONGLONG GetContentLength(CONNID dwConnID)									= 0;
+	/* 获取内容类型 */
+	virtual LPCSTR GetContentType(CONNID dwConnID)										= 0;
+	/* 获取内容编码 */
+	virtual LPCSTR GetContentEncoding(CONNID dwConnID)									= 0;
+	/* 获取传输编码 */
+	virtual LPCSTR GetTransferEncoding(CONNID dwConnID)									= 0;
+	/* 获取协议升级类型 */
+	virtual EnHttpUpgradeType GetUpgradeType(CONNID dwConnID)							= 0;
+	/* 获取解析错误代码 */
+	virtual USHORT GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc = nullptr)	= 0;
+
+	/* 获取某个请求头(单值) */
+	virtual BOOL GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)						= 0;
+	/* 获取某个请求头(多值) */
+	virtual BOOL GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)	= 0;
+	/* 获取所有请求头 */
+	virtual BOOL GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount)				= 0;
+	/* 获取所有请求头名称 */
+	virtual BOOL GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount)				= 0;
+
+	/* 获取 Cookie */
+	virtual BOOL GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)						= 0;
+	/* 获取所有 Cookie */
+	virtual BOOL GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount)				= 0;
+
+	/*
+	// !! maybe implemented in future !! //
+
+	virtual BOOL GetParam(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)						= 0;
+	virtual BOOL GetParams(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)	= 0;
+	virtual BOOL GetAllParams(CONNID dwConnID, LPPARAM lpszParam[], DWORD& dwCount)					= 0;
+	virtual BOOL GetAllParamNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount)				= 0;
+	*/
+
+	/* 获取当前 WebSocket 消息状态,传入 nullptr 则不获取相应字段 */
+	virtual BOOL GetWSMessageState(CONNID dwConnID, BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)	= 0;
+
+public:
+	virtual ~IComplexHttp() {}
+};
+
+/************************************************************************
+名称:复合 Http 请求者组件接口
+描述:定义复合 Http 请求者组件的所有操作方法和属性访问方法
+************************************************************************/
+class IComplexHttpRequester : public IComplexHttp
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送请求
+	* 描述:向服务端发送 HTTP 请求
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			lpszMethod		-- 请求方法
+	*			lpszPath		-- 请求路径
+	*			lpHeaders		-- 请求头
+	*			iHeaderCount	-- 请求头数量
+	*			pBody			-- 请求体
+	*			iLength			-- 请求体长度
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendRequest(CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0)	= 0;
+
+	/*
+	* 名称:发送本地文件
+	* 描述:向指定连接发送 4096 KB 以下的小文件
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			lpszFileName	-- 文件路径
+	*			lpszMethod		-- 请求方法
+	*			lpszPath		-- 请求路径
+	*			lpHeaders		-- 请求头
+	*			iHeaderCount	-- 请求头数量
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)							= 0;
+
+	/* 发送 POST 请求 */
+	virtual BOOL SendPost(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)													= 0;
+	/* 发送 PUT 请求 */
+	virtual BOOL SendPut(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)														= 0;
+	/* 发送 PATCH 请求 */
+	virtual BOOL SendPatch(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)													= 0;
+	/* 发送 GET 请求 */
+	virtual BOOL SendGet(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 DELETE 请求 */
+	virtual BOOL SendDelete(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																	= 0;
+	/* 发送 HEAD 请求 */
+	virtual BOOL SendHead(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 TRACE 请求 */
+	virtual BOOL SendTrace(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 OPTIONS 请求 */
+	virtual BOOL SendOptions(CONNID dwConnID, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																	= 0;
+	/* 发送 CONNECT 请求 */
+	virtual BOOL SendConnect(CONNID dwConnID, LPCSTR lpszHost, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 获取 HTTP 状态码 */
+	virtual USHORT GetStatusCode(CONNID dwConnID)						= 0;
+
+	/* 设置是否使用 Cookie(默认:TRUE) */
+	virtual void SetUseCookie(BOOL bUseCookie)							= 0;
+	/* 检查是否使用 Cookie */
+	virtual BOOL IsUseCookie()											= 0;
+};
+
+/************************************************************************
+名称:复合 Http 响应者组件接口
+描述:定义复合 Http 响应者组件的所有操作方法和属性访问方法
+************************************************************************/
+class IComplexHttpResponder : public IComplexHttp
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:回复请求
+	* 描述:向客户端回复 HTTP 请求
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			usStatusCode	-- HTTP 状态码
+	*			lpszDesc		-- HTTP 状态描述
+	*			lpHeaders		-- 回复请求头
+	*			iHeaderCount	-- 回复请求头数量
+	*			pData			-- 回复请求体
+	*			iLength			-- 回复请求体长度
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendResponse(CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc = nullptr, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pData = nullptr, int iLength = 0)	= 0;
+
+	/*
+	* 名称:发送本地文件
+	* 描述:向指定连接发送 4096 KB 以下的小文件
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			lpszFileName	-- 文件路径
+	*			usStatusCode	-- HTTP 状态码
+	*			lpszDesc		-- HTTP 状态描述
+	*			lpHeaders		-- 回复请求头
+	*			iHeaderCount	-- 回复请求头数量
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, USHORT usStatusCode = HSC_OK, LPCSTR lpszDesc = nullptr, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)				= 0;
+
+	/*
+	* 名称:释放连接
+	* 描述:把连接放入释放队列,等待某个时间(通过 SetReleaseDelay() 设置)关闭连接
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL Release(CONNID dwConnID)								= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 获取主机 */
+	virtual LPCSTR GetHost(CONNID dwConnID)								= 0;
+
+	/* 设置连接释放延时(默认:3000 毫秒) */
+	virtual void SetReleaseDelay(DWORD dwReleaseDelay)					= 0;
+	/* 获取连接释放延时 */
+	virtual DWORD GetReleaseDelay()										= 0;
+
+	/* 获取请求行 URL 域掩码(URL 域参考:EnHttpUrlField) */
+	virtual USHORT GetUrlFieldSet(CONNID dwConnID)						= 0;
+	/* 获取某个 URL 域值 */
+	virtual LPCSTR GetUrlField(CONNID dwConnID, EnHttpUrlField enField)	= 0;
+	/* 获取请求方法 */
+	virtual LPCSTR GetMethod(CONNID dwConnID)							= 0;
+};
+
+/************************************************************************
+名称:简单 HTTP 组件接口
+描述:定义 简单 HTTP 组件的所有操作方法和属性访问方法
+************************************************************************/
+class IHttp
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送 WebSocket 消息
+	* 描述:向对端端发送 WebSocket 消息
+	*		
+	* 参数:		bFinal			-- 是否结束帧
+	*			iReserved		-- RSV1/RSV2/RSV3 各 1 位
+	*			iOperationCode	-- 操作码:0x0 - 0xF
+	*			lpszMask		-- 掩码(nullptr 或 4 字节掩码,如果为 nullptr 则没有掩码)
+	*			pData			-- 消息体数据缓冲区
+	*			iLength			-- 消息体数据长度
+	*			ullBodyLen		-- 消息总长度
+	* 								ullBodyLen = 0		 -> 消息总长度为 iLength
+	* 								ullBodyLen = iLength -> 消息总长度为 ullBodyLen
+	* 								ullBodyLen > iLength -> 消息总长度为 ullBodyLen,后续消息体长度为 ullBOdyLen - iLength,后续消息体通过底层方法 Send() / SendPackets() 发送
+	* 								ullBodyLen < iLength -> 错误参数,发送失败
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4] = nullptr, BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0)	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置本地协议版本 */
+	virtual void SetLocalVersion(EnHttpVersion usVersion)				= 0;
+	/* 获取本地协议版本 */
+	virtual EnHttpVersion GetLocalVersion()								= 0;
+
+	/* 检查是否升级协议 */
+	virtual BOOL IsUpgrade()											= 0;
+	/* 检查是否有 Keep-Alive 标识 */
+	virtual BOOL IsKeepAlive()											= 0;
+	/* 获取协议版本 */
+	virtual USHORT GetVersion()											= 0;
+	/* 获取内容长度 */
+	virtual ULONGLONG GetContentLength()								= 0;
+	/* 获取内容类型 */
+	virtual LPCSTR GetContentType()										= 0;
+	/* 获取内容编码 */
+	virtual LPCSTR GetContentEncoding()									= 0;
+	/* 获取传输编码 */
+	virtual LPCSTR GetTransferEncoding()								= 0;
+	/* 获取协议升级类型 */
+	virtual EnHttpUpgradeType GetUpgradeType()							= 0;
+	/* 获取解析错误代码 */
+	virtual USHORT GetParseErrorCode(LPCSTR* lpszErrorDesc = nullptr)	= 0;
+
+	/* 获取 HTTP 状态码 */
+	virtual USHORT GetStatusCode()										= 0;
+
+	/* 获取某个请求头(单值) */
+	virtual BOOL GetHeader(LPCSTR lpszName, LPCSTR* lpszValue)						= 0;
+	/* 获取某个请求头(多值) */
+	virtual BOOL GetHeaders(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)	= 0;
+	/* 获取所有请求头 */
+	virtual BOOL GetAllHeaders(THeader lpHeaders[], DWORD& dwCount)					= 0;
+	/* 获取所有请求头名称 */
+	virtual BOOL GetAllHeaderNames(LPCSTR lpszName[], DWORD& dwCount)				= 0;
+
+	/* 获取 Cookie */
+	virtual BOOL GetCookie(LPCSTR lpszName, LPCSTR* lpszValue)						= 0;
+	/* 获取所有 Cookie */
+	virtual BOOL GetAllCookies(TCookie lpCookies[], DWORD& dwCount)					= 0;
+
+	/*
+	// !! maybe implemented in future !! //
+
+	virtual BOOL GetParam(LPCSTR lpszName, LPCSTR* lpszValue)						= 0;
+	virtual BOOL GetParams(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)		= 0;
+	virtual BOOL GetAllParams(LPPARAM lpszParam[], DWORD& dwCount)					= 0;
+	virtual BOOL GetAllParamNames(LPCSTR lpszName[], DWORD& dwCount)				= 0;
+	*/
+
+	/* 获取当前 WebSocket 消息状态,传入 nullptr 则不获取相应字段 */
+	virtual BOOL GetWSMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)	= 0;
+
+public:
+	virtual ~IHttp() {}
+};
+
+/************************************************************************
+名称:简单 Http 请求者组件接口
+描述:定义简单 Http 请求者组件的所有操作方法和属性访问方法
+************************************************************************/
+class IHttpRequester : public IHttp
+{
+public:
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:发送请求
+	* 描述:向服务端发送 HTTP 请求
+	*		
+	* 参数:		lpszMethod		-- 请求方法
+	*			lpszPath		-- 请求路径
+	*			lpHeaders		-- 请求头
+	*			iHeaderCount	-- 请求头数量
+	*			pBody			-- 请求体
+	*			iLength			-- 请求体长度
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0)	= 0;
+
+	/*
+	* 名称:发送本地文件
+	* 描述:向指定连接发送 4096 KB 以下的小文件
+	*		
+	* 参数:		dwConnID		-- 连接 ID
+	*			lpszFileName	-- 文件路径
+	*			lpszMethod		-- 请求方法
+	*			lpszPath		-- 请求路径
+	*			lpHeaders		-- 请求头
+	*			iHeaderCount	-- 请求头数量
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL SendLocalFile(LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)							= 0;
+
+	/* 发送 POST 请求 */
+	virtual BOOL SendPost(LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)														= 0;
+	/* 发送 PUT 请求 */
+	virtual BOOL SendPut(LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)														= 0;
+	/* 发送 PATCH 请求 */
+	virtual BOOL SendPatch(LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)													= 0;
+	/* 发送 GET 请求 */
+	virtual BOOL SendGet(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 DELETE 请求 */
+	virtual BOOL SendDelete(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 HEAD 请求 */
+	virtual BOOL SendHead(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 TRACE 请求 */
+	virtual BOOL SendTrace(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																		= 0;
+	/* 发送 OPTIONS 请求 */
+	virtual BOOL SendOptions(LPCSTR lpszPath, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																	= 0;
+	/* 发送 CONNECT 请求 */
+	virtual BOOL SendConnect(LPCSTR lpszHost, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0)																	= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置是否使用 Cookie(默认:TRUE) */
+	virtual void SetUseCookie(BOOL bUseCookie)								= 0;
+	/* 检查是否使用 Cookie */
+	virtual BOOL IsUseCookie()												= 0;
+};
+
+/************************************************************************
+名称:简单 Http 同步请求者组件接口
+描述:定义简单 Http 同步请求者组件的所有操作方法和属性访问方法
+************************************************************************/
+class IHttpSyncRequester : public IHttpRequester
+{
+public:
+
+	/*
+	* 名称:发送 URL 请求
+	* 描述:向服务端发送 HTTP URL 请求
+	*		
+	* 参数:		lpszMethod		-- 请求方法
+	*			lpszUrl			-- 请求 URL
+	*			lpHeaders		-- 请求头
+	*			iHeaderCount	-- 请求头数量
+	*			pBody			-- 请求体
+	*			iLength			-- 请求体长度
+	*			bForceReconnect	-- 强制重新连接(默认:FALSE,当请求 URL 的主机和端口与现有连接一致时,重用现有连接)
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL OpenUrl(LPCSTR lpszMethod, LPCSTR lpszUrl, const THeader lpHeaders[] = nullptr, int iHeaderCount = 0, const BYTE* pBody = nullptr, int iLength = 0, BOOL bForceReconnect = FALSE)	= 0;
+
+	/***********************************************************************/
+	/***************************** 组件操作方法 *****************************/
+
+	/*
+	* 名称:清除请求结果
+	* 描述:清除上一次请求的响应头和响应体等结果信息(该方法会在每次发送请求前自动调用)
+	*
+	* 参数:		
+	* 返回值:	TRUE			-- 成功
+	*			FALSE			-- 失败
+	*/
+	virtual BOOL CleanupRequestResult	()									= 0;
+
+public:
+
+	/***********************************************************************/
+	/***************************** 属性访问方法 *****************************/
+
+	/* 设置连接超时(毫秒,0:系统默认超时,默认:5000) */
+	virtual void SetConnectTimeout		(DWORD dwConnectTimeout)			= 0;
+	/* 设置请求超时(毫秒,0:无限等待,默认:10000) */
+	virtual void SetRequestTimeout		(DWORD dwRequestTimeout)			= 0;
+
+	/* 获取连接超时 */
+	virtual DWORD GetConnectTimeout		()									= 0;
+	/* 获取请求超时 */
+	virtual DWORD GetRequestTimeout		()									= 0;
+
+	/* 获取响应体 */
+	virtual BOOL GetResponseBody		(LPCBYTE* lpszBody, int* iLength)	= 0;
+};
+
+
+/************************************************************************
+名称:HTTP 组件接口
+描述:继承了 HTTP 和 Socket 接口
+************************************************************************/
+typedef DualInterface<IComplexHttpResponder, ITcpServer>	IHttpServer;
+typedef DualInterface<IComplexHttpRequester, ITcpAgent>		IHttpAgent;
+typedef DualInterface<IHttpRequester, ITcpClient>			IHttpClient;
+typedef DualInterface<IHttpSyncRequester, ITcpClient>		IHttpSyncClient;
+
+/************************************************************************
+名称:IComplexHttp 组件监听器基接口
+描述:定义 IComplexHttp 组件监听器的所有事件
+************************************************************************/
+template<class T> class IHttpListenerT
+{
+public:
+
+	/*
+	* 名称:开始解析通知
+	* 描述:开始解析 HTTP 报文时,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnMessageBegin(T* pSender, CONNID dwConnID)										= 0;
+
+	/*
+	* 名称:请求行解析完成通知(仅用于 HTTP 服务端)
+	* 描述:请求行解析完成后,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			lpszMethod	-- 请求方法名
+	*			lpszUrl		-- 请求行中的 URL 域
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnRequestLine(T* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)		= 0;
+
+	/*
+	* 名称:状态行解析完成通知(仅用于 HTTP 客户端)
+	* 描述:状态行解析完成后,向监听器发送该通知
+	*		
+	* 参数:		pSender			-- 事件源对象
+	*			dwConnID		-- 连接 ID
+	*			usStatusCode	-- HTTP 状态码
+	*			lpszDesc		-- 状态描述
+	* 返回值:	HPR_OK			-- 继续执行
+	*			HPR_ERROR		-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnStatusLine(T* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)	= 0;
+
+	/*
+	* 名称:请求头通知
+	* 描述:每当解析完成一个请求头后,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			lpszName	-- 请求头名称
+	*			lpszValue	-- 请求头值
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnHeader(T* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)			= 0;
+
+	/*
+	* 名称:请求头完成通知
+	* 描述:解析完成所有请求头后,向监听器发送该通知
+	*		
+	* 参数:		pSender			-- 事件源对象
+	*			dwConnID		-- 连接 ID
+	* 返回值:	HPR_OK			-- 继续执行
+	*			HPR_SKIP_BODY	-- 跳过当前请求的 HTTP BODY
+	*			HPR_UPGRADE		-- 升级协议
+	*			HPR_ERROR		-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnHeadersComplete(T* pSender, CONNID dwConnID)									= 0;
+
+	/*
+	* 名称:BODY 报文通知
+	* 描述:每当接收到 HTTP BODY 报文,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			pData		-- 数据缓冲区
+	*			iLength		-- 数据长度
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnBody(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)				= 0;
+
+	/*
+	* 名称:Chunked 报文头通知
+	* 描述:每当解析出一个 Chunked 报文头,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			iLength		-- Chunked 报文体数据长度
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnChunkHeader(T* pSender, CONNID dwConnID, int iLength)							= 0;
+
+	/*
+	* 名称:Chunked 报文结束通知
+	* 描述:每当解析完一个 Chunked 报文,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnChunkComplete(T* pSender, CONNID dwConnID)										= 0;
+
+	/*
+	* 名称:完成解析通知
+	* 描述:每当解析完成一个完整 HTTP 报文,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HPR_OK		-- 继续执行
+	*			HPR_ERROR	-- 引发 OnParserError() 和 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnMessageComplete(T* pSender, CONNID dwConnID)									= 0;
+
+	/*
+	* 名称:升级协议通知
+	* 描述:当需要升级协议时,向监听器发送该通知
+	*		
+	* 参数:		pSender			-- 事件源对象
+	*			dwConnID		-- 连接 ID
+	*			enUpgradeType	-- 协议类型
+	* 返回值:	HPR_OK			-- 继续执行
+	*			HPR_ERROR		-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnUpgrade(T* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)			= 0;
+
+	/*
+	* 名称:解析错误通知
+	* 描述:当解析 HTTP 报文错误时,向监听器发送该通知
+	*		
+	* 参数:		pSender			-- 事件源对象
+	*			dwConnID		-- 连接 ID
+	*			iErrorCode		-- 错误代码
+	*			lpszErrorDesc	-- 错误描述
+	* 返回值:	HPR_OK			-- 继续执行
+	*			HPR_ERROR		-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHttpParseResult OnParseError(T* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)	= 0;
+
+	/*
+	* 名称:WebSocket 数据包头通知
+	* 描述:当解析 WebSocket 数据包头时,向监听器发送该通知
+	*		
+	* 参数:		pSender			-- 事件源对象
+	*			dwConnID		-- 连接 ID
+	*			bFinal			-- 是否结束帧
+	*			iReserved		-- RSV1/RSV2/RSV3 各 1 位
+	*			iOperationCode	-- 操作码:0x0 - 0xF
+	*			lpszMask		-- 掩码(nullptr 或 4 字节掩码,如果为 nullptr 则没有掩码)
+	*			ullBodyLen		-- 消息体长度
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHandleResult OnWSMessageHeader(T* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)	= 0;
+
+	/*
+	* 名称:WebSocket 数据包体通知
+	* 描述:当接收到 WebSocket 数据包体时,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	*			pData		-- 消息体数据缓冲区
+	*			iLength		-- 消息体数据长度
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHandleResult OnWSMessageBody(T* pSender, CONNID dwConnID, const BYTE* pData, int iLength)			= 0;
+
+	/*
+	* 名称:WebSocket 数据包完成通知
+	* 描述:当完整接收一个 WebSocket 数据包时,向监听器发送该通知
+	*		
+	* 参数:		pSender		-- 事件源对象
+	*			dwConnID	-- 连接 ID
+	* 返回值:	HR_OK / HR_IGNORE	-- 继续执行
+	*			HR_ERROR			-- 引发 OnClose() 事件并关闭连接
+	*/
+	virtual EnHandleResult OnWSMessageComplete(T* pSender, CONNID dwConnID)										= 0;
+
+public:
+	virtual ~IHttpListenerT() {}
+};
+
+/************************************************************************
+名称:IHttpServer 组件端监听器接口
+描述:定义 IHttpServer 监听器的所有事件
+************************************************************************/
+class IHttpServerListener : public IHttpListenerT<IHttpServer>, public ITcpServerListener
+{
+public:
+
+};
+
+/************************************************************************
+名称:IHttpAgent 组件端监听器接口
+描述:定义 IHttpAgent 监听器的所有事件
+************************************************************************/
+class IHttpAgentListener : public IHttpListenerT<IHttpAgent>, public ITcpAgentListener
+{
+public:
+
+};
+
+/************************************************************************
+名称:IHttpClient 组件端监听器接口
+描述:定义 IHttpClient 监听器的所有事件
+************************************************************************/
+class IHttpClientListener : public IHttpListenerT<IHttpClient>, public ITcpClientListener
+{
+public:
+
+};
+
+/************************************************************************
+名称:IHttpServerListener 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CHttpServerListener : public IHttpServerListener
+{
+public:
+	virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen)										{return HR_IGNORE;}
+	virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient)							{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID)											{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength)									{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)				{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)					{return HR_IGNORE;}
+	virtual EnHandleResult OnShutdown(ITcpServer* pSender)																{return HR_IGNORE;}
+
+	virtual EnHttpParseResult OnMessageBegin(IHttpServer* pSender, CONNID dwConnID)										{return HPR_OK;}
+	virtual EnHttpParseResult OnRequestLine(IHttpServer* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)	{return HPR_OK;}
+	virtual EnHttpParseResult OnStatusLine(IHttpServer* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)	{return HPR_OK;}
+	virtual EnHttpParseResult OnHeader(IHttpServer* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)		{return HPR_OK;}
+	virtual EnHttpParseResult OnChunkHeader(IHttpServer* pSender, CONNID dwConnID, int iLength)							{return HPR_OK;}
+	virtual EnHttpParseResult OnChunkComplete(IHttpServer* pSender, CONNID dwConnID)									{return HPR_OK;}
+	virtual EnHttpParseResult OnUpgrade(IHttpServer* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)			{return HPR_OK;}
+
+	virtual EnHandleResult OnWSMessageHeader(IHttpServer* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)	{return HR_IGNORE;}
+	virtual EnHandleResult OnWSMessageBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+	virtual EnHandleResult OnWSMessageComplete(IHttpServer* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:IHttpAgentListener 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+class CHttpAgentListener : public IHttpAgentListener
+{
+public:
+	virtual EnHandleResult OnPrepareConnect(ITcpAgent* pSender, CONNID dwConnID, SOCKET socket)							{return HR_IGNORE;}
+	virtual EnHandleResult OnConnect(ITcpAgent* pSender, CONNID dwConnID)												{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(ITcpAgent* pSender, CONNID dwConnID)												{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, int iLength)									{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)				{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(ITcpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)					{return HR_IGNORE;}
+	virtual EnHandleResult OnShutdown(ITcpAgent* pSender)																{return HR_IGNORE;}
+
+	virtual EnHttpParseResult OnMessageBegin(IHttpAgent* pSender, CONNID dwConnID)										{return HPR_OK;}
+	virtual EnHttpParseResult OnRequestLine(IHttpAgent* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)	{return HPR_OK;}
+	virtual EnHttpParseResult OnStatusLine(IHttpAgent* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)	{return HPR_OK;}
+	virtual EnHttpParseResult OnHeader(IHttpAgent* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)			{return HPR_OK;}
+	virtual EnHttpParseResult OnChunkHeader(IHttpAgent* pSender, CONNID dwConnID, int iLength)							{return HPR_OK;}
+	virtual EnHttpParseResult OnChunkComplete(IHttpAgent* pSender, CONNID dwConnID)										{return HPR_OK;}
+	virtual EnHttpParseResult OnUpgrade(IHttpAgent* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)			{return HPR_OK;}
+
+	virtual EnHandleResult OnWSMessageHeader(IHttpAgent* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)	{return HR_IGNORE;}
+	virtual EnHandleResult OnWSMessageBody(IHttpAgent* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+	virtual EnHandleResult OnWSMessageComplete(IHttpAgent* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:IHttpClientListener 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+
+class CHttpClientListener : public IHttpClientListener
+{
+public:
+	virtual EnHandleResult OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket)						{return HR_IGNORE;}
+	virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID)												{return HR_IGNORE;}
+	virtual EnHandleResult OnHandShake(ITcpClient* pSender, CONNID dwConnID)											{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, int iLength)									{return HR_IGNORE;}
+	virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)				{return HR_IGNORE;}
+	virtual EnHandleResult OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)					{return HR_IGNORE;}
+
+	virtual EnHttpParseResult OnMessageBegin(IHttpClient* pSender, CONNID dwConnID)										{return HPR_OK;}
+	virtual EnHttpParseResult OnRequestLine(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)	{return HPR_OK;}
+	virtual EnHttpParseResult OnStatusLine(IHttpClient* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)	{return HPR_OK;}
+	virtual EnHttpParseResult OnHeader(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)		{return HPR_OK;}
+	virtual EnHttpParseResult OnChunkHeader(IHttpClient* pSender, CONNID dwConnID, int iLength)							{return HPR_OK;}
+	virtual EnHttpParseResult OnChunkComplete(IHttpClient* pSender, CONNID dwConnID)									{return HPR_OK;}
+	virtual EnHttpParseResult OnUpgrade(IHttpClient* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)			{return HPR_OK;}
+
+	virtual EnHandleResult OnWSMessageHeader(IHttpClient* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)	{return HR_IGNORE;}
+	virtual EnHandleResult OnWSMessageBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)		{return HR_IGNORE;}
+	virtual EnHandleResult OnWSMessageComplete(IHttpClient* pSender, CONNID dwConnID)									{return HR_IGNORE;}
+};
+
+/************************************************************************
+名称:IHttpClientListener 监听器抽象基类
+描述:定义某些事件的默认处理方法(忽略事件)
+************************************************************************/
+
+class CHttpSyncClientListener : public CHttpClientListener
+{
+public:
+	virtual EnHandleResult OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)	{return HR_IGNORE;}
+
+	virtual EnHttpParseResult OnHeadersComplete(IHttpClient* pSender, CONNID dwConnID)									{return HPR_OK;}
+	virtual EnHttpParseResult OnBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)				{return HPR_OK;}
+	virtual EnHttpParseResult OnMessageComplete(IHttpClient* pSender, CONNID dwConnID)									{return HPR_OK;}
+	virtual EnHttpParseResult OnParseError(IHttpClient* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)	{return HPR_OK;}
+
+};

+ 734 - 0
HP-Socket/Src/TcpClient.cpp

@@ -0,0 +1,734 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "TcpClient.h"
+#include "../../Common/Src/WaitFor.h"
+
+#include <process.h>
+
+BOOL CTcpClient::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress)
+{
+	if(!CheckParams() || !CheckStarting())
+		return FALSE;
+
+	PrepareStart();
+	m_ccContext.Reset();
+
+	BOOL isOK		= FALSE;
+	m_bAsyncConnect	= bAsyncConnect;
+
+	if(CreateClientSocket())
+	{
+		if(BindClientSocket(lpszBindAddress))
+		{
+			if(FirePrepareConnect(m_soClient) != HR_ERROR)
+			{
+				if(ConnectToServer(lpszRemoteAddress, usPort))
+				{
+					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__, ERROR_CANCELLED);
+		}
+		else
+			SetLastError(SE_SOCKET_BIND, __FUNCTION__, ::WSAGetLastError());
+	}
+	else
+		SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
+
+	if(!isOK)
+	{
+		m_ccContext.Reset(FALSE);
+		Stop();
+	}
+
+	return isOK;
+}
+
+BOOL CTcpClient::CheckParams()
+{
+	if	(((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((int)m_dwSocketBufferSize);
+	m_itPool.SetPoolSize((int)m_dwFreeBufferPoolSize);
+	m_itPool.SetPoolHold((int)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_OPERATION);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+BOOL CTcpClient::CheckStoping(DWORD dwCurrentThreadID)
+{
+	if(m_enState == SS_STOPPED)
+		return FALSE;
+
+	CSpinLock locallock(m_csState);
+
+	if(HasStarted())
+	{
+		m_enState = SS_STOPPING;
+		return TRUE;
+	}
+	else if(m_enState == SS_STOPPING)
+	{
+		if(dwCurrentThreadID != m_dwWorkerID)
+		{
+			while(m_enState != SS_STOPPED)
+				::Sleep(30);
+		}
+
+		SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_OPERATION);
+	}
+
+	return FALSE;
+}
+
+BOOL CTcpClient::CreateClientSocket()
+{
+	m_soClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+	if(m_soClient != INVALID_SOCKET)
+	{
+		BOOL bOnOff	= (m_dwKeepAliveTime > 0 && m_dwKeepAliveInterval > 0);
+		VERIFY(::SSO_KeepAliveVals(m_soClient, bOnOff, m_dwKeepAliveTime, m_dwKeepAliveInterval) == NO_ERROR);
+
+		m_evSocket = ::WSACreateEvent();
+		ASSERT(m_evSocket != WSA_INVALID_EVENT);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+BOOL CTcpClient::BindClientSocket(LPCTSTR lpszBindAddress)
+{
+	if(lpszBindAddress)
+	{
+		SOCKADDR_IN bindAddr;
+		if(!::sockaddr_A_2_IN(AF_INET, lpszBindAddress, 0, bindAddr))
+		{
+			::WSASetLastError(WSAEADDRNOTAVAIL);
+			return FALSE;
+		}
+
+		if(::bind(m_soClient, (struct sockaddr*)&bindAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
+			return FALSE;
+	}
+
+	m_dwConnID = ::GenerateConnectionID();
+
+	return TRUE;
+}
+
+BOOL CTcpClient::ConnectToServer(LPCTSTR lpszRemoteAddress, USHORT usPort)
+{
+	TCHAR szAddress[40];
+	int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
+
+	if(!::GetIPAddress(lpszRemoteAddress, szAddress, iAddressLen))
+	{
+		::WSASetLastError(WSAEADDRNOTAVAIL);
+		return FALSE;
+	}
+
+	SOCKADDR_IN addr;
+	if(!::sockaddr_A_2_IN(AF_INET, szAddress, usPort, addr))
+	{
+		::WSASetLastError(WSAEADDRNOTAVAIL);
+		return FALSE;
+	}
+
+	SetRemoteHost(lpszRemoteAddress, usPort);
+
+	BOOL isOK = FALSE;
+
+	if(m_bAsyncConnect)
+	{
+		if(::WSAEventSelect(m_soClient, m_evSocket, FD_CONNECT | FD_CLOSE) != SOCKET_ERROR)
+		{
+			int rc = ::connect(m_soClient, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
+			isOK = (rc == NO_ERROR ||(rc == SOCKET_ERROR && ::WSAGetLastError() == WSAEWOULDBLOCK));
+		}
+	}
+	else
+	{
+		if(::connect(m_soClient, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)) != SOCKET_ERROR)
+		{
+			if(::WSAEventSelect(m_soClient, m_evSocket, FD_READ | FD_WRITE | FD_CLOSE) != SOCKET_ERROR)
+			{
+				if(FireConnect() != HR_ERROR)
+				{
+					m_enState	= SS_STARTED;
+					isOK		= TRUE;
+				}
+			}
+		}
+	}
+
+	return isOK;
+}
+
+BOOL CTcpClient::CreateWorkerThread()
+{
+	m_hWorker = (HANDLE)_beginthreadex(nullptr, 0, WorkerThreadProc, (LPVOID)this, 0, &m_dwWorkerID);
+
+	return m_hWorker != nullptr;
+}
+
+UINT WINAPI CTcpClient::WorkerThreadProc(LPVOID pv)
+{
+	TRACE("---------------> Client Worker Thread 0x%08X started <---------------\n", ::GetCurrentThreadId());
+
+	BOOL bCallStop		= TRUE;
+	CTcpClient* pClient	= (CTcpClient*)pv;
+	HANDLE hEvents[]	= {pClient->m_evSocket, pClient->m_evBuffer, pClient->m_evWorker};
+
+	pClient->m_rcBuffer.Malloc(pClient->m_dwSocketBufferSize);
+
+	while(pClient->HasStarted())
+	{
+		DWORD retval = ::WSAWaitForMultipleEvents(3, hEvents, FALSE, WSA_INFINITE, FALSE);
+
+		if(retval == WSA_WAIT_EVENT_0)
+		{
+			if(!pClient->ProcessNetworkEvent())
+				break;
+		}
+		else if(retval == WSA_WAIT_EVENT_0 + 1)
+		{
+			if(!pClient->SendData())
+				break;
+		}
+		else if(retval == WSA_WAIT_EVENT_0 + 2)
+		{
+			bCallStop = FALSE;
+			break;
+		}
+		else if(retval == WSA_WAIT_FAILED)
+		{
+			pClient->m_ccContext.Reset(TRUE, SO_UNKNOWN, ::WSAGetLastError());
+			break;
+		}
+		else
+			VERIFY(FALSE);
+	}
+
+	pClient->OnWorkerThreadEnd(::GetCurrentThreadId());
+
+	if(bCallStop && pClient->HasStarted())
+		pClient->Stop();
+
+	TRACE("---------------> Client Worker Thread 0x%08X stoped <---------------\n", ::GetCurrentThreadId());
+
+	return 0;
+}
+
+BOOL CTcpClient::ProcessNetworkEvent()
+{
+	BOOL bContinue = TRUE;
+	WSANETWORKEVENTS events;
+	
+	int rc = ::WSAEnumNetworkEvents(m_soClient, m_evSocket, &events);
+
+	if(rc == SOCKET_ERROR)
+		bContinue = HandleError(events);
+
+	if(m_bAsyncConnect && bContinue && events.lNetworkEvents & FD_CONNECT)
+		bContinue = HandleConnect(events);
+
+	if(bContinue && events.lNetworkEvents & FD_READ)
+		bContinue = HandleRead(events);
+
+	if(bContinue && events.lNetworkEvents & FD_WRITE)
+		bContinue = HandleWrite(events);
+
+	if(bContinue && events.lNetworkEvents & FD_CLOSE)
+		bContinue = HandleClose(events);
+
+	return bContinue;
+}
+
+BOOL CTcpClient::HandleError(WSANETWORKEVENTS& events)
+{
+	int iCode						= ::WSAGetLastError();
+	EnSocketOperation enOperation	= SO_UNKNOWN;
+
+	if(events.lNetworkEvents & FD_CONNECT)
+		enOperation = SO_CONNECT;
+	else if(events.lNetworkEvents & FD_CLOSE)
+		enOperation = SO_CLOSE;
+	else if(events.lNetworkEvents & FD_READ)
+		enOperation = SO_RECEIVE;
+	else if(events.lNetworkEvents & FD_WRITE)
+		enOperation = SO_SEND;
+
+	VERIFY(::WSAResetEvent(m_evSocket));
+	m_ccContext.Reset(TRUE, enOperation, iCode);
+
+	return FALSE;
+}
+
+BOOL CTcpClient::HandleRead(WSANETWORKEVENTS& events)
+{
+	BOOL bContinue	= TRUE;
+	int iCode		= events.iErrorCode[FD_READ_BIT];
+
+	if(iCode == 0)
+		bContinue = ReadData();
+	else
+	{
+		m_ccContext.Reset(TRUE, SO_RECEIVE, iCode);
+		bContinue = FALSE;
+	}
+
+	return bContinue;
+}
+
+BOOL CTcpClient::HandleWrite(WSANETWORKEVENTS& events)
+{
+	BOOL bContinue	= TRUE;
+	int iCode		= events.iErrorCode[FD_WRITE_BIT];
+
+	if(iCode == 0)
+		bContinue = SendData();
+	else
+	{
+		m_ccContext.Reset(TRUE, SO_SEND, iCode);
+		bContinue = FALSE;
+	}
+
+	return bContinue;
+}
+
+BOOL CTcpClient::HandleConnect(WSANETWORKEVENTS& events)
+{
+	BOOL bContinue	= TRUE;
+	int iCode		= events.iErrorCode[FD_CONNECT_BIT];
+
+	if(iCode == 0)
+	{
+		if(::WSAEventSelect(m_soClient, m_evSocket, FD_READ | FD_WRITE | FD_CLOSE) != SOCKET_ERROR)
+		{
+			if(FireConnect() != HR_ERROR)
+				m_enState = SS_STARTED;
+			else
+				iCode = ERROR_CANCELLED;
+		}
+		else
+			iCode = ::WSAGetLastError();
+	}
+
+	if(iCode != 0)
+	{
+		if(iCode != ERROR_CANCELLED)
+			m_ccContext.Reset(TRUE, SO_CONNECT, iCode);
+		else
+			m_ccContext.Reset(FALSE);
+
+		bContinue = FALSE;
+	}
+
+	return bContinue;
+}
+
+BOOL CTcpClient::HandleClose(WSANETWORKEVENTS& events)
+{
+	int iCode = events.iErrorCode[FD_CLOSE_BIT];
+
+	if(iCode == 0)
+		m_ccContext.Reset(TRUE, SO_CLOSE, SE_OK);
+	else
+		m_ccContext.Reset(TRUE, SO_CLOSE, iCode);
+
+	return FALSE;
+}
+
+BOOL CTcpClient::ReadData()
+{
+	while(TRUE)
+	{
+		int rc = recv(m_soClient, (char*)(BYTE*)m_rcBuffer, m_dwSocketBufferSize, 0);
+
+		if(rc > 0)
+		{
+			if(FireReceive(m_rcBuffer, rc) == HR_ERROR)
+			{
+				TRACE("<C-CNNID: %Iu> OnReceive() event return 'HR_ERROR', connection will be closed !\n", m_dwConnID);
+
+				m_ccContext.Reset(TRUE, SO_RECEIVE, ERROR_CANCELLED);
+				return FALSE;
+			}
+		}
+		else if(rc == SOCKET_ERROR)
+		{
+			int code = ::WSAGetLastError();
+
+			if(code == WSAEWOULDBLOCK)
+				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::SendData()
+{
+	BOOL isOK = TRUE;
+
+	while(TRUE)
+	{
+		TItemPtr itPtr(m_itPool, GetSendBuffer());
+
+		if(itPtr.IsValid())
+		{
+			ASSERT(!itPtr->IsEmpty());
+
+			isOK = DoSendData(itPtr);
+
+			if(isOK)
+			{
+				if(!itPtr->IsEmpty())
+				{
+					CCriSecLock locallock(m_csSend);
+					m_lsSend.PushFront(itPtr.Detach());
+					
+					break;
+				}
+			}
+			else
+				break;
+		}
+		else
+			break;
+	}
+
+	return isOK;
+}
+
+TItem* CTcpClient::GetSendBuffer()
+{
+	TItem* pItem = nullptr;
+
+	if(m_lsSend.Size() > 0)
+	{
+		CCriSecLock locallock(m_csSend);
+
+		if(m_lsSend.Size() > 0)
+			pItem = m_lsSend.PopFront();
+	}
+
+	return pItem;
+}
+
+BOOL CTcpClient::DoSendData(TItem* pItem)
+{
+	while(!pItem->IsEmpty())
+	{
+		int rc = 0;
+
+		{
+			CCriSecLock locallock(m_csSend);
+
+			rc = send(m_soClient, (char*)pItem->Ptr(), min(pItem->Size(), (int)m_dwSocketBufferSize), 0);
+			if(rc > 0) m_iPending -= rc;
+		}
+
+		if(rc > 0)
+		{
+			if(FireSend(pItem->Ptr(), rc) == HR_ERROR)
+			{
+				TRACE("<C-CNNID: %Iu> OnSend() event should not return 'HR_ERROR' !!\n", m_dwConnID);
+				ASSERT(FALSE);
+			}
+
+			pItem->Reduce(rc);
+		}
+		else if(rc == SOCKET_ERROR)
+		{
+			int code = ::WSAGetLastError();
+
+			if(code == WSAEWOULDBLOCK)
+				break;
+			else
+			{
+				m_ccContext.Reset(TRUE, SO_SEND, code);
+				return FALSE;
+			}
+		}
+		else
+			ASSERT(FALSE);
+	}
+
+	return TRUE;
+}
+
+BOOL CTcpClient::Stop()
+{
+	DWORD dwCurrentThreadID = ::GetCurrentThreadId();
+
+	if(!CheckStoping(dwCurrentThreadID))
+		return FALSE;
+
+	WaitForWorkerThreadEnd(dwCurrentThreadID);
+
+	if(m_ccContext.bFireOnClose)
+		FireClose(m_ccContext.enOperation, m_ccContext.iErrorCode);
+
+	if(m_evSocket != nullptr)
+	{
+		::WSACloseEvent(m_evSocket);
+		m_evSocket	= nullptr;
+	}
+
+	if(m_soClient != INVALID_SOCKET)
+	{
+		shutdown(m_soClient, SD_SEND);
+		closesocket(m_soClient);
+		m_soClient	= INVALID_SOCKET;
+	}
+
+	Reset();
+
+	return TRUE;
+}
+
+void CTcpClient::Reset()
+{
+	CCriSecLock locallock(m_csSend);
+
+	m_rcBuffer.Free();
+	m_evBuffer.Reset();
+	m_evWorker.Reset();
+	m_lsSend.Clear();
+	m_itPool.Clear();
+
+	m_strHost.Empty();
+
+	m_usPort	= 0;
+	m_iPending	= 0;
+	m_enState	= SS_STOPPED;
+}
+
+void CTcpClient::WaitForWorkerThreadEnd(DWORD dwCurrentThreadID)
+{
+	if(m_hWorker != nullptr)
+	{
+		if(dwCurrentThreadID != m_dwWorkerID)
+		{
+			m_evWorker.Set();
+			VERIFY(::WaitForSingleObject(m_hWorker, INFINITE) == WAIT_OBJECT_0);
+		}
+
+		::CloseHandle(m_hWorker);
+
+		m_hWorker		= nullptr;
+		m_dwWorkerID	= 0;
+	}
+}
+
+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 = (char*)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(HasStarted())
+		{
+			CCriSecLock locallock(m_csSend);
+
+			if(HasStarted())
+				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);
+}
+
+BOOL CTcpClient::SendInternal(const WSABUF pBuffers[], int iCount)
+{
+	int result = NO_ERROR;
+
+	ASSERT(m_iPending >= 0);
+
+	int iPending	= m_iPending;
+	BOOL isPending	= m_iPending > 0;
+
+	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);
+			m_iPending += iBufLen;
+		}
+	}
+
+	if(!isPending && m_iPending > iPending) m_evBuffer.Set();
+
+	return result;
+}
+
+BOOL CTcpClient::SendSmallFile(LPCTSTR lpszFileName, const LPWSABUF pHead, const LPWSABUF pTail)
+{
+	CAtlFile file;
+	CAtlFileMapping<> fmap;
+	WSABUF szBuf[3];
+
+	HRESULT hr = ::MakeSmallFilePackage(lpszFileName, file, fmap, szBuf, pHead, pTail);
+
+	if(FAILED(hr))
+	{
+		::SetLastError(HRESULT_CODE(hr));
+		return FALSE;
+	}
+
+	return SendPackets(szBuf, 3);
+}
+
+void CTcpClient::SetLastError(EnSocketError code, LPCSTR func, int ec)
+{
+	TRACE("%s --> Error: %d, EC: %d\n", 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();
+}

+ 222 - 0
HP-Socket/Src/TcpClient.h

@@ -0,0 +1,222 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 4.2.1
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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/Src/Event.h"
+#include "../../Common/Src/bufferptr.h"
+#include "../../Common/Src/bufferpool.h"
+#include "../../Common/Src/CriticalSection.h"
+
+class CTcpClient : public ITcpClient
+{
+public:
+	virtual BOOL Start	(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr);
+	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			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_iPending; return HasStarted();}
+
+public:
+	virtual BOOL IsSecure				() {return FALSE;}
+
+	virtual void SetSocketBufferSize	(DWORD dwSocketBufferSize)		{m_dwSocketBufferSize	= dwSocketBufferSize;}
+	virtual void SetKeepAliveTime		(DWORD dwKeepAliveTime)			{m_dwKeepAliveTime		= dwKeepAliveTime;}
+	virtual void SetKeepAliveInterval	(DWORD dwKeepAliveInterval)		{m_dwKeepAliveInterval	= dwKeepAliveInterval;}
+	virtual void SetFreeBufferPoolSize	(DWORD dwFreeBufferPoolSize)	{m_dwFreeBufferPoolSize = dwFreeBufferPoolSize;}
+	virtual void SetFreeBufferPoolHold	(DWORD dwFreeBufferPoolHold)	{m_dwFreeBufferPoolHold = dwFreeBufferPoolHold;}
+	virtual void SetExtra				(PVOID pExtra)					{m_pExtra				= pExtra;}						
+
+	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 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 void OnWorkerThreadEnd(DWORD dwThreadID) {}
+
+	BOOL DoSendPackets(const WSABUF pBuffers[], int iCount);
+
+	static BOOL DoSendPackets(CTcpClient* pClient, const WSABUF pBuffers[], int iCount)
+		{return pClient->DoSendPackets(pBuffers, iCount);}
+
+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);
+
+	BOOL CheckStarting();
+	BOOL CheckStoping(DWORD dwCurrentThreadID);
+	BOOL CreateClientSocket();
+	BOOL BindClientSocket(LPCTSTR lpszBindAddress);
+	BOOL ConnectToServer(LPCTSTR lpszRemoteAddress, USHORT usPort);
+	BOOL CreateWorkerThread();
+	BOOL ProcessNetworkEvent();
+	BOOL ReadData();
+	BOOL SendData();
+	BOOL DoSendData(TItem* pItem);
+	TItem* GetSendBuffer();
+	BOOL SendInternal(const WSABUF pBuffers[], int iCount);
+	void WaitForWorkerThreadEnd(DWORD dwCurrentThreadID);
+
+	BOOL HandleError	(WSANETWORKEVENTS& events);
+	BOOL HandleRead		(WSANETWORKEVENTS& events);
+	BOOL HandleWrite	(WSANETWORKEVENTS& events);
+	BOOL HandleConnect	(WSANETWORKEVENTS& events);
+	BOOL HandleClose	(WSANETWORKEVENTS& events);
+
+	static UINT WINAPI WorkerThreadProc(LPVOID pv);
+
+public:
+	CTcpClient(ITcpClientListener* pListener)
+	: m_pListener			(pListener)
+	, m_lsSend				(m_itPool)
+	, m_soClient			(INVALID_SOCKET)
+	, m_evSocket			(nullptr)
+	, m_dwConnID			(0)
+	, m_usPort				(0)
+	, m_hWorker				(nullptr)
+	, m_dwWorkerID			(0)
+	, m_bAsyncConnect		(FALSE)
+	, m_iPending			(0)
+	, m_enState				(SS_STOPPED)
+	, m_enLastError			(SE_OK)
+	, m_pExtra				(nullptr)
+	, m_pReserved			(nullptr)
+	, 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_wsSocket.IsValid());
+		ASSERT(m_pListener);
+	}
+
+	virtual ~CTcpClient()
+	{
+		Stop();
+	}
+
+private:
+	CInitSocket			m_wsSocket;
+
+private:
+	ITcpClientListener*	m_pListener;
+	TClientCloseContext m_ccContext;
+
+	BOOL				m_bAsyncConnect;
+	SOCKET				m_soClient;
+	HANDLE				m_evSocket;
+	CONNID				m_dwConnID;
+
+
+	DWORD				m_dwSocketBufferSize;
+	DWORD				m_dwFreeBufferPoolSize;
+	DWORD				m_dwFreeBufferPoolHold;
+	DWORD				m_dwKeepAliveTime;
+	DWORD				m_dwKeepAliveInterval;
+
+	HANDLE				m_hWorker;
+	UINT				m_dwWorkerID;
+
+	volatile EnServiceState	m_enState;
+	EnSocketError		m_enLastError;
+
+	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;
+	TItemList			m_lsSend;
+
+	CEvt				m_evBuffer;
+	CEvt				m_evWorker;
+
+	volatile int		m_iPending;
+};

+ 26 - 0
common/Src/CriticalSection.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "CriticalSection.h"

+ 311 - 0
common/Src/CriticalSection.h

@@ -0,0 +1,311 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 <intrin.h>
+
+#pragma intrinsic(_ReadBarrier)
+#pragma intrinsic(_WriteBarrier)
+#pragma intrinsic(_ReadWriteBarrier)
+
+#define DEFAULT_CRISEC_SPIN_COUNT	4096
+
+#if defined (_WIN64)
+	#define DEFAULT_PAUSE_RETRY		16
+	#define DEFAULT_PAUSE_YIELD		128
+	#define DEFAULT_PAUSE_CYCLE		8192
+#else
+	#define DEFAULT_PAUSE_RETRY		4
+	#define DEFAULT_PAUSE_YIELD		32
+	#define DEFAULT_PAUSE_CYCLE		4096
+#endif
+
+#ifndef YieldProcessor
+	#pragma intrinsic(_mm_pause)
+	#define YieldProcessor _mm_pause
+#endif
+
+static inline void YieldThread(UINT i = DEFAULT_PAUSE_RETRY)
+{
+	if		(i < DEFAULT_PAUSE_RETRY)		;
+	else if	(i < DEFAULT_PAUSE_YIELD)		YieldProcessor();
+	else if	(i < DEFAULT_PAUSE_CYCLE - 1)	SwitchToThread();
+	else if	(i < DEFAULT_PAUSE_CYCLE)		Sleep(1);
+	else									YieldThread(i & (DEFAULT_PAUSE_CYCLE - 1));
+}
+
+class CInterCriSec
+{
+public:
+	CInterCriSec(DWORD dwSpinCount = DEFAULT_CRISEC_SPIN_COUNT)
+		{VERIFY(::InitializeCriticalSectionAndSpinCount(&m_crisec, dwSpinCount));}
+	~CInterCriSec()
+		{::DeleteCriticalSection(&m_crisec);}
+
+	void Lock()								{::EnterCriticalSection(&m_crisec);}
+	void Unlock()							{::LeaveCriticalSection(&m_crisec);}
+	BOOL TryLock()							{return ::TryEnterCriticalSection(&m_crisec);}
+	DWORD SetSpinCount(DWORD dwSpinCount)	{return ::SetCriticalSectionSpinCount(&m_crisec, dwSpinCount);}
+
+	CRITICAL_SECTION* GetObject()			{return &m_crisec;}
+
+private:
+	CInterCriSec(const CInterCriSec& cs);
+	CInterCriSec operator = (const CInterCriSec& cs);
+
+private:
+	CRITICAL_SECTION m_crisec;
+};
+
+class CInterCriSec2
+{
+public:
+	CInterCriSec2(DWORD dwSpinCount = DEFAULT_CRISEC_SPIN_COUNT, BOOL bInitialize = TRUE)
+	{
+		if(bInitialize)
+		{
+			m_pcrisec = new CRITICAL_SECTION;
+			VERIFY(::InitializeCriticalSectionAndSpinCount(m_pcrisec, dwSpinCount));
+		}
+		else
+			m_pcrisec = nullptr;
+	}
+
+	~CInterCriSec2() {Reset();}
+
+	void Attach(CRITICAL_SECTION* pcrisec)
+	{
+		Reset();
+		m_pcrisec = pcrisec;
+	}
+
+	CRITICAL_SECTION* Detach()
+	{
+		CRITICAL_SECTION* pcrisec = m_pcrisec;
+		m_pcrisec = nullptr;
+		return pcrisec;
+	}
+
+	void Lock()								{::EnterCriticalSection(m_pcrisec);}
+	void Unlock()							{::LeaveCriticalSection(m_pcrisec);}
+	BOOL TryLock()							{return ::TryEnterCriticalSection(m_pcrisec);}
+	DWORD SetSpinCount(DWORD dwSpinCount)	{return ::SetCriticalSectionSpinCount(m_pcrisec, dwSpinCount);}
+
+	CRITICAL_SECTION* GetObject()			{return m_pcrisec;}
+
+private:
+	CInterCriSec2(const CInterCriSec2& cs);
+	CInterCriSec2 operator = (const CInterCriSec2& cs);
+
+	void Reset()
+	{
+		if(m_pcrisec)
+		{
+			::DeleteCriticalSection(m_pcrisec);
+			delete m_pcrisec;
+			m_pcrisec = nullptr;
+		}
+	}
+
+private:
+	CRITICAL_SECTION* m_pcrisec;
+};
+
+class CMTX
+{
+public:
+	CMTX(BOOL bInitialOwner = FALSE, LPCTSTR pszName = nullptr, LPSECURITY_ATTRIBUTES pSecurity = nullptr)	
+	{
+		m_hMutex = ::CreateMutex(pSecurity, bInitialOwner, pszName);
+		ASSERT(IsValid());
+	}
+
+	~CMTX()
+	{
+		if(IsValid())
+			::CloseHandle(m_hMutex);
+	}
+
+	BOOL Open(DWORD dwAccess, BOOL bInheritHandle, LPCTSTR pszName)
+	{
+		if(IsValid())
+			VERIFY(::CloseHandle(m_hMutex));
+
+		m_hMutex = ::OpenMutex(dwAccess, bInheritHandle, pszName);
+		return(IsValid());
+	}
+
+	void Lock(DWORD dwMilliseconds = INFINITE)	{::WaitForSingleObject(m_hMutex, dwMilliseconds);}
+	void Unlock()								{::ReleaseMutex(m_hMutex);}
+
+	HANDLE& GetHandle	() 	{return m_hMutex;}
+	operator HANDLE		()	{return m_hMutex;}
+	BOOL IsValid		()	{return m_hMutex != nullptr;}
+
+private:
+	CMTX(const CMTX& mtx);
+	CMTX operator = (const CMTX& mtx);
+
+private:
+	HANDLE m_hMutex;
+};
+
+class CSpinGuard
+{
+public:
+	CSpinGuard() : m_lFlag(0)
+	{
+
+	}
+
+	~CSpinGuard()
+	{
+		ASSERT(m_lFlag == 0);
+	}
+
+	void Lock()
+	{
+		for(UINT i = 0; !TryLock(); ++i)
+			YieldThread(i);
+	}
+
+	BOOL TryLock()
+	{
+		if(::InterlockedCompareExchange(&m_lFlag, 1, 0) == 0)
+		{
+			::_ReadWriteBarrier();
+			return TRUE;
+		}
+
+		return FALSE;
+	}
+
+	void Unlock()
+	{
+		ASSERT(m_lFlag == 1);
+		m_lFlag = 0;
+	}
+
+private:
+	CSpinGuard(const CSpinGuard& cs);
+	CSpinGuard operator = (const CSpinGuard& cs);
+
+private:
+	volatile LONG m_lFlag;
+};
+
+class CReentrantSpinGuard
+{
+public:
+	CReentrantSpinGuard()
+	: m_dwThreadID	(0)
+	, m_iCount		(0)
+	{
+
+	}
+
+	~CReentrantSpinGuard()
+	{
+		ASSERT(m_dwThreadID	== 0);
+		ASSERT(m_iCount		== 0);
+	}
+
+	void Lock()
+	{
+		for(UINT i = 0; !_TryLock(i == 0); ++i)
+			YieldThread(i);
+	}
+
+	BOOL TryLock()
+	{
+		return _TryLock(TRUE);
+	}
+
+	void Unlock()
+	{
+		ASSERT(m_dwThreadID == ::GetCurrentThreadId());
+
+		if((--m_iCount) == 0)
+			m_dwThreadID = 0;
+	}
+
+private:
+	CReentrantSpinGuard(const CReentrantSpinGuard& cs);
+	CReentrantSpinGuard operator = (const CReentrantSpinGuard& cs);
+
+	BOOL _TryLock(BOOL bFirst)
+	{
+		DWORD dwCurrentThreadID = ::GetCurrentThreadId();
+
+		if(bFirst && m_dwThreadID == dwCurrentThreadID)
+		{
+			++m_iCount;
+			return TRUE;
+		}
+
+		if(::InterlockedCompareExchange(&m_dwThreadID, dwCurrentThreadID, 0) == 0)
+		{
+			::_ReadWriteBarrier();
+			ASSERT(m_iCount == 0);
+
+			m_iCount = 1;
+
+			return TRUE;
+		}
+
+		return FALSE;
+	}
+
+private:
+	volatile DWORD	m_dwThreadID;
+	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;
+};
+
+typedef CInterCriSec					CCriSec;
+
+typedef CLocalLock<CCriSec>				CCriSecLock;
+typedef CLocalLock<CInterCriSec>		CInterCriSecLock;
+typedef CLocalLock<CInterCriSec2>		CInterCriSecLock2;
+typedef CLocalLock<CMTX>				CMutexLock;
+typedef CLocalLock<CSpinGuard>			CSpinLock;
+typedef CLocalLock<CReentrantSpinGuard>	CReentrantSpinLock;
+typedef	CLocalLock<CFakeGuard>			CFakeLock;

+ 26 - 0
common/Src/Event.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "Event.h"

+ 70 - 0
common/Src/Event.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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
+
+class CEvt
+{
+public:
+	CEvt(BOOL bManualReset = FALSE, BOOL bInitialState = FALSE, LPCTSTR pszName = nullptr, LPSECURITY_ATTRIBUTES pSecurity = nullptr)
+	{
+		m_hEvent = ::CreateEvent(pSecurity, bManualReset, bInitialState, pszName);
+		ASSERT(IsValid());
+	}
+
+	~CEvt()
+	{
+		if(IsValid())
+			VERIFY(::CloseHandle(m_hEvent));
+	}
+
+	BOOL Open(DWORD dwAccess, BOOL bInheritHandle, LPCTSTR pszName)
+	{
+		if(IsValid())
+			VERIFY(::CloseHandle(m_hEvent));
+
+		m_hEvent = ::OpenEvent(dwAccess, bInheritHandle, pszName);
+		return(IsValid());
+	}
+
+	BOOL Pulse()	{return(::PulseEvent(m_hEvent));}
+	BOOL Reset()	{return(::ResetEvent(m_hEvent));}
+	BOOL Set()		{return(::SetEvent(m_hEvent));}
+
+	BOOL IsValid()	{return m_hEvent != nullptr;}
+
+	HANDLE GetHandle		()			{return m_hEvent;}
+	const HANDLE GetHandle	()	const	{return m_hEvent;}
+
+	operator HANDLE			()			{return m_hEvent;}
+	operator const HANDLE	()	const	{return m_hEvent;}
+
+private:
+	CEvt(const CEvt&);
+	CEvt operator = (const CEvt&);
+
+private:
+	HANDLE m_hEvent;
+};
+

+ 26 - 0
common/Src/GeneralHelper.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "GeneralHelper.h"

+ 234 - 0
common/Src/GeneralHelper.h

@@ -0,0 +1,234 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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.
+ */
+ 
+/*
+
+Optional Macros:
+
+Windows:
+++++++++++++++++++++++
+_WIN32_WINNT		: Windows NT 版本	(默认:_WIN32_WINNT_WINXP / _WIN32_WINNT_WIN7)
+WINVER				: Windows 版本		(默认:_WIN32_WINNT)
+_USE_MFC			: 使用 MFC
+_WINSOCK_SUPPORT	: 支持 Windows Socket
+_NO_RIBBONS_SUPPORT	: 不支持 Ribbons 界面风格
+_DETECT_MEMORY_LEAK	: DEBUG 状态下支持内存泄露检查
+
+Windows CE:
+++++++++++++++++++++++
+WINVER				: Windows 版本
+_USE_MFC			: 使用 MFC
+_WINSOCK_SUPPORT	: 支持 Windows Socket
+_DETECT_MEMORY_LEAK	: DEBUG 状态下支持内存泄露检查
+_ONLY_DETECT_CONFIRMED_MEMORY_LEAK_	: 只报告能够确认的内存泄露(不能确定的不报告)
+---------------------------
+VC 2015
+	_MSC_VER == 1900
+VC 2013
+	_MSC_VER == 1800
+VC 2012
+	_MSC_VER == 1700
+VC 2010
+	_MSC_VER == 1600
+VC 2008
+	_MSC_VER == 1500
+VC 2005
+	_MSC_VER == 1400
+VC 7.1
+	_MSC_VER == 1310
+VC 7.0
+	_MSC_VER == 1300
+VC 6.0
+	_MSC_VER == 1200
+---------------------------
+Windows Versions:
+_WIN32_WINNT_NT4		x0400
+_WIN32_WINNT_WIN2K		0x0500
+_WIN32_WINNT_WINXP		0x0501
+_WIN32_WINNT_WS03		0x0502
+_WIN32_WINNT_WIN6		0x0600
+_WIN32_WINNT_VISTA		0x0600
+_WIN32_WINNT_WS08		0x0600
+_WIN32_WINNT_LONGHORN	0x0600
+_WIN32_WINNT_WIN7		0x0601
+_WIN32_WINNT_WIN8		0x0602
+_WIN32_WINNT_WINBLUE	0x0603
+_WIN32_WINNT_WIN10		0x0A00
+---------------------------
+*/
+
+#pragma once
+
+#ifndef VC_EXTRALEAN
+	#define VC_EXTRALEAN
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+	#define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifndef _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
+	#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
+#endif
+
+#if _MSC_VER >= 1400
+
+	#if defined _DEBUG && _MSC_VER < 1600
+		#ifndef _SECURE_SCL
+			#define _SECURE_SCL					0
+		#endif
+		#ifndef _HAS_ITERATOR_DEBUGGING
+			#define _HAS_ITERATOR_DEBUGGING		0
+		#endif
+	#endif
+
+	#ifndef _CRT_SECURE_NO_DEPRECATE
+		#define _CRT_SECURE_NO_DEPRECATE		1
+	#endif
+
+	#ifndef _SCL_SECURE_NO_DEPRECATE
+		#define _SCL_SECURE_NO_DEPRECATE		1
+	#endif
+
+	#ifndef _ATL_SECURE_NO_WARNINGS
+		#define _ATL_SECURE_NO_WARNINGS			1
+	#endif
+
+	#ifndef _CRT_NON_CONFORMING_SWPRINTFS
+		#define _CRT_NON_CONFORMING_SWPRINTFS	1
+	#endif
+
+	#ifndef _SECURE_ATL
+		#define _SECURE_ATL						1
+	#endif
+
+	#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
+		#define _WINSOCK_DEPRECATED_NO_WARNINGS	1
+	#endif
+
+#endif
+
+#ifndef _WIN32_WINNT
+	#if defined (_WIN64)
+		#define _WIN32_WINNT	_WIN32_WINNT_WIN7
+	#else
+		#define _WIN32_WINNT	_WIN32_WINNT_WINXP
+	#endif
+#endif
+
+#ifndef WINVER
+	#define WINVER	_WIN32_WINNT
+#endif
+
+#if _MSC_VER >= 1600
+	#include <SDKDDKVer.h>
+#else
+	#if !defined(nullptr)
+		#define nullptr	NULL
+	#endif
+#endif
+
+#ifdef _DETECT_MEMORY_LEAK
+	#ifndef _CRTDBG_MAP_ALLOC
+		#define _CRTDBG_MAP_ALLOC
+	#endif
+#endif
+
+#ifdef _USE_MFC
+
+	#ifndef _AFX_ALL_WARNINGS
+		#define _AFX_ALL_WARNINGS
+	#endif
+
+	#include <afxwin.h>
+	#include <afxext.h>
+	#include <afxdisp.h>
+
+	#ifndef _AFX_NO_OLE_SUPPORT
+		#include <afxdtctl.h>
+	#endif
+
+	#ifndef _AFX_NO_AFXCMN_SUPPORT
+		#include <afxcmn.h>
+	#endif
+
+	#ifndef _NO_RIBBONS_SUPPORT
+		#include <afxcontrolbars.h>
+	#endif
+
+#else
+
+	#include <Windows.h>
+	#include <WindowsX.h>
+	#include <commctrl.h>
+	#include <stdio.h>
+	#include <stdlib.h>
+	#include <malloc.h>
+	#include <memory.h>
+	#include <tchar.h>
+	#include <atlstr.h>
+	#include <atltime.h>
+
+	#ifndef ASSERT
+		#define ASSERT(f)	ATLASSERT(f)
+	#endif
+	#ifndef VERIFY
+		#define VERIFY(f)	ATLVERIFY(f)
+	#endif
+
+	#ifndef TRACE
+		#include <atltrace.h>
+
+		#define TRACE							AtlTrace
+		#define TRACE0(f)						TRACE(f)
+		#define TRACE1(f, p1)					TRACE(f, p1)
+		#define TRACE2(f, p1, p2)				TRACE(f, p1, p2)
+		#define TRACE3(f, p1, p2, p3)			TRACE(f, p1, p2, p3)
+		#define TRACE4(f, p1, p2, p3, p4)		TRACE(f, p1, p2, p3, p4)
+		#define TRACE5(f, p1, p2, p3, p4, p5)	TRACE(f, p1, p2, p3, p4, p5)
+	#endif
+
+#endif
+
+#ifdef _WINSOCK_SUPPORT
+	#include <winsock2.h>
+	#include <ws2tcpip.h>
+	#include <mswsock.h>
+#endif
+
+#include <atlbase.h>
+#include <atlconv.h>
+
+#include "Singleton.h"
+#include "Event.h"
+#include "Semaphore.h"
+#include "CriticalSection.h"
+#include "STLHelper.h"
+#include "Win32Helper.h"
+#include "PrivateHeap.h"
+#include "bufferptr.h"
+
+#if defined (_DEBUG) && defined (_DETECT_MEMORY_LEAK)
+	#include "debug/win32_crtdbg.h"
+#endif

+ 32 - 0
common/Src/PrivateHeap.cpp

@@ -0,0 +1,32 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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:  PrivateHeap.cpp
+Notices: Copyright (c) 2006 Bruce Liang
+Purpose: ¹ÜÀí½ø³Ì˽ÓжÑ.
+******************************************************************************/
+
+#include "StdAfx.h"
+#include "PrivateHeap.h"

+ 238 - 0
common/Src/PrivateHeap.h

@@ -0,0 +1,238 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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:  PrivateHeap.h
+Notices: Copyright (c) 2006 Bruce Liang
+Purpose: 管理进程私有堆.
+Desc:
+		 1. CPrivateHeap:		自动创建和销毁进程私有堆
+								每一个该类的对象都代表一个私有堆, 所以
+								该类对象的特点是: 一般声明周期都比较长
+								通常作为全局对象, 其他类的静态成员对象
+								或者一些长生命周期类对象的成员对象
+		 2. CPrivateHeapBuffer: 在私有堆中自动分配和释放指定大小的内存
+								一般用于在函数体内分配和释放局部作用域的堆内存
+								从而避免对 CPrivateHeap::Alloc() 和 
+								CPrivateHeap::Free() 的调用
+
+Examples:
+			CPrivateHeap g_hpPrivate;
+
+			int _tmain(int argc, _TCHAR* argv[])
+			{
+				CPrivateHeapStrBuffer buff(g_hpPrivate, 32);
+				lstrcpy(buff, _T("失败乃成功之母"));
+				SIZE_T size = buff.Size();
+				buff.ReAlloc(40);
+				size = buff.Size();
+				std::cout << (TCHAR*)buff << '\n';
+				// OR
+				// ASSERT(g_hpPrivate.IsValid());
+				// TCHAR* pch	= (TCHAR*)g_hpPrivate.Alloc(32 * sizeof(TCHAR));
+				// lstrcpy(pch, _T("失败乃成功之母"));
+				// SIZE_T size = g_hpPrivate.Size(pch);
+				// g_hpPrivate.ReAlloc(pch, 40 * sizeof(TCHAR));
+				// size = g_hpPrivate.Size(pch);
+				// std::cout << pch << '\n';
+				// g_hpPrivate.Free(pch);
+				// 
+				return 0;
+			}
+
+******************************************************************************/
+
+#pragma once
+
+class CPrivateHeapImpl
+{
+public:
+	PVOID Alloc(SIZE_T dwSize, DWORD dwFlags = 0)
+		{return ::HeapAlloc(m_hHeap, dwFlags, dwSize);}
+
+	PVOID ReAlloc(PVOID pvMemory, SIZE_T dwSize, DWORD dwFlags = 0)
+		{return ::HeapReAlloc(m_hHeap, dwFlags, pvMemory, dwSize);}
+
+	SIZE_T Size(PVOID pvMemory, DWORD dwFlags = 0)
+		{return ::HeapSize(m_hHeap, dwFlags, pvMemory);}
+
+	BOOL Free(PVOID pvMemory, DWORD dwFlags = 0)
+		{return ::HeapFree(m_hHeap, dwFlags, pvMemory);}
+
+	SIZE_T Compact(DWORD dwFlags = 0)
+		{return ::HeapCompact(m_hHeap, dwFlags);}
+
+	BOOL IsValid() {return m_hHeap != nullptr;}
+
+	BOOL Reset()
+	{
+		if(IsValid()) ::HeapDestroy(m_hHeap);
+		m_hHeap = ::HeapCreate(m_dwOptions, m_dwInitSize, m_dwMaxSize);
+
+		return IsValid();
+	}
+
+public:
+	CPrivateHeapImpl(DWORD dwOptions = 0, SIZE_T dwInitSize = 0, SIZE_T dwMaxSize = 0)
+	: m_dwOptions(dwOptions), m_dwInitSize(dwInitSize), m_dwMaxSize(dwMaxSize)
+		{m_hHeap = ::HeapCreate(m_dwOptions, m_dwInitSize, m_dwMaxSize);}
+
+	~CPrivateHeapImpl	()	{if(IsValid()) ::HeapDestroy(m_hHeap);}
+
+	operator HANDLE	()	{return m_hHeap;}
+
+private:
+	CPrivateHeapImpl(const CPrivateHeapImpl&);
+	CPrivateHeapImpl operator = (const CPrivateHeapImpl&);
+
+private:
+	HANDLE	m_hHeap;
+	DWORD	m_dwOptions;
+	SIZE_T	m_dwInitSize;
+	SIZE_T	m_dwMaxSize;
+};
+
+class CGlobalHeapImpl
+{
+public:
+	PVOID Alloc(SIZE_T dwSize, DWORD dwFlags = 0)
+	{
+		PVOID pv = malloc(dwSize);
+		
+		if(pv && (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 && (dwFlags | HEAP_ZERO_MEMORY))
+			ZeroMemory(pv, dwSize);
+		else if(!pv)
+			free(pvMemory);
+
+		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()	{}
+
+	operator HANDLE	()	{return nullptr;}
+
+private:
+	CGlobalHeapImpl(const CGlobalHeapImpl&);
+	CGlobalHeapImpl operator = (const CGlobalHeapImpl&);
+};
+
+#ifndef _NOT_USE_PRIVATE_HEAP
+	typedef CPrivateHeapImpl	CPrivateHeap;
+#else
+	typedef CGlobalHeapImpl		CPrivateHeap;
+#endif
+
+template<class T>
+class CPrivateHeapBuffer
+{
+public:
+	CPrivateHeapBuffer(CPrivateHeap& hpPrivate,
+						SIZE_T dwSize		= 0,
+						DWORD dwAllocFlags	= 0,
+						DWORD dwFreeFlags	= 0)
+	: m_hpPrivate(hpPrivate)
+	, m_dwAllocFlags(dwAllocFlags)
+	, m_dwFreeFlags(dwFreeFlags)
+	, m_pvMemory(nullptr)
+	{
+		ASSERT(m_hpPrivate.IsValid());
+		Alloc(dwSize);
+	}
+
+	~CPrivateHeapBuffer() {Free();}
+
+public:
+
+	T* Alloc(SIZE_T dwSize)
+	{
+		if(IsValid())
+			Free();
+
+		return m_pvMemory = (T*)m_hpPrivate.Alloc(dwSize * sizeof(T), m_dwAllocFlags);
+	}
+
+	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);}
+
+	BOOL Free()
+	{
+		BOOL isOK = TRUE;
+
+		if(IsValid())
+		{
+			isOK = m_hpPrivate.Free(m_pvMemory, m_dwFreeFlags);
+			m_pvMemory = nullptr;
+		}
+
+		return isOK;
+	}
+
+	BOOL IsValid()			{return m_pvMemory != nullptr;}
+	operator T* ()	const	{return m_pvMemory;}
+
+private:
+	CPrivateHeapBuffer(const CPrivateHeapBuffer&);
+	CPrivateHeapBuffer operator = (const CPrivateHeapBuffer&);
+
+private:
+	CPrivateHeap&	m_hpPrivate;
+	T*				m_pvMemory;
+	DWORD			m_dwAllocFlags;
+	DWORD			m_dwFreeFlags;
+};
+
+typedef CPrivateHeapBuffer<BYTE>	CPrivateHeapByteBuffer;
+typedef CPrivateHeapBuffer<TCHAR>	CPrivateHeapStrBuffer;

+ 402 - 0
common/Src/RWLock.cpp

@@ -0,0 +1,402 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "StdAfx.h"
+#include "RWLock.h"
+
+////////////////////////////////// CSWMR Functions ////////////////////////////////////
+
+CSWMR::CSWMR()
+: m_smRead			(MAXLONG)
+, m_smWrite			(1)
+, m_nWaitingReaders	(0)
+, m_nWaitingWriters	(0)
+, m_nActive			(0)
+{
+
+}
+
+CSWMR::~CSWMR()
+{
+	ASSERT(m_nWaitingReaders == 0);
+	ASSERT(m_nWaitingWriters == 0);
+	ASSERT(m_nActive		 == 0);
+}
+
+VOID CSWMR::WaitToRead()
+{
+	BOOL fResourceWritePending;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		fResourceWritePending = (m_nWaitingWriters || (m_nActive < 0));
+
+		if(fResourceWritePending)
+			++m_nWaitingReaders;
+		else
+			++m_nActive;
+	}
+
+	if(fResourceWritePending)
+		m_smRead.Wait();
+}
+
+VOID CSWMR::WaitToWrite()
+{
+	BOOL fResourceOwned;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		fResourceOwned = (m_nActive != 0);
+
+		if(fResourceOwned)
+			++m_nWaitingWriters;
+		else
+			m_nActive = -1;
+	}
+
+	if(fResourceOwned)
+		m_smWrite.Wait();
+}
+
+VOID CSWMR::Done()
+{
+	CSEM* pSem  = nullptr;
+	LONG lCount = 1;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		if(m_nActive > 0)
+			--m_nActive;
+		else
+			++m_nActive;
+
+		if(m_nActive == 0)
+		{
+			if(m_nWaitingWriters > 0)
+			{
+				m_nActive = -1;
+				--m_nWaitingWriters;
+				pSem = &m_smWrite;
+			}
+			else if(m_nWaitingReaders > 0)
+			{
+				m_nActive = m_nWaitingReaders;
+				m_nWaitingReaders = 0;
+				pSem = &m_smRead;
+				lCount = m_nActive;
+			}
+		}
+	}
+
+	if(pSem != nullptr)
+		pSem->Release(lCount);
+}
+
+//////////////////////////////// CRWLock Functions //////////////////////////////////
+
+#if _WIN32_WINNT >= _WIN32_WINNT_WS08
+
+CSlimRWLock::CSlimRWLock()
+	: m_nActive			(0)
+	, m_nReadCount		(0)
+	, m_dwWriterTID		(0)
+{
+
+}
+
+CSlimRWLock::~CSlimRWLock()
+{
+	ASSERT(m_nActive	 == 0);
+	ASSERT(m_nReadCount	 == 0);
+	ASSERT(m_dwWriterTID == 0);
+}
+
+VOID CSlimRWLock::WaitToRead()
+{
+	BOOL bWait = FALSE;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		if(m_nActive > 0)
+			++m_nActive;
+		else if(m_nActive == 0)
+		{
+			if(m_smLock.TryWaitToRead())
+			{
+				++m_nReadCount;
+				++m_nActive;
+			}
+			else
+				bWait = TRUE;
+		}
+		else if(!IsOwner())
+			bWait = TRUE;
+	}
+
+	if(bWait)
+	{
+		m_smLock.WaitToRead();
+
+		CSpinLock locallock(m_cs);
+		{
+			++m_nReadCount;
+			++m_nActive;
+		}
+	}
+}
+
+VOID CSlimRWLock::WaitToWrite()
+{
+	BOOL bWait = FALSE;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		if(m_nActive > 0)
+			bWait = TRUE;
+		else if(m_nActive == 0)
+		{
+			if(m_smLock.TryWaitToWrite())
+			{
+				SetOwner();
+				--m_nActive;
+			}
+			else
+				bWait = TRUE;
+		}
+		else
+		{
+			if(IsOwner())
+				--m_nActive;
+			else
+				bWait = TRUE;
+		}
+	}
+
+	if(bWait)
+	{
+		m_smLock.WaitToWrite();
+
+		SetOwner();
+		--m_nActive;
+	}
+}
+
+VOID CSlimRWLock::ReadDone()
+{
+	ASSERT(m_nActive != 0);
+
+	if(m_nActive > 0)
+	{
+		ASSERT(m_nReadCount > 0);
+
+		CSpinLock locallock(m_cs);
+
+		if(--m_nActive == 0)
+		{
+			for(; m_nReadCount > 0; --m_nReadCount)
+				m_smLock.ReadDone();
+		}
+	}
+	else
+		ASSERT(IsOwner());
+}
+
+VOID CSlimRWLock::WriteDone()
+{
+	ASSERT(m_nActive < 0);
+
+	CSpinLock locallock(m_cs);
+
+	if(++m_nActive == 0)
+	{
+		DetachOwner();
+		m_smLock.WriteDone();
+	}
+	else
+		ASSERT(IsOwner());
+}
+
+#endif
+
+CSEMRWLock::CSEMRWLock()
+: m_smRead			(MAXLONG)
+, m_smWrite			(1)
+, 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()
+{
+	BOOL bWait = FALSE;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		if(m_nActive > 0)
+			++m_nActive;
+		else if(m_nActive == 0)
+		{
+			if(m_nWaitingWriters == 0)
+				++m_nActive;
+			else
+			{
+				++m_nWaitingReaders;
+				bWait = TRUE;
+			}
+		}
+		else
+		{
+			if(!IsOwner())
+			{
+				++m_nWaitingReaders;
+				bWait = TRUE;
+			}
+		}
+	}
+
+	if(bWait)
+	{
+		m_smRead.Wait();
+	}
+}
+
+VOID CSEMRWLock::WaitToWrite()
+{
+	BOOL bWait = FALSE;
+
+	{
+		CSpinLock locallock(m_cs);
+
+		if(m_nActive > 0)
+		{
+			++m_nWaitingWriters;
+			bWait = TRUE;
+		}
+		else if(m_nActive == 0)
+		{
+			--m_nActive;
+			SetOwner();
+		}
+		else
+		{
+			if(IsOwner())
+				--m_nActive;
+			else
+			{
+				++m_nWaitingWriters;
+				bWait = TRUE;
+			}
+		}
+	}
+
+	if(bWait)
+	{
+		m_smWrite.Wait();
+		SetOwner();
+	}
+}
+
+VOID CSEMRWLock::ReadDone()
+{
+	CSEM* pSem	 = nullptr;
+	LONG  lCount = 0;
+
+	ASSERT(m_nActive != 0);
+
+	if(m_nActive > 0)
+	{
+		CSpinLock locallock(m_cs);
+
+		if(--m_nActive == 0)
+			Done(&pSem, lCount);
+	}
+	else
+		ASSERT(IsOwner());
+
+	if(pSem != nullptr)
+		pSem->Release(lCount);
+}
+
+VOID CSEMRWLock::WriteDone()
+{
+	CSEM* pSem	 = nullptr;
+	LONG  lCount = 0;
+
+	{
+		ASSERT(m_nActive < 0);
+
+		CSpinLock locallock(m_cs);
+
+		if(++m_nActive == 0)
+		{
+			DetachOwner();
+			Done(&pSem, lCount);
+		}
+		else
+			ASSERT(IsOwner());
+	}
+
+	if(pSem != nullptr)
+		pSem->Release(lCount);
+}
+
+VOID CSEMRWLock::Done(CSEM** ppSem, LONG& lCount)
+{
+	ASSERT(m_nActive	 == 0);
+	ASSERT(m_dwWriterTID == 0);
+
+	if(m_nWaitingWriters > 0)
+	{
+		--m_nActive;
+		--m_nWaitingWriters;
+
+		lCount = 1;
+		*ppSem = &m_smWrite;
+	}
+	else if(m_nWaitingReaders > 0)
+	{
+		m_nActive			= m_nWaitingReaders;
+		m_nWaitingReaders	= 0;
+		lCount				= m_nActive;
+		*ppSem				= &m_smRead;
+	}
+}
+
+/////////////////////////////////// End of File /////////////////////////////////////

+ 418 - 0
common/Src/RWLock.h

@@ -0,0 +1,418 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "CriticalSection.h"
+#include "Semaphore.h"
+
+class CSWMR
+{
+public:
+	VOID WaitToRead();
+	VOID WaitToWrite();
+	VOID ReadDone()  {Done();}
+	VOID WriteDone() {Done();}
+
+private:
+	VOID Done();
+
+public:
+	CSWMR();
+	~CSWMR();
+
+private:
+	CSWMR(const CSWMR&);
+	CSWMR operator = (const CSWMR&);
+
+private:
+	int m_nWaitingReaders;
+	int m_nWaitingWriters;
+	int m_nActive;
+
+	CSpinGuard	m_cs;
+	CSEM		m_smRead;
+	CSEM		m_smWrite;
+};
+
+#if _WIN32_WINNT >= _WIN32_WINNT_WS08
+
+class CSlimLock
+{
+public:
+	VOID WaitToRead()		{::AcquireSRWLockShared(&m_lock);}
+	VOID WaitToWrite()		{::AcquireSRWLockExclusive(&m_lock);}
+	VOID ReadDone()			{::ReleaseSRWLockShared(&m_lock);}
+	VOID WriteDone()		{::ReleaseSRWLockExclusive(&m_lock);}
+	BOOL TryWaitToRead()	{return ::TryAcquireSRWLockShared(&m_lock);}
+	BOOL TryWaitToWrite()	{return ::TryAcquireSRWLockExclusive(&m_lock);}
+
+	SRWLOCK* GetObject()	{return &m_lock;}
+
+public:
+	CSlimLock()		{::InitializeSRWLock(&m_lock);}
+	~CSlimLock()	{}
+
+private:
+	CSlimLock(const CSlimLock&);
+	CSlimLock operator = (const CSlimLock&);
+
+private:
+	SRWLOCK m_lock;
+};
+
+class CSlimRWLock
+{
+public:
+	VOID WaitToRead();
+	VOID WaitToWrite();
+	VOID ReadDone();
+	VOID WriteDone();
+
+private:
+	BOOL IsOwner()		{return m_dwWriterTID == ::GetCurrentThreadId();}
+	VOID SetOwner()		{m_dwWriterTID = ::GetCurrentThreadId();}
+	VOID DetachOwner()	{m_dwWriterTID = 0;}
+
+public:
+	CSlimRWLock();
+	~CSlimRWLock();
+
+private:
+	CSlimRWLock(const CSlimRWLock&);
+	CSlimRWLock operator = (const CSlimRWLock&);
+
+private:
+	int m_nActive;
+	int m_nReadCount;
+	DWORD m_dwWriterTID;
+
+	CSpinGuard	m_cs;
+	CSlimLock	m_smLock;
+};
+
+#endif
+
+class CSEMRWLock
+{
+public:
+	VOID WaitToRead();
+	VOID WaitToWrite();
+	VOID ReadDone();
+	VOID WriteDone();
+
+private:
+	VOID Done			(CSEM** ppSem, LONG& lCount);
+	BOOL IsOwner()		{return m_dwWriterTID == ::GetCurrentThreadId();}
+	VOID SetOwner()		{m_dwWriterTID = ::GetCurrentThreadId();}
+	VOID DetachOwner()	{m_dwWriterTID = 0;}
+
+public:
+	CSEMRWLock();
+	~CSEMRWLock();
+
+private:
+	CSEMRWLock(const CSEMRWLock&);
+	CSEMRWLock operator = (const CSEMRWLock&);
+
+private:
+	int m_nWaitingReaders;
+	int m_nWaitingWriters;
+	int m_nActive;
+	DWORD m_dwWriterTID;
+
+	CSpinGuard	m_cs;
+	CSEM		m_smRead;
+	CSEM		m_smWrite;
+};
+
+template<class CLockObj> class CLocalReadLock
+{
+public:
+	CLocalReadLock(CLockObj& obj) : m_wait(obj) {m_wait.WaitToRead();}
+	~CLocalReadLock() {m_wait.ReadDone();}
+private:
+	CLocalReadLock(const CLocalReadLock&);
+	CLocalReadLock operator = (const CLocalReadLock&);
+private:
+	CLockObj& m_wait;
+};
+
+template<class CLockObj> class CLocalWriteLock
+{
+public:
+	CLocalWriteLock(CLockObj& obj) : m_wait(obj) {m_wait.WaitToWrite();}
+	~CLocalWriteLock() {m_wait.WriteDone();}
+private:
+	CLocalWriteLock(const CLocalWriteLock&);
+	CLocalWriteLock operator = (const CLocalWriteLock&);
+private:
+	CLockObj& m_wait;
+};
+
+#if _WIN32_WINNT >= _WIN32_WINNT_WS08
+	typedef CSlimLock	CSimpleRWLock;
+#else
+	typedef CSWMR		CSimpleRWLock;
+#endif
+
+typedef CLocalReadLock<CSimpleRWLock>	CReadLock;
+typedef CLocalWriteLock<CSimpleRWLock>	CWriteLock;
+
+typedef CSEMRWLock						CRWLock;
+typedef CLocalReadLock<CRWLock>			CReentrantReadLock;
+typedef CLocalWriteLock<CRWLock>		CReentrantWriteLock;
+
+#if _WIN32_WINNT >= _WIN32_WINNT_WS08
+
+class ICVCondition
+{
+public:
+	virtual BOOL Detect() = 0;
+
+public:
+	virtual ~ICVCondition() {}
+};
+
+class CCVCriSec
+{
+public:
+	CCVCriSec(CInterCriSec& cs)
+	: m_cs(cs)
+	{
+		::InitializeConditionVariable(&m_cv);
+	}
+
+	~CCVCriSec() {}
+
+	void WaitToRead(ICVCondition* pCondition)
+	{
+		Wait(pCondition);
+	}
+
+	void WaitToWrite(ICVCondition* pCondition)
+	{
+		Wait(pCondition);
+	}
+
+	void ReadDone()
+	{
+		Done();
+	}
+
+	void WriteDone()
+	{
+		Done();
+	}
+
+	void WakeUp()
+	{
+		::WakeConditionVariable(&m_cv);
+	}
+
+	void WakeUpAll()
+	{
+		::WakeAllConditionVariable(&m_cv);
+	}
+
+private:
+	void Wait(ICVCondition* pCondition)
+	{
+		ASSERT(pCondition);
+
+		m_cs.Lock();
+
+		while(!pCondition->Detect()) 
+			::SleepConditionVariableCS(&m_cv, m_cs.GetObject(), INFINITE);
+	}
+
+	void Done()
+	{
+		m_cs.Unlock();
+	}
+
+private:
+	CCVCriSec(const CCVCriSec& cs);
+	CCVCriSec operator = (const CCVCriSec& cs);
+
+private:
+	CInterCriSec&		m_cs;
+	CONDITION_VARIABLE	m_cv;
+};
+
+class CCVSlim
+{
+public:
+	CCVSlim(CSlimLock& cs)
+	: m_cs(cs)
+	{
+		::InitializeConditionVariable(&m_cv);
+	}
+
+	~CCVSlim() {}
+
+	void WaitToRead(ICVCondition* pCondition)
+	{
+		ASSERT(pCondition);
+
+		m_cs.WaitToRead();
+
+		while(!pCondition->Detect()) 
+			::SleepConditionVariableSRW(&m_cv, m_cs.GetObject(), INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
+	}
+
+	void WaitToWrite(ICVCondition* pCondition)
+	{
+		ASSERT(pCondition);
+
+		m_cs.WaitToWrite();
+
+		while(!pCondition->Detect())  
+			::SleepConditionVariableSRW(&m_cv, m_cs.GetObject(), INFINITE, 0);
+	}
+
+	void ReadDone()
+	{
+		m_cs.ReadDone();
+	}
+
+	void WriteDone()
+	{
+		m_cs.WriteDone();
+	}
+
+	void WakeUp()
+	{
+		::WakeConditionVariable(&m_cv);
+	}
+
+	void WakeUpAll()
+	{
+		::WakeAllConditionVariable(&m_cv);
+	}
+
+private:
+	CCVSlim(const CCVSlim& cs);
+	CCVSlim operator = (const CCVSlim& cs);
+
+private:
+	CSlimLock&			m_cs;
+	CONDITION_VARIABLE	m_cv;
+};
+
+template<class _Lock, class _Var> class CCVGuard
+{
+public:
+	void WaitForProduce()
+	{
+		m_cvP.WaitToWrite(m_pcdtProduce);
+	}
+
+	void WaitForConsume()
+	{
+		m_cvC.WaitToRead(m_pcdtConsume);
+	}
+
+	void ProduceDone()
+	{
+		m_cvP.WriteDone();
+	}
+
+	void WakeUpProduce()
+	{
+		m_cvP.WakeUp();
+	}
+
+	void ConsumeDone()
+	{
+		m_cvC.ReadDone();
+	}
+
+	void WakeUpConsume()
+	{
+		m_cvC.WakeUp();
+	}
+
+	void WakeUpAllConsumes()
+	{
+		m_cvC.WakeUpAll();
+	}
+
+public:
+	CCVGuard(ICVCondition* pcdtProduce, ICVCondition* pcdtConsume)
+	: m_cvP(m_cs)
+	, m_cvC(m_cs)
+	, m_pcdtProduce(pcdtProduce)
+	, m_pcdtConsume(pcdtConsume)
+	{
+		ASSERT(m_pcdtConsume && m_pcdtProduce);
+	}
+
+	~CCVGuard()	{}
+
+private:
+	CCVGuard(const CCVGuard& cs);
+	CCVGuard operator = (const CCVGuard& cs);
+
+private:
+	ICVCondition* m_pcdtProduce;
+	ICVCondition* m_pcdtConsume;
+
+	_Lock	m_cs;
+	_Var	m_cvP;
+	_Var	m_cvC;
+};
+
+template<class _GuardObj> class CConsumeLock
+{
+public:
+	CConsumeLock(_GuardObj& obj) : m_guard(obj) {m_guard.WaitForConsume();}
+	~CConsumeLock() {m_guard.ConsumeDone();}
+private:
+	CConsumeLock(const CConsumeLock&);
+	CConsumeLock operator = (const CConsumeLock&);
+private:
+	_GuardObj& m_guard;
+};
+
+template<class _GuardObj> class CProduceLock
+{
+public:
+	CProduceLock(_GuardObj& obj) : m_guard(obj) {m_guard.WaitForProduce();}
+	~CProduceLock() {m_guard.ProduceDone();}
+private:
+	CProduceLock(const CProduceLock&);
+	CProduceLock operator = (const CProduceLock&);
+private:
+	_GuardObj& m_guard;
+};
+
+typedef CCVGuard<CInterCriSec, CCVCriSec>	CCVGuardCS;
+typedef CCVGuard<CSlimLock, CCVSlim>		CCVGuardSRW;
+typedef CProduceLock<CCVGuardCS>			CProduceLockCS;
+typedef CConsumeLock<CCVGuardCS>			CConsumeLockCS;
+typedef CProduceLock<CCVGuardSRW>			CProduceLockSRW;
+typedef CConsumeLock<CCVGuardSRW>			CConsumeLockSRW;
+
+#endif

+ 26 - 0
common/Src/RingBuffer.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "RingBuffer.h"

+ 1526 - 0
common/Src/RingBuffer.h

@@ -0,0 +1,1526 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "STLHelper.h"
+#include "RWLock.h"
+#include "CriticalSection.h"
+
+#define CACHE_LINE		64
+#define PACK_SIZE_OF(T)	(CACHE_LINE - sizeof(T) % CACHE_LINE)
+
+#if !defined (_WIN64)
+	#pragma pack(push, 4)
+#endif
+
+template <class T, class _PutGuard = CCriSec, class _GetGuard = CCriSec> class CRingBuffer
+{
+public:
+	static const UINT DEFAULT_EXPECT = 4096;
+
+public:
+	BOOL Put(T* pElement)
+	{
+		ASSERT(pElement != nullptr);
+
+		{
+			CLocalLock<_PutGuard> locallock(m_csPut);
+
+			ULONGLONG seqPut = m_seqPut;
+
+			WaitForPut(seqPut);
+			if(!IsValid()) return FALSE;
+
+			DoPut(pElement, seqPut);
+		}
+
+		return TRUE;
+	}
+
+	BOOL TryPut(T* pElement)
+	{
+		ASSERT(pElement != nullptr);
+
+		if(!IsValid() || !HasPutSpace(m_seqPut))
+			return FALSE;
+
+		{
+			CLocalLock<_PutGuard> locallock(m_csPut);
+
+			ULONGLONG seqPut = m_seqPut;
+
+			if(!IsValid() || !HasPutSpace(seqPut))
+				return FALSE;
+
+			DoPut(pElement, seqPut);
+		}
+
+		return TRUE;
+	}
+
+	BOOL PutBatch(T* pElements[], int& iCount)
+	{
+		ASSERT(pElements != nullptr && iCount > 0);
+
+		{
+			CLocalLock<_PutGuard> locallock(m_csPut);
+
+			ULONGLONG seqPut = m_seqPut;
+
+			for(int i = 0; i < iCount; ++i)
+			{
+				WaitForPut(seqPut);
+
+				if(!IsValid())
+				{
+					iCount = i;
+					return FALSE;
+				}
+
+				DoPut(*(pElements + i), seqPut);
+			}
+		}
+
+		return TRUE;
+	}
+
+	BOOL TryPutBatch(T* pElements[], int& iCount)
+	{
+		ASSERT(pElements != nullptr && iCount > 0);
+
+		if(!IsValid() || !HasPutSpace(m_seqPut))
+		{
+			iCount = 0;
+			return FALSE;
+		}
+
+		{
+			CLocalLock<_PutGuard> locallock(m_csPut);
+
+			ULONGLONG seqPut = m_seqPut;
+
+			for(int i = 0; i < iCount; ++i)
+			{
+				if(!IsValid() || !HasPutSpace(seqPut))
+				{
+					iCount = i;
+					return FALSE;
+				}
+
+				DoPut(*(pElements + i), seqPut);
+			}
+		}
+
+		return TRUE;
+	}
+
+	BOOL Get(T** pElement)
+	{
+		ASSERT(pElement != nullptr);
+
+		{
+			CLocalLock<_GetGuard> locallock(m_csGet);
+
+			ULONGLONG seqGet = m_seqGet;
+
+			WaitForGet(seqGet);
+			if(!IsValid()) return FALSE;
+
+			DoGet(pElement, seqGet);
+		}
+
+		return TRUE;
+	}
+
+	BOOL TryGet(T** pElement)
+	{
+		ASSERT(pElement != nullptr);
+
+		if(!IsValid() || !HasGetSpace(m_seqGet))
+			return FALSE;
+
+		{
+			CLocalLock<_GetGuard> locallock(m_csGet);
+
+			ULONGLONG seqGet = m_seqGet;
+
+			if(!IsValid() || !HasGetSpace(seqGet))
+				return FALSE;
+
+			DoGet(pElement, seqGet);
+		}
+
+		return TRUE;
+	}
+
+	BOOL GetBatch(T* pElements[], int& iCount)
+	{
+		ASSERT(pElements != nullptr && iCount > 0);
+
+		{
+			CLocalLock<_GetGuard> locallock(m_csGet);
+
+			ULONGLONG seqGet = m_seqGet;
+
+			for(int i = 0; i < iCount; ++i)
+			{
+				WaitForGet(seqGet);
+
+				if(!IsValid())
+				{
+					iCount = i;
+					return FALSE;
+				}
+
+				DoGet(pElements + i, seqGet);
+			}
+		}
+
+		return TRUE;
+	}
+
+	BOOL TryGetBatch(T* pElements[], int& iCount)
+	{
+		ASSERT(pElements != nullptr && iCount > 0);
+
+		if(!IsValid() || !HasGetSpace(m_seqGet))
+		{
+			iCount = 0;
+			return FALSE;
+		}
+
+		{
+			CLocalLock<_GetGuard> locallock(m_csGet);
+
+			ULONGLONG seqGet = m_seqGet;
+
+			for(int i = 0; i < iCount; ++i)
+			{
+				if(!IsValid() || !HasGetSpace(seqGet))
+				{
+					iCount = i;
+					return FALSE;
+				}
+
+				DoGet(pElements + i, seqGet);
+			}
+		}
+
+		return TRUE;
+	}
+
+	BOOL Peek(T** pElement)
+	{
+		ASSERT(pElement != nullptr);
+
+		ULONGLONG seqGet = m_seqGet;
+
+		if(!IsValid() || !HasGetSpace(seqGet))
+			return FALSE;
+
+		DoPeek(pElement, seqGet);
+
+		return TRUE;
+	}
+
+private:
+	void DoPut(T* pElement, ULONGLONG& seqPut)
+	{
+		DWORD index = seqPut & (m_dwReal - 1);
+		*(m_pv + index)	= pElement;
+
+		++seqPut;
+		m_seqPut = seqPut;
+	}
+
+	void DoGet(T** pElement, ULONGLONG& seqGet)
+	{
+		DWORD index = seqGet & (m_dwReal - 1);
+		*(pElement) = *(m_pv + index);
+
+		++seqGet;
+		m_seqGet = seqGet;
+	}
+
+	void DoPeek(T** pElement, ULONGLONG& seqGet)
+	{
+		DWORD index = seqGet & (m_dwReal - 1);
+		*(pElement) = *(m_pv + index);
+	}
+
+	BOOL HasPutSpace(ULONGLONG seqPut)
+	{
+		return (seqPut - m_seqGet < m_dwReal);
+	}
+
+	void WaitForPut(ULONGLONG seqPut)
+	{
+		for(DWORD w = 0; IsValid(); ++w)
+		{
+			if(HasPutSpace(seqPut))
+				break;
+
+			::YieldThread(w);
+		}
+	}
+
+	BOOL HasGetSpace(ULONGLONG seqGet)
+	{
+		return (m_seqPut - seqGet > 0);
+	}
+
+	void WaitForGet(ULONGLONG seqGet)
+	{
+		for(DWORD w = 0; IsValid(); ++w)
+		{
+			if(HasGetSpace(seqGet))
+				break;
+
+			::YieldThread(w);
+		}
+	}
+
+	DWORD Revise(DWORD dwExpect)
+	{
+		int index = 0;
+		int shift = sizeof(DWORD) * 8 - 1;
+
+		for(int i = shift; i >= 0; i--)
+		{
+			if(index == 0)
+			{
+				if(dwExpect & (1 << i))
+				{
+					index = i;
+
+					if(index == shift)
+						break;
+				}
+			}
+			else
+			{
+				if(dwExpect & (1 << i))
+					++index;
+
+				break;
+			}
+		}
+
+		return 1 << index;
+	}
+
+public:
+	CRingBuffer(DWORD uiExpect = DEFAULT_EXPECT)
+	: m_pv(nullptr)
+	, m_dwReal(0)
+	, m_seqPut(0)
+	, m_seqGet(0)
+	{
+		Reset(uiExpect);
+	}
+
+	~CRingBuffer()
+	{
+		Reset(0);
+	}
+
+	void Reset(DWORD uiExpect = DEFAULT_EXPECT)
+	{
+		if(IsValid())
+			Destroy();
+		if(uiExpect > 0)
+			Create(uiExpect);
+	}
+
+	BOOL IsValid() {return m_pv != nullptr;}
+
+private:
+	void Create(DWORD dwExpect = DEFAULT_EXPECT)
+	{
+		ASSERT(!IsValid() && dwExpect > 0);
+
+		m_seqPut = 0;
+		m_seqGet = 0;
+		m_dwReal = Revise(dwExpect);
+		m_pv	 = (T**)malloc(m_dwReal * sizeof(T*));
+	}
+
+	void Destroy()
+	{
+		ASSERT(IsValid());
+
+		CLocalLock<_PutGuard> locallock1(m_csPut);
+		CLocalLock<_GetGuard> locallock2(m_csGet);
+
+		free((void*)m_pv);
+		m_pv	 = nullptr;
+		m_dwReal = 0;
+		m_seqPut = 0;
+		m_seqGet = 0;
+	}
+
+private:
+	CRingBuffer(const CRingBuffer&);
+	CRingBuffer operator = (const CRingBuffer&);
+
+private:
+	DWORD				m_dwReal;
+	T**					m_pv;
+	char				pack1[PACK_SIZE_OF(T**)];
+	volatile ULONGLONG	m_seqPut;
+	char				pack4[PACK_SIZE_OF(ULONGLONG)];
+	volatile ULONGLONG	m_seqGet;
+	char				pack5[PACK_SIZE_OF(ULONGLONG)];
+	_PutGuard			m_csPut;
+	char				pack2[PACK_SIZE_OF(_PutGuard)];
+	_GetGuard			m_csGet;
+	char				pack3[PACK_SIZE_OF(_GetGuard)];
+};
+
+typedef CRingBuffer<void, CCriSec, CCriSec>				CCSRingBuffer;
+typedef CRingBuffer<void, CInterCriSec, CInterCriSec>	CICSRingBuffer;
+typedef CRingBuffer<void, CSpinGuard, CSpinGuard>		CSGRingBuffer;
+typedef CRingBuffer<void, CFakeGuard, CFakeGuard>		CFKRingBuffer;
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+template <class T, class index_type = DWORD, bool adjust_index = false> class CRingCache
+{
+public:
+
+	enum EnGetResult {GR_FAIL = -1, GR_INVALID = 0, GR_VALID = 1};
+
+	typedef T*									TPTR;
+	typedef volatile T*							VTPTR;
+
+	typedef unordered_set<index_type>			IndexSet;
+	typedef typename IndexSet::const_iterator	IndexSetCI;
+	typedef typename IndexSet::iterator			IndexSetI;
+
+	static TPTR const E_EMPTY;
+	static TPTR const E_LOCKED;
+	static TPTR const E_MAX_STATUS;
+
+public:
+
+	static index_type& INDEX_INC(index_type& dwIndex)	{if(adjust_index) ++dwIndex; return dwIndex;}
+	static index_type& INDEX_DEC(index_type& dwIndex)	{if(adjust_index) --dwIndex; return dwIndex;}
+
+private:
+
+	VTPTR& INDEX_VAL(index_type dwIndex) {return *(m_pv + dwIndex);}
+
+public:
+
+	BOOL Put(TPTR pElement, index_type& dwIndex)
+	{
+		ASSERT(pElement != nullptr);
+
+		if(!IsValid()) return FALSE;
+
+		BOOL isOK = FALSE;
+
+		while(true)
+		{
+			if(!HasSpace())
+				break;
+
+			DWORD dwCurSeq			= m_dwCurSeq;
+			index_type dwCurIndex	= dwCurSeq % m_dwSize;
+			VTPTR& pValue			= INDEX_VAL(dwCurIndex);
+
+			if(pValue == E_EMPTY)
+			{
+				if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, pElement, E_EMPTY) == E_EMPTY)
+				{
+					::InterlockedIncrement(&m_dwCount);
+					::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
+
+					dwIndex = INDEX_INC(dwCurIndex);
+					isOK	= TRUE;
+
+					if(pElement != E_LOCKED)
+						EmplaceIndex(dwIndex);
+
+					break;
+				}
+			}
+
+			::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
+		}
+
+		return isOK;
+	}
+
+	EnGetResult Get(index_type dwIndex, TPTR* ppElement)
+	{
+		ASSERT(dwIndex <= m_dwSize);
+		ASSERT(ppElement != nullptr);
+
+		if(!IsValid() || INDEX_DEC(dwIndex) >= m_dwSize)
+		{
+			*ppElement = nullptr;
+			return GR_FAIL;
+		}
+
+		*ppElement = (TPTR)INDEX_VAL(dwIndex);
+
+		return IsValidElement(*ppElement) ? GR_VALID : GR_INVALID;
+	}
+
+	BOOL Set(index_type dwIndex, TPTR pElement, TPTR* ppOldElement = nullptr)
+	{
+		TPTR pElement2 = nullptr;
+
+		if(Get(dwIndex, &pElement2) == GR_FAIL)
+			return FALSE;
+
+		if(ppOldElement != nullptr)
+			*ppOldElement = pElement2;
+
+		if(pElement == pElement2)
+			return FALSE;
+
+		int f1 = 0;
+		int f2 = 0;
+
+		if(pElement == E_EMPTY)
+		{
+			if(pElement2 == E_LOCKED)
+				f1 = -1;
+			else
+				f1 = f2 = -1;
+		}
+		else if(pElement == E_LOCKED)
+		{
+			if(pElement2 == E_EMPTY)
+				f1 = 1;
+			else
+				f2 = -1;
+		}
+		else
+		{
+			if(pElement2 == E_EMPTY)
+				f1 = f2 = 1;
+			else if(pElement2 == E_LOCKED)
+				f2 = 1;
+		}
+
+		BOOL bSetValueFirst		= (f1 + f2 >= 0);
+		index_type dwOuterIndex	= dwIndex;
+
+		INDEX_DEC(dwIndex);
+
+		if(bSetValueFirst)	INDEX_VAL(dwIndex) = pElement;
+		if(f1 > 0)			::InterlockedIncrement(&m_dwCount);
+		if(f2 != 0)			(f2 > 0) ? EmplaceIndex(dwOuterIndex) : EraseIndex(dwOuterIndex);
+		if(f1 < 0)			::InterlockedDecrement(&m_dwCount);
+		if(!bSetValueFirst) INDEX_VAL(dwIndex) = pElement;
+
+		ASSERT(Spaces() <= Size());
+
+		return TRUE;
+	}
+
+	BOOL Remove(index_type dwIndex, TPTR* ppElement = nullptr)
+	{
+		return Set(dwIndex, E_EMPTY, ppElement);
+	}
+
+	BOOL AcquireLock(index_type& dwIndex)
+	{
+		return Put(E_LOCKED, dwIndex);
+	}
+
+	BOOL ReleaseLock(index_type dwIndex, TPTR pElement)
+	{
+		ASSERT(pElement == nullptr || IsValidElement(pElement));
+
+		TPTR pElement2 = nullptr;
+		Get(dwIndex, &pElement2);
+
+		ASSERT(pElement2 == E_LOCKED);
+
+		if(pElement2 != E_LOCKED)
+			return FALSE;
+
+		return Set(dwIndex, pElement);
+	}
+
+public:
+
+	void Reset(DWORD dwSize = 0)
+	{
+		if(IsValid())
+			Destroy();
+		if(dwSize > 0)
+			Create(dwSize);
+	}
+	
+	BOOL GetAllElementIndexes(index_type ids[], DWORD& dwCount, BOOL bCopy = TRUE)
+	{
+		if(ids == nullptr || dwCount == 0)
+		{
+			dwCount = Elements();
+			return FALSE;
+		}
+
+		IndexSet* pIndexes = nullptr;
+		IndexSet indexes;
+
+		if(bCopy)
+			pIndexes = &CopyIndexes(indexes);
+		else
+			pIndexes = &m_indexes;
+
+		BOOL isOK	 = FALSE;
+		DWORD dwSize = (DWORD)pIndexes->size();
+
+		if(dwSize > 0 && dwSize <= dwCount)
+		{
+			IndexSetCI it  = pIndexes->begin();
+			IndexSetCI end = pIndexes->end();
+
+			for(int i = 0; it != end; ++it, ++i)
+				ids[i] = *it;
+
+			isOK = TRUE;
+		}
+
+		dwCount = dwSize;
+		return isOK;
+	}
+	
+	unique_ptr<index_type[]> GetAllElementIndexes(DWORD& dwCount, BOOL bCopy = TRUE)
+	{
+		IndexSet* pIndexes = nullptr;
+		IndexSet indexes;
+
+		if(bCopy)
+			pIndexes = &CopyIndexes(indexes);
+		else
+			pIndexes = &m_indexes;
+
+		unique_ptr<index_type[]> ids;
+		dwCount = (DWORD)pIndexes->size();
+
+		if(dwCount > 0)
+		{
+			ids.reset(new index_type[dwCount]);
+
+			IndexSetCI it  = pIndexes->begin();
+			IndexSetCI end = pIndexes->end();
+
+			for(int i = 0; it != end; ++it, ++i)
+				ids[i] = *it;
+		}
+
+		return ids;
+	}
+
+	static BOOL IsValidElement(TPTR pElement) {return pElement > E_MAX_STATUS;}
+
+	DWORD Size		()	{return m_dwSize;}
+	DWORD Elements	()	{return (DWORD)m_indexes.size();}
+	DWORD Spaces	()	{return m_dwSize - m_dwCount;}
+	BOOL HasSpace	()	{return m_dwCount < m_dwSize;}
+	BOOL IsEmpty	()	{return m_dwCount == 0;}
+	BOOL IsValid	()	{return m_pv != nullptr;}
+
+private:
+
+	void Create(DWORD dwSize)
+	{
+		ASSERT(!IsValid() && dwSize > 0);
+
+		m_dwCurSeq	= 0;
+		m_dwCount	= 0;
+		m_dwSize	= dwSize;
+		m_pv		= (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
+
+		::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
+	}
+
+	void Destroy()
+	{
+		ASSERT(IsValid());
+
+		m_indexes.clear();
+		free((void*)m_pv);
+
+		m_pv		= nullptr;
+		m_dwSize	= 0;
+		m_dwCount	= 0;
+		m_dwCurSeq	= 0;
+	}
+
+	IndexSet& CopyIndexes(IndexSet& indexes)
+	{
+		{
+			CReadLock locallock(m_cs);
+			indexes = m_indexes;
+		}
+
+		return indexes;
+	}
+
+	void EmplaceIndex(index_type dwIndex)
+	{
+		CWriteLock locallock(m_cs);
+		m_indexes.emplace(dwIndex);
+	}
+
+	void EraseIndex(index_type dwIndex)
+	{
+		CWriteLock locallock(m_cs);
+		m_indexes.erase(dwIndex);
+	}
+
+public:
+	CRingCache	(DWORD dwSize = 0)
+	: m_pv		(nullptr)
+	, m_dwSize	(0)
+	, m_dwCount	(0)
+	, m_dwCurSeq(0)
+	{
+		Reset(dwSize);
+	}
+
+	~CRingCache()
+	{
+		Reset(0);
+	}
+
+private:
+	CRingCache(const CRingCache&);
+	CRingCache operator = (const CRingCache&);
+
+private:
+	DWORD				m_dwSize;
+	VTPTR*				m_pv;
+	char				pack1[PACK_SIZE_OF(VTPTR*)];
+	volatile DWORD		m_dwCurSeq;
+	char				pack2[PACK_SIZE_OF(DWORD)];
+	volatile DWORD		m_dwCount;
+	char				pack3[PACK_SIZE_OF(DWORD)];
+
+	CSimpleRWLock		m_cs;
+	IndexSet			m_indexes;
+};
+
+template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_EMPTY		= (T*)0x00;
+template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_LOCKED		= (T*)0x01;
+template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_MAX_STATUS	= (T*)0x0F;
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+template <class T, class index_type = DWORD, bool adjust_index = false> class CRingCache2
+{
+public:
+
+	enum EnGetResult {GR_FAIL = -1, GR_INVALID = 0, GR_VALID = 1};
+
+	typedef T*									TPTR;
+	typedef volatile T*							VTPTR;
+
+	typedef unordered_set<index_type>			IndexSet;
+	typedef typename IndexSet::const_iterator	IndexSetCI;
+	typedef typename IndexSet::iterator			IndexSetI;
+
+	static TPTR const E_EMPTY;
+	static TPTR const E_LOCKED;
+	static TPTR const E_MAX_STATUS;
+	static DWORD const MAX_SIZE;
+
+public:
+
+	static index_type& INDEX_INC(index_type& dwIndex)	{if(adjust_index) ++dwIndex; return dwIndex;}
+	static index_type& INDEX_DEC(index_type& dwIndex)	{if(adjust_index) --dwIndex; return dwIndex;}
+
+	index_type& INDEX_R2V(index_type& dwIndex)			{dwIndex += *(m_px + dwIndex) * m_dwSize; return dwIndex;}
+
+	BOOL INDEX_V2R(index_type& dwIndex)
+	{
+		index_type m = dwIndex % m_dwSize;
+		BYTE x		 = *(m_px + m);
+
+		if(dwIndex / m_dwSize != x)
+			return FALSE;
+
+		dwIndex = m;
+		return TRUE;
+	}
+
+
+private:
+
+	VTPTR& INDEX_VAL(index_type dwIndex) {return *(m_pv + dwIndex);}
+
+public:
+
+	BOOL Put(TPTR pElement, index_type& dwIndex)
+	{
+		ASSERT(pElement != nullptr);
+
+		if(!IsValid()) return FALSE;
+
+		BOOL isOK = FALSE;
+
+		while(true)
+		{
+			if(!HasSpace())
+				break;
+
+			DWORD dwCurSeq			= m_dwCurSeq;
+			index_type dwCurIndex	= dwCurSeq % m_dwSize;
+			VTPTR& pValue			= INDEX_VAL(dwCurIndex);
+
+			if(pValue == E_EMPTY)
+			{
+				if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, pElement, E_EMPTY) == E_EMPTY)
+				{
+					::InterlockedIncrement(&m_dwCount);
+					::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
+
+					dwIndex = INDEX_INC(INDEX_R2V(dwCurIndex));
+					isOK	= TRUE;
+
+					if(pElement != E_LOCKED)
+						EmplaceIndex(dwIndex);
+
+					break;
+				}
+			}
+
+			::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
+		}
+
+		return isOK;
+	}
+
+	EnGetResult Get(index_type dwIndex, TPTR* ppElement, index_type* pdwRealIndex = nullptr)
+	{
+		ASSERT(ppElement != nullptr);
+
+		if(!IsValid() || !INDEX_V2R(INDEX_DEC(dwIndex)))
+		{
+			*ppElement = nullptr;
+			return GR_FAIL;
+		}
+
+		*ppElement = (TPTR)INDEX_VAL(dwIndex);
+		if(pdwRealIndex) *pdwRealIndex = dwIndex;
+
+		return IsValidElement(*ppElement) ? GR_VALID : GR_INVALID;
+	}
+
+	BOOL Set(index_type dwIndex, TPTR pElement, TPTR* ppOldElement = nullptr, index_type* pdwRealIndex = nullptr)
+	{
+		TPTR pElement2 = nullptr;
+
+		if(pdwRealIndex == nullptr)
+			pdwRealIndex = (index_type*)_alloca(sizeof(index_type));
+
+		if(Get(dwIndex, &pElement2, pdwRealIndex) == GR_FAIL)
+			return FALSE;
+
+		if(ppOldElement != nullptr)
+			*ppOldElement = pElement2;
+
+		if(pElement == pElement2)
+			return FALSE;
+
+		int f1 = 0;
+		int f2 = 0;
+
+		if(pElement == E_EMPTY)
+		{
+			if(pElement2 == E_LOCKED)
+				f1 = -1;
+			else
+				f1 = f2 = -1;
+		}
+		else if(pElement == E_LOCKED)
+		{
+			if(pElement2 == E_EMPTY)
+				f1 = 1;
+			else
+				f2 = -1;
+		}
+		else
+		{
+			if(pElement2 == E_EMPTY)
+				f1 = f2 = 1;
+			else if(pElement2 == E_LOCKED)
+				f2 = 1;
+		}
+
+		BOOL bSetValueFirst		= (f1 + f2 >= 0);
+		index_type dwRealIndex	= *pdwRealIndex;
+
+		if(bSetValueFirst)	INDEX_VAL(dwRealIndex) = pElement;
+		if(f1 > 0)			::InterlockedIncrement(&m_dwCount);
+		if(f2 != 0)			(f2 > 0) ? EmplaceIndex(dwIndex) : EraseIndex(dwIndex);
+		if(f1 < 0)			{::InterlockedDecrement(&m_dwCount); ++(*(m_px + dwRealIndex));}
+		if(!bSetValueFirst) INDEX_VAL(dwRealIndex) = pElement;
+
+		ASSERT(Spaces() <= Size());
+
+		return TRUE;
+	}
+
+	BOOL Remove(index_type dwIndex, TPTR* ppElement = nullptr)
+	{
+		return Set(dwIndex, E_EMPTY, ppElement);
+	}
+
+	BOOL AcquireLock(index_type& dwIndex)
+	{
+		return Put(E_LOCKED, dwIndex);
+	}
+
+	BOOL ReleaseLock(index_type dwIndex, TPTR pElement)
+	{
+		ASSERT(pElement == nullptr || IsValidElement(pElement));
+
+		TPTR pElement2 = nullptr;
+		Get(dwIndex, &pElement2);
+
+		ASSERT(pElement2 == E_LOCKED);
+
+		if(pElement2 != E_LOCKED)
+			return FALSE;
+
+		return Set(dwIndex, pElement);
+	}
+
+public:
+
+	void Reset(DWORD dwSize = 0)
+	{
+		if(IsValid())
+			Destroy();
+		if(dwSize > 0)
+			Create(dwSize);
+	}
+	
+	BOOL GetAllElementIndexes(index_type ids[], DWORD& dwCount, BOOL bCopy = TRUE)
+	{
+		if(ids == nullptr || dwCount == 0)
+		{
+			dwCount = Elements();
+			return FALSE;
+		}
+
+		IndexSet* pIndexes = nullptr;
+		IndexSet indexes;
+
+		if(bCopy)
+			pIndexes = &CopyIndexes(indexes);
+		else
+			pIndexes = &m_indexes;
+
+		BOOL isOK	 = FALSE;
+		DWORD dwSize = (DWORD)pIndexes->size();
+
+		if(dwSize > 0 && dwSize <= dwCount)
+		{
+			IndexSetCI it  = pIndexes->begin();
+			IndexSetCI end = pIndexes->end();
+
+			for(int i = 0; it != end; ++it, ++i)
+				ids[i] = *it;
+
+			isOK = TRUE;
+		}
+
+		dwCount = dwSize;
+
+		return isOK;
+	}
+	
+	unique_ptr<index_type[]> GetAllElementIndexes(DWORD& dwCount, BOOL bCopy = TRUE)
+	{
+		IndexSet* pIndexes = nullptr;
+		IndexSet indexes;
+
+		if(bCopy)
+			pIndexes = &CopyIndexes(indexes);
+		else
+			pIndexes = &m_indexes;
+
+		unique_ptr<index_type[]> ids;
+		dwCount = (DWORD)pIndexes->size();
+
+		if(dwCount > 0)
+		{
+			ids.reset(new index_type[dwCount]);
+
+			IndexSetCI it  = pIndexes->begin();
+			IndexSetCI end = pIndexes->end();
+
+			for(int i = 0; it != end; ++it, ++i)
+				ids[i] = *it;
+		}
+
+		return ids;
+	}
+
+	static BOOL IsValidElement(TPTR pElement) {return pElement > E_MAX_STATUS;}
+
+	DWORD Size		()	{return m_dwSize;}
+	DWORD Elements	()	{return (DWORD)m_indexes.size();}
+	DWORD Spaces	()	{return m_dwSize - m_dwCount;}
+	BOOL HasSpace	()	{return m_dwCount < m_dwSize;}
+	BOOL IsEmpty	()	{return m_dwCount == 0;}
+	BOOL IsValid	()	{return m_pv != nullptr;}
+
+private:
+
+	void Create(DWORD dwSize)
+	{
+		ASSERT(!IsValid() && dwSize > 0 && dwSize <= MAX_SIZE);
+
+		m_dwCurSeq	= 0;
+		m_dwCount	= 0;
+		m_dwSize	= dwSize;
+		m_pv		= (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
+		m_px		= (BYTE*)malloc(m_dwSize * sizeof(BYTE));
+
+		::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
+		::ZeroMemory(m_px, m_dwSize * sizeof(BYTE));
+	}
+
+	void Destroy()
+	{
+		ASSERT(IsValid());
+
+		m_indexes.clear();
+		free((void*)m_pv);
+		free((void*)m_px);
+
+		m_pv		= nullptr;
+		m_px		= nullptr;
+		m_dwSize	= 0;
+		m_dwCount	= 0;
+		m_dwCurSeq	= 0;
+	}
+
+	IndexSet& CopyIndexes(IndexSet& indexes)
+	{
+		{
+			CReadLock locallock(m_cs);
+			indexes = m_indexes;
+		}
+
+		return indexes;
+	}
+
+	void EmplaceIndex(index_type dwIndex)
+	{
+		CWriteLock locallock(m_cs);
+		m_indexes.emplace(dwIndex);
+	}
+
+	void EraseIndex(index_type dwIndex)
+	{
+		CWriteLock locallock(m_cs);
+		m_indexes.erase(dwIndex);
+	}
+
+public:
+	CRingCache2	(DWORD dwSize = 0)
+	: m_pv		(nullptr)
+	, m_px		(nullptr)
+	, m_dwSize	(0)
+	, m_dwCount	(0)
+	, m_dwCurSeq(0)
+	{
+		Reset(dwSize);
+	}
+
+	~CRingCache2()
+	{
+		Reset(0);
+	}
+
+private:
+	CRingCache2(const CRingCache2&);
+	CRingCache2 operator = (const CRingCache2&);
+
+private:
+	DWORD				m_dwSize;
+	VTPTR*				m_pv;
+	char				pack1[PACK_SIZE_OF(VTPTR*)];
+	BYTE*				m_px;
+	char				pack2[PACK_SIZE_OF(BYTE*)];
+	volatile DWORD		m_dwCurSeq;
+	char				pack3[PACK_SIZE_OF(DWORD)];
+	volatile DWORD		m_dwCount;
+	char				pack4[PACK_SIZE_OF(DWORD)];
+
+	CSimpleRWLock		m_cs;
+	IndexSet			m_indexes;
+};
+
+template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_EMPTY		= (T*)0x00;
+template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_LOCKED		= (T*)0x01;
+template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_MAX_STATUS	= (T*)0x0F;
+
+template <class T, class index_type, bool adjust_index> DWORD const CRingCache2<T, index_type, adjust_index>::MAX_SIZE	= 
+#if !defined(_WIN64)
+																														  0x00FFFFFF
+#else
+																														  0xFFFFFFFF
+#endif
+																																	;
+// ------------------------------------------------------------------------------------------------------------- //
+
+template <class T> class CRingPool
+{
+private:
+
+	typedef T*			TPTR;
+	typedef volatile T*	VTPTR;
+
+	static TPTR const E_EMPTY;
+	static TPTR const E_LOCKED;
+	static TPTR const E_RELEASED;
+	static TPTR const E_OCCUPIED;
+	static TPTR const E_MAX_STATUS;
+
+private:
+
+	VTPTR& INDEX_VAL(DWORD dwIndex) {return *(m_pv + dwIndex);}
+
+public:
+
+	BOOL TryPut(TPTR pElement)
+	{
+		ASSERT(pElement != nullptr);
+
+		if(!IsValid()) return FALSE;
+
+		BOOL isOK = FALSE;
+
+		while(true)
+		{
+			BOOL bOccupy = FALSE;
+			DWORD seqPut = m_seqPut;
+
+			if(!HasPutSpace(seqPut))
+				break;
+
+			DWORD dwIndex = seqPut % m_dwSize;
+			VTPTR& pValue = INDEX_VAL(dwIndex);
+
+			if(pValue == E_RELEASED)
+			{
+				if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, E_OCCUPIED, E_RELEASED) == E_RELEASED)
+					bOccupy = TRUE;
+				else
+					continue;
+			}
+
+			if(pValue == E_EMPTY || bOccupy)
+			{
+				if(::InterlockedCompareExchange(&m_seqPut, seqPut + 1, seqPut) == seqPut)
+				{
+					pValue	= pElement;
+					isOK	= TRUE;
+
+					break;
+				}
+			}
+			else if(pValue == E_LOCKED)
+				break;
+		}
+
+		return isOK;
+	}
+
+	BOOL TryGet(TPTR* ppElement)
+	{
+		ASSERT(ppElement != nullptr);
+
+		if(!IsValid()) return FALSE;
+
+		BOOL isOK = FALSE;
+
+		while(true)
+		{
+			DWORD seqGet = m_seqGet;
+
+			if(!HasGetSpace(seqGet))
+				break;
+
+			DWORD dwIndex = seqGet % m_dwSize;
+			VTPTR& pValue = INDEX_VAL(dwIndex);
+
+			if(pValue == E_LOCKED)
+				break;
+			else if(pValue != E_EMPTY && pValue != E_RELEASED && pValue != E_OCCUPIED)
+			{
+				if(::InterlockedCompareExchange(&m_seqGet, seqGet + 1, seqGet) == seqGet)
+				{
+					ASSERT(pValue > E_MAX_STATUS);
+
+					*(ppElement)	= (TPTR)pValue;
+					pValue			= E_EMPTY;
+					isOK			= TRUE;
+
+					break;
+				}
+			}
+		}
+
+		return isOK;
+	}
+
+	BOOL TryLock(TPTR* ppElement, DWORD& dwIndex)
+	{
+		ASSERT(ppElement != nullptr);
+
+		if(!IsValid()) return FALSE;
+
+		BOOL isOK = FALSE;
+
+		while(true)
+		{
+			DWORD seqGet = m_seqGet;
+
+			if(!HasGetSpace(seqGet))
+				break;
+
+			dwIndex			= seqGet % m_dwSize;
+			VTPTR& pValue	= INDEX_VAL(dwIndex);
+
+			if(pValue == E_LOCKED)
+				break;
+			else if(pValue != E_EMPTY && pValue != E_RELEASED && pValue != E_OCCUPIED)
+			{
+				if(::InterlockedCompareExchange(&m_seqGet, seqGet + 1, seqGet) == seqGet)
+				{
+					ASSERT(pValue > E_MAX_STATUS);
+
+					*(ppElement)	= (TPTR)pValue;
+					pValue			= E_LOCKED;
+					isOK			= TRUE;
+
+					break;
+				}
+			}
+		}
+
+		return isOK;
+	}
+
+	BOOL ReleaseLock(TPTR pElement, DWORD dwIndex)
+	{
+		ASSERT(dwIndex < m_dwSize);
+		ASSERT(pElement == nullptr || pElement > E_MAX_STATUS);
+
+		if(!IsValid()) return FALSE;
+
+		VTPTR& pValue = INDEX_VAL(dwIndex);
+		VERIFY(pValue == E_LOCKED);
+
+		if(pElement != nullptr)
+		{
+			for(DWORD i = 0; ; i++)
+			{
+				if(TryPut(pElement))
+					break;
+
+				DWORD dwPutIndex = m_seqPut % m_dwSize;
+
+				if(dwIndex == dwPutIndex)
+				{
+					pValue = pElement;
+					::InterlockedIncrement(&m_seqPut);
+
+					return TRUE;
+				}
+
+				::YieldThread(i);
+			}
+		}
+
+		pValue = E_RELEASED;
+
+		return TRUE;
+	}
+
+public:
+
+	void Reset(DWORD dwSize = 0)
+	{
+		if(IsValid())
+			Destroy();
+		if(dwSize > 0)
+			Create(dwSize);
+	}
+
+	DWORD Size()		{return m_dwSize;}
+	DWORD Elements()	{return m_seqPut - m_seqGet;}
+	BOOL IsFull()		{return Elements() == Size();}
+	BOOL IsEmpty()		{return Elements() == 0;}
+	BOOL IsValid()		{return m_pv != nullptr;}
+
+private:
+
+	BOOL HasPutSpace(DWORD seqPut)
+	{
+		return ((int)(seqPut - m_seqGet) < (int)m_dwSize);
+	}
+
+	BOOL HasGetSpace(DWORD seqGet)
+	{
+		return ((int)(m_seqPut - seqGet) > 0);
+	}
+
+	void Create(DWORD dwSize)
+	{
+		ASSERT(!IsValid() && dwSize > 0);
+
+		m_seqPut = 0;
+		m_seqGet = 0;
+		m_dwSize = dwSize;
+		m_pv	 = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
+
+		::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
+	}
+
+	void Destroy()
+	{
+		ASSERT(IsValid());
+
+		free((void*)m_pv);
+		m_pv = nullptr;
+		m_dwSize = 0;
+		m_seqPut = 0;
+		m_seqGet = 0;
+	}
+
+public:
+	CRingPool(DWORD dwSize = 0)
+	: m_pv(nullptr)
+	, m_dwSize(0)
+	, m_seqPut(0)
+	, m_seqGet(0)
+	{
+		Reset(dwSize);
+	}
+
+	~CRingPool()
+	{
+		Reset(0);
+	}
+
+private:
+	CRingPool(const CRingPool&);
+	CRingPool operator = (const CRingPool&);
+
+private:
+	DWORD				m_dwSize;
+	VTPTR*				m_pv;
+	char				pack1[PACK_SIZE_OF(VTPTR*)];
+	volatile DWORD		m_seqPut;
+	char				pack2[PACK_SIZE_OF(DWORD)];
+	volatile DWORD		m_seqGet;
+	char				pack3[PACK_SIZE_OF(DWORD)];
+};
+
+template <class T> T* const CRingPool<T>::E_EMPTY		= (T*)0x00;
+template <class T> T* const CRingPool<T>::E_LOCKED		= (T*)0x01;
+template <class T> T* const CRingPool<T>::E_RELEASED	= (T*)0x02;
+template <class T> T* const CRingPool<T>::E_OCCUPIED	= (T*)0x03;
+template <class T> T* const CRingPool<T>::E_MAX_STATUS	= (T*)0x0F;
+
+// ------------------------------------------------------------------------------------------------------------- //
+
+template <class T> class CCASQueue
+{
+private:
+	struct Node;
+	typedef Node*			NPTR;
+	typedef volatile Node*	VNPTR;
+	typedef volatile ULONG	VLONG;
+
+	struct Node
+	{
+		T*		pValue;
+		VNPTR	pNext;
+
+		Node(T* val, NPTR next = nullptr)
+			: pValue(val), pNext(next)
+		{
+
+		}
+	};
+
+public:
+
+	void PushBack(T* pVal)
+	{
+		ASSERT(pVal != nullptr);
+
+		VNPTR pTail	= nullptr;
+		NPTR pNode	= new Node(pVal);
+
+		while(true)
+		{
+			pTail = m_pTail;
+
+			if(::InterlockedCompareExchangePointer((volatile PVOID*)&m_pTail, (PVOID)pNode, (PVOID)pTail) == pTail)
+			{
+				pTail->pNext = pNode;
+				break;
+			}
+		}
+
+		::InterlockedIncrement(&m_lSize);
+	}
+
+	void UnsafePushBack(T* pVal)
+	{
+		ASSERT(pVal != nullptr);
+
+		NPTR pNode		= new Node(pVal);
+		m_pTail->pNext	= pNode;
+		m_pTail			= pNode;
+		
+		::InterlockedIncrement(&m_lSize);
+	}
+
+	BOOL PopFront(T** ppVal)
+	{
+		ASSERT(ppVal != nullptr);
+
+		if(IsEmpty())
+			return FALSE;
+
+		BOOL isOK	= FALSE;
+		NPTR pHead	= nullptr;
+		NPTR pNext	= nullptr;
+		T* pVal		= nullptr;
+
+		while(true)
+		{
+			while(::InterlockedCompareExchange(&m_lLock, 1, 0) != 0)
+				::YieldProcessor();
+
+			pHead = (NPTR)m_pHead;
+			pNext = (NPTR)pHead->pNext;
+
+			if(pNext == nullptr)
+			{
+				m_lLock = 0;
+				break;
+			}
+
+			*ppVal	= pNext->pValue;
+			m_pHead	= pNext;
+
+			m_lLock = 0;
+			isOK	= TRUE;
+
+			::InterlockedDecrement(&m_lSize);
+
+			delete pHead;
+			break;
+		}
+
+		return isOK;
+	}
+
+	BOOL UnsafePopFront(T** ppVal)
+	{
+		if(!UnsafePeekFront(ppVal))
+			return FALSE;
+
+		NPTR pHead	= (NPTR)m_pHead;
+		NPTR pNext	= (NPTR)pHead->pNext;
+		m_pHead		= pNext;
+
+		::InterlockedDecrement(&m_lSize);
+
+		delete pHead;
+		return TRUE;
+	}
+
+	BOOL UnsafePeekFront(T** ppVal)
+	{
+		ASSERT(ppVal != nullptr);
+
+		NPTR pNext = (NPTR)m_pHead->pNext;
+
+		if(pNext == nullptr)
+			return FALSE;
+
+		*ppVal = pNext->pValue;
+
+		return TRUE;
+	}
+
+public:
+
+	ULONG Size()	{return m_lSize;}
+	BOOL IsEmpty()	{return m_lSize == 0;}
+
+public:
+
+	CCASQueue() : m_lLock(0), m_lSize(0)
+	{
+		NPTR pHead = new Node(nullptr);
+		m_pHead = m_pTail = pHead;
+	}
+
+	~CCASQueue()
+	{
+		ASSERT(m_lLock == 0);
+		ASSERT(m_lSize == 0);
+		ASSERT(m_pHead != nullptr);
+		ASSERT(m_pHead->pNext == nullptr);
+
+		while(m_pHead != nullptr)
+		{
+			VNPTR pNode = m_pHead->pNext;
+
+			delete m_pHead;
+			m_pHead = pNode;
+		}
+	}
+
+private:
+	VLONG	m_lLock;
+	VLONG	m_lSize;
+	VNPTR	m_pHead;
+	VNPTR	m_pTail;
+};
+
+#if !defined (_WIN64)
+	#pragma pack(pop)
+#endif

+ 1241 - 0
common/Src/STLHelper.h

@@ -0,0 +1,1241 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "GeneralHelper.h"
+
+#include <memory>
+#include <string>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <queue>
+#include <stack>
+#include <list>
+#include <set>
+#include <map>
+#if _MSC_VER >= 1500
+	#include <unordered_set>
+	#include <unordered_map>
+
+	#define hash_set			unordered_set
+	#define hash_map			unordered_map
+	#define hash_multimap		unordered_multimap
+#else
+	#include <hash_set>
+	#include <hash_map>
+
+	#define unordered_set		hash_set
+	#define unordered_map		hash_map
+	#define unordered_multimap	hash_multimap
+#endif
+
+
+using namespace std;
+using namespace stdext;
+using namespace std::tr1;
+
+typedef	wstring		CStdStringW;
+typedef string		CStdStringA;
+
+#ifdef _UNICODE
+	typedef	CStdStringW		CStdString;
+#else
+	typedef CStdStringA		CStdString;
+#endif
+
+typedef list<short>						short_list;
+typedef list<int>						int_list;
+typedef list<long>						long_list;
+typedef list<__int64>					int64_list;
+typedef list<unsigned short>			ushort_list;
+typedef list<unsigned int>				uint_list;
+typedef list<unsigned long>				ulong_list;
+typedef list<unsigned __int64>			uint64_list;
+typedef list<float>						float_list;
+typedef list<double>					double_list;
+typedef stack<short>					short_stack;
+typedef stack<int>						int_stack;
+typedef stack<long>						long_stack;
+typedef stack<__int64>					int64_stack;
+typedef stack<unsigned short>			ushort_stack;
+typedef stack<unsigned int>				uint_stack;
+typedef stack<unsigned long>			ulong_stack;
+typedef stack<unsigned __int64>			uint64_stack;
+typedef stack<float>					float_stack;
+typedef stack<double>					double_stack;
+typedef queue<short>					short_queue;
+typedef queue<int>						int_queue;
+typedef queue<long>						long_queue;
+typedef queue<__int64>					int64_queue;
+typedef queue<unsigned short>			ushort_queue;
+typedef queue<unsigned int>				uint_queue;
+typedef queue<unsigned long>			ulong_queue;
+typedef queue<unsigned __int64>			uint64_queue;
+typedef queue<float>					float_queue;
+typedef queue<double>					double_queue;
+typedef deque<short>					short_deque;
+typedef deque<int>						int_deque;
+typedef deque<long>						long_deque;
+typedef deque<__int64>					int64_deque;
+typedef deque<unsigned short>			ushort_deque;
+typedef deque<unsigned int>				uint_deque;
+typedef deque<unsigned long>			ulong_deque;
+typedef deque<unsigned __int64>			uint64_deque;
+typedef deque<float>					float_deque;
+typedef deque<double>					double_deque;
+typedef vector<short>					short_vector;
+typedef vector<int>						int_vector;
+typedef vector<long>					long_vector;
+typedef vector<__int64>					int64_vector;
+typedef vector<unsigned short>			ushort_vector;
+typedef vector<unsigned int>			uint_vector;
+typedef vector<unsigned long>			ulong_vector;
+typedef vector<unsigned __int64>		uint64_vector;
+typedef vector<float>					float_vector;
+typedef vector<double>					double_vector;
+typedef set<short>						short_set;
+typedef set<int>						int_set;
+typedef set<long>						long_set;
+typedef set<__int64>					int64_set;
+typedef set<unsigned short>				ushort_set;
+typedef set<unsigned int>				uint_set;
+typedef set<unsigned long>				ulong_set;
+typedef set<unsigned __int64>			uint64_set;
+typedef set<float>						float_set;
+typedef set<double>						double_set;
+typedef hash_set<short>					short_hash_set;
+typedef hash_set<int>					int_hash_set;
+typedef hash_set<long>					long_hash_set;
+typedef hash_set<__int64>				int64_hash_set;
+typedef hash_set<unsigned short>		ushort_hash_set;
+typedef hash_set<unsigned int>			uint_hash_set;
+typedef hash_set<unsigned long>			ulong_hash_set;
+typedef hash_set<unsigned __int64>		uint64_hash_set;
+typedef hash_set<float>					float_hash_set;
+typedef hash_set<double>				double_hash_set;
+typedef unordered_set<short>			short_unordered_set;
+typedef unordered_set<int>				int_unordered_set;
+typedef unordered_set<long>				long_unordered_set;
+typedef unordered_set<__int64>			int64_unordered_set;
+typedef unordered_set<unsigned short>	ushort_unordered_set;
+typedef unordered_set<unsigned int>		uint_unordered_set;
+typedef unordered_set<unsigned long>	ulong_unordered_set;
+typedef unordered_set<unsigned __int64>	uint64_unordered_set;
+typedef unordered_set<float>			float_unordered_set;
+typedef unordered_set<double>			double_unordered_set;
+
+typedef list<INT_PTR>					int_ptr_list;
+typedef list<LONG_PTR>					long_ptr_list;
+typedef list<UINT_PTR>					uint_ptr_list;
+typedef list<ULONG_PTR>					ulong_ptr_list;
+typedef stack<INT_PTR>					int_ptr_stack;
+typedef stack<LONG_PTR>					long_ptr_stack;
+typedef stack<UINT_PTR>					uint_ptr_stack;
+typedef stack<ULONG_PTR>				ulong_ptr_stack;
+typedef queue<INT_PTR>					int_ptr_queue;
+typedef queue<LONG_PTR>					long_ptr_queue;
+typedef queue<UINT_PTR>					uint_ptr_queue;
+typedef queue<ULONG_PTR>				ulong_ptr_queue;
+typedef deque<INT_PTR>					int_ptr_deque;
+typedef deque<LONG_PTR>					long_ptr_deque;
+typedef deque<UINT_PTR>					uint_ptr_deque;
+typedef deque<ULONG_PTR>				ulong_ptr_deque;
+typedef vector<INT_PTR>					int_ptr_vector;
+typedef vector<LONG_PTR>				long_ptr_vector;
+typedef vector<UINT_PTR>				uint_ptr_vector;
+typedef vector<ULONG_PTR>				ulong_ptr_vector;
+typedef set<INT_PTR>					int_ptr_set;
+typedef set<LONG_PTR>					long_ptr_set;
+typedef set<UINT_PTR>					uint_ptr_set;
+typedef set<ULONG_PTR>					ulong_ptr_set;
+typedef hash_set<INT_PTR>				int_ptr_hash_set;
+typedef hash_set<LONG_PTR>				long_ptr_hash_set;
+typedef hash_set<UINT_PTR>				uint_ptr_hash_set;
+typedef hash_set<ULONG_PTR>				ulong_ptr_hash_set;
+typedef unordered_set<INT_PTR>			int_ptr_unordered_set;
+typedef unordered_set<LONG_PTR>			long_ptr_unordered_set;
+typedef unordered_set<UINT_PTR>			uint_ptr_unordered_set;
+typedef unordered_set<ULONG_PTR>		ulong_ptr_unordered_set;
+
+/*****************************************************************************/
+/******************************** 容器操作函数 *******************************/
+
+/**********************************
+描述: 清除普通集合 , 适用于 vector<Object> / list<Object>
+参数: 
+	v		: vector / list / set
+
+返回值: 		
+**********************************/
+template<class Set> void ClearSet(Set& v)
+{
+	v.clear();
+}
+
+template<class Set> struct Set_Cleaner
+{
+	static void Clear(Set& v) {ClearSet(v);}
+};
+
+/**********************************
+描述: 清除指针集合 (清除前先释放指针), 适用于 vector<Object*> / list<Object*>
+参数: 
+		v		: vector / list / set
+
+返回值: 		
+**********************************/
+template<class PtrSet> void ClearPtrSet(PtrSet& v)
+{
+	for(PtrSet::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+		delete (*it);
+
+	v.clear();
+}
+
+template<class PtrSet> struct PtrSet_Cleaner
+{
+	static void Clear(PtrSet& v) {ClearPtrSet(v);}
+};
+
+/**********************************
+描述: 清除指针集合 (指针同时又指向数组), 适用于 vector<Object*[]> / list<Object*[]>
+参数: 
+		v		: vector / list / set
+
+返回值: 		
+**********************************/
+template<class PtrArraySet> void ClearPtrArraySet(PtrArraySet& v)
+{
+	for(PtrArraySet::iterator	it	= v.begin(),
+								end	= v.end(); 
+								it != end;
+								++it)
+		delete[] (*it);
+
+	v.clear();
+}
+
+template<class PtrArraySet> struct PtrArraySet_Cleaner
+{
+	static void Clear(PtrArraySet& v) {ClearPtrArraySet(v);}
+};
+
+/**********************************
+描述: 清除普通影射 , 适用于 map<key, value>
+参数: 
+	v		: map
+
+返回值: 		
+**********************************/
+template<class Map> void ClearMap(Map& v)
+{
+	v.clear();
+}
+
+template<class Map> struct Map_Cleaner
+{
+	static void Clear(Map& v) {ClearMap(v);}
+};
+
+/**********************************
+描述: 清除指针影射 (清除前先释放指针), 适用于 map<key, Object*>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class PtrMap> void ClearPtrMap(PtrMap& v)
+{
+	for(PtrMap::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+		delete it->second;
+
+	v.clear();
+}
+
+template<class PtrMap> struct PtrMap_Cleaner
+{
+	static void Clear(PtrMap& v) {ClearPtrMap(v);}
+};
+
+/**********************************
+描述: 清除指针影射 (指针同时又指向数组), 适用于 map<key, Object*[]>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class PtrArrayMap> void ClearPtrArrayMap(PtrArrayMap& v)
+{
+	for(PtrArrayMap::iterator	it	= v.begin(),
+								end	= v.end(); 
+								it != end;
+								++it)
+		delete[] it->second;
+
+	v.clear();
+}
+
+template<class PtrArrayMap> struct PtrArrayMap_Cleaner
+{
+	static void Clear(PtrArrayMap& v) {ClearPtrArrayMap(v);}
+};
+
+/**********************************
+描述: 清除集合-集合 (清除前先清除内部集合), 适用于 set<vector<Object>*>
+参数: 
+		v		: vector / list / set
+
+返回值: 		
+**********************************/
+template<class SetSet> void ClearSetSet(SetSet& v)
+{
+	for(SetSet::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+	{
+		(*it)->clear();
+		delete (*it);
+	}
+
+	v.clear();
+}
+
+template<class SetSet> struct SetSet_Cleaner
+{
+	static void Clear(SetSet& v) {ClearSetSet(v);}
+};
+
+/**********************************
+描述: 清除指针集合-集合 (清除前先清除内部指针集合), 适用于 set<vector<Object*>*>
+参数: 
+		v		: vector / list / set
+
+返回值: 		
+**********************************/
+template<class PtrSetSet> void ClearPtrSetSet(PtrSetSet& v)
+{
+	for(PtrSetSet::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+	{
+		ClearPtrSet(**it);
+		delete (*it);
+	}
+
+	v.clear();
+}
+
+template<class PtrSetSet> struct PtrSetSet_Cleaner
+{
+	static void Clear(PtrSetSet& v) {ClearPtrSetSet(v);}
+};
+
+/**********************************
+描述: 清除指针数组集合影射 (清除前先清除指针数组集合), 适用于 map<vector<Object*[]>*>
+参数: 
+		v		: vector / list / set
+
+返回值: 		
+**********************************/
+template<class PtrArraySetSet> void ClearPtrArraySetSet(PtrArraySetSet& v)
+{
+	for(PtrArraySetSet::iterator	it	= v.begin(),
+									end	= v.end(); 
+									it != end;
+									++it)
+	{
+		ClearPtrArraySet(**it);
+		delete (*it);
+	}
+
+	v.clear();
+}
+
+template<class PtrArraySetSet> struct PtrArraySetSet_Cleaner
+{
+	static void Clear(PtrArraySetSet& v) {ClearPtrArraySetSet(v);}
+};
+
+/**********************************
+描述: 清除集合影射 (清除前先清除集合), 适用于 map<key, vector<Object>*>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class SetMap> void ClearSetMap(SetMap& v)
+{
+	for(SetMap::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+	{
+		it->second->clear();
+		delete it->second;
+	}
+
+	v.clear();
+}
+
+template<class SetMap> struct SetMap_Cleaner
+{
+	static void Clear(SetMap& v) {ClearSetMap(v);}
+};
+
+/**********************************
+描述: 清除指针集合影射 (清除前先清除指针集合), 适用于 map<key, vector<Object*>*>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class PtrSetMap> void ClearPtrSetMap(PtrSetMap& v)
+{
+	for(PtrSetMap::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+	{
+		ClearPtrSet(*(it->second));
+		delete it->second;
+	}
+
+	v.clear();
+}
+
+template<class PtrSetMap> struct PtrSetMap_Cleaner
+{
+	static void Clear(PtrSetMap& v) {ClearPtrSetMap(v);}
+};
+
+/**********************************
+描述: 清除指针数组集合影射 (清除前先清除指针数组集合), 适用于 map<key, vector<Object*[]>*>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class PtrArraySetMap> void ClearPtrArraySetMap(PtrArraySetMap& v)
+{
+	for(PtrArraySetMap::iterator	it	= v.begin(),
+									end	= v.end(); 
+									it != end;
+									++it)
+	{
+		ClearPtrArraySet(*(it->second));
+		delete it->second;
+	}
+
+	v.clear();
+}
+
+template<class PtrArraySetMap> struct PtrArraySetMap_Cleaner
+{
+	static void Clear(PtrArraySetMap& v) {ClearPtrArraySetMap(v);}
+};
+
+/**********************************
+描述: 清除映射-影射 (清除前先清除内部映射), 适用于 map<key, map<key2, Object>*>
+参数: 
+v		: map
+
+返回值: 		
+**********************************/
+template<class MapMap> void ClearMapMap(MapMap& v)
+{
+	for(MapMap::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+	{
+		it->second->clear();
+		delete it->second;
+	}
+
+	v.clear();
+}
+
+template<class MapMap> struct MapMap_Cleaner
+{
+	static void Clear(MapMap& v) {ClearMapMap(v);}
+};
+
+/**********************************
+描述: 清除指针映射-影射 (清除前先清除指针内部映射), 适用于 map<key, map<key2, Object*>*>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class PtrMapMap> void ClearPtrMapMap(PtrMapMap& v)
+{
+	for(PtrMapMap::iterator	it	= v.begin(),
+							end	= v.end(); 
+							it != end;
+							++it)
+	{
+		ClearPtrMap(*(it->second));
+		delete it->second;
+	}
+
+	v.clear();
+}
+
+template<class PtrMapMap> struct PtrMapMap_Cleaner
+{
+	static void Clear(PtrMapMap& v) {ClearPtrMapMap(v);}
+};
+
+/**********************************
+描述: 清除指针映射-影射 (清除前先清除指针数组内部映射), 适用于 map<key, map<key2, Object*[]>*>
+参数: 
+		v		: map
+
+返回值: 		
+**********************************/
+template<class PtrArrayMapMap> void ClearPtrArrayMapMap(PtrArrayMapMap& v)
+{
+	for(PtrArrayMapMap::iterator	it	= v.begin(),
+									end	= v.end(); 
+									it != end;
+									++it)
+	{
+		ClearPtrArrayMap(*(it->second));
+		delete it->second;
+	}
+
+	v.clear();
+}
+
+template<class PtrArrayMapMap> struct PtrArrayMapMap_Cleaner
+{
+	static void Clear(PtrArrayMapMap& v) {ClearPtrArrayMapMap(v);}
+};
+
+/************************************************************************/
+/*                           指针集合容器                               */
+/************************************************************************/
+template<class Set, class Cleaner> struct SetWrapper
+{
+	typedef typename Set::iterator			iterator;
+	typedef typename Set::const_iterator	const_iterator;
+	typedef typename Set::value_type		value_type;
+	typedef typename Set::reference			reference;
+	typedef typename Set::const_reference	const_reference;
+	typedef typename Set::pointer			pointer;
+	typedef typename Set::const_pointer		const_pointer;
+	typedef typename Set::size_type			size_type;
+	typedef typename Set::difference_type	difference_type;
+
+	SetWrapper()
+	{
+	}
+
+	virtual ~SetWrapper()
+	{
+		Clear();
+	}
+
+	void Clear()
+	{
+		if(!IsEmpty())
+		{
+			Cleaner::Clear(m_set);
+		}
+	}
+
+	Set& operator *			()			{return m_set;}
+	const Set& operator *	()	const	{return m_set;}
+	Set* operator ->		()			{return &m_set;}
+	const Set* operator ->	()	const	{return &m_set;}
+	Set& Get				()			{return m_set;}
+	operator Set&			()			{return m_set;}
+	bool IsEmpty			()	const	{return m_set.empty();}
+	size_t Size				()	const	{return m_set.size();}
+
+protected:
+	Set m_set;
+
+	DECLARE_NO_COPY_CLASS(SetWrapper)
+};
+
+template<class Set, class Cleaner> struct VectorWrapper : public SetWrapper<Set, Cleaner>
+{
+	VectorWrapper()
+	{
+	}
+
+	reference		operator []	(size_type i)			{return m_set[i];}
+	const_reference operator []	(size_type i)	const	{return m_set[i];}
+
+	DECLARE_NO_COPY_CLASS(VectorWrapper)
+};
+
+/************************************************************************/
+/*                         指针数组集合容器                             */
+/************************************************************************/
+
+
+/************************************************************************/
+/*                           指针映射容器                               */
+/************************************************************************/
+template<class Map, class Cleaner> struct MapWrapper
+{
+	typedef typename Map::iterator			iterator;
+	typedef typename Map::const_iterator	const_iterator;
+	typedef typename Map::key_type			key_type;
+	typedef typename Map::mapped_type		mapped_type;
+	typedef typename Map::value_type		value_type;
+	typedef typename Map::reference			reference;
+	typedef typename Map::const_reference	const_reference;
+	typedef typename Map::pointer			pointer;
+	typedef typename Map::size_type			size_type;
+	typedef typename Map::difference_type	difference_type;
+
+	MapWrapper()
+	{
+	}
+
+	~MapWrapper()
+	{
+		Clear();
+	}
+
+	void Clear()
+	{
+		if(!IsEmpty())
+		{
+			Cleaner::Clear(m_map);
+		}
+	}
+
+	Map&				operator *	()								{return m_map;}
+	const Map&			operator *	()						const	{return m_map;}
+	Map*				operator ->	()								{return &m_map;}
+	const Map*			operator ->	()						const	{return &m_map;}
+	mapped_type&		operator []	(const key_type& key)			{return m_map[key];}
+	const mapped_type&	operator []	(const key_type& key)	const	{return m_map[key];}
+	Map& Get			()			{return m_map;}
+	operator Map&		()			{return m_map;}
+	bool IsEmpty		()	const	{return m_map.empty();}
+	size_t Size			()	const	{return m_map.size();}
+
+private:
+	Map m_map;
+
+	DECLARE_NO_COPY_CLASS(MapWrapper)
+};
+
+/************************************************************************/
+/*                            比较仿函数                                */
+/************************************************************************/
+
+template<class T> struct char_comparator
+{
+	typedef T	row_type;
+	static row_type row_type_value(const T& v)		{return (row_type)v;}
+	static bool equal_to(const T& v1, const T& v2)	{return strcmp(v1, v2) == 0;}
+};
+
+template<class T> struct char_nc_comparator
+{
+	typedef T	row_type;
+	static row_type row_type_value(const T& v)		{return (row_type)v;}
+	static bool equal_to(const T& v1, const T& v2)	{return stricmp(v1, v2) == 0;}
+};
+
+template<class T> struct wchar_comparator
+{
+	typedef T	row_type;
+	static row_type row_type_value(const T& v)		{return (row_type)v;}
+	static bool equal_to(const T& v1, const T& v2)	{return wcscmp(v1, v2) == 0;}
+};
+
+template<class T> struct wchar_nc_comparator
+{
+	typedef T	row_type;
+	static row_type row_type_value(const T& v)		{return (row_type)v;}
+	static bool equal_to(const T& v1, const T& v2)	{return wcsicmp(v1, v2) == 0;}
+};
+
+template<class T> struct cstring_comparator
+{
+	typedef typename T::PCXSTR	row_type;
+	static row_type row_type_value(const T& v)		{return (row_type)v;}
+	static bool equal_to(const T& v1, const T& v2)	{return v1.Compare(v2) == 0;}
+};
+
+template<class T> struct cstring_nc_comparator
+{
+	typedef typename T::PCXSTR	row_type;
+	static row_type row_type_value(const T& v)		{return (row_type)v;}
+	static bool equal_to(const T& v1, const T& v2)	{return v1.CompareNoCase(v2) == 0;}
+};
+
+// char/wchar_t/CStringX hash function
+template<class T, class H> struct str_hash_func_t
+{
+	struct hash
+	{
+		size_t operator() (const T& t) const
+		{
+			return hash_value(H::row_type_value(t));
+		}
+	};
+
+	struct equal_to
+	{
+		bool operator() (const T& t1, const T& t2) const
+		{
+			return H::equal_to(t1, t2);
+		}
+	};
+
+};
+
+// char/wchar_t/CStringX hash function (no case)
+template<class T, class H> struct str_nc_hash_func_t
+{
+	struct hash
+	{
+		size_t operator() (const T& t) const
+		{
+			size_t _Val		 = 2166136261U;
+			H::row_type lpsz = H::row_type_value(t);
+			char c;
+
+			while((c = *lpsz++) != 0) 
+			{
+				if(c >= 'A' && c <= 'Z')
+					c += 32;
+
+				_Val = 16777619U * _Val ^ c;
+
+			}
+
+			return _Val;
+		}
+	};
+
+	struct equal_to
+	{
+		bool operator() (const T& t1, const T& t2) const
+		{
+			return H::equal_to(t1, t2);
+		}
+	};
+
+};
+
+typedef str_hash_func_t<LPCSTR, char_comparator<LPCSTR>>			str_hash_func;
+typedef str_hash_func_t<LPCWSTR, wchar_comparator<LPCWSTR>>			wstr_hash_func;
+typedef str_hash_func_t<CStringA, cstring_comparator<CStringA>>		cstringa_hash_func;
+typedef str_hash_func_t<CStringW, cstring_comparator<CStringW>>		cstringw_hash_func;
+typedef str_nc_hash_func_t<LPCSTR, char_comparator<LPCSTR>>			str_nc_hash_func;
+typedef str_nc_hash_func_t<LPCWSTR, wchar_comparator<LPCWSTR>>		wstr_nc_hash_func;
+typedef str_nc_hash_func_t<CStringA, cstring_comparator<CStringA>>	cstringa_nc_hash_func;
+typedef str_nc_hash_func_t<CStringW, cstring_comparator<CStringW>>	cstringw_nc_hash_func;
+
+#ifdef _UNICODE
+	typedef cstringw_hash_func		cstring_hash_func;
+	typedef cstringw_nc_hash_func	cstring_nc_hash_func;
+#else
+	typedef cstringa_hash_func		cstring_hash_func;
+	typedef cstringa_nc_hash_func	cstring_nc_hash_func;
+#endif
+
+struct bool_comp_func
+{
+	bool operator() (bool v1, bool v2) const
+	{
+		if(!v1)
+			return false;
+		if(v1 == v2)
+			return false;
+
+		return true;
+	}
+};
+
+template<class T>
+// T -> (signed / unsigned) short / int / long / __int64
+struct integer_comp_func
+{
+	bool operator() (T v1, T v2) const
+	{
+		return v1 < v2;
+	}
+};
+
+typedef integer_comp_func<short>				short_comp_func;
+typedef integer_comp_func<int>					int_comp_func;
+typedef integer_comp_func<long>					long_comp_func;
+typedef integer_comp_func<__int64>				int64_comp_func;
+typedef integer_comp_func<unsigned short>		ushort_comp_func;
+typedef integer_comp_func<unsigned int>			uint_comp_func;
+typedef integer_comp_func<unsigned long>		ulong_comp_func;
+typedef integer_comp_func<unsigned __int64>		uint64_comp_func;
+
+struct float_comp_func
+{
+	bool operator() (float v1, float v2) const
+	{
+		float disc	= v1 - v2;
+		if(fabsf(disc) < 1E-5)
+			return false;
+
+		return disc < 0;
+	}
+};
+
+struct double_comp_func
+{
+	bool operator() (double v1, double v2) const
+	{
+		double disc	= v1 - v2;
+		if(fabs(disc) < 1E-8)
+			return false;
+
+		return disc < 0;
+	}
+};
+
+template<class T, bool CASE = false>
+// T -> (unsigned) char / wchar_t
+struct character_comp_func
+{
+	bool operator() (T v1, T v2) const
+	{
+		if(!CASE)
+		{
+			if(v1 >= 'A' && v1 <= 'Z')	v1 += 32;
+			if(v2 >= 'A' && v2 <= 'Z')	v2 += 32;
+		}
+
+		return v1 < v2;
+	}
+};
+
+typedef character_comp_func<char, true>				char_case_comp_func;
+typedef character_comp_func<unsigned char, true>	uchar_case_comp_func;
+typedef character_comp_func<wchar_t, true>			wchar_case_comp_func;
+typedef character_comp_func<char, false>			char_ucase_comp_func;
+typedef character_comp_func<unsigned char, false>	uchar_ucase_comp_func;
+typedef character_comp_func<wchar_t, false>			wchar_ucase_comp_func;
+
+template<class T, bool CASE = false>
+// T -> TCHAR* / CString
+struct str_comp_func
+{
+	//比较函数。
+	bool operator() (const T &A, const T &B) const
+	{
+		if(!CASE)
+			return lstrcmpi((LPCTSTR)A, (LPCTSTR)B) < 0;
+		else
+			return lstrcmp((LPCTSTR)A, (LPCTSTR)B) < 0;
+	}
+};
+
+typedef str_comp_func<LPCTSTR, true>		case_tchar_comp_func;
+typedef str_comp_func<LPCTSTR, false>		uncase_tchar_comp_func;
+typedef str_comp_func<CString, true>		case_string_comp_func;
+typedef str_comp_func<CString, false>		uncase_string_comp_func;
+typedef case_tchar_comp_func				tchar_ptr_case_comp_func;
+typedef uncase_tchar_comp_func				tchar_ptr_ucase_comp_func;
+typedef case_string_comp_func				string_case_comp_func;
+typedef uncase_string_comp_func				string_ucase_comp_func;
+/************************************************************************/
+/*                            排序仿函数                                */
+/************************************************************************/
+template<bool ASC = true>
+struct bool_sort_func
+{
+	bool operator() (bool v1, bool v2) const
+	{
+		if(v1 == v2)
+			return false;
+
+		bool result = !v1;
+		return ASC ? result : !result;
+	}
+};
+
+typedef bool_sort_func<true>	bool_asc_sort_func;
+typedef bool_sort_func<false>	bool_desc_sort_func;
+
+template<class T, bool ASC = true>
+// T -> (signed / unsigned) short / int / long / __int64
+struct integer_sort_func
+{
+	bool operator() (T v1, T v2) const
+	{
+		if(v1 == v2)
+			return false;
+
+		bool result = v1 < v2;
+		return ASC ? result : !result;
+	}
+};
+
+typedef integer_sort_func<short,			true>		short_asc_sort_func;
+typedef integer_sort_func<unsigned short,	true>		ushort_asc_sort_func;
+typedef integer_sort_func<int,				true>		int_asc_sort_func;
+typedef integer_sort_func<unsigned int,		true>		uint_asc_sort_func;
+typedef integer_sort_func<long,				true>		long_asc_sort_func;
+typedef integer_sort_func<unsigned long,	true>		ulong_asc_sort_func;
+typedef integer_sort_func<__int64,			true>		int64_asc_sort_func;
+typedef integer_sort_func<unsigned __int64,	true>		uint64_asc_sort_func;
+typedef integer_sort_func<short,			false>		short_desc_sort_func;
+typedef integer_sort_func<unsigned short,	false>		ushort_desc_sort_func;
+typedef integer_sort_func<int,				false>		int_desc_sort_func;
+typedef integer_sort_func<unsigned int,		false>		uint_desc_sort_func;
+typedef integer_sort_func<long,				false>		long_desc_sort_func;
+typedef integer_sort_func<unsigned long,	false>		ulong_desc_sort_func;
+typedef integer_sort_func<__int64,			false>		int64_desc_sort_func;
+typedef integer_sort_func<unsigned __int64,	false>		uint64_desc_sort_func;
+
+template<bool ASC = true>
+struct float_sort_func
+{
+	bool operator() (float v1, float v2) const
+	{
+		float disc	= v1 - v2;
+		if(fabsf(disc) < 1E-5)
+			return false;
+
+		bool result = disc < 0;
+		return ASC ? result : !result;
+	}
+};
+
+typedef float_sort_func<true>		float_asc_sort_func;
+typedef float_sort_func<false>		float_desc_sort_func;
+
+template<bool ASC = true>
+struct double_sort_func
+{
+	bool operator() (double v1, double v2) const
+	{
+		double disc	= v1 - v2;
+		if(fabs(disc) < 1E-8)
+			return false;
+
+		bool result = disc < 0;
+		return ASC ? result : !result;
+	}
+};
+
+typedef double_sort_func<true>		double_asc_sort_func;
+typedef double_sort_func<false>		double_desc_sort_func;
+
+template<class T, bool ASC = true, bool CASE = false>
+// T -> (unsigned) char / wchar_t
+struct character_sort_func
+{
+	bool operator() (T v1, T v2) const
+	{
+		if(!CASE)
+		{
+			if(v1 >= 'A' && v1 <= 'Z')	v1 += 32;
+			if(v2 >= 'A' && v2 <= 'Z')	v2 += 32;
+		}
+
+		if(v1 == v2)
+			return false;
+
+		bool result = v1 < v2;
+		return ASC ? result : !result;
+	}
+};
+
+typedef character_sort_func<char, true, true>				char_asc_case_sort_func;
+typedef character_sort_func<unsigned char, true, true>		uchar_asc_case_sort_func;
+typedef character_sort_func<wchar_t, true, true>			wchar_asc_case_sort_func;
+typedef character_sort_func<char, true, false>				char_asc_ucase_sort_func;
+typedef character_sort_func<unsigned char, true, false>		uchar_asc_ucase_sort_func;
+typedef character_sort_func<wchar_t, true, false>			wchar_asc_ucase_sort_func;
+typedef character_sort_func<char, false, true>				char_desc_case_sort_func;
+typedef character_sort_func<unsigned char, false, true>		uchar_desc_case_sort_func;
+typedef character_sort_func<wchar_t, false, true>			wchar_desc_case_sort_func;
+typedef character_sort_func<char, false, false>				char_desc_ucase_sort_func;
+typedef character_sort_func<unsigned char, false, false>	uchar_desc_ucase_sort_func;
+typedef character_sort_func<wchar_t, false, false>			wchar_desc_ucase_sort_func;
+
+template<class T, bool ASC = true, bool CASE = false>
+// T -> TCHAR* / CString
+struct str_sort_func
+{
+	bool operator() (const T& v1, const T& v2) const
+	{
+		bool result;
+
+		if(CASE)
+		{
+			int v = lstrcmp((LPCTSTR)v1, (LPCTSTR)v2);
+			if(v == 0)
+				result = false;
+			else
+				result = v < 0;
+		}
+		else
+		{
+			int v = lstrcmpi((LPCTSTR)v1, (LPCTSTR)v2);
+			if(v == 0)
+				result = false;
+			else
+				result = v < 0;
+		}
+
+		return ASC ? result : !result;
+	}
+};
+
+typedef str_sort_func<TCHAR*, true, true>		tchar_ptr_asc_case_sort_func;
+typedef str_sort_func<CString, true, true>		string_asc_case_sort_func;
+typedef str_sort_func<TCHAR*, true, false>		tchar_ptr_asc_ucase_sort_func;
+typedef str_sort_func<CString, true, false>		string_asc_ucase_sort_func;
+typedef str_sort_func<TCHAR*, false, true>		tchar_ptr_desc_case_sort_func;
+typedef str_sort_func<CString, false, true>		string_desc_case_sort_func;
+typedef str_sort_func<TCHAR*, false, false>		tchar_ptr_desc_ucase_sort_func;
+typedef str_sort_func<CString, false, false>	string_desc_ucase_sort_func;
+
+/************************************************************************/
+/*					   smart_ptr 单实体或数组智能指针                    */
+/************************************************************************/
+
+template<class _Ty>
+struct simple_deleter
+{
+	static void delete_ptr(_Ty* pv) {delete pv;}
+};
+
+template<class _Ty>
+struct global_simple_deleter
+{
+	static void delete_ptr(_Ty* pv) {::delete pv;}
+};
+
+template<class _Ty>
+struct array_deleter
+{
+	static void delete_ptr(_Ty* pv) {delete[] pv;}
+};
+
+template<class _Ty>
+struct global_array_deleter
+{
+	static void delete_ptr(_Ty* pv) {::delete[] pv;}
+};
+
+template<class _Ty, class _Deleter>
+class smart_ptr
+{
+public:
+	smart_ptr(_Ty* _Ptr = 0)					: _Myptr(_Ptr)				{}
+	smart_ptr(smart_ptr<_Ty, _Deleter>& _Right)	: _Myptr(_Right.release())	{}
+
+	~smart_ptr()
+	{
+		reset();
+	}
+
+	smart_ptr<_Ty, _Deleter>& reset(_Ty* _Ptr = 0)
+	{
+		if (_Ptr != _Myptr)
+		{
+			if(_Myptr)
+				_Deleter::delete_ptr(_Myptr);
+
+			_Myptr = _Ptr;
+		}
+
+		return *this;
+	}
+
+	smart_ptr<_Ty, _Deleter>& reset(smart_ptr<_Ty, _Deleter>& _Right)
+	{
+		if (this != &_Right)
+			reset(_Right.release());
+
+		return *this;
+	}
+
+	_Ty* release()
+	{
+		_Ty* _Ptr	= _Myptr;
+		_Myptr		= 0;
+
+		return _Ptr;
+	}
+
+	smart_ptr<_Ty, _Deleter>& operator = (_Ty* _Ptr)						{return reset(_Ptr);}
+	smart_ptr<_Ty, _Deleter>& operator = (smart_ptr<_Ty, _Deleter>& _Right)	{return reset(_Right);}
+
+	bool is_valid		()	const	{return _Myptr != 0;}
+	_Ty& operator *		()	const	{return *_Myptr;}
+	_Ty* get			()	const	{return _Myptr;}
+	_Ty* operator ->	()	const	{return _Myptr;}
+	operator _Ty*		()	const	{return _Myptr;}
+
+private:
+	template<class _Other> smart_ptr<_Ty, _Deleter>					(const smart_ptr<_Ty, _Other>&);
+	template<class _Other> smart_ptr<_Ty, _Deleter>&	reset		(const smart_ptr<_Ty, _Other>&);
+	template<class _Other> smart_ptr<_Ty, _Deleter>&	operator =	(const smart_ptr<_Ty, _Other>&);
+
+	template<class _Other> smart_ptr<_Ty, _Deleter>					(const smart_ptr<_Other, _Deleter>&);
+	template<class _Other> smart_ptr<_Ty, _Deleter>&	reset		(const smart_ptr<_Other, _Deleter>&);
+	template<class _Other> smart_ptr<_Ty, _Deleter>&	operator =	(const smart_ptr<_Other, _Deleter>&);
+
+protected:
+	_Ty* _Myptr;
+};
+
+
+/************************************************************************/
+/*				    smart_simple_ptr 单实体智能指针                      */
+/************************************************************************/
+
+template<class _Ty>
+class smart_simple_ptr : public smart_ptr<_Ty, simple_deleter<_Ty>>
+{
+public:
+	smart_simple_ptr(_Ty* _Ptr = 0)									: smart_ptr(_Ptr)	{}
+	smart_simple_ptr(smart_simple_ptr<_Ty>& _Right)					: smart_ptr(_Right)	{}
+	smart_simple_ptr(smart_ptr<_Ty, simple_deleter<_Ty>>& _Right)	: smart_ptr(_Right)	{}
+
+	smart_simple_ptr<_Ty>& operator = (smart_ptr<_Ty, simple_deleter<_Ty>>& _Right)
+	{return (smart_simple_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_simple_ptr<_Ty>& operator = (smart_simple_ptr<_Ty>& _Right)
+	{return (smart_simple_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_simple_ptr<_Ty>& operator = (_Ty* _Ptr)
+	{return (smart_simple_ptr<_Ty>&)__super::operator = (_Ptr);}
+
+private:
+	template<class _Other> smart_simple_ptr<_Ty>				(const smart_ptr<_Ty, _Other>&);
+	template<class _Other> smart_simple_ptr<_Ty>&	operator =	(const smart_ptr<_Ty, _Other>&);
+
+	template<class _Other> smart_simple_ptr<_Ty>				(const smart_simple_ptr<_Other>&);
+	template<class _Other> smart_simple_ptr<_Ty>&	operator =	(const smart_simple_ptr<_Other>&);
+};
+
+/************************************************************************/
+/*		   smart_gd_simple_ptr 单实体智能指针 (使用全局 delete)          */
+/************************************************************************/
+
+template<class _Ty>
+class smart_gd_simple_ptr : public smart_ptr<_Ty, global_simple_deleter<_Ty>>
+{
+public:
+	smart_gd_simple_ptr(_Ty* _Ptr = 0)										: smart_ptr(_Ptr)	{}
+	smart_gd_simple_ptr(smart_gd_simple_ptr<_Ty>& _Right)					: smart_ptr(_Right)	{}
+	smart_gd_simple_ptr(smart_ptr<_Ty, global_simple_deleter<_Ty>>& _Right)	: smart_ptr(_Right)	{}
+
+	smart_gd_simple_ptr<_Ty>& operator = (smart_ptr<_Ty, global_simple_deleter<_Ty>>& _Right)
+	{return (smart_gd_simple_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_gd_simple_ptr<_Ty>& operator = (smart_gd_simple_ptr<_Ty>& _Right)
+	{return (smart_gd_simple_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_gd_simple_ptr<_Ty>& operator = (_Ty* _Ptr)
+	{return (smart_gd_simple_ptr<_Ty>&)__super::operator = (_Ptr);}
+
+private:
+	template<class _Other> smart_gd_simple_ptr<_Ty>					(const smart_ptr<_Ty, _Other>&);
+	template<class _Other> smart_gd_simple_ptr<_Ty>&	operator =	(const smart_ptr<_Ty, _Other>&);
+
+	template<class _Other> smart_gd_simple_ptr<_Ty>					(const smart_gd_simple_ptr<_Other>&);
+	template<class _Other> smart_gd_simple_ptr<_Ty>&	operator =	(const smart_gd_simple_ptr<_Other>&);
+};
+
+/************************************************************************/
+/*                   smart_array_ptr 数组智能指针                        */
+/************************************************************************/
+
+template<class _Ty>
+class smart_array_ptr : public smart_ptr<_Ty, array_deleter<_Ty>>
+{
+public:
+	smart_array_ptr(_Ty* _Ptr = 0)								: smart_ptr(_Ptr)	{}
+	smart_array_ptr(smart_simple_ptr<_Ty>& _Right)				: smart_ptr(_Right)	{}
+	smart_array_ptr(smart_ptr<_Ty, array_deleter<_Ty>>& _Right)	: smart_ptr(_Right)	{}
+
+	smart_array_ptr<_Ty>& operator = (smart_ptr<_Ty, array_deleter<_Ty>>& _Right)
+	{return (smart_array_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_array_ptr<_Ty>& operator = (smart_array_ptr<_Ty>& _Right)
+	{return (smart_array_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_array_ptr<_Ty>& operator = (_Ty* _Ptr)
+	{return (smart_array_ptr<_Ty>&)__super::operator = (_Ptr);}
+
+private:
+	template<class _Other> smart_array_ptr<_Ty>					(const smart_ptr<_Ty, _Other>&);
+	template<class _Other> smart_array_ptr<_Ty>&	operator =	(const smart_ptr<_Ty, _Other>&);
+
+	template<class _Other> smart_array_ptr<_Ty>					(const smart_array_ptr<_Other>&);
+	template<class _Other> smart_array_ptr<_Ty>&	operator =	(const smart_array_ptr<_Other>&);
+};
+
+/************************************************************************/
+/*          smart_gd_array_ptr 单实体智能指针 (使用全局 delete)          */
+/************************************************************************/
+
+template<class _Ty>
+class smart_gd_array_ptr : public smart_ptr<_Ty, global_array_deleter<_Ty>>
+{
+public:
+	smart_gd_array_ptr(_Ty* _Ptr = 0)										: smart_ptr(_Ptr)	{}
+	smart_gd_array_ptr(smart_gd_array_ptr<_Ty>& _Right)						: smart_ptr(_Right)	{}
+	smart_gd_array_ptr(smart_ptr<_Ty, global_array_deleter<_Ty>>& _Right)	: smart_ptr(_Right)	{}
+
+	smart_gd_array_ptr<_Ty>& operator = (smart_ptr<_Ty, global_array_deleter<_Ty>>& _Right)
+	{return (smart_gd_array_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_gd_array_ptr<_Ty>& operator = (smart_gd_array_ptr<_Ty>& _Right)
+	{return (smart_gd_array_ptr<_Ty>&)__super::operator = (_Right);}
+
+	smart_gd_array_ptr<_Ty>& operator = (_Ty* _Ptr)
+	{return (smart_gd_array_ptr<_Ty>&)__super::operator = (_Ptr);}
+
+private:
+	template<class _Other> smart_gd_array_ptr<_Ty>				(const smart_ptr<_Ty, _Other>&);
+	template<class _Other> smart_gd_array_ptr<_Ty>&	operator =	(const smart_ptr<_Ty, _Other>&);
+
+	template<class _Other> smart_gd_array_ptr<_Ty>				(const smart_gd_array_ptr<_Other>&);
+	template<class _Other> smart_gd_array_ptr<_Ty>&	operator =	(const smart_gd_array_ptr<_Other>&);
+};

+ 26 - 0
common/Src/Semaphore.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "Semaphore.h"

+ 70 - 0
common/Src/Semaphore.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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
+
+class CSEM
+{
+public:
+	CSEM(LONG lMaximumCount, LONG lInitialCount = 0, LPCTSTR lpName = nullptr, LPSECURITY_ATTRIBUTES pSecurity = nullptr)
+	{
+		m_hsem = ::CreateSemaphore(pSecurity, lInitialCount, lMaximumCount, lpName);
+		ASSERT(IsValid());
+	}
+
+	~CSEM()
+	{
+		if(IsValid())
+			VERIFY(::CloseHandle(m_hsem));
+	}
+
+	BOOL Open(DWORD dwAccess, BOOL bInheritHandle, LPCTSTR pszName)
+	{
+		if(IsValid())
+			VERIFY(::CloseHandle(m_hsem));
+
+		m_hsem = ::OpenSemaphore(dwAccess, bInheritHandle, pszName);
+		return(IsValid());
+	}
+
+	void Wait(DWORD dwMilliseconds = INFINITE)
+	{
+		::WaitForSingleObject(m_hsem, dwMilliseconds);
+	}
+
+	BOOL Release(LONG lReleaseCount = 1, LPLONG lpPreviousCount = nullptr)
+	{
+		return ::ReleaseSemaphore(m_hsem, lReleaseCount, lpPreviousCount);
+	}
+
+	HANDLE& GetHandle	() 	{return m_hsem;}
+	operator HANDLE		()	{return m_hsem;}
+	BOOL IsValid		()	{return m_hsem != nullptr;}
+
+private:
+	CSEM(const CSEM& sem);
+	CSEM operator = (const CSEM& sem);
+private:
+	HANDLE m_hsem;
+};

+ 111 - 0
common/Src/Singleton.h

@@ -0,0 +1,111 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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
+
+#define SINGLETON_THIS(ClassName)		ClassName::GetThis()
+#define SINGLETON_INSTANCE(ClassName)	ClassName::GetInstance()
+#define SINGLETON_OBJECT(ObjName)		SINGLETON_INSTANCE(C##ObjName)
+
+#define DEFINE_SINGLETON(ClassName)											\
+	ClassName* ClassName::m_pThis = nullptr;
+
+#define DEFINE_P_THIS(ClassName)											\
+		DEFINE_SINGLETON(ClassName)
+
+#define DECLARE_SINGLETON_INTERFACE(ClassName)								\
+public:																		\
+	static ClassName* GetThis()		{return m_pThis;}						\
+	static ClassName& GetInstance() {return *m_pThis;}						\
+protected:																	\
+	static ClassName* m_pThis;
+
+#define DECLARE_SINGLETON_CREATE_INSTANCE(ClassName)						\
+public:																		\
+	static BOOL CreateInstance()											\
+	{																		\
+		if(!m_pThis)														\
+			m_pThis = new ClassName;										\
+																			\
+		return m_pThis != nullptr;											\
+	}																		\
+																			\
+	static BOOL DeleteInstance()											\
+	{																		\
+		if(m_pThis)															\
+		{																	\
+			delete m_pThis;													\
+			m_pThis = nullptr;												\
+		}																	\
+																			\
+		return m_pThis == nullptr;											\
+	}
+
+#define DECLARE_PRIVATE_DEFAULT_CONSTRUCTOR(ClassName)						\
+private:																	\
+	ClassName(){}
+
+#define DECLARE_PRIVATE_COPY_CONSTRUCTOR(ClassName)							\
+private:																	\
+	ClassName(const ClassName&);											\
+	ClassName& operator = (const ClassName&);
+
+#define DECLARE_NO_COPY_CLASS(className)									\
+		DECLARE_PRIVATE_COPY_CONSTRUCTOR(className)
+
+
+#define DECLARE_SINGLETON_IMPLEMENT_NO_CREATE_INSTANCE(ClassName)			\
+	DECLARE_SINGLETON_INTERFACE(ClassName)									\
+	DECLARE_PRIVATE_DEFAULT_CONSTRUCTOR(ClassName)							\
+	DECLARE_PRIVATE_COPY_CONSTRUCTOR(ClassName)								
+
+#define DECLARE_SINGLETON_IMPLEMENT_NO_DEFAULT_CONSTRUCTOR(ClassName)		\
+	DECLARE_SINGLETON_CREATE_INSTANCE(ClassName)							\
+	DECLARE_PRIVATE_COPY_CONSTRUCTOR(ClassName)
+
+#define DECLARE_SINGLETON_IMPLEMENT(ClassName)								\
+	DECLARE_SINGLETON_IMPLEMENT_NO_DEFAULT_CONSTRUCTOR(ClassName)			\
+	DECLARE_PRIVATE_DEFAULT_CONSTRUCTOR(ClassName)
+
+#define DECLARE_SINGLETON_NO_DEFAULT_CONSTRUCTOR(ClassName)					\
+	DECLARE_SINGLETON_INTERFACE(ClassName)									\
+	DECLARE_SINGLETON_IMPLEMENT_NO_DEFAULT_CONSTRUCTOR(ClassName)
+
+#define DECLARE_SINGLETON(ClassName)										\
+	DECLARE_SINGLETON_NO_DEFAULT_CONSTRUCTOR(ClassName)						\
+	DECLARE_PRIVATE_DEFAULT_CONSTRUCTOR(ClassName)
+
+
+template<class T>
+class CSingleObject
+{
+public:
+	CSingleObject	()	{T::CreateInstance();}
+	~CSingleObject	()	{T::DeleteInstance();}
+	T* GetPointer	()	{return T::GetThis();}
+	T& GetObject	()	{return T::GetInstance();}
+	BOOL IsValid	()	{return GetPointer() != nullptr;}
+};
+
+#define DECLARE_SINGLE_OBJECT(ClassName) CSingleObject<ClassName> _##ClassName##_Single_Object_;

+ 72 - 0
common/Src/SysHelper.cpp

@@ -0,0 +1,72 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "SysHelper.h"
+#include "GeneralHelper.h"
+
+VOID SysGetSystemInfo(LPSYSTEM_INFO pInfo)
+{
+	ASSERT(pInfo != nullptr);
+	::GetNativeSystemInfo(pInfo);
+}
+
+DWORD SysGetNumberOfProcessors()
+{
+	SYSTEM_INFO si;
+	SysGetSystemInfo(&si);
+	
+	return si.dwNumberOfProcessors;
+}
+
+DWORD SysGetPageSize()
+{
+	SYSTEM_INFO si;
+	SysGetSystemInfo(&si);
+
+	return si.dwPageSize;
+}
+
+#if _MSC_VER < 1800
+
+BOOL SysGetOSVersionInfo(LPOSVERSIONINFO pInfo, BOOL bInfoEx)
+{
+	ASSERT(pInfo != nullptr);
+
+	pInfo->dwOSVersionInfoSize = bInfoEx ? sizeof(LPOSVERSIONINFOEX) : sizeof(LPOSVERSIONINFO);
+	return ::GetVersionEx(pInfo);
+}
+
+DWORD SysGetOSVersion()
+{
+	OSVERSIONINFO vi;
+	DWORD dwOSVersion = 0;
+
+	if(SysGetOSVersionInfo(&vi))
+		dwOSVersion = (vi.dwMajorVersion << 16) + vi.dwMinorVersion;
+
+	return dwOSVersion;
+}
+
+#endif

+ 41 - 0
common/Src/SysHelper.h

@@ -0,0 +1,41 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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
+
+// 获取系统信息
+VOID SysGetSystemInfo(LPSYSTEM_INFO pInfo);
+// 获取 CPU 核数
+DWORD SysGetNumberOfProcessors();
+// 获取页面大小
+DWORD SysGetPageSize();
+
+#if _MSC_VER < 1800
+
+// 获取操作系统版本
+BOOL SysGetOSVersionInfo(LPOSVERSIONINFO pInfo, BOOL bInfoEx = FALSE);
+// 获取操作系统版本(高位双字节:主版本号;低位双字节:副版本号)
+DWORD SysGetOSVersion();
+
+#endif

+ 150 - 0
common/Src/WaitFor.cpp

@@ -0,0 +1,150 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "WaitFor.h"
+#include "GeneralHelper.h"
+#include "CriticalSection.h"
+
+#include <MmSystem.h>
+#pragma comment(lib, "Winmm")
+
+DWORD TimeGetTime()
+{
+	return ::timeGetTime();
+}
+
+DWORD GetTimeGap32(DWORD dwOriginal)
+{
+	return ::timeGetTime() - dwOriginal;
+}
+
+#if _WIN32_WINNT >= _WIN32_WINNT_WS08
+ULONGLONG GetTimeGap64(ULONGLONG ullOriginal)
+{
+	return ::GetTickCount64() - ullOriginal;
+}
+#endif
+
+BOOL PeekMessageLoop(BOOL bDispatchQuitMsg)
+{
+	BOOL value = TRUE;
+
+	MSG msg;
+	while(::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
+	{
+		if(msg.message == WM_QUIT && !bDispatchQuitMsg)
+		{
+			value = FALSE;
+			break;
+		}
+
+		::TranslateMessage(&msg);
+		::DispatchMessage(&msg);
+	}
+
+	return value;
+}
+
+DWORD WaitForMultipleObjectsWithMessageLoop(DWORD dwHandles, HANDLE szHandles[], DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags)
+{
+	DWORD dwResult		= WAIT_FAILED;
+	DWORD dwBeginTime	= (dwMilliseconds == INFINITE) ? INFINITE : ::timeGetTime();
+
+	while(TRUE)
+	{
+		int iWaitTime;
+		if(dwBeginTime != INFINITE)
+		{
+			iWaitTime	= dwMilliseconds - (GetTimeGap32(dwBeginTime));
+
+			if(iWaitTime <= 0)
+			{
+				dwResult = WAIT_TIMEOUT;
+				break;
+			}
+		}
+		else
+			iWaitTime	= INFINITE;
+
+		dwResult = ::MsgWaitForMultipleObjectsEx(dwHandles, szHandles, iWaitTime, dwWakeMask, dwFlags);
+		ASSERT(dwResult != WAIT_FAILED);
+
+		if(dwResult == (WAIT_OBJECT_0 + dwHandles))
+			PeekMessageLoop();
+		else
+			break;
+	}
+
+	return dwResult;
+
+}
+
+BOOL MsgWaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags)
+{
+	DWORD dwResult = WaitForMultipleObjectsWithMessageLoop(1, &hHandle, dwMilliseconds, dwWakeMask, dwFlags);
+
+	switch(dwResult)
+	{
+	case WAIT_OBJECT_0:
+		return TRUE;
+	case WAIT_FAILED:
+		ASSERT(FALSE);
+	case WAIT_TIMEOUT:
+		return FALSE;
+	default:
+		ASSERT(FALSE);
+	}
+
+	return FALSE;
+}
+
+void WaitWithMessageLoop(DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags)
+{
+	static CEvt evWait;
+
+	VERIFY(MsgWaitForSingleObject(evWait, dwMilliseconds, dwWakeMask, dwFlags) == FALSE);
+}
+
+void WaitForWorkingQueue(long* plWorkingItemCount, long lMaxWorkingItemCount, DWORD dwCheckInterval)
+{
+	while(*plWorkingItemCount > lMaxWorkingItemCount)
+		::Sleep(dwCheckInterval);
+}
+
+void WaitForComplete(long* plWorkingItemCount, DWORD dwCheckInterval)
+{
+	WaitForWorkingQueue(plWorkingItemCount, 0, dwCheckInterval);
+}
+
+void MsgWaitForWorkingQueue(long* plWorkingItemCount, long lMaxWorkingItemCount, DWORD dwCheckInterval)
+{
+	while(*plWorkingItemCount > lMaxWorkingItemCount)
+		WaitWithMessageLoop(dwCheckInterval);
+}
+
+void MsgWaitForComplete(long* plWorkingItemCount, DWORD dwCheckInterval)
+{
+	MsgWaitForWorkingQueue(plWorkingItemCount, 0, dwCheckInterval);
+}

+ 138 - 0
common/Src/WaitFor.h

@@ -0,0 +1,138 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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
+
+/* timeGetTime() 包装方法 */
+DWORD TimeGetTime();
+
+/**********************************
+描述: 获取当前时间与原始时间的时间差
+参数: 
+		dwOriginal	: 原始时间(毫秒),通常用 timeGetTime() 或 GetTickCount() 获取
+
+返回值:	与当前 timeGetTime() 之间的时间差
+**********************************/
+DWORD GetTimeGap32(DWORD dwOriginal);
+
+#if _WIN32_WINNT >= _WIN32_WINNT_WS08
+/**********************************
+描述: 获取当前时间与原始时间的时间差
+参数: 
+		ullOriginal	: 原始时间(毫秒),通常用 GetTickCount64() 获取
+
+返回值:	与当前 GetTickCount64() 之间的时间差
+**********************************/
+ULONGLONG GetTimeGap64(ULONGLONG ullOriginal);
+#endif
+
+/**********************************
+描述: 处理Windows消息
+参数: 
+			bDispatchQuitMsg	: 是否转发 WM_QUIT 消息
+									TRUE : 转发(默认)
+									FALSE: 不转发,并返回 FALSE
+
+返回值:		TRUE  : 收完消息
+			FALSE : bDispatchQuitMsg 参数为 FALSE 并收到 WM_QUIT 消息		
+**********************************/
+BOOL PeekMessageLoop(BOOL bDispatchQuitMsg = TRUE);
+
+/**********************************
+描述: 等待指定时间, 同时处理Windows消息
+参数: (参考: MsgWaitForMultipleObjectsEx() )
+		dwHandles		: 数组元素个数
+		szHandles		: 对象句柄数组
+		dwMilliseconds	: 等待时间 (毫秒)
+		dwWakeMask		: 消息过滤标识
+		dwFlags			: 等待类型
+
+返回值: (0 ~ dwHandles - 1): 等待成功
+		WAIT_TIMEOUT		: 超时
+		WAIT_FAILED			: 执行失败
+**********************************/
+DWORD WaitForMultipleObjectsWithMessageLoop(DWORD dwHandles, HANDLE szHandles[], DWORD dwMilliseconds = INFINITE, DWORD dwWakeMask = QS_ALLINPUT, DWORD dwFlags = MWMO_INPUTAVAILABLE);
+
+/**********************************
+描述: 等待指定时间, 同时处理Windows消息
+参数: (参考: MsgWaitForMultipleObjectsEx() )
+		hHandle			: 对象句柄
+		dwMilliseconds	: 等待时间 (毫秒)
+		dwWakeMask		: 消息过滤标识
+		dwFlags			: 等待类型
+
+返回值: TRUE: 等待成功,FALSE: 超时		
+**********************************/
+BOOL MsgWaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds = INFINITE, DWORD dwWakeMask = QS_ALLINPUT, DWORD dwFlags = MWMO_INPUTAVAILABLE);
+
+/**********************************
+描述: 等待指定时间, 同时处理Windows消息
+参数: (参考: MsgWaitForMultipleObjectsEx() )
+		dwMilliseconds	: 等待时间 (毫秒)
+		dwWakeMask		: 消息过滤标识
+		dwFlags			: 等待类型
+
+返回值: MsgWaitForMultipleObjectsEx() 函数的操作结果		
+**********************************/
+void WaitWithMessageLoop(DWORD dwMilliseconds, DWORD dwWakeMask = QS_ALLINPUT, DWORD dwFlags = MWMO_INPUTAVAILABLE);
+
+/**********************************
+描述: 等待用Sleep()函数等待某个变量小于指定值
+参数: 
+		plWorkingItemCount		: 监视变量
+		lMaxWorkingItemCount	: 指定值
+		dwCheckInterval			: 检查间隔 (毫秒)
+
+返回值: 		
+**********************************/
+void WaitForWorkingQueue(long* plWorkingItemCount, long lMaxWorkingItemCount, DWORD dwCheckInterval);
+/**********************************
+描述: 等待用Sleep()函数等待某个变量减小到 0
+参数: 
+		plWorkingItemCount		: 监视变量
+		dwCheckInterval			: 检查间隔 (毫秒)
+
+返回值: 		
+**********************************/
+void WaitForComplete	(long* plWorkingItemCount, DWORD dwCheckInterval);
+
+/**********************************
+描述: 等待用WaitWithMessageLoop()函数等待某个变量小于指定值
+参数: 
+		plWorkingItemCount		: 监视变量
+		lMaxWorkingItemCount	: 指定值
+		dwCheckInterval			: 检查间隔 (毫秒)
+
+返回值: 		
+**********************************/
+void MsgWaitForWorkingQueue	(long* plWorkingItemCount, long lMaxWorkingItemCount, DWORD dwCheckInterval = 10);
+/**********************************
+描述: 等待用WaitWithMessageLoop()函数等待某个变量减小到 0
+参数: 
+		plWorkingItemCount		: 监视变量
+		dwCheckInterval			: 检查间隔 (毫秒)
+
+返回值: 		
+**********************************/
+void MsgWaitForComplete		(long* plWorkingItemCount, DWORD dwCheckInterval = 10);

+ 819 - 0
common/Src/Win32Helper.h

@@ -0,0 +1,819 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "GeneralHelper.h"
+
+// RECT 帮助宏
+#define RC_WIDTH(rc)		(rc.right - rc.left)
+#define RC_HEIGHT(rc)		(rc.bottom - rc.top)
+#define RC_CENTER_X(rc)		((rc.right + rc.left) / 2)
+#define RC_CENTER_Y(rc)		((rc.bottom + rc.top) / 2)
+
+/************************************************************************/
+/*                 			  消息映射帮助宏			 					*/
+/************************************************************************/
+
+/* see: WindowsX.h */
+#define HANDLE_SYS_MSG(hwnd, message, fn)	HANDLE_MSG(hwnd, message, fn)
+
+/* LRESULT Cls_OnMessage(HWND hwnd, WPARAM wParam, LPARAM lParam) */
+#define HANDLE_USER_MSG(hwnd, message, fn)								\
+	case (message): return (LRESULT)(fn)((hwnd), (wParam), (lParam))
+
+#define FORWARD_USER_MSG(hwnd, message, wParam, lParam, fn)				\
+	(LRESULT)(fn)((hwnd), (message), (wParam), (lParam))
+
+#define GET_WND_PROC_INTERNAL(theClass, flag)	((WNDPROC)theClass##flag##WndProc)
+#define GET_DLG_PROC_INTERNAL(theClass, flag)	((DLGPROC)theClass##flag##DlgProc)
+
+#define DECLARE_MSG_MAP_INTERNAL(theClass, flag)		\
+	static LRESULT CALLBACK theClass##flag##WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#define DECLARE_DLG_MSG_MAP_INTERNAL(theClass, flag)	\
+	static BOOL CALLBACK theClass##flag##DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#define BEGIN_MSG_MAP_INTERNAL(theClass, flag)			\
+	LRESULT theClass##flag##WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)	\
+	{																					\
+		LRESULT result = 0;																\
+																						\
+		switch(msg)																		\
+		{
+
+#define BEGIN_DLG_MSG_MAP_INTERNAL(theClass, flag)		\
+	BOOL theClass##flag##DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)		\
+	{																					\
+		BOOL	retVal = TRUE;															\
+		LRESULT result = 0;																\
+																						\
+		switch(msg)																		\
+		{
+
+// 窗口过程为类中的静态成员函数
+#define GET_WND_PROC(theClass)			GET_WND_PROC_INTERNAL(theClass, ::)
+#define GET_DLG_PROC(theClass)			GET_DLG_PROC_INTERNAL(theClass, ::)
+
+#define DECLARE_MSG_MAP(theClass)					\
+public:												\
+	DECLARE_MSG_MAP_INTERNAL(theClass, ::)
+
+#define DECLARE_DLG_MSG_MAP(theClass)				\
+public:												\
+	DECLARE_DLG_MSG_MAP_INTERNAL(theClass, ::)
+
+#define BEGIN_MSG_MAP(theClass)			BEGIN_MSG_MAP_INTERNAL(theClass, ::)
+#define BEGIN_DLG_MSG_MAP(theClass)		BEGIN_DLG_MSG_MAP_INTERNAL(theClass, ::)
+
+/* 消息处理函数的声明请参考: <WindowsX.h> 的 HANDLE_MSG */
+#define ADD_MSG_MAP(msg, fn)						\
+		case (msg): result = HANDLE_##msg((hWnd), (wParam), (lParam), (fn));	break;
+
+/* LRESULT Cls_OnMessage(HWND hwnd, WPARAM wParam, LPARAM lParam) */
+#define ADD_USER_MSG_MAP(msg, fn)					\
+		case (msg): result = (LRESULT)(fn)((hWnd), (wParam), (lParam));			break;
+
+#define END_MSG_MAP()								\
+		default:									\
+			result = ::DefWindowProc(hWnd, msg, wParam, lParam);						\
+		}																				\
+																						\
+		return result;																	\
+	}
+
+#define END_DLG_MSG_MAP()							\
+		default:									\
+			retVal = FALSE;																\
+		}																				\
+																						\
+		if(retVal)																		\
+			SetDlgMsgResult(hWnd, msg, result);											\
+																						\
+		return retVal;																	\
+	}
+
+// 窗口过程为全局函数
+#define GET_GLOBAL_WND_PROC(theClass)			GET_WND_PROC_INTERNAL(theClass,			_)
+#define DECLARE_GLOBAL_MSG_MAP(theClass)		DECLARE_MSG_MAP_INTERNAL(theClass,		_)
+#define BEGIN_GLOBAL_MSG_MAP(theClass)			BEGIN_MSG_MAP_INTERNAL(theClass,		_)
+#define END_GLOBAL_MSG_MAP()					END_MSG_MAP()
+
+#define GET_GLOBAL_DLG_PROC(theClass)			GET_DLG_PROC_INTERNAL(theClass,			_)
+#define DECLARE_GLOBAL_DLG_MSG_MAP(theClass)	DECLARE_DLG_MSG_MAP_INTERNAL(theClass,	_)
+#define BEGIN_GLOBAL_DLG_MSG_MAP(theClass)		BEGIN_DLG_MSG_MAP_INTERNAL(theClass,	_)
+#define END_GLOBAL_DLG_MSG_MAP()				END_DLG_MSG_MAP()
+
+// 绑定对象指针到窗口
+#define ATTACH_OBJ_PTR_TO_WINDOW(hwnd, objPtr)	::SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)objPtr)
+#define GET_OBJ_PTR_FROM_WINDOW(hwnd, theClass)	(theClass*)(LONG_PTR)::GetWindowLongPtr(hwnd, GWL_USERDATA)
+
+#define DEFINE_OBJ_PTR_FROM_WINDOW(hwnd, theClass, pObj)		\
+	theClass* pObj = GET_OBJ_PTR_FROM_WINDOW(hwnd, theClass);	\
+	ASSERT(pObj);
+
+
+/************************************************************************/
+/*                 		  应用程序唯一实例			 	            */
+/************************************************************************/
+
+class COnlyOneApp
+{
+public:
+	BOOL IsFirstApp	() {return m_bIsFirstApp;}
+	DWORD GetProcID	() {return m_dwProcID;}
+
+	COnlyOneApp(LPCTSTR pszAppFlag)
+	: m_dwProcID(0), m_bIsFirstApp(FALSE)
+	{
+		m_hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sizeof(DWORD), pszAppFlag);
+
+		if(m_hMap)
+		{
+			if(::GetLastError() != ERROR_ALREADY_EXISTS)
+			{
+				m_bIsFirstApp	= TRUE;
+				m_dwProcID		= ::GetCurrentProcessId();
+
+				LPVOID lpBuff	= ::MapViewOfFile(m_hMap, FILE_MAP_WRITE, 0, 0, sizeof(DWORD));
+				ASSERT(lpBuff);
+
+				memcpy(lpBuff, &m_dwProcID, sizeof(DWORD));
+				::UnmapViewOfFile(lpBuff);
+			}
+			else
+			{
+				m_bIsFirstApp	= FALSE;
+				LPVOID lpBuff	= ::MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, sizeof(DWORD));
+				ASSERT(lpBuff);
+
+				memcpy(&m_dwProcID, lpBuff, sizeof(DWORD));
+				::UnmapViewOfFile(lpBuff);
+			}
+		}
+		else
+		{
+			ASSERT(FALSE);
+		}
+	}
+
+	~COnlyOneApp() {if(m_hMap) {::CloseHandle(m_hMap); m_hMap = nullptr;}}
+
+private:
+	HANDLE	m_hMap;
+	DWORD	m_dwProcID;
+	BOOL	m_bIsFirstApp;
+
+	DECLARE_NO_COPY_CLASS(COnlyOneApp)
+};
+
+class COnlyOneWndApp
+{
+public:
+	BOOL IsFirstApp()			{return m_hwndPre == nullptr;}
+	HWND GetPreInstanceWindow()	{return m_hwndPre;}
+
+	COnlyOneWndApp(LPCTSTR lpszClassName, LPCTSTR lpszWindowName = nullptr)
+	{
+		m_hwndPre = ::FindWindow(lpszClassName, lpszWindowName);
+	}
+
+private:
+	HWND m_hwndPre;
+
+	DECLARE_NO_COPY_CLASS(COnlyOneWndApp)
+};
+
+/************************************************************************/
+/*                   	句柄 (HANDLE) 智能包装器 		 		        */
+/************************************************************************/
+
+template<HANDLE NULL_VALUE>
+class auto_handle
+{
+public:
+	auto_handle(HANDLE h = NULL_VALUE)			{set(h);}
+	auto_handle(auto_handle<NULL_VALUE>& other)	{set(other.release());}
+
+	~auto_handle()	{reset();}
+
+	auto_handle<NULL_VALUE>& reset(HANDLE h = NULL_VALUE)
+	{
+		if(h != m_h)
+		{
+			if(is_valid())
+				VERIFY(::CloseHandle(m_h));
+
+			set(h);
+		}
+
+		return *this;
+	}
+
+	auto_handle<NULL_VALUE>& reset(auto_handle<NULL_VALUE>& other)
+	{
+		if(this != &other)
+			reset(other.release());
+
+		return *this;
+	}
+
+	HANDLE release()
+	{
+		HANDLE h = get();
+		set(NULL_VALUE);
+	
+		return h;
+	}
+
+	operator HANDLE	()	const	{return m_h;}
+	HANDLE get		()	const	{return m_h;}
+	HANDLE& get_ref	()	const	{return m_h;}
+	bool is_valid	()	const	{return m_h != NULL_VALUE;}
+
+	auto_handle<NULL_VALUE>& operator = (HANDLE h)							{return reset(h);}
+	auto_handle<NULL_VALUE>& operator = (auto_handle<NULL_VALUE>& other)	{return reset(other);}
+
+	bool operator == (HANDLE h)								const	{return m_h == h;}
+	bool operator != (HANDLE h)								const	{return !(operator == (h));	}
+	bool operator == (const auto_handle<NULL_VALUE>& other)	const	{return m_h == other.m_h;}
+	bool operator != (const auto_handle<NULL_VALUE>& other)	const	{return !(operator == (other));}
+
+private:
+	void set(HANDLE h)	{m_h = h;}
+
+	// ~! do not define these conversion, because it's very easy to making mistake !~
+	template<HANDLE _Other> auto_handle(const auto_handle<_Other>&);
+	template<HANDLE _Other> auto_handle<NULL_VALUE>& operator = (const auto_handle<_Other>&);
+
+private:
+	HANDLE	m_h;
+};
+
+typedef auto_handle<INVALID_HANDLE_VALUE>	auto_file_handle;	// 文件智能句柄
+typedef auto_handle<nullptr>				auto_res_handle;	// 普通资源智能句柄
+
+/************************************************************************/
+/*                 	  	 	DC 智能包装器 					            */
+/************************************************************************/
+
+class auto_dc
+{
+public:
+	auto_dc(HDC h = nullptr, HWND w = nullptr, bool is_create = false)
+	{
+		set(h, w, is_create);
+	}
+
+	auto_dc(auto_dc& other)
+	{
+		set(other.m_h, other.m_w, other.m_is_create);
+		other.release();
+	}
+
+	~auto_dc()	{reset();}
+
+	HDC GetDC(HWND hWnd)
+	{
+		HDC h = ::GetDC(hWnd);
+		reset(h, hWnd, false);
+
+		return h;
+	}
+
+	HDC GetWindowDC(HWND hWnd)
+	{
+		HDC h = ::GetWindowDC(hWnd);
+		reset(h, hWnd, false);
+
+		return h;
+	}
+
+	HDC GetDCEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
+	{
+		HDC h = ::GetDCEx(hWnd, hrgnClip, flags);
+		reset(h, hWnd, false);
+
+		return h;
+	}
+
+	HDC CreateDC(LPCTSTR lpszDriver, LPCTSTR lpszDevice, LPCTSTR lpszOutput, CONST DEVMODE* lpInitData)
+	{
+		HDC h = ::CreateDC(lpszDriver, lpszDevice, lpszOutput, lpInitData);
+		reset(h, nullptr, true);
+
+		return h;
+	}
+
+	HDC CreateCompatibleDC(HDC hSrc)
+	{
+		HDC h = ::CreateCompatibleDC(hSrc);
+		reset(h, nullptr, true);
+
+		return h;
+	}
+
+	HGDIOBJ GetCurrentObject(UINT uObjectType)
+	{
+		return ::GetCurrentObject(m_h, uObjectType);
+	}
+
+	HBITMAP _GetCurrentBitmap()
+	{
+		return (HBITMAP)GetCurrentObject(OBJ_BITMAP);
+	}
+
+	HBRUSH _GetCurrentBrush()
+	{
+		return (HBRUSH)GetCurrentObject(OBJ_BRUSH);
+	}
+
+	HPALETTE _GetCurrentPalette()
+	{
+		return (HPALETTE)GetCurrentObject(OBJ_PAL);
+	}
+
+	HPEN _GetCurrentPen()
+	{
+		return (HPEN)GetCurrentObject(OBJ_PEN);
+	}
+
+	HFONT _GetCurrentFont()
+	{
+		return (HFONT)GetCurrentObject(OBJ_FONT);
+	}
+
+	int SelectClipRgn(HRGN hrgn)
+	{
+		return ::SelectClipRgn(m_h, hrgn);
+	}
+
+	int ExtSelectClipRgn(HRGN hrgn, int mode)
+	{
+		return ::ExtSelectClipRgn(m_h, hrgn, mode);
+	}
+
+	HGDIOBJ SelectObject(HGDIOBJ hgdiobj)
+	{
+		return ::SelectObject(m_h, hgdiobj);
+	}
+
+	HPALETTE SelectPalette(HPALETTE hpal, BOOL bForceBackground)
+	{
+		return ::SelectPalette(m_h, hpal, bForceBackground);
+	}
+
+	HBITMAP _SelectBitmap(HBITMAP hbm)
+	{
+		return (HBITMAP)SelectObject(hbm);
+	}
+
+	HBRUSH _SelectBrush(HBRUSH hbr)
+	{
+		return (HBRUSH)SelectObject(hbr);
+	}
+
+	HPEN _SelectPen(HPEN hpen)
+	{
+		return (HPEN)SelectObject(hpen);
+	}
+
+	HRGN _SelectRgn(HRGN hrgn)
+	{
+		return (HRGN)SelectObject(hrgn);
+	}
+
+	HFONT _SelectFont(HFONT hf)
+	{
+		return (HFONT)SelectObject(hf);
+	}
+
+	auto_dc& reset(HDC h = nullptr, HWND w = nullptr, bool is_create = false)
+	{
+		if(h != m_h || w != m_w)
+		{
+			if(is_valid())
+			{
+				if(m_is_create)
+					VERIFY(::DeleteDC(m_h));
+				else
+					VERIFY(::ReleaseDC(m_w, m_h));
+			}
+
+			set(h, w, is_create);
+		}
+
+		return *this;
+	}
+
+	auto_dc& reset(auto_dc& other)
+	{
+		if(this != &other)
+		{
+			reset(other.m_h, other.m_w, other.m_is_create);
+			other.release();
+		}
+
+		return *this;
+	}
+
+	HDC release()
+	{
+		HDC h = get_dc();
+		set(nullptr, nullptr, false);
+
+		return h;
+	}
+
+	/*
+	auto_dc& operator = (HDC h)
+	{
+		return reset(h);
+	}
+	*/
+
+	auto_dc& operator = (auto_dc& other)	{return reset(other);}
+
+	operator	HDC			()	const	{return m_h;}
+	HDC			get_dc		()	const	{return m_h;}
+	const HDC&	get_dc_ref	()	const	{return m_h;}
+	HWND		get_wnd		()	const	{return m_w;}
+	bool		is_valid	()	const	{return m_h != nullptr;}
+	bool		is_create	()	const	{return m_is_create;}
+
+private:
+	void set(HDC h, HWND w, bool is_create)
+	{
+		m_h			= h;
+		m_w			= w;
+		m_is_create	= is_create;
+	}
+
+private:
+	HDC		m_h;
+	HWND	m_w;
+	bool	m_is_create;
+};
+
+class paint_dc
+{
+public:
+	paint_dc(HWND hwnd) : m_hwnd(hwnd)
+	{
+		VERIFY(m_hdc = ::BeginPaint(m_hwnd, &m_ps));
+	}
+
+	~paint_dc()
+	{
+		VERIFY(::EndPaint(m_hwnd, &m_ps));
+	}
+
+	operator HDC ()	const	{return m_hdc;}
+	bool is_valid()	const	{return m_hdc != nullptr;}
+
+public:
+	PAINTSTRUCT	m_ps;
+	HWND		m_hwnd;
+	HDC			m_hdc;
+};
+/************************************************************************/
+/*                 	  	 	GDI Object 智能包装器 					    */
+/************************************************************************/
+
+template<class T>
+class auto_gdi_obj
+{
+public:
+	auto_gdi_obj(T obj = nullptr)				{set(obj);}
+	auto_gdi_obj(auto_gdi_obj<T>& other)	{set(other.release());}
+
+	~auto_gdi_obj()	{reset();}
+
+	auto_gdi_obj<T>& reset(T obj = nullptr)
+	{
+		if(obj != m_obj)
+		{
+			if(is_valid())
+			{
+				VERIFY(::DeleteObject(m_obj));
+			}
+
+			set(obj);
+		}
+
+		return *this;
+	}
+
+	auto_gdi_obj<T>& reset(auto_gdi_obj<T>& other)
+	{
+		if(this != &other)
+			reset(other.release());
+
+		return *this;
+	}
+
+	T release()
+	{
+		T obj = get();
+		set(nullptr);
+
+		return obj;
+	}
+
+	auto_gdi_obj<T>& operator = (T obj)						{return reset(obj);}
+	auto_gdi_obj<T>& operator = (auto_gdi_obj<T>& other)	{return reset(other);}
+
+	operator	T		()	const	{return m_obj;}
+	T			get		()	const	{return m_obj;}
+	const T&	get_ref	()	const	{return m_obj;}
+	bool		is_valid()	const	{return m_obj != nullptr;}
+
+private:
+	void set(T obj)	{m_obj = obj;}
+
+protected:
+	T m_obj;
+};
+
+typedef auto_gdi_obj<HBITMAP>		auto_bitmap_base;
+typedef auto_gdi_obj<HBRUSH>		auto_brush_base;
+typedef auto_gdi_obj<HPALETTE>		auto_palette_base;
+typedef auto_gdi_obj<HPEN>			auto_pen_base;
+typedef auto_gdi_obj<HRGN>			auto_rgn_base;
+typedef auto_gdi_obj<HFONT>			auto_font_base;
+
+class auto_bitmap : public auto_bitmap_base
+{
+public:
+	auto_bitmap(HBITMAP obj = nullptr) : auto_bitmap_base(obj) {}
+
+	auto_bitmap& operator = (HBITMAP obj)
+	{
+		return (auto_bitmap&)reset(obj);
+	}
+
+	HBITMAP CreateBitmap(int nWidth, int nHeight, UINT cPlanes, UINT cBitsPerPel, CONST VOID* lpvBits)
+	{
+		HBITMAP obj = ::CreateBitmap(nWidth, nHeight, cPlanes, cBitsPerPel, lpvBits);
+		reset(obj);
+
+		return obj;
+	}
+
+	HBITMAP CreateBitmapIndirect(CONST BITMAP *lpbm)
+	{
+		HBITMAP obj = ::CreateBitmapIndirect(lpbm);
+		reset(obj);
+
+		return obj;
+	}
+
+	HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight)
+	{
+		HBITMAP obj = ::CreateCompatibleBitmap(hdc, nWidth, nHeight);
+		reset(obj);
+
+		return obj;
+	}
+
+	HBITMAP CreateDIBSection(HDC hdc, const BITMAPINFO* pbmi, UINT iUsage, void** ppvBits, HANDLE hSection, DWORD dwOffset)
+	{
+		HBITMAP obj = ::CreateDIBSection(hdc, pbmi, iUsage, ppvBits, hSection, dwOffset);
+		reset(obj);
+
+		return obj;
+	}
+
+	HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName)
+	{
+		HBITMAP obj = ::LoadBitmap(hInstance, lpBitmapName);
+		reset(obj);
+
+		return obj;
+	}
+
+	int GetBitmap(BITMAP* pBitMap)
+	{
+		ASSERT(m_obj != nullptr);
+		return ::GetObject(m_obj, sizeof(BITMAP), pBitMap);
+	}
+
+	int GetDIBSection(DIBSECTION* pDIBSection)
+	{
+		ASSERT(m_obj != nullptr);
+		return ::GetObject(m_obj, sizeof(DIBSECTION), pDIBSection);
+	}
+};
+
+class auto_brush : public auto_brush_base
+{
+public:
+	auto_brush(HBRUSH obj = nullptr) : auto_brush_base(obj) {}
+
+	auto_brush& operator = (HBRUSH obj)
+	{
+		return (auto_brush&)reset(obj);
+	}
+
+	HBRUSH CreateDIBPatternBrushPt(const void* lpPackedDIB, UINT iUsage)
+	{
+		HBRUSH obj = ::CreateDIBPatternBrushPt(lpPackedDIB, iUsage);
+		reset(obj);
+
+		return obj;
+	}
+
+	HBRUSH CreatePatternBrush(HBITMAP hbmp)
+	{
+		HBRUSH obj = ::CreatePatternBrush(hbmp);
+		reset(obj);
+
+		return obj;
+	}
+
+	HBRUSH CreateSolidBrush(COLORREF crColor)
+	{
+		HBRUSH obj = ::CreateSolidBrush(crColor);
+		reset(obj);
+
+		return obj;
+	}
+
+	int GetLogBrush(LOGBRUSH* pLogBrush)
+	{
+		ASSERT(m_obj != nullptr);
+		return ::GetObject(m_obj, sizeof(LOGBRUSH), pLogBrush);
+	}
+};
+
+class auto_palette : public auto_palette_base
+{
+public:
+	auto_palette(HPALETTE obj = nullptr) : auto_palette_base(obj) {}
+
+	auto_palette& operator = (HPALETTE obj)
+	{
+		return (auto_palette&)reset(obj);
+	}
+
+	HPALETTE CreatePalette(CONST LOGPALETTE* lplgpl)
+	{
+		HPALETTE obj = ::CreatePalette(lplgpl);
+		reset(obj);
+
+		return obj;
+	}
+
+	int GetEntryCount()
+	{
+		ASSERT(m_obj != nullptr);
+
+		WORD nEntries;
+		::GetObject(m_obj, sizeof(WORD), &nEntries);
+		return (int)nEntries;
+	}
+};
+
+class auto_pen : public auto_pen_base
+{
+public:
+	auto_pen(HPEN obj = nullptr) : auto_pen_base(obj) {}
+
+	auto_pen& operator = (HPEN obj)
+	{
+		return (auto_pen&)reset(obj);
+	}
+
+	HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor)
+	{
+		HPEN obj = ::CreatePen(fnPenStyle, nWidth, crColor);
+		reset(obj);
+
+		return obj;
+	}
+
+	HPEN CreatePenIndirect(const LOGPEN* lplgpn)
+	{
+		HPEN obj = ::CreatePenIndirect(lplgpn);
+		reset(obj);
+
+		return obj;
+	}
+
+	int GetLogPen(LOGPEN* pLogPen)
+	{
+		ASSERT(m_obj != nullptr);
+		return ::GetObject(m_obj, sizeof(LOGPEN), pLogPen);
+	}
+};
+
+class auto_rgn : public auto_rgn_base
+{
+public:
+	auto_rgn(HRGN obj = nullptr) : auto_rgn_base(obj) {}
+
+	auto_rgn& operator = (HRGN obj)
+	{
+		return (auto_rgn&)reset(obj);
+	}
+
+	HRGN CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
+	{
+		HRGN obj = ::CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect);
+		reset(obj);
+
+		return obj;
+	}
+
+	HRGN CreateRectRgnIndirect(const RECT* lprc)
+	{
+		HRGN obj = ::CreateRectRgnIndirect(lprc);
+		reset(obj);
+
+		return obj;
+	}
+};
+
+class auto_font : public auto_font_base
+{
+public:
+	auto_font(HFONT obj = nullptr) : auto_font_base(obj) {}
+
+	auto_font& operator = (HFONT obj)
+	{
+		return (auto_font&)reset(obj);
+	}
+
+	HFONT CreateFont(
+						int nHeight,				// height of font
+						int nWidth,					// average character width
+						int nEscapement,			// angle of escapement
+						int nOrientation,			// base-line orientation angle
+						int fnWeight,				// font weight
+						DWORD bItalic,				// italic attribute option
+						DWORD bUnderline,			// underline attribute option
+						DWORD cStrikeOut,			// strikeout attribute option
+						DWORD nCharSet,				// character set identifier
+						DWORD nOutPrecision,		// output precision
+						DWORD nClipPrecision,		// clipping precision
+						DWORD nQuality,				// output quality
+						DWORD nPitchAndFamily,		// pitch and family
+						LPCTSTR lpszFace           // typeface name
+					)
+	{
+		HFONT obj = ::CreateFont(
+									nHeight,
+									nWidth,
+									nEscapement,
+									nOrientation,
+									fnWeight,
+									bItalic,
+									bUnderline,
+									cStrikeOut,
+									nCharSet,
+									nOutPrecision,
+									nClipPrecision,
+									nQuality,
+									nPitchAndFamily,
+									lpszFace
+								);
+		reset(obj);
+
+		return obj;
+	}
+
+	HFONT CreateFontIndirect(const LOGFONT* lplf)
+	{
+		HFONT obj = ::CreateFontIndirect(lplf);
+		reset(obj);
+
+		return obj;
+	}
+
+	int GetLogFont(LOGFONT* pLogFont)
+	{
+		ASSERT(m_obj != nullptr);
+		return ::GetObject(m_obj, sizeof(LOGFONT), pLogFont);
+	}
+};

+ 437 - 0
common/Src/bufferpool.cpp

@@ -0,0 +1,437 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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:  BufferPool.cpp
+Notices: Copyright (c) 2013 Bruce Liang
+Purpose: ¼òµ¥Äڴ滺³å³Ø
+Desc:
+******************************************************************************/
+
+#include "stdafx.h"
+#include "bufferpool.h"
+#include "SysHelper.h"
+#include "WaitFor.h"
+
+const DWORD TItem::DEFAULT_ITEM_CAPACITY			= ::SysGetPageSize();
+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	= 10 * 1000;
+const DWORD CBufferPool::DEFAULT_BUFFER_POOL_SIZE	= 150;
+const DWORD CBufferPool::DEFAULT_BUFFER_POOL_HOLD	= 600;
+
+TItem* TItem::Construct(CPrivateHeap& heap, int capacity, BYTE* pData, int length)
+{
+	ASSERT(capacity > 0);
+
+	int item_size	= sizeof(TItem);
+	TItem* pItem	= (TItem*)heap.Alloc(item_size + capacity);
+	pItem->head		= (BYTE*)pItem + item_size;
+
+	pItem->TItem::TItem(heap, capacity, pData, length);
+
+	return pItem;
+}
+
+void TItem::Destruct(TItem* pItem)
+{
+	ASSERT(pItem != nullptr);
+
+	CPrivateHeap& heap = pItem->heap;
+	pItem->TItem::~TItem();
+	heap.Free(pItem);
+}
+
+inline 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;
+}
+
+inline int TItem::Cat(const TItem& other)
+{
+	ASSERT(this != &other);
+	return Cat(other.Ptr(), other.Size());
+}
+
+inline 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;
+}
+
+inline int TItem::Peek(BYTE* pData, int length)
+{
+	ASSERT(pData != nullptr && length > 0);
+
+	int peek = min(Size(), length);
+	memcpy(pData, begin, peek);
+
+	return peek;
+}
+
+inline int TItem::Reduce(int length)
+{
+	ASSERT(length > 0);
+
+	int reduce   = min(Size(), length);
+	begin		+= reduce;
+
+	return reduce;
+}
+
+inline 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);
+}
+
+int TItemList::Cat(const BYTE* pData, int length)
+{
+	int remain = length;
+
+	while(remain > 0)
+	{
+		TItem* pItem = Back();
+
+		if(pItem == nullptr || pItem->IsFull())
+			pItem = PushBack(itPool.PickFreeItem());
+
+		int cat  = pItem->Cat(pData, remain);
+
+		pData	+= cat;
+		remain	-= cat;
+	}
+
+	return length;
+}
+
+int TItemList::Cat(const TItem* pItem)
+{
+	return Cat(pItem->Ptr(), pItem->Size());
+}
+
+int TItemList::Cat(const TItemList& other)
+{
+	ASSERT(this != &other);
+
+	int length = 0;
+
+	for(TItem* pItem = other.Front(); pItem != nullptr; pItem = pItem->next)
+		length += Cat(pItem);
+
+	return length;
+}
+
+int TItemList::Fetch(BYTE* pData, int length)
+{
+	int remain = length;
+
+	while(remain > 0 && Size() > 0)
+	{
+		TItem* pItem = Front();
+		int fetch	 = pItem->Fetch(pData, remain);
+
+		pData	+= fetch;
+		remain	-= fetch;
+
+		if(pItem->IsEmpty())
+			itPool.PutFreeItem(PopFront());
+	}
+
+	return length - remain;
+}
+
+int TItemList::Peek(BYTE* pData, int length)
+{
+	int remain	 = length;
+	TItem* pItem = Front();
+
+	while(remain > 0 && pItem != nullptr)
+	{
+		int peek = pItem->Peek(pData, remain);
+
+		pData	+= peek;
+		remain	-= peek;
+		pItem	 = pItem->next;
+	}
+
+	return length - remain;
+}
+
+int TItemList::Reduce(int length)
+{
+	int remain = length;
+
+	while(remain > 0 && Size() > 0)
+	{
+		TItem* pItem = Front();
+		remain		-= pItem->Reduce(remain);
+
+		if(pItem->IsEmpty())
+			itPool.PutFreeItem(PopFront());
+	}
+
+	return length - remain;
+}
+
+void TItemList::Release()
+{
+	itPool.PutFreeItem(*this);
+}
+
+TBuffer* TBuffer::Construct(CBufferPool& pool, ULONG_PTR dwID)
+{
+	ASSERT(dwID != 0);
+
+	CPrivateHeap& heap	= pool.GetPrivateHeap();
+	TBuffer* pBuffer	= (TBuffer*)heap.Alloc(sizeof(TBuffer));
+
+	pBuffer->TBuffer::TBuffer(heap, pool.GetItemPool(), dwID);
+
+	return pBuffer;
+}
+
+void TBuffer::Destruct(TBuffer* pBuffer)
+{
+	ASSERT(pBuffer != nullptr);
+
+	CPrivateHeap& heap = pBuffer->heap;
+	pBuffer->TBuffer::~TBuffer();
+	heap.Free(pBuffer);
+}
+
+inline 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.Remove(pBuffer->ID());
+
+	BOOL bOK = FALSE;
+
+	{
+		CCriSecLock locallock(pBuffer->cs);
+
+		if(pBuffer->IsValid())
+		{
+			pBuffer->Reset();
+			bOK = TRUE;
+		}
+	}
+
+	if(bOK)
+	{
+		m_itPool.PutFreeItem(pBuffer->items);
+
+		if(!m_lsFreeBuffer.TryPut(pBuffer))
+		{
+			m_lsGCBuffer.PushBack(pBuffer);
+
+			if(m_lsGCBuffer.Size() > m_dwBufferPoolSize)
+				ReleaseGCBuffer();
+		}
+	}
+}
+
+void CBufferPool::ReleaseGCBuffer(BOOL bForce)
+{
+	TBuffer* pBuffer = nullptr;
+	DWORD now		 = ::TimeGetTime();
+
+	while(m_lsGCBuffer.PopFront(&pBuffer))
+	{
+		if(bForce || (int)(now - pBuffer->freeTime) >= (int)m_dwBufferLockTime)
+			TBuffer::Destruct(pBuffer);
+		else
+		{
+			m_lsGCBuffer.PushBack(pBuffer);
+			break;
+		}
+	}
+}
+
+TBuffer* CBufferPool::PutCacheBuffer(ULONG_PTR dwID)
+{
+	ASSERT(dwID != 0);
+
+	TBuffer* pBuffer = PickFreeBuffer(dwID);
+	m_bfCache.Set(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.Get(dwID, &pBuffer) != TBufferCache::GR_VALID)
+		pBuffer = nullptr;
+
+	return pBuffer;
+}
+
+void CBufferPool::Prepare()
+{
+	m_itPool.Prepare();
+
+	m_bfCache.Reset(m_dwMaxCacheSize);
+	m_lsFreeBuffer.Reset(m_dwBufferPoolHold);
+}
+
+void CBufferPool::Clear()
+{
+	DWORD size					= 0;
+	unique_ptr<ULONG_PTR[]> ids	= m_bfCache.GetAllElementIndexes(size, FALSE);
+
+	for(DWORD i = 0; i < size; i++)
+	{
+		TBuffer* pBuffer = FindCacheBuffer(ids[i]);
+		if(pBuffer) TBuffer::Destruct(pBuffer);
+	}
+
+	m_bfCache.Reset();
+
+	TBuffer* pBuffer = nullptr;
+
+	while(m_lsFreeBuffer.TryGet(&pBuffer))
+		TBuffer::Destruct(pBuffer);
+
+	VERIFY(m_lsFreeBuffer.IsEmpty());
+	m_lsFreeBuffer.Reset();
+
+	ReleaseGCBuffer(TRUE);
+	VERIFY(m_lsGCBuffer.IsEmpty());
+
+	m_itPool.Clear();
+	m_heap.Reset();
+}

+ 683 - 0
common/Src/bufferpool.h

@@ -0,0 +1,683 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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:  BufferPool.h
+Notices: Copyright (c) 2013 Bruce Liang
+Purpose: ¼òµ¥Äڴ滺³å³Ø
+Desc:
+******************************************************************************/
+
+#pragma once
+
+#include "Singleton.h"
+#include "STLHelper.h"
+#include "RingBuffer.h"
+#include "PrivateHeap.h"
+
+struct TItem
+{
+	template<typename T> friend struct	TSimpleList;
+	template<typename T> friend class	CNodePoolT;
+
+	friend struct	TItemList;
+	friend struct	TBuffer;
+
+public:
+	inline int Cat		(const BYTE* pData, int length);
+	inline int Cat		(const TItem& other);
+	inline int Fetch	(BYTE* pData, int length);
+	inline int Peek		(BYTE* pData, int length);
+	inline int Reduce	(int length);
+	inline 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;}
+
+public:
+	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);
+
+	static void Destruct(TItem* pItem);
+
+private:
+	TItem(CPrivateHeap& hp, int cap = DEFAULT_ITEM_CAPACITY, BYTE* pData = nullptr, int length = 0)
+	: heap(hp), capacity(cap), begin(head), end(head), 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 = 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 = 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->Reset();
+		else
+			pItem = T::Construct(m_heap, m_dwItemCapacity);
+
+		return pItem;
+	}
+
+	inline void Prepare()
+	{
+		m_lsFreeItem.Reset(m_dwPoolHold);
+	}
+
+	inline void Clear()
+	{
+		T* pItem = nullptr;
+
+		while(m_lsFreeItem.TryGet(&pItem))
+			T::Destruct(pItem);
+
+		VERIFY(m_lsFreeItem.IsEmpty());
+		m_lsFreeItem.Reset();
+
+		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;}
+
+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		= 300;
+template<class T> const DWORD CNodePoolT<T>::DEFAULT_POOL_HOLD		= 1200;
+
+typedef CNodePoolT<TItem>	CItemPool;
+
+struct TItemList : public TSimpleList<TItem>
+{
+public:
+	int Cat		(const BYTE* pData, int length);
+	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 length);
+	void Release();
+
+public:
+	TItemList(CItemPool& pool) : itPool(pool)
+	{
+	}
+
+private:
+	CItemPool& itPool;
+};
+
+struct TItemListEx : public TItemList
+{
+public:
+	TItem* PushFront(TItem* pItem)
+	{
+		length += pItem->Size();
+		return __super::PushFront(pItem);
+	}
+
+	TItem* PushBack(TItem* pItem)
+	{
+		length += pItem->Size();
+		return __super::PushBack(pItem);
+	}
+
+	TItem* PopFront()
+	{
+		TItem* pItem = __super::PopFront();
+
+		if(pItem != nullptr)
+			length -= pItem->Size();
+
+		return pItem;
+	}
+
+	TItem* PopBack()
+	{
+		TItem* pItem = __super::PopBack();
+
+		if(pItem != nullptr)
+			length -= pItem->Size();
+
+		return pItem;
+	}
+
+	TItemListEx& Shift(TItemListEx& 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 Cat(const BYTE* pData, int length)
+	{
+		int cat = __super::Cat(pData, length);
+		this->length += cat;
+
+		return cat;
+	}
+
+	int Cat(const TItem* pItem)
+	{
+		int cat = __super::Cat(pItem->Ptr(), pItem->Size());
+		this->length += cat;
+
+		return cat;
+	}
+
+	int Cat(const TItemList& 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 Reduce(int length)
+	{
+		int reduce	  = __super::Reduce(length);
+		this->length -= reduce;
+
+		return reduce;
+	}
+	
+	int Length() const {return length;}
+
+public:
+	TItemListEx(CItemPool& pool) : TItemList(pool), length(0)
+	{
+	}
+
+	~TItemListEx()
+	{
+		ASSERT(length >= 0);
+	}
+
+	DECLARE_NO_COPY_CLASS(TItemListEx)
+
+private:
+	int length;
+};
+
+struct TItemPtr
+{
+public:
+	TItem* Reset(TItem* pItem = nullptr)
+	{
+		if(m_pItem != nullptr)
+			itPool.PutFreeItem(m_pItem);
+
+		m_pItem = pItem;
+
+		return m_pItem;
+	}
+
+	TItem* Attach(TItem* pItem)
+	{
+		return Reset(pItem);
+	}
+
+	TItem* Detach()
+	{
+		TItem* pItem = m_pItem;
+		m_pItem		 = nullptr;
+
+		return pItem;
+	}
+
+	bool IsValid			()				{return m_pItem != nullptr;}
+	TItem* operator ->		()				{return m_pItem;}
+	TItem* operator =		(TItem* pItem)	{return Reset(pItem);}
+	operator TItem*			()				{return m_pItem;}
+	TItem* Ptr				()				{return m_pItem;}
+	const TItem* Ptr		()	const		{return m_pItem;}
+	operator const TItem*	()	const		{return m_pItem;}
+
+public:
+	TItemPtr(CItemPool& pool, TItem* pItem = nullptr)
+	: itPool(pool), m_pItem(pItem)
+	{
+
+	}
+
+	~TItemPtr()
+	{
+		Reset();
+	}
+
+	DECLARE_NO_COPY_CLASS(TItemPtr)
+
+private:
+	CItemPool&	itPool;
+	TItem*		m_pItem;
+};
+
+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;}
+
+private:
+	int IncreaseLength	(int len)	{return (length += len);}
+	int DecreaseLength	(int len)	{return (length -= len);}
+
+	inline void Reset	();
+
+private:
+	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
+{
+	typedef CRingPool<TBuffer>						TBufferList;
+	typedef CCASQueue<TBuffer>						TBufferQueue;
+
+	typedef CRingCache2<TBuffer, ULONG_PTR, true>	TBufferCache;
+
+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			();
+
+private:
+	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;
+};

+ 26 - 0
common/Src/bufferptr.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 "stdafx.h"
+#include "bufferptr.h"

+ 184 - 0
common/Src/bufferptr.h

@@ -0,0 +1,184 @@
+/*
+ * Copyright: JessMA Open Source (ldcsaa@gmail.com)
+ *
+ * Version	: 2.3.18
+ * Author	: Bruce Liang
+ * Website	: http://www.jessma.org
+ * Project	: https://github.com/ldcsaa
+ * Blog		: http://www.cnblogs.com/ldcsaa
+ * Wiki		: http://www.oschina.net/p/hp-socket
+ * QQ Group	: 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 <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);
+	}
+
+	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;}
+	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 >= 0 && size != m_size)
+		{
+			size_t rsize = GetAllocSize(size);
+			if(size > m_capacity || rsize < m_size)
+			{
+				m_pch = is_realloc							?
+					(T*)realloc(m_pch, rsize * sizeof(T))	:
+					(T*)malloc(rsize * sizeof(T))			;
+
+				if(m_pch || rsize == 0)
+				{
+					m_size		= size;
+					m_capacity	= rsize;
+				}
+				else
+					Reset();
+			}
+			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