1009 lines
30 KiB
C++
1009 lines
30 KiB
C++
/*
|
||
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
||
*
|
||
* Author : Bruce Liang
|
||
* Website : https://github.com/ldcsaa
|
||
* Project : https://github.com/ldcsaa/HP-Socket
|
||
* Blog : http://www.cnblogs.com/ldcsaa
|
||
* Wiki : http://www.oschina.net/p/hp-socket
|
||
* QQ Group : 44636872, 75375912
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
#pragma once
|
||
|
||
#include "hpsocket/HPTypeDef.h"
|
||
#include "hpsocket/SocketInterface.h"
|
||
#include "common/StringT.h"
|
||
#include "common/SysHelper.h"
|
||
#include "common/BufferPtr.h"
|
||
#include "common/BufferPool.h"
|
||
#include "common/RingBuffer.h"
|
||
#include "common/FileHelper.h"
|
||
#include "InternalDef.h"
|
||
|
||
#include <netdb.h>
|
||
#include <sys/un.h>
|
||
#include <sys/socket.h>
|
||
#include <arpa/inet.h>
|
||
|
||
#ifdef _ZLIB_SUPPORT
|
||
#include <zlib.h>
|
||
#endif
|
||
|
||
#ifdef _BROTLI_SUPPORT
|
||
#include <brotli/decode.h>
|
||
#include <brotli/encode.h>
|
||
#endif
|
||
|
||
using ADDRESS_FAMILY = sa_family_t;
|
||
using IN_ADDR = in_addr;
|
||
using IN6_ADDR = in6_addr;
|
||
using SOCKADDR = sockaddr;
|
||
using SOCKADDR_IN = sockaddr_in;
|
||
using SOCKADDR_IN6 = sockaddr_in6;
|
||
|
||
typedef struct hp_addr
|
||
{
|
||
ADDRESS_FAMILY family;
|
||
|
||
union
|
||
{
|
||
ULONG_PTR addr;
|
||
IN_ADDR addr4;
|
||
IN6_ADDR addr6;
|
||
};
|
||
|
||
static const hp_addr ANY_ADDR4;
|
||
static const hp_addr ANY_ADDR6;
|
||
|
||
inline int AddrSize() const
|
||
{
|
||
return AddrSize(family);
|
||
}
|
||
|
||
inline static int AddrSize(ADDRESS_FAMILY f)
|
||
{
|
||
if(f == AF_INET)
|
||
return sizeof(IN_ADDR);
|
||
|
||
return sizeof(IN6_ADDR);
|
||
}
|
||
|
||
inline static const hp_addr& AnyAddr(ADDRESS_FAMILY f)
|
||
{
|
||
if(f == AF_INET)
|
||
return ANY_ADDR4;
|
||
|
||
return ANY_ADDR6;
|
||
}
|
||
|
||
inline const ULONG_PTR* Addr() const {return &addr;}
|
||
inline ULONG_PTR* Addr() {return &addr;}
|
||
|
||
inline BOOL IsIPv4() const {return family == AF_INET;}
|
||
inline BOOL IsIPv6() const {return family == AF_INET6;}
|
||
inline BOOL IsSpecified() const {return IsIPv4() || IsIPv6();}
|
||
inline void ZeroAddr() {::ZeroMemory(&addr6, sizeof(addr6));}
|
||
inline void Reset() {::ZeroMemory(this, sizeof(*this));}
|
||
|
||
inline hp_addr& Copy(hp_addr& other) const
|
||
{
|
||
if(this != &other)
|
||
memcpy(&other, this, offsetof(hp_addr, addr) + AddrSize());
|
||
|
||
return other;
|
||
}
|
||
|
||
hp_addr(ADDRESS_FAMILY f = AF_UNSPEC, BOOL bZeroAddr = FALSE)
|
||
{
|
||
family = f;
|
||
|
||
if(bZeroAddr) ZeroAddr();
|
||
}
|
||
|
||
} HP_ADDR, *HP_PADDR;
|
||
|
||
typedef struct hp_sockaddr
|
||
{
|
||
union
|
||
{
|
||
ADDRESS_FAMILY family;
|
||
SOCKADDR addr;
|
||
SOCKADDR_IN addr4;
|
||
SOCKADDR_IN6 addr6;
|
||
};
|
||
|
||
inline int AddrSize() const
|
||
{
|
||
return AddrSize(family);
|
||
}
|
||
|
||
inline static int AddrSize(ADDRESS_FAMILY f)
|
||
{
|
||
if(f == AF_INET)
|
||
return sizeof(SOCKADDR_IN);
|
||
|
||
return sizeof(SOCKADDR_IN6);
|
||
}
|
||
|
||
inline int EffectAddrSize() const
|
||
{
|
||
return EffectAddrSize(family);
|
||
}
|
||
|
||
inline static int EffectAddrSize(ADDRESS_FAMILY f)
|
||
{
|
||
return (f == AF_INET) ? offsetof(SOCKADDR_IN, sin_zero) : sizeof(SOCKADDR_IN6);
|
||
}
|
||
|
||
inline static const hp_sockaddr& AnyAddr(ADDRESS_FAMILY f)
|
||
{
|
||
static const hp_sockaddr s_any_addr4(AF_INET, TRUE);
|
||
static const hp_sockaddr s_any_addr6(AF_INET6, TRUE);
|
||
|
||
if(f == AF_INET)
|
||
return s_any_addr4;
|
||
|
||
return s_any_addr6;
|
||
}
|
||
|
||
inline static int AddrMinStrLength(ADDRESS_FAMILY f)
|
||
{
|
||
if(f == AF_INET)
|
||
return INET_ADDRSTRLEN;
|
||
|
||
return INET6_ADDRSTRLEN;
|
||
}
|
||
|
||
inline BOOL IsIPv4() const {return family == AF_INET;}
|
||
inline BOOL IsIPv6() const {return family == AF_INET6;}
|
||
inline BOOL IsSpecified() const {return IsIPv4() || IsIPv6();}
|
||
inline USHORT Port() const {return ntohs(addr4.sin_port);}
|
||
inline void SetPort(USHORT usPort) {addr4.sin_port = htons(usPort);}
|
||
inline void* SinAddr() const {return IsIPv4() ? (void*)&addr4.sin_addr : (void*)&addr6.sin6_addr;}
|
||
inline void* SinAddr() {return IsIPv4() ? (void*)&addr4.sin_addr : (void*)&addr6.sin6_addr;}
|
||
|
||
inline const SOCKADDR* Addr() const {return &addr;}
|
||
inline SOCKADDR* Addr() {return &addr;}
|
||
inline void ZeroAddr() {::ZeroMemory(((char*)this) + sizeof(family), sizeof(*this) - sizeof(family));}
|
||
inline void Reset() {::ZeroMemory(this, sizeof(*this));}
|
||
|
||
inline hp_sockaddr& Copy(hp_sockaddr& other) const
|
||
{
|
||
if(this != &other)
|
||
memcpy(&other, this, AddrSize());
|
||
|
||
return other;
|
||
}
|
||
|
||
size_t Hash() const
|
||
{
|
||
ASSERT(IsSpecified());
|
||
|
||
size_t _Val = 2166136261U;
|
||
const int size = EffectAddrSize();
|
||
const BYTE* pAddr = (const BYTE*)Addr();
|
||
|
||
for(int i = 0; i < size; i++)
|
||
_Val = 16777619U * _Val ^ (size_t)pAddr[i];
|
||
|
||
return (_Val);
|
||
}
|
||
|
||
bool EqualTo(const hp_sockaddr& other) const
|
||
{
|
||
ASSERT(IsSpecified() && other.IsSpecified());
|
||
|
||
return EqualMemory(this, &other, EffectAddrSize());
|
||
}
|
||
|
||
hp_sockaddr(ADDRESS_FAMILY f = AF_UNSPEC, BOOL bZeroAddr = FALSE)
|
||
{
|
||
family = f;
|
||
|
||
if(bZeroAddr) ZeroAddr();
|
||
}
|
||
|
||
} HP_SOCKADDR, *HP_PSOCKADDR;
|
||
|
||
typedef struct hp_scope_host
|
||
{
|
||
LPCTSTR addr;
|
||
LPCTSTR name;
|
||
|
||
BOOL bNeedFree;
|
||
|
||
hp_scope_host(LPCTSTR lpszOriginAddress)
|
||
{
|
||
ASSERT(lpszOriginAddress != nullptr);
|
||
|
||
LPCTSTR lpszFind = ::StrChr(lpszOriginAddress, HOST_SEPARATOR_CHAR);
|
||
|
||
if(lpszFind == nullptr)
|
||
{
|
||
addr = lpszOriginAddress;
|
||
name = lpszOriginAddress;
|
||
bNeedFree = FALSE;
|
||
}
|
||
else
|
||
{
|
||
int i = (int)(lpszFind - lpszOriginAddress);
|
||
int iSize = (int)lstrlen(lpszOriginAddress) + 1;
|
||
LPTSTR lpszCopy = new TCHAR[iSize];
|
||
|
||
::memcpy((PVOID)lpszCopy, (PVOID)lpszOriginAddress, iSize * sizeof(TCHAR));
|
||
|
||
lpszCopy[i] = 0;
|
||
addr = lpszCopy;
|
||
name = lpszCopy + i + 1;
|
||
bNeedFree = TRUE;
|
||
|
||
if(::IsStrEmpty(name))
|
||
name = addr;
|
||
}
|
||
}
|
||
|
||
~hp_scope_host()
|
||
{
|
||
if(bNeedFree)
|
||
delete[] addr;
|
||
}
|
||
|
||
} HP_SCOPE_HOST, *HP_PSCOPE_HOST;
|
||
|
||
struct TNodeBufferObj : public TItem
|
||
{
|
||
using __super = TItem;
|
||
|
||
HP_SOCKADDR remoteAddr;
|
||
|
||
public:
|
||
void Reset(int first = 0, int last = 0)
|
||
{
|
||
__super::Reset(first, last);
|
||
remoteAddr.Reset();
|
||
}
|
||
|
||
public:
|
||
static TNodeBufferObj* Construct(CPrivateHeap& heap,
|
||
int capacity = DEFAULT_ITEM_CAPACITY,
|
||
BYTE* pData = nullptr,
|
||
int length = 0)
|
||
{
|
||
return ::ConstructItemT((TNodeBufferObj*)(nullptr), heap, capacity, pData, length);
|
||
}
|
||
|
||
static void Destruct(TNodeBufferObj* pBufferObj)
|
||
{
|
||
::DestructItemT(pBufferObj);
|
||
}
|
||
|
||
TNodeBufferObj(CPrivateHeap& hp, BYTE* pHead, int cap = DEFAULT_ITEM_CAPACITY, BYTE* pData = nullptr, int length = 0)
|
||
: TItem(hp, pHead, cap, pData, length)
|
||
{
|
||
|
||
}
|
||
|
||
~TNodeBufferObj()
|
||
{
|
||
}
|
||
|
||
DECLARE_NO_COPY_CLASS(TNodeBufferObj)
|
||
};
|
||
|
||
typedef CCASQueue<TNodeBufferObj> CNodeRecvQueue;
|
||
typedef TItemPtrT<TNodeBufferObj> TNodeBufferObjPtr;
|
||
typedef CNodePoolT<TNodeBufferObj> CNodeBufferObjPool;
|
||
typedef TItemListExT<TNodeBufferObj, volatile int> TNodeBufferObjList;
|
||
|
||
/* Server 组件和 Agent 组件内部使用的事件处理结果常量 */
|
||
|
||
// 连接已关闭
|
||
#define HR_CLOSED 0xFF
|
||
|
||
/* 命令类型 */
|
||
enum EnDispCmdType
|
||
{
|
||
DISP_CMD_SEND = 0x01, // 发送数据
|
||
DISP_CMD_RECEIVE = 0x02, // 接收数据
|
||
DISP_CMD_UNPAUSE = 0x03, // 恢复接收数据
|
||
DISP_CMD_DISCONNECT = 0x04, // 断开连接
|
||
DISP_CMD_TIMEOUT = 0x05 // 保活超时
|
||
};
|
||
|
||
/* 关闭连接标识 */
|
||
enum EnSocketCloseFlag
|
||
{
|
||
SCF_NONE = 0, // 不触发事件
|
||
SCF_CLOSE = 1, // 触发 正常关闭 OnClose 事件
|
||
SCF_ERROR = 2 // 触发 异常关闭 OnClose 事件
|
||
};
|
||
|
||
/* 数据缓冲节点 */
|
||
typedef TItem TBufferObj;
|
||
/* 数据缓冲节点智能指针 */
|
||
typedef TItemPtr TBufferObjPtr;
|
||
/* 数据缓冲区对象池 */
|
||
typedef CItemPool CBufferObjPool;
|
||
/* 数据缓冲区链表模板 */
|
||
typedef TItemListExV TBufferObjList;
|
||
|
||
/* 线程 ID - 接收缓冲区哈希表 */
|
||
typedef unordered_map<THR_ID, CBufferPtr*> TReceiveBufferMap;
|
||
/* 线程 ID - 接收缓冲区哈希表迭代器 */
|
||
typedef TReceiveBufferMap::iterator TReceiveBufferMapI;
|
||
/* 线程 ID - 接收缓冲区哈希表 const 迭代器 */
|
||
typedef TReceiveBufferMap::const_iterator TReceiveBufferMapCI;
|
||
|
||
/* Socket 缓冲区基础结构 */
|
||
struct TSocketObjBase : public CSafeCounter
|
||
{
|
||
CPrivateHeap& heap;
|
||
|
||
CONNID connID;
|
||
HP_SOCKADDR remoteAddr;
|
||
PVOID extra;
|
||
PVOID reserved;
|
||
PVOID reserved2;
|
||
DWORD activeTime;
|
||
|
||
union
|
||
{
|
||
DWORD freeTime;
|
||
DWORD connTime;
|
||
};
|
||
|
||
volatile BOOL valid;
|
||
volatile BOOL connected;
|
||
volatile BOOL paused;
|
||
|
||
TSocketObjBase(CPrivateHeap& hp) : heap(hp) {}
|
||
|
||
static BOOL IsExist(TSocketObjBase* pSocketObj)
|
||
{return pSocketObj != nullptr;}
|
||
|
||
static BOOL IsValid(TSocketObjBase* pSocketObj)
|
||
{return (IsExist(pSocketObj) && pSocketObj->valid == TRUE);}
|
||
|
||
static void Invalid(TSocketObjBase* pSocketObj)
|
||
{ASSERT(IsExist(pSocketObj)); pSocketObj->valid = FALSE;}
|
||
|
||
static void Release(TSocketObjBase* pSocketObj)
|
||
{ASSERT(IsExist(pSocketObj)); pSocketObj->freeTime = ::TimeGetTime();}
|
||
|
||
DWORD GetConnTime () const {return connTime;}
|
||
DWORD GetFreeTime () const {return freeTime;}
|
||
DWORD GetActiveTime () const {return activeTime;}
|
||
BOOL IsPaused () const {return paused;}
|
||
|
||
BOOL HasConnected() {return connected == TRUE;}
|
||
BOOL IsConnecting() {return connected == CST_CONNECTING;}
|
||
void SetConnected(BOOL bConnected = TRUE) {connected = bConnected;}
|
||
|
||
void Reset(CONNID dwConnID)
|
||
{
|
||
ResetCount();
|
||
|
||
connID = dwConnID;
|
||
connected = FALSE;
|
||
valid = TRUE;
|
||
paused = FALSE;
|
||
extra = nullptr;
|
||
reserved = nullptr;
|
||
reserved2 = nullptr;
|
||
}
|
||
};
|
||
|
||
/* 数据缓冲区结构 */
|
||
struct TSocketObj : public TSocketObjBase
|
||
{
|
||
using __super = TSocketObjBase;
|
||
|
||
CReentrantCriSec csIo;
|
||
CReentrantCriSec csSend;
|
||
|
||
SOCKET socket;
|
||
TBufferObjList sndBuff;
|
||
|
||
static TSocketObj* Construct(CPrivateHeap& hp, CBufferObjPool& bfPool)
|
||
{
|
||
TSocketObj* pSocketObj = (TSocketObj*)hp.Alloc(sizeof(TSocketObj));
|
||
ASSERT(pSocketObj);
|
||
|
||
return new (pSocketObj) TSocketObj(hp, bfPool);
|
||
}
|
||
|
||
static void Destruct(TSocketObj* pSocketObj)
|
||
{
|
||
ASSERT(pSocketObj);
|
||
|
||
CPrivateHeap& heap = pSocketObj->heap;
|
||
pSocketObj->TSocketObj::~TSocketObj();
|
||
heap.Free(pSocketObj);
|
||
}
|
||
|
||
TSocketObj(CPrivateHeap& hp, CBufferObjPool& bfPool)
|
||
: __super(hp), sndBuff(bfPool)
|
||
{
|
||
|
||
}
|
||
|
||
static void Release(TSocketObj* pSocketObj)
|
||
{
|
||
__super::Release(pSocketObj);
|
||
pSocketObj->sndBuff.Release();
|
||
}
|
||
|
||
int Pending() {return sndBuff.Length();}
|
||
BOOL IsPending() {return Pending() > 0;}
|
||
|
||
static BOOL InvalidSocketObj(TSocketObj* pSocketObj)
|
||
{
|
||
BOOL bDone = FALSE;
|
||
|
||
if(TSocketObjBase::IsValid(pSocketObj))
|
||
{
|
||
pSocketObj->SetConnected(FALSE);
|
||
|
||
CReentrantCriSecLock locallock(pSocketObj->csIo);
|
||
CReentrantCriSecLock locallock2(pSocketObj->csSend);
|
||
|
||
if(TSocketObjBase::IsValid(pSocketObj))
|
||
{
|
||
TSocketObjBase::Invalid(pSocketObj);
|
||
bDone = TRUE;
|
||
}
|
||
}
|
||
|
||
return bDone;
|
||
}
|
||
|
||
void Reset(CONNID dwConnID, SOCKET soClient)
|
||
{
|
||
__super::Reset(dwConnID);
|
||
|
||
socket = soClient;
|
||
}
|
||
};
|
||
|
||
/* Agent 数据缓冲区结构 */
|
||
struct TAgentSocketObj : public TSocketObj
|
||
{
|
||
using __super = TSocketObj;
|
||
|
||
CStringA host;
|
||
|
||
static TAgentSocketObj* Construct(CPrivateHeap& hp, CBufferObjPool& bfPool)
|
||
{
|
||
TAgentSocketObj* pSocketObj = (TAgentSocketObj*)hp.Alloc(sizeof(TAgentSocketObj));
|
||
ASSERT(pSocketObj);
|
||
|
||
return new (pSocketObj) TAgentSocketObj(hp, bfPool);
|
||
}
|
||
|
||
static void Destruct(TAgentSocketObj* pSocketObj)
|
||
{
|
||
ASSERT(pSocketObj);
|
||
|
||
CPrivateHeap& heap = pSocketObj->heap;
|
||
pSocketObj->TAgentSocketObj::~TAgentSocketObj();
|
||
heap.Free(pSocketObj);
|
||
}
|
||
|
||
TAgentSocketObj(CPrivateHeap& hp, CBufferObjPool& bfPool)
|
||
: __super(hp, bfPool)
|
||
{
|
||
|
||
}
|
||
|
||
void Reset(CONNID dwConnID, SOCKET soClient)
|
||
{
|
||
__super::Reset(dwConnID, soClient);
|
||
|
||
host.Empty();
|
||
}
|
||
|
||
BOOL GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort = nullptr)
|
||
{
|
||
*lpszHost = host;
|
||
|
||
if(pusPort)
|
||
*pusPort = remoteAddr.Port();
|
||
|
||
return (!host.IsEmpty());
|
||
}
|
||
};
|
||
|
||
/* UDP 数据缓冲区结构 */
|
||
struct TUdpSocketObj : public TSocketObjBase
|
||
{
|
||
using __super = TSocketObjBase;
|
||
using CRecvQueue = CCASQueue<TItem>;
|
||
|
||
PVOID pHolder;
|
||
FD fdTimer;
|
||
|
||
CBufferObjPool& itPool;
|
||
|
||
CRWLock lcIo;
|
||
CRWLock lcSend;
|
||
CCriSec csSend;
|
||
|
||
TBufferObjList sndBuff;
|
||
CRecvQueue recvQueue;
|
||
|
||
volatile DWORD detectFails;
|
||
|
||
static TUdpSocketObj* Construct(CPrivateHeap& hp, CBufferObjPool& bfPool)
|
||
{
|
||
TUdpSocketObj* pSocketObj = (TUdpSocketObj*)hp.Alloc(sizeof(TUdpSocketObj));
|
||
ASSERT(pSocketObj);
|
||
|
||
return new (pSocketObj) TUdpSocketObj(hp, bfPool);
|
||
}
|
||
|
||
static void Destruct(TUdpSocketObj* pSocketObj)
|
||
{
|
||
ASSERT(pSocketObj);
|
||
|
||
CPrivateHeap& heap = pSocketObj->heap;
|
||
pSocketObj->TUdpSocketObj::~TUdpSocketObj();
|
||
heap.Free(pSocketObj);
|
||
}
|
||
|
||
TUdpSocketObj(CPrivateHeap& hp, CBufferObjPool& bfPool)
|
||
: __super(hp), sndBuff(bfPool), itPool(bfPool)
|
||
{
|
||
|
||
}
|
||
|
||
~TUdpSocketObj()
|
||
{
|
||
ClearRecvQueue();
|
||
}
|
||
|
||
static void Release(TUdpSocketObj* pSocketObj)
|
||
{
|
||
__super::Release(pSocketObj);
|
||
|
||
pSocketObj->ClearRecvQueue();
|
||
pSocketObj->sndBuff.Release();
|
||
}
|
||
|
||
int Pending() {return sndBuff.Length();}
|
||
BOOL IsPending() {return Pending() > 0;}
|
||
BOOL HasRecvData() {return !recvQueue.IsEmpty();}
|
||
|
||
static BOOL InvalidSocketObj(TUdpSocketObj* pSocketObj)
|
||
{
|
||
BOOL bDone = FALSE;
|
||
|
||
if(TSocketObjBase::IsValid(pSocketObj))
|
||
{
|
||
pSocketObj->SetConnected(FALSE);
|
||
|
||
CReentrantWriteLock locallock(pSocketObj->lcIo);
|
||
CReentrantWriteLock locallock2(pSocketObj->lcSend);
|
||
CCriSecLock locallock3(pSocketObj->csSend);
|
||
|
||
if(TSocketObjBase::IsValid(pSocketObj))
|
||
{
|
||
TSocketObjBase::Invalid(pSocketObj);
|
||
bDone = TRUE;
|
||
}
|
||
}
|
||
|
||
return bDone;
|
||
}
|
||
|
||
void Reset(CONNID dwConnID)
|
||
{
|
||
__super::Reset(dwConnID);
|
||
|
||
pHolder = nullptr;
|
||
fdTimer = INVALID_FD;
|
||
detectFails = 0;
|
||
}
|
||
|
||
void ClearRecvQueue()
|
||
{
|
||
TItem* pItem = nullptr;
|
||
|
||
while(recvQueue.PopFront(&pItem))
|
||
itPool.PutFreeItem(pItem);
|
||
|
||
VERIFY(recvQueue.IsEmpty());
|
||
}
|
||
};
|
||
|
||
/* 有效 TSocketObj 缓存 */
|
||
typedef CRingCache2<TSocketObj, CONNID, true> TSocketObjPtrPool;
|
||
/* 失效 TSocketObj 缓存 */
|
||
typedef CRingPool<TSocketObj> TSocketObjPtrList;
|
||
/* 失效 TSocketObj 垃圾回收结构链表 */
|
||
typedef CCASQueue<TSocketObj> TSocketObjPtrQueue;
|
||
|
||
/* 有效 TSocketObj 缓存 */
|
||
typedef CRingCache2<TAgentSocketObj, CONNID, true> TAgentSocketObjPtrPool;
|
||
/* 失效 TSocketObj 缓存 */
|
||
typedef CRingPool<TAgentSocketObj> TAgentSocketObjPtrList;
|
||
/* 失效 TSocketObj 垃圾回收结构链表 */
|
||
typedef CCASQueue<TAgentSocketObj> TAgentSocketObjPtrQueue;
|
||
|
||
/* 有效 TUdpSocketObj 缓存 */
|
||
typedef CRingCache2<TUdpSocketObj, CONNID, true> TUdpSocketObjPtrPool;
|
||
/* 失效 TUdpSocketObj 缓存 */
|
||
typedef CRingPool<TUdpSocketObj> TUdpSocketObjPtrList;
|
||
/* 失效 TUdpSocketObj 垃圾回收结构链表 */
|
||
typedef CCASQueue<TUdpSocketObj> TUdpSocketObjPtrQueue;
|
||
|
||
/* HP_SOCKADDR 比较器 */
|
||
struct hp_sockaddr_func
|
||
{
|
||
struct hash
|
||
{
|
||
size_t operator() (const HP_SOCKADDR* pA) const
|
||
{
|
||
return pA->Hash();
|
||
}
|
||
};
|
||
|
||
struct equal_to
|
||
{
|
||
bool operator () (const HP_SOCKADDR* pA, const HP_SOCKADDR* pB) const
|
||
{
|
||
return pA->EqualTo(*pB);
|
||
}
|
||
};
|
||
|
||
};
|
||
|
||
/* 地址-连接 ID 哈希表 */
|
||
typedef unordered_map<const HP_SOCKADDR*, CONNID, hp_sockaddr_func::hash, hp_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;
|
||
BOOL bNotify;
|
||
|
||
TClientCloseContext(BOOL bFire = TRUE, EnSocketOperation enOp = SO_CLOSE, int iCode = SE_OK, BOOL bNtf = TRUE)
|
||
{
|
||
Reset(bFire, enOp, iCode, bNtf);
|
||
}
|
||
|
||
void Reset(BOOL bFire = TRUE, EnSocketOperation enOp = SO_CLOSE, int iCode = SE_OK, BOOL bNtf = TRUE)
|
||
{
|
||
bFireOnClose = bFire;
|
||
enOperation = enOp;
|
||
iErrorCode = iCode;
|
||
bNotify = bNtf;
|
||
}
|
||
|
||
};
|
||
|
||
/*****************************************************************************************************/
|
||
/******************************************** 公共帮助方法 ********************************************/
|
||
/*****************************************************************************************************/
|
||
|
||
/* 默认工作线程前缀 */
|
||
#define DEFAULT_WORKER_THREAD_PREFIX "hp-worker-"
|
||
|
||
/* 设置当前工作线程名称 */
|
||
BOOL SetCurrentWorkerThreadName();
|
||
/* 设置工作线程默认名称 */
|
||
BOOL SetWorkerThreadDefaultName(THR_ID tid);
|
||
|
||
/* 获取错误描述文本 */
|
||
LPCTSTR GetSocketErrorDesc(EnSocketError enCode);
|
||
/* 确定地址簇 */
|
||
ADDRESS_FAMILY DetermineAddrFamily(LPCTSTR lpszAddress);
|
||
/* 地址字符串地址转换为 HP_ADDR */
|
||
BOOL GetInAddr(LPCTSTR lpszAddress, HP_ADDR& addr);
|
||
/* 地址字符串地址转换为 HP_SOCKADDR */
|
||
BOOL GetSockAddr(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr);
|
||
/* 检查字符串是否符合 IP 地址格式 */
|
||
BOOL IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType = nullptr);
|
||
/* 通过主机名获取 IP 地址 */
|
||
BOOL GetIPAddress(LPCTSTR lpszHost, LPTSTR lpszIP, int& iIPLenth, EnIPAddrType& enType);
|
||
/* 通过主机名获取 HP_SOCKADDR */
|
||
BOOL GetSockAddrByHostName(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR& addr);
|
||
/* 通过主机名获取 HP_SOCKADDR */
|
||
BOOL GetSockAddrByHostNameDirectly(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR &addr);
|
||
/* 枚举主机 IP 地址 */
|
||
BOOL EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount);
|
||
/* 填充 LPTIPAddr* */
|
||
BOOL RetrieveSockAddrIPAddresses(const vector<HP_PSOCKADDR>& vt, LPTIPAddr** lpppIPAddr, int& iIPAddrCount);
|
||
/* 释放 LPTIPAddr* */
|
||
BOOL FreeHostIPAddresses(LPTIPAddr* lppIPAddr);
|
||
/* 把 HP_SOCKADDR 结构转换为地址字符串 */
|
||
BOOL sockaddr_IN_2_A(const HP_SOCKADDR& addr, ADDRESS_FAMILY& usFamily, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort);
|
||
/* 把地址字符串转换为 HP_SOCKADDR 结构 */
|
||
BOOL sockaddr_A_2_IN(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr);
|
||
/* 获取 Socket 的本地或远程地址信息 */
|
||
BOOL GetSocketAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort, BOOL bLocal = TRUE);
|
||
/* 获取 Socket 的本地地址信息 */
|
||
BOOL GetSocketLocalAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort);
|
||
/* 获取 Socket 的远程地址信息 */
|
||
BOOL GetSocketRemoteAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort);
|
||
/* 设置组播选项 */
|
||
BOOL SetMultiCastSocketOptions(SOCKET sock, const HP_SOCKADDR& bindAddr, const HP_SOCKADDR& castAddr, int iMCTtl, BOOL bMCLoop);
|
||
|
||
/* 64 位网络字节序转主机字节序 */
|
||
ULONGLONG NToH64(ULONGLONG value);
|
||
/* 64 位主机字节序转网络字节序 */
|
||
ULONGLONG HToN64(ULONGLONG value);
|
||
|
||
/* 短整型高低字节交换 */
|
||
#define ENDIAN_SWAP_16(A) ((USHORT)((((USHORT)(A) & 0xff00) >> 8) | (((USHORT)(A) & 0x00ff) << 8)))
|
||
/* 长整型高低字节交换 */
|
||
#define ENDIAN_SWAP_32(A) ((((DWORD)(A) & 0xff000000) >> 24) | \
|
||
(((DWORD)(A) & 0x00ff0000) >> 8) | \
|
||
(((DWORD)(A) & 0x0000ff00) << 8) | \
|
||
(((DWORD)(A) & 0x000000ff) << 24) )
|
||
|
||
/* 检查是否小端字节序 */
|
||
BOOL IsLittleEndian();
|
||
/* 短整型主机字节序转小端字节序 */
|
||
USHORT HToLE16(USHORT value);
|
||
/* 短整型主机字节序转大端字节序 */
|
||
USHORT HToBE16(USHORT value);
|
||
/* 长整型主机字节序转小端字节序 */
|
||
DWORD HToLE32(DWORD value);
|
||
/* 长整型主机字节序转大端字节序 */
|
||
DWORD HToBE32(DWORD value);
|
||
|
||
HRESULT ReadSmallFile(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, DWORD dwMaxFileSize = MAX_SMALL_FILE_SIZE);
|
||
HRESULT MakeSmallFilePackage(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, WSABUF szBuf[3], const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr);
|
||
|
||
/************************************************************************
|
||
名称: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, PVOID arg);
|
||
|
||
int SSO_NoBlock (SOCKET sock, BOOL bNoBlock = TRUE);
|
||
int SSO_NoDelay (SOCKET sock, BOOL bNoDelay = TRUE);
|
||
int SSO_DontLinger (SOCKET sock, BOOL bDont = TRUE);
|
||
int SSO_Linger (SOCKET sock, int l_onoff, int l_linger);
|
||
int SSO_KeepAlive (SOCKET sock, BOOL bKeepAlive = TRUE);
|
||
int SSO_KeepAliveVals (SOCKET sock, BOOL bOnOff, DWORD dwIdle, DWORD dwInterval, DWORD dwCount = 5);
|
||
int SSO_ReuseAddress (SOCKET sock, EnReuseAddressPolicy opt);
|
||
int SSO_RecvBuffSize (SOCKET sock, int size);
|
||
int SSO_SendBuffSize (SOCKET sock, int size);
|
||
int SSO_RecvTimeOut (SOCKET sock, int ms);
|
||
int SSO_SendTimeOut (SOCKET sock, int ms);
|
||
int SSO_GetError (SOCKET sock);
|
||
|
||
/* 生成 Connection ID */
|
||
CONNID GenerateConnectionID();
|
||
/* 检测 UDP 连接关闭通知 */
|
||
int IsUdpCloseNotify(const BYTE* pData, int iLength);
|
||
/* 发送 UDP 连接关闭通知 */
|
||
int SendUdpCloseNotify(SOCKET sock);
|
||
/* 发送 UDP 连接关闭通知 */
|
||
int SendUdpCloseNotify(SOCKET sock, const HP_SOCKADDR& remoteAddr);
|
||
/* 关闭 Socket */
|
||
int ManualCloseSocket(SOCKET sock, int iShutdownFlag = 0xFF, BOOL bGraceful = TRUE);
|
||
|
||
#ifdef _ICONV_SUPPORT
|
||
|
||
#define CHARSET_GBK "GBK"
|
||
#define CHARSET_UTF_8 "UTF-8"
|
||
#define CHARSET_UTF_16LE "UTF-16LE"
|
||
#define CHARSET_UTF_32LE "UTF-32LE"
|
||
#define CHARSET_UTF_16BE "UTF-16BE"
|
||
#define CHARSET_UTF_32BE "UTF-32BE"
|
||
|
||
// 系统 UNICODE 字符集
|
||
#define SYSTEM_CHARSET_UNICODE ( (sizeof(WCHAR) == 4) \
|
||
? (IsLittleEndian() ? CHARSET_UTF_32LE : CHARSET_UTF_32BE) \
|
||
: (IsLittleEndian() ? CHARSET_UTF_16LE : CHARSET_UTF_16BE) )
|
||
|
||
// Charset A -> Charset B
|
||
BOOL CharsetConvert(LPCSTR lpszFromCharset, LPCSTR lpszToCharset, LPCSTR lpszInBuf, int iInBufLen, LPSTR lpszOutBuf, int& iOutBufLen);
|
||
|
||
// GBK -> UNICODE
|
||
BOOL GbkToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength);
|
||
// UNICODE -> GBK
|
||
BOOL UnicodeToGbkEx(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||
// UTF8 -> UNICODE
|
||
BOOL Utf8ToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength);
|
||
// UNICODE -> UTF8
|
||
BOOL UnicodeToUtf8Ex(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||
// GBK -> UTF8
|
||
BOOL GbkToUtf8Ex(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength);
|
||
// UTF8 -> GBK
|
||
BOOL Utf8ToGbkEx(const char szSrc[], int iSrcLength, 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);
|
||
|
||
#endif
|
||
|
||
// 计算 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);
|
||
|
||
/* 销毁压缩器对象 */
|
||
void DestroyCompressor(IHPCompressor* pCompressor);
|
||
/* 销毁解压器对象 */
|
||
void DestroyDecompressor(IHPDecompressor* pDecompressor);
|
||
|
||
#ifdef _ZLIB_SUPPORT
|
||
|
||
/* ZLib 压缩器 */
|
||
class CHPZLibCompressor : public IHPCompressor
|
||
{
|
||
public:
|
||
virtual BOOL Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext = nullptr);
|
||
virtual BOOL ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush = FALSE, PVOID pContext = nullptr);
|
||
virtual BOOL IsValid() {return m_bValid;}
|
||
virtual BOOL Reset();
|
||
|
||
public:
|
||
CHPZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits = MAX_WBITS, int iLevel = Z_DEFAULT_COMPRESSION, int iMethod = Z_DEFLATED, int iMemLevel = MAX_MEM_LEVEL, int iStrategy = Z_DEFAULT_STRATEGY, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
virtual ~CHPZLibCompressor();
|
||
|
||
private:
|
||
Fn_CompressDataCallback m_fnCallback;
|
||
z_stream m_Stream;
|
||
BOOL m_bValid;
|
||
DWORD m_dwBuffSize;
|
||
};
|
||
|
||
/* ZLib 解压器 */
|
||
class CHPZLibDecompressor : public IHPDecompressor
|
||
{
|
||
public:
|
||
virtual BOOL Process(const BYTE* pData, int iLength, PVOID pContext = nullptr);
|
||
virtual BOOL IsValid() {return m_bValid;}
|
||
virtual BOOL Reset();
|
||
|
||
public:
|
||
CHPZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits = MAX_WBITS, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
virtual ~CHPZLibDecompressor();
|
||
|
||
private:
|
||
Fn_DecompressDataCallback m_fnCallback;
|
||
z_stream m_Stream;
|
||
BOOL m_bValid;
|
||
DWORD m_dwBuffSize;
|
||
};
|
||
|
||
/* 创建 ZLib 压缩器对象 */
|
||
IHPCompressor* CreateZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits = MAX_WBITS, int iLevel = Z_DEFAULT_COMPRESSION, int iMethod = Z_DEFLATED, int iMemLevel = MAX_MEM_LEVEL, int iStrategy = Z_DEFAULT_STRATEGY, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
/* 创建 GZip 压缩器对象 */
|
||
IHPCompressor* CreateGZipCompressor(Fn_CompressDataCallback fnCallback, int iLevel = Z_DEFAULT_COMPRESSION, int iMethod = Z_DEFLATED, int iMemLevel = MAX_MEM_LEVEL, int iStrategy = Z_DEFAULT_STRATEGY, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
/* 创建 ZLib 解压器对象 */
|
||
IHPDecompressor* CreateZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits = MAX_WBITS, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
/* 创建 GZip 解压器对象 */
|
||
IHPDecompressor* CreateGZipDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
|
||
// 普通压缩(返回值: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 = MAX_WBITS, int iMemLevel = MAX_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 = MAX_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);
|
||
|
||
#endif
|
||
|
||
#ifdef _BROTLI_SUPPORT
|
||
|
||
/* Brotli 压缩器 */
|
||
class CHPBrotliCompressor : public IHPCompressor
|
||
{
|
||
public:
|
||
virtual BOOL Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext = nullptr);
|
||
virtual BOOL ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush = FALSE, PVOID pContext = nullptr);
|
||
virtual BOOL IsValid() {return m_bValid;}
|
||
virtual BOOL Reset();
|
||
|
||
public:
|
||
CHPBrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality = BROTLI_DEFAULT_QUALITY, int iWindow = BROTLI_DEFAULT_WINDOW, int iMode = BROTLI_DEFAULT_MODE, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
virtual ~CHPBrotliCompressor();
|
||
|
||
private:
|
||
Fn_CompressDataCallback m_fnCallback;
|
||
BrotliEncoderState* m_pState;
|
||
BOOL m_bValid;
|
||
|
||
int m_iQuality;
|
||
int m_iWindow;
|
||
int m_iMode;
|
||
DWORD m_dwBuffSize;
|
||
};
|
||
|
||
/* Brotli 解压器 */
|
||
class CHPBrotliDecompressor : public IHPDecompressor
|
||
{
|
||
public:
|
||
virtual BOOL Process(const BYTE* pData, int iLength, PVOID pContext = nullptr);
|
||
virtual BOOL IsValid() {return m_bValid;}
|
||
virtual BOOL Reset();
|
||
|
||
public:
|
||
CHPBrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
virtual ~CHPBrotliDecompressor();
|
||
|
||
private:
|
||
Fn_DecompressDataCallback m_fnCallback;
|
||
BrotliDecoderState* m_pState;
|
||
BOOL m_bValid;
|
||
DWORD m_dwBuffSize;
|
||
};
|
||
|
||
/* 创建 Brotli 压缩器对象 */
|
||
IHPCompressor* CreateBrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality = BROTLI_DEFAULT_QUALITY, int iWindow = BROTLI_DEFAULT_WINDOW, int iMode = BROTLI_DEFAULT_MODE, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
/* 创建 Brotli 解压器对象 */
|
||
IHPDecompressor* CreateBrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = DEFAULT_COMPRESS_BUFFER_SIZE);
|
||
|
||
// Brotli 压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||
int BrotliCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||
// Brotli 高级压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||
int BrotliCompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iQuality = BROTLI_DEFAULT_QUALITY, int iWindow = BROTLI_DEFAULT_WINDOW, int iMode = BROTLI_DEFAULT_MODE);
|
||
// Brotli 解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
|
||
int BrotliUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
|
||
// Brotli 推测压缩结果长度
|
||
DWORD BrotliGuessCompressBound(DWORD dwSrcLen);
|
||
|
||
#endif
|