| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638 |
- /*
- * Copyright: JessMA Open Source (ldcsaa@gmail.com)
- *
- * Author : Bruce Liang
- * Website : https://github.com/ldcsaa
- * Project : https://github.com/ldcsaa/HP-Socket
- * Blog : http://www.cnblogs.com/ldcsaa
- * Wiki : http://www.oschina.net/p/hp-socket
- * QQ Group : 44636872, 75375912
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "SocketHelper.h"
- #include <sys/ioctl.h>
- #include <arpa/inet.h>
- #include <netinet/tcp.h>
- #include <netinet/udp.h>
- #ifdef _ICONV_SUPPORT
- #include <iconv.h>
- #endif
- #ifndef SO_REUSEPORT
- #define SO_REUSEPORT 15
- #endif
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- static const BYTE s_szUdpCloseNotify[] = {0xBE, 0xB6, 0x1F, 0xEB, 0xDA, 0x52, 0x46, 0xBA, 0x92, 0x33, 0x59, 0xDB, 0xBF, 0xE6, 0xC8, 0xE4};
- static const int s_iUdpCloseNotifySize = ARRAY_SIZE(s_szUdpCloseNotify);
- const hp_addr hp_addr::ANY_ADDR4(AF_INET, TRUE);
- const hp_addr hp_addr::ANY_ADDR6(AF_INET6, TRUE);
- BOOL SetCurrentWorkerThreadName()
- {
- return SetWorkerThreadDefaultName(0);
- }
- BOOL SetWorkerThreadDefaultName(THR_ID tid)
- {
- static volatile UINT _s_uiSeq = 0;
- return ::SetSequenceThreadName(tid, DEFAULT_WORKER_THREAD_PREFIX, _s_uiSeq);
- }
- LPCTSTR GetSocketErrorDesc(EnSocketError enCode)
- {
- switch(enCode)
- {
- case SE_OK: return _T("SUCCESS");
- case SE_ILLEGAL_STATE: return _T("Illegal State");
- case SE_INVALID_PARAM: return _T("Invalid Parameter");
- case SE_SOCKET_CREATE: return _T("Create SOCKET Fail");
- case SE_SOCKET_BIND: return _T("Bind SOCKET Fail");
- case SE_SOCKET_PREPARE: return _T("Prepare SOCKET Fail");
- case SE_SOCKET_LISTEN: return _T("Listen SOCKET Fail");
- case SE_CP_CREATE: return _T("Create IOCP Fail");
- case SE_WORKER_THREAD_CREATE: return _T("Create Worker Thread Fail");
- case SE_DETECT_THREAD_CREATE: return _T("Create Detector Thread Fail");
- case SE_SOCKE_ATTACH_TO_CP: return _T("Attach SOCKET to IOCP Fail");
- case SE_CONNECT_SERVER: return _T("Connect to Server Fail");
- case SE_NETWORK: return _T("Network Error");
- case SE_DATA_PROC: return _T("Process Data Error");
- case SE_DATA_SEND: return _T("Send Data Fail");
- case SE_SSL_ENV_NOT_READY: return _T("SSL environment not ready");
- default: ASSERT(FALSE); return _T("UNKNOWN ERROR");
- }
- }
- ADDRESS_FAMILY DetermineAddrFamily(LPCTSTR lpszAddress)
- {
- if (!lpszAddress || lpszAddress[0] == 0)
- return AF_UNSPEC;
- if(::StrChr(lpszAddress, IPV6_ADDR_SEPARATOR_CHAR))
- return AF_INET6;
- TCHAR c;
- int arr[4];
- if(stscanf(lpszAddress, _T("%d.%d.%d.%d%c"), &arr[0], &arr[1], &arr[2], &arr[3], &c) != 4)
- return AF_UNSPEC;
- for(int i = 0; i < 4; i++)
- {
- if(arr[i] < 0 || arr[i] > 255)
- return AF_UNSPEC;
- }
- return AF_INET;
- }
- BOOL GetInAddr(LPCTSTR lpszAddress, HP_ADDR& addr)
- {
- addr.family = DetermineAddrFamily(lpszAddress);
- if (addr.family == AF_UNSPEC)
- return FALSE;
- return (::InetPton(addr.family, lpszAddress, addr.Addr()) == TRUE);
- }
- BOOL GetSockAddr(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr)
- {
- if(addr.family != AF_INET && addr.family != AF_INET6)
- {
- ::WSASetLastError(ERROR_ADDRNOTAVAIL);
- return FALSE;
- }
- if(addr.family == AF_INET6 && StrChr(lpszAddress, IPV6_ZONE_INDEX_CHAR))
- return GetSockAddrByHostNameDirectly(lpszAddress, usPort, addr);
- addr.ZeroAddr();
- int rs = ::InetPton(addr.family, lpszAddress, addr.SinAddr());
- if(rs != 1)
- {
- if(rs == 0) ::WSASetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- if(usPort != 0)
- addr.SetPort(usPort);
- return TRUE;
- }
- BOOL IsIPAddress(LPCTSTR lpszAddress, EnIPAddrType* penType)
- {
- HP_ADDR addr;
- BOOL isOK = GetInAddr(lpszAddress, addr);
- if(isOK && penType)
- *penType = addr.IsIPv4() ? IPT_IPV4 : IPT_IPV6;
- return isOK;
- }
- BOOL GetIPAddress(LPCTSTR lpszHost, LPTSTR lpszIP, int& iIPLen, EnIPAddrType& enType)
- {
- HP_SOCKADDR addr;
- if(!GetSockAddrByHostName(lpszHost, 0, addr))
- return FALSE;
- enType = addr.IsIPv4() ? IPT_IPV4 : IPT_IPV6;
- USHORT usPort;
- ADDRESS_FAMILY usFamily;
- return sockaddr_IN_2_A(addr, usFamily, lpszIP, iIPLen, usPort);
- }
- BOOL GetSockAddrByHostName(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR& addr)
- {
- addr.family = DetermineAddrFamily(lpszHost);
- if(addr.family != AF_UNSPEC)
- return GetSockAddr(lpszHost, usPort, addr);
- return GetSockAddrByHostNameDirectly(lpszHost, usPort, addr);
- }
- BOOL GetSockAddrByHostNameDirectly(LPCTSTR lpszHost, USHORT usPort, HP_SOCKADDR& addr)
- {
- addr.ZeroAddr();
- addrinfo* pInfo = nullptr;
- addrinfo hints = {0};
- #if defined(__ANDROID__)
- hints.ai_flags = 0;
- #else
- hints.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
- #endif
- hints.ai_family = addr.family;
- hints.ai_socktype = SOCK_STREAM;
- int rs = ::getaddrinfo(CT2A(lpszHost), nullptr, &hints, &pInfo);
- if(!IS_NO_ERROR(rs))
- {
- ::WSASetLastError(ERROR_HOSTUNREACH);
- return FALSE;
- }
- BOOL isOK = FALSE;
- for(addrinfo* pCur = pInfo; pCur != nullptr; pCur = pCur->ai_next)
- {
- if(pCur->ai_family == AF_INET || pCur->ai_family == AF_INET6)
- {
- memcpy(addr.Addr(), pCur->ai_addr, pCur->ai_addrlen);
- isOK = TRUE;
- break;
- }
- }
- EXECUTE_RESTORE_ERROR(::freeaddrinfo(pInfo));
- if(isOK)
- addr.SetPort(usPort);
- else
- ::WSASetLastError(ERROR_HOSTUNREACH);
- return isOK;
- }
- BOOL EnumHostIPAddresses(LPCTSTR lpszHost, EnIPAddrType enType, LPTIPAddr** lpppIPAddr, int& iIPAddrCount)
- {
- *lpppIPAddr = nullptr;
- iIPAddrCount = 0;
- ADDRESS_FAMILY usFamily = (enType == IPT_ALL ?
- AF_UNSPEC : (enType == IPT_IPV4 ?
- AF_INET : (enType == IPT_IPV6 ?
- AF_INET6 : 0xFF)));
- if(usFamily == 0xFF)
- {
- ::WSASetLastError(ERROR_AFNOSUPPORT);
- return FALSE;
- }
- vector<HP_PSOCKADDR> vt;
- ADDRESS_FAMILY usFamily2 = DetermineAddrFamily(lpszHost);
- if(usFamily2 != AF_UNSPEC)
- {
- if(usFamily != AF_UNSPEC && usFamily != usFamily2)
- {
- ::WSASetLastError(ERROR_HOSTUNREACH);
- return FALSE;
- }
- HP_SOCKADDR addr(usFamily2);
- if(!GetSockAddr(lpszHost, 0, addr))
- return FALSE;
- vt.emplace_back(&addr);
- return RetrieveSockAddrIPAddresses(vt, lpppIPAddr, iIPAddrCount);
- }
- addrinfo* pInfo = nullptr;
- addrinfo hints = {0};
- #if defined(__ANDROID__)
- hints.ai_flags = 0;
- #else
- hints.ai_flags = AI_ALL;
- #endif
- hints.ai_family = usFamily;
- hints.ai_socktype = SOCK_STREAM;
- int rs = ::getaddrinfo(CT2A(lpszHost), nullptr, &hints, &pInfo);
- if(rs != NO_ERROR)
- {
- ::WSASetLastError(rs);
- return FALSE;
- }
- for(addrinfo* pCur = pInfo; pCur != nullptr; pCur = pCur->ai_next)
- {
- if(pCur->ai_family == AF_INET || pCur->ai_family == AF_INET6)
- vt.emplace_back((HP_PSOCKADDR)pCur->ai_addr);
- }
- BOOL isOK = RetrieveSockAddrIPAddresses(vt, lpppIPAddr, iIPAddrCount);
- ::freeaddrinfo(pInfo);
- if(!isOK) ::WSASetLastError(EHOSTUNREACH);
- return isOK;
- }
- BOOL RetrieveSockAddrIPAddresses(const vector<HP_PSOCKADDR>& vt, LPTIPAddr** lpppIPAddr, int& iIPAddrCount)
- {
- iIPAddrCount = (int)vt.size();
- if(iIPAddrCount == 0) return FALSE;
- HP_PSOCKADDR pSockAddr;
- ADDRESS_FAMILY usFamily;
- USHORT usPort;
- int iAddrLength;
- LPTSTR lpszAddr;
- LPTIPAddr lpItem;
- (*lpppIPAddr) = new LPTIPAddr[iIPAddrCount + 1];
- (*lpppIPAddr)[iIPAddrCount] = nullptr;
- for(int i = 0; i < iIPAddrCount; i++)
- {
- pSockAddr = vt[i];
- iAddrLength = HP_SOCKADDR::AddrMinStrLength(pSockAddr->family);
- lpszAddr = new TCHAR[iAddrLength];
- VERIFY(sockaddr_IN_2_A(*vt[i], usFamily, lpszAddr, iAddrLength, usPort));
- lpItem = new TIPAddr;
- lpItem->type = pSockAddr->IsIPv4() ? IPT_IPV4 : IPT_IPV6;
- lpItem->address = lpszAddr;
- (*lpppIPAddr)[i] = lpItem;
- }
- return TRUE;
- }
- BOOL FreeHostIPAddresses(LPTIPAddr* lppIPAddr)
- {
- if(!lppIPAddr) return FALSE;
- LPTIPAddr p;
- LPTIPAddr* lppCur = lppIPAddr;
- while((p = *lppCur++) != nullptr)
- {
- delete[] p->address;
- delete p;
- }
- delete[] lppIPAddr;
- return TRUE;
- }
- BOOL sockaddr_IN_2_A(const HP_SOCKADDR& addr, ADDRESS_FAMILY& usFamily, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
- {
- BOOL isOK = FALSE;
- usFamily = addr.family;
- usPort = addr.Port();
- if(::InetNtop(addr.family, addr.SinAddr(), lpszAddress, iAddressLen))
- {
- iAddressLen = (int)lstrlen(lpszAddress) + 1;
- isOK = TRUE;
- }
- else
- {
- if(::WSAGetLastError() == ENOSPC)
- iAddressLen = HP_SOCKADDR::AddrMinStrLength(usFamily);
- }
- return isOK;
- }
- BOOL sockaddr_A_2_IN(LPCTSTR lpszAddress, USHORT usPort, HP_SOCKADDR& addr)
- {
- addr.family = DetermineAddrFamily(lpszAddress);
- return GetSockAddr(lpszAddress, usPort, addr);
- }
- BOOL GetSocketAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort, BOOL bLocal)
- {
- HP_SOCKADDR addr;
- int addr_len = addr.AddrSize();
- int result = bLocal ? getsockname(socket, addr.Addr(), (socklen_t*)&addr_len) : getpeername(socket, addr.Addr(), (socklen_t*)&addr_len);
- if(result != NO_ERROR)
- return FALSE;
- ADDRESS_FAMILY usFamily;
- return sockaddr_IN_2_A(addr, usFamily, lpszAddress, iAddressLen, usPort);
- }
- BOOL GetSocketLocalAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
- {
- return GetSocketAddress(socket, lpszAddress, iAddressLen, usPort, TRUE);
- }
- BOOL GetSocketRemoteAddress(SOCKET socket, LPTSTR lpszAddress, int& iAddressLen, USHORT& usPort)
- {
- return GetSocketAddress(socket, lpszAddress, iAddressLen, usPort, FALSE);
- }
- BOOL SetMultiCastSocketOptions(SOCKET sock, const HP_SOCKADDR& bindAddr, const HP_SOCKADDR& castAddr, int iMCTtl, BOOL bMCLoop)
- {
- if(castAddr.IsIPv4())
- {
- BYTE ttl = (BYTE)iMCTtl;
- BYTE loop = (BYTE)bMCLoop;
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) != SOCKET_ERROR);
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != SOCKET_ERROR);
- ip_mreq mcast;
- ::ZeroMemory(&mcast, sizeof(mcast));
- mcast.imr_multiaddr = castAddr.addr4.sin_addr;
- mcast.imr_interface = bindAddr.addr4.sin_addr;
- if(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof(mcast)) == SOCKET_ERROR)
- return FALSE;
- if(::SSO_SetSocketOption(sock, IPPROTO_IP, IP_MULTICAST_IF, bindAddr.SinAddr(), sizeof(IN_ADDR)) == SOCKET_ERROR)
- return FALSE;
- }
- else
- {
- INT ttl = (INT)iMCTtl;
- UINT loop = (UINT)bMCLoop;
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) != SOCKET_ERROR);
- VERIFY(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)) != SOCKET_ERROR);
- ipv6_mreq mcast;
- ::ZeroMemory(&mcast, sizeof(mcast));
- mcast.ipv6mr_multiaddr = castAddr.addr6.sin6_addr;
- mcast.ipv6mr_interface = bindAddr.addr6.sin6_scope_id;
- if(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mcast, sizeof(mcast)) == SOCKET_ERROR)
- return FALSE;
- if(::SSO_SetSocketOption(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (PVOID)(&bindAddr.addr6.sin6_scope_id), sizeof(UINT)) == SOCKET_ERROR)
- return FALSE;
- }
- return TRUE;
- }
- ULONGLONG NToH64(ULONGLONG value)
- {
- return (((ULONGLONG)ntohl((UINT)((value << 32) >> 32))) << 32) | ntohl((UINT)(value >> 32));
- }
- ULONGLONG HToN64(ULONGLONG value)
- {
- return (((ULONGLONG)htonl((UINT)((value << 32) >> 32))) << 32) | htonl((UINT)(value >> 32));
- }
- BOOL IsLittleEndian()
- {
- static const USHORT _s_endian_test_value = 0x0102;
- static const BOOL _s_bLE = (*((BYTE*)&_s_endian_test_value) == 0x02);
- return _s_bLE;
- }
- USHORT HToLE16(USHORT value)
- {
- return IsLittleEndian() ? value : ENDIAN_SWAP_16(value);
- }
- USHORT HToBE16(USHORT value)
- {
- return IsLittleEndian() ? ENDIAN_SWAP_16(value) : value;
- }
- DWORD HToLE32(DWORD value)
- {
- return IsLittleEndian() ? value : ENDIAN_SWAP_32(value);
- }
- DWORD HToBE32(DWORD value)
- {
- return IsLittleEndian() ? ENDIAN_SWAP_32(value) : value;
- }
- HRESULT ReadSmallFile(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, DWORD dwMaxFileSize)
- {
- ASSERT(lpszFileName != nullptr);
- if(file.Open(lpszFileName, O_RDONLY))
- {
- SIZE_T dwSize;
- if(file.GetSize(dwSize))
- {
- if(dwSize > 0 && dwSize <= dwMaxFileSize)
- {
- if(fmap.Map(file, dwSize))
- return NO_ERROR;
- }
- else if(dwSize == 0)
- ::SetLastError(ERROR_EMPTY);
- else
- ::SetLastError(ERROR_FILE_TOO_LARGE);
- }
- }
- HRESULT rs = ::GetLastError();
- return (!IS_NO_ERROR(rs) ? rs : ERROR_UNKNOWN);
- }
- HRESULT MakeSmallFilePackage(LPCTSTR lpszFileName, CFile& file, CFileMapping& fmap, WSABUF szBuf[3], const LPWSABUF pHead, const LPWSABUF pTail)
- {
- DWORD dwMaxFileSize = MAX_SMALL_FILE_SIZE - (pHead ? pHead->len : 0) - (pTail ? pTail->len : 0);
- ASSERT(dwMaxFileSize <= MAX_SMALL_FILE_SIZE);
- HRESULT hr = ReadSmallFile(lpszFileName, file, fmap, dwMaxFileSize);
- if(IS_NO_ERROR(hr))
- {
- szBuf[1].len = (UINT)fmap.Size();
- szBuf[1].buf = fmap;
- if(pHead) memcpy(&szBuf[0], pHead, sizeof(WSABUF));
- else memset(&szBuf[0], 0, sizeof(WSABUF));
- if(pTail) memcpy(&szBuf[2], pTail, sizeof(WSABUF));
- else memset(&szBuf[2], 0, sizeof(WSABUF));
- }
- return hr;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- int SSO_SetSocketOption(SOCKET sock, int level, int name, LPVOID val, int len)
- {
- return setsockopt(sock, level, name, val, (socklen_t)len);
- }
- int SSO_GetSocketOption(SOCKET sock, int level, int name, LPVOID val, int* len)
- {
- return getsockopt(sock, level, name, val, (socklen_t*)len);
- }
- int SSO_IoctlSocket(SOCKET sock, long cmd, PVOID arg)
- {
- return ioctl(sock, cmd, arg);
- }
- int SSO_NoBlock(SOCKET sock, BOOL bNoBlock)
- {
- return fcntl_SETFL(sock, O_NONBLOCK, bNoBlock) ? NO_ERROR : SOCKET_ERROR;
- }
- int SSO_NoDelay(SOCKET sock, BOOL bNoDelay)
- {
- int val = bNoDelay ? 1 : 0;
- return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
- }
- int SSO_DontLinger(SOCKET sock, BOOL bDont)
- {
- return SSO_Linger(sock, 0, 0);
- }
- int SSO_Linger(SOCKET sock, int l_onoff, int l_linger)
- {
- linger ln = {l_onoff, l_linger};
- return setsockopt(sock, SOL_SOCKET, SO_LINGER, &ln, sizeof(linger));
- }
- int SSO_KeepAlive(SOCKET sock, BOOL bKeepAlive)
- {
- int val = bKeepAlive ? 1 : 0;
- return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(int));
- }
- int SSO_KeepAliveVals(SOCKET sock, BOOL bOnOff, DWORD dwIdle, DWORD dwInterval, DWORD dwCount)
- {
- if(bOnOff)
- {
- dwIdle /= 1000;
- dwInterval /= 1000;
- if(dwIdle == 0 || dwInterval == 0 || dwCount == 0)
- {
- ::WSASetLastError(ERROR_INVALID_PARAMETER);
- return SOCKET_ERROR;
- }
- }
- BOOL isOK = IS_NO_ERROR(SSO_KeepAlive(sock, bOnOff));
- if(isOK && bOnOff)
- {
- isOK &= IS_NO_ERROR(setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &dwIdle, sizeof(DWORD)));
- isOK &= IS_NO_ERROR(setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &dwInterval, sizeof(DWORD)));
- isOK &= IS_NO_ERROR(setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &dwCount, sizeof(DWORD)));
- }
- return isOK ? NO_ERROR : SOCKET_ERROR;
- }
- int SSO_ReuseAddress(SOCKET sock, EnReuseAddressPolicy opt)
- {
- int iSet = 1;
- int iUnSet = 0;
- int rs = NO_ERROR;
- BOOL bReusePortSupported =
- #if defined(__linux) || defined(__linux__)
- ::IsKernelVersionAbove(3, 9, 0);
- #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) || defined(__MACH__)
- TRUE;
- #else
- FALSE;
- #endif
- if(opt == RAP_NONE)
- {
- rs = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iUnSet, sizeof(int));
- if(bReusePortSupported)
- rs |= setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &iUnSet, sizeof(int));
- }
- else if(opt == RAP_ADDR_ONLY)
- {
- rs = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iSet, sizeof(int));
- if(bReusePortSupported)
- rs |= setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &iUnSet, sizeof(int));
- }
- else if(opt == RAP_ADDR_AND_PORT)
- {
- rs = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iSet, sizeof(int));
- if(bReusePortSupported)
- rs |= setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &iSet, sizeof(int));
- }
- else
- {
- ::SetLastError(ERROR_INVALID_PARAMETER);
- rs = -1;
- }
- return rs;
- }
- int SSO_RecvBuffSize(SOCKET sock, int size)
- {
- return setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int));
- }
- int SSO_SendBuffSize(SOCKET sock, int size)
- {
- return setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int));
- }
- int SSO_RecvTimeOut(SOCKET sock, int ms)
- {
- timeval tv;
- ::MillisecondToTimeval(ms, tv);
-
- return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
- }
- int SSO_SendTimeOut(SOCKET sock, int ms)
- {
- timeval tv;
- ::MillisecondToTimeval(ms, tv);
- return setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
- }
- int SSO_GetError(SOCKET sock)
- {
- int e;
- socklen_t len = sizeof(e);
- if(IS_NO_ERROR(getsockopt(sock, SOL_SOCKET, SO_ERROR, &e, &len)))
- return e;
- return SOCKET_ERROR;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- CONNID GenerateConnectionID()
- {
- static volatile CONNID s_dwConnID = 0;
- CONNID dwConnID = ::InterlockedIncrement(&s_dwConnID);
-
- if(dwConnID == 0)
- dwConnID = ::InterlockedIncrement(&s_dwConnID);
- return dwConnID;
- }
- int IsUdpCloseNotify(const BYTE* pData, int iLength)
- {
- return (iLength == s_iUdpCloseNotifySize &&
- memcmp(pData, s_szUdpCloseNotify, s_iUdpCloseNotifySize) == 0) ;
- }
- int SendUdpCloseNotify(SOCKET sock)
- {
- return (int)send(sock, (LPCSTR)s_szUdpCloseNotify, s_iUdpCloseNotifySize, 0);
- }
- int SendUdpCloseNotify(SOCKET sock, const HP_SOCKADDR& remoteAddr)
- {
- return (int)sendto(sock, (LPCSTR)s_szUdpCloseNotify, s_iUdpCloseNotifySize, 0, remoteAddr.Addr(), remoteAddr.AddrSize());
- }
- int ManualCloseSocket(SOCKET sock, int iShutdownFlag, BOOL bGraceful)
- {
- if(!bGraceful)
- SSO_Linger(sock, 1, 0);
- if(iShutdownFlag != 0xFF)
- shutdown(sock, iShutdownFlag);
- return closesocket(sock);
- }
- DWORD GuessBase64EncodeBound(DWORD dwSrcLen)
- {
- return 4 * ((dwSrcLen + 2) / 3);
- }
- DWORD GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- if(dwSrcLen < 2)
- return 0;
- if(lpszSrc[dwSrcLen - 2] == '=')
- dwSrcLen -= 2;
- else if(lpszSrc[dwSrcLen - 1] == '=')
- --dwSrcLen;
- DWORD dwMod = dwSrcLen % 4;
- DWORD dwAdd = dwMod == 2 ? 1 : (dwMod == 3 ? 2 : 0);
- return 3 * (dwSrcLen / 4) + dwAdd;
- }
- int Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- static const BYTE CODES[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- DWORD dwRealLen = GuessBase64EncodeBound(dwSrcLen);
- if(lpszDest == nullptr || dwDestLen < dwRealLen)
- {
- dwDestLen = dwRealLen;
- return -5;
- }
- BYTE* p = lpszDest;
- DWORD leven = 3 * (dwSrcLen / 3);
- DWORD i = 0;
- for (; i < leven; i += 3)
- {
- *p++ = CODES[lpszSrc[0] >> 2];
- *p++ = CODES[((lpszSrc[0] & 3) << 4) + (lpszSrc[1] >> 4)];
- *p++ = CODES[((lpszSrc[1] & 0xf) << 2) + (lpszSrc[2] >> 6)];
- *p++ = CODES[lpszSrc[2] & 0x3f];
- lpszSrc += 3;
- }
- if(i < dwSrcLen)
- {
- BYTE a = lpszSrc[0];
- BYTE b = (i + 1 < dwSrcLen) ? lpszSrc[1] : 0;
- *p++ = CODES[a >> 2];
- *p++ = CODES[((a & 3) << 4) + (b >> 4)];
- *p++ = (i + 1 < dwSrcLen) ? CODES[((b & 0xf) << 2)] : '=';
- *p++ = '=';
- }
- ASSERT(dwRealLen == (DWORD)(p - lpszDest));
- if(dwDestLen > dwRealLen)
- {
- *p = 0;
- dwDestLen = dwRealLen;
- }
- return 0;
- }
- int Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- static const BYTE MAP[256] =
- {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
- 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
- 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
- };
- DWORD dwRealLen = GuessBase64DecodeBound(lpszSrc, dwSrcLen);
- if(lpszDest == nullptr || dwDestLen < dwRealLen)
- {
- dwDestLen = dwRealLen;
- return -5;
- }
- BYTE c;
- int g = 3;
- DWORD i, x, y, z;
- for(i = x = y = z = 0; i < dwSrcLen || x != 0;)
- {
- c = i < dwSrcLen ? MAP[lpszSrc[i++]] : 254;
- if(c == 255) {dwDestLen = 0; return -3;}
- else if(c == 254) {c = 0; g--;}
- else if(c == 253) continue;
- z = (z << 6) | c;
- if(++x == 4)
- {
- lpszDest[y++] = (BYTE)((z >> 16) & 255);
- if (g > 1) lpszDest[y++] = (BYTE)((z >> 8) & 255);
- if (g > 2) lpszDest[y++] = (BYTE)(z & 255);
- x = z = 0;
- }
- }
- BOOL isOK = (y == dwRealLen);
- if(!isOK)
- dwDestLen = 0;
- else
- {
- if(dwDestLen > dwRealLen)
- {
- lpszDest[dwRealLen] = 0;
- dwDestLen = dwRealLen;
- }
- }
- return isOK ? 0 : -3;
- }
- DWORD GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- DWORD dwAdd = 0;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- BYTE c = lpszSrc[i];
- if(!(isalnum(c) || c == ' ' || c == '.' || c == '-' || c == '_' || c == '*'))
- dwAdd += 2;
- }
- return dwSrcLen + dwAdd;
- }
- DWORD GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- DWORD dwPercent = 0;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- if(lpszSrc[i] == '%')
- {
- ++dwPercent;
- i += 2;
- }
- }
- DWORD dwSub = dwPercent * 2;
- if(dwSrcLen < dwSub)
- return 0;
- return dwSrcLen - dwSub;
- }
- int UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- BYTE c;
- DWORD j = 0;
- if(lpszDest == nullptr || dwDestLen == 0)
- goto ERROR_DEST_LEN;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- if(j >= dwDestLen)
- goto ERROR_DEST_LEN;
- c = lpszSrc[i];
- if (isalnum(c) || c == '.' || c == '-' || c == '_' || c == '*')
- lpszDest[j++] = c;
- else if(c == ' ')
- lpszDest[j++] = '+';
- else
- {
- if(j + 3 >= dwDestLen)
- goto ERROR_DEST_LEN;
- lpszDest[j++] = '%';
- HEX_VALUE_TO_DOUBLE_CHAR(lpszDest + j, c);
- j += 2;
-
- }
- }
- if(dwDestLen > j)
- {
- lpszDest[j] = 0;
- dwDestLen = j;
- }
- return 0;
- ERROR_DEST_LEN:
- dwDestLen = GuessUrlEncodeBound(lpszSrc, dwSrcLen);
- return -5;
- }
- int UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- char c;
- DWORD j = 0;
- if(lpszDest == nullptr || dwDestLen == 0)
- goto ERROR_DEST_LEN;
- for(DWORD i = 0; i < dwSrcLen; i++)
- {
- if(j >= dwDestLen)
- goto ERROR_DEST_LEN;
- c = lpszSrc[i];
- if(c == '+')
- lpszDest[j++] = ' ';
- else if(c != '%')
- lpszDest[j++] = c;
- else
- {
- if(i + 2 >= dwSrcLen)
- goto ERROR_SRC_DATA;
- lpszDest[j++] = HEX_DOUBLE_CHAR_TO_VALUE(lpszSrc + i + 1);
- i += 2;
- }
- }
- if(dwDestLen > j)
- {
- lpszDest[j] = 0;
- dwDestLen = j;
- }
- return 0;
- ERROR_SRC_DATA:
- dwDestLen = 0;
- return -3;
- ERROR_DEST_LEN:
- dwDestLen = GuessUrlDecodeBound(lpszSrc, dwSrcLen);
- return -5;
- }
- void DestroyCompressor(IHPCompressor* pCompressor)
- {
- delete pCompressor;
- }
- void DestroyDecompressor(IHPDecompressor* pDecompressor)
- {
- delete pDecompressor;
- }
- #ifdef _ZLIB_SUPPORT
- CHPZLibCompressor::CHPZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- ::ZeroObject(m_Stream);
- m_bValid = (::deflateInit2(&m_Stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy) == Z_OK);
- }
- CHPZLibCompressor::~CHPZLibCompressor()
- {
- if(m_bValid) ::deflateEnd(&m_Stream);
- }
- BOOL CHPZLibCompressor::Reset()
- {
- return (m_bValid = (::deflateReset(&m_Stream) == Z_OK));
- }
- BOOL CHPZLibCompressor::Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext)
- {
- return ProcessEx(pData, iLength, bLast, FALSE, pContext);
- }
- BOOL CHPZLibCompressor::ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- m_Stream.next_in = (z_const Bytef*)pData;
- m_Stream.avail_in = iLength;
-
- BOOL isOK = TRUE;
- int rs = Z_OK;
- int flush = bLast ? Z_FINISH : (bFlush ? Z_SYNC_FLUSH : Z_NO_FLUSH);
- while(m_Stream.avail_in > 0)
- {
- do
- {
- m_Stream.next_out = szBuff.get();
- m_Stream.avail_out = m_dwBuffSize;
- rs = ::deflate(&m_Stream, flush);
- if(rs == Z_STREAM_ERROR)
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
-
- goto ZLIB_COMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - m_Stream.avail_out);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
- goto ZLIB_COMPRESS_END;
- }
- } while(m_Stream.avail_out == 0);
- }
- ZLIB_COMPRESS_END:
- ASSERT(!isOK || (rs == Z_OK && !bLast) || (rs == Z_STREAM_END && bLast));
- if(!isOK || bLast) Reset();
- return isOK;
- }
- CHPZLibDecompressor::CHPZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- ::ZeroObject(m_Stream);
- m_bValid = (::inflateInit2(&m_Stream, iWindowBits) == Z_OK);
- }
- CHPZLibDecompressor::~CHPZLibDecompressor()
- {
- if(m_bValid) ::inflateEnd(&m_Stream);
- }
- BOOL CHPZLibDecompressor::Reset()
- {
- return (m_bValid = (::inflateReset(&m_Stream) == Z_OK));
- }
- BOOL CHPZLibDecompressor::Process(const BYTE* pData, int iLength, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- m_Stream.next_in = (z_const Bytef*)pData;
- m_Stream.avail_in = iLength;
- BOOL isOK = TRUE;
- int rs = Z_OK;
- while(m_Stream.avail_in > 0)
- {
- do
- {
- m_Stream.next_out = szBuff.get();
- m_Stream.avail_out = m_dwBuffSize;
- rs = ::inflate(&m_Stream, Z_NO_FLUSH);
- if(rs != Z_OK && rs != Z_STREAM_END)
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
- goto ZLIB_DECOMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - m_Stream.avail_out);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
- goto ZLIB_DECOMPRESS_END;
- }
- } while(m_Stream.avail_out == 0);
- if(rs == Z_STREAM_END)
- break;
- }
- ZLIB_DECOMPRESS_END:
- ASSERT(!isOK || rs == Z_OK || rs == Z_STREAM_END);
- if(!isOK || rs == Z_STREAM_END) Reset();
- return isOK;
- }
- IHPCompressor* CreateZLibCompressor(Fn_CompressDataCallback fnCallback, int iWindowBits, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
- {
- return new CHPZLibCompressor(fnCallback, iWindowBits, iLevel, iMethod, iMemLevel, iStrategy, dwBuffSize);
- }
- IHPCompressor* CreateGZipCompressor(Fn_CompressDataCallback fnCallback, int iLevel, int iMethod, int iMemLevel, int iStrategy, DWORD dwBuffSize)
- {
- return new CHPZLibCompressor(fnCallback, MAX_WBITS + 16, iLevel, iMethod, iMemLevel, iStrategy, dwBuffSize);
- }
- IHPDecompressor* CreateZLibDecompressor(Fn_DecompressDataCallback fnCallback, int iWindowBits, DWORD dwBuffSize)
- {
- return new CHPZLibDecompressor(fnCallback, iWindowBits, dwBuffSize);
- }
- IHPDecompressor* CreateGZipDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
- {
- return new CHPZLibDecompressor(fnCallback, MAX_WBITS + 32, dwBuffSize);
- }
- int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
- }
- int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel, int iMethod, int iWindowBits, int iMemLevel, int iStrategy)
- {
- z_stream stream;
- stream.next_in = (z_const Bytef*)lpszSrc;
- stream.avail_in = dwSrcLen;
- stream.next_out = lpszDest;
- stream.avail_out = dwDestLen;
- stream.zalloc = nullptr;
- stream.zfree = nullptr;
- stream.opaque = nullptr;
- int err = ::deflateInit2(&stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy);
- if(err != Z_OK) return err;
- err = ::deflate(&stream, Z_FINISH);
- if(err != Z_STREAM_END)
- {
- ::deflateEnd(&stream);
- return err == Z_OK ? Z_BUF_ERROR : err;
- }
- if(dwDestLen > stream.total_out)
- {
- lpszDest[stream.total_out] = 0;
- dwDestLen = (DWORD)stream.total_out;
- }
- return ::deflateEnd(&stream);
- }
- int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
- }
- int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits)
- {
- z_stream stream;
- stream.next_in = (z_const Bytef*)lpszSrc;
- stream.avail_in = (uInt)dwSrcLen;
- stream.next_out = lpszDest;
- stream.avail_out = dwDestLen;
- stream.zalloc = nullptr;
- stream.zfree = nullptr;
- int err = ::inflateInit2(&stream, iWindowBits);
- if(err != Z_OK) return err;
- err = ::inflate(&stream, Z_FINISH);
- if(err != Z_STREAM_END)
- {
- ::inflateEnd(&stream);
- return (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) ? Z_DATA_ERROR : err;
- }
- if(dwDestLen > stream.total_out)
- {
- lpszDest[stream.total_out] = 0;
- dwDestLen = (DWORD)stream.total_out;
- }
- return inflateEnd(&stream);
- }
- DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip)
- {
- DWORD dwBound = (DWORD)::compressBound(dwSrcLen);
-
- if(bGZip) dwBound += 16;
- return dwBound;
- }
- int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16);
- }
- int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, MAX_WBITS + 32);
- }
- DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen)
- {
- if(dwSrcLen < 20 || *(USHORT*)lpszSrc != 0x8B1F)
- return 0;
- return *(DWORD*)(lpszSrc + dwSrcLen - 4);
- }
- #endif
- #ifdef _BROTLI_SUPPORT
- CHPBrotliCompressor::CHPBrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality, int iWindow, int iMode, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_iQuality (iQuality)
- , m_iWindow (iWindow)
- , m_iMode (iMode)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- Reset();
- }
- CHPBrotliCompressor::~CHPBrotliCompressor()
- {
- if(m_bValid) ::BrotliEncoderDestroyInstance(m_pState);
- }
- BOOL CHPBrotliCompressor::Reset()
- {
- if(m_bValid) ::BrotliEncoderDestroyInstance(m_pState);
- m_pState = ::BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
- if(m_pState != nullptr)
- {
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_QUALITY , (UINT)m_iQuality);
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_LGWIN , (UINT)m_iWindow);
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_MODE , (UINT)m_iMode);
- if (m_iWindow > BROTLI_MAX_WINDOW_BITS)
- ::BrotliEncoderSetParameter(m_pState, BROTLI_PARAM_LARGE_WINDOW, BROTLI_TRUE);
- }
- return (m_bValid = (m_pState != nullptr));
- }
- BOOL CHPBrotliCompressor::Process(const BYTE* pData, int iLength, BOOL bLast, PVOID pContext)
- {
- return ProcessEx(pData, iLength, bLast, FALSE, pContext);
- }
- BOOL CHPBrotliCompressor::ProcessEx(const BYTE* pData, int iLength, BOOL bLast, BOOL bFlush, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- const BYTE* pNextInData = pData;
- size_t iAvlInLen = (SIZE_T)iLength;
- BYTE* pNextOutData = nullptr;
- size_t iAvlOutLen = 0;
- BOOL isOK = TRUE;
- BrotliEncoderOperation op = bLast ? BROTLI_OPERATION_FINISH : (bFlush ? BROTLI_OPERATION_FLUSH : BROTLI_OPERATION_PROCESS);
- while(iAvlInLen > 0)
- {
- do
- {
- pNextOutData = szBuff.get();
- iAvlOutLen = m_dwBuffSize;
- if(!::BrotliEncoderCompressStream(m_pState, op, &iAvlInLen, &pNextInData, &iAvlOutLen, &pNextOutData, nullptr))
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
- goto BROTLI_COMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - iAvlOutLen);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
-
- goto BROTLI_COMPRESS_END;
- }
- } while (iAvlOutLen == 0);
- }
- BROTLI_COMPRESS_END:
- if(!isOK || bLast) Reset();
- return isOK;
- }
- CHPBrotliDecompressor::CHPBrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
- : m_fnCallback (fnCallback)
- , m_dwBuffSize (dwBuffSize)
- , m_bValid (FALSE)
- {
- ASSERT(m_fnCallback != nullptr);
- Reset();
- }
- CHPBrotliDecompressor::~CHPBrotliDecompressor()
- {
- if(m_bValid) ::BrotliDecoderDestroyInstance(m_pState);
- }
- BOOL CHPBrotliDecompressor::Reset()
- {
- if(m_bValid) ::BrotliDecoderDestroyInstance(m_pState);
- m_pState = ::BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
- return (m_bValid = (m_pState != nullptr));
- }
- BOOL CHPBrotliDecompressor::Process(const BYTE* pData, int iLength, PVOID pContext)
- {
- ASSERT(IsValid() && iLength > 0);
- if(!IsValid())
- {
- ::SetLastError(ERROR_INVALID_STATE);
- return FALSE;
- }
- unique_ptr<BYTE[]> szBuff = make_unique<BYTE[]>(m_dwBuffSize);
- const BYTE* pNextInData = pData;
- size_t iAvlInLen = (SIZE_T)iLength;
- BYTE* pNextOutData = nullptr;
- size_t iAvlOutLen = 0;
- BOOL isOK = TRUE;
- BrotliDecoderResult rs = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
- do
- {
- do
- {
- pNextOutData = szBuff.get();
- iAvlOutLen = m_dwBuffSize;
- rs = ::BrotliDecoderDecompressStream(m_pState, &iAvlInLen, &pNextInData, &iAvlOutLen, &pNextOutData, nullptr);
- if(rs == BROTLI_DECODER_RESULT_ERROR)
- {
- ::SetLastError(ERROR_INVALID_DATA);
- isOK = FALSE;
- goto BROTLI_DECOMPRESS_END;
- }
- int iRead = (int)(m_dwBuffSize - iAvlOutLen);
- if(iRead == 0)
- break;
- if(!m_fnCallback(szBuff.get(), iRead, pContext))
- {
- ::SetLastError(ERROR_CANCELLED);
- isOK = FALSE;
- goto BROTLI_DECOMPRESS_END;
- }
- } while (iAvlOutLen == 0);
- if(rs == BROTLI_DECODER_RESULT_SUCCESS)
- break;
- } while(rs == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
- BROTLI_DECOMPRESS_END:
- if(!isOK || rs == BROTLI_DECODER_RESULT_SUCCESS) Reset();
- return isOK;
- }
- IHPCompressor* CreateBrotliCompressor(Fn_CompressDataCallback fnCallback, int iQuality, int iWindow, int iMode, DWORD dwBuffSize)
- {
- return new CHPBrotliCompressor(fnCallback, iQuality, iWindow, iMode, dwBuffSize);
- }
- IHPDecompressor* CreateBrotliDecompressor(Fn_DecompressDataCallback fnCallback, DWORD dwBuffSize)
- {
- return new CHPBrotliDecompressor(fnCallback, dwBuffSize);
- }
- int BrotliCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- return BrotliCompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE);
- }
- int BrotliCompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iQuality, int iWindow, int iMode)
- {
- size_t stDestLen = (size_t)dwDestLen;
- int rs = ::BrotliEncoderCompress(iQuality, iWindow, (BrotliEncoderMode)iMode, (size_t)dwSrcLen, lpszSrc, &stDestLen, lpszDest);
- dwDestLen = (DWORD)stDestLen;
- return (rs == 1) ? 0 : ((rs == 3) ? -5 : -3);
- }
- int BrotliUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
- {
- size_t stDestLen = (size_t)dwDestLen;
- BrotliDecoderResult rs = ::BrotliDecoderDecompress((size_t)dwSrcLen, lpszSrc, &stDestLen, lpszDest);
- dwDestLen = (DWORD)stDestLen;
- return (rs == BROTLI_DECODER_RESULT_SUCCESS) ? 0 : ((rs == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) ? -5 : -3);
- }
- DWORD BrotliGuessCompressBound(DWORD dwSrcLen)
- {
- return (DWORD)::BrotliEncoderMaxCompressedSize((size_t)dwSrcLen);
- }
- #endif
- #ifdef _ICONV_SUPPORT
- BOOL CharsetConvert(LPCSTR lpszFromCharset, LPCSTR lpszToCharset, LPCSTR lpszInBuf, int iInBufLen, LPSTR lpszOutBuf, int& iOutBufLen)
- {
- ASSERT(lpszInBuf != nullptr);
- SIZE_T nInBufLeft = iInBufLen;
- SIZE_T nOutBufLeft = iOutBufLen;
- int iOutBufSize = iOutBufLen;
- iOutBufLen = 0;
- if(lpszInBuf == nullptr)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- iconv_t ic = iconv_open(lpszToCharset, lpszFromCharset);
- if(IS_INVALID_PVOID(ic))
- return FALSE;
- SIZE_T rs = iconv(ic, (LPSTR*)&lpszInBuf, &nInBufLeft, &lpszOutBuf, &nOutBufLeft);
- iOutBufLen = iOutBufSize - (int)nOutBufLeft;
- EXECUTE_RESTORE_ERROR(iconv_close(ic));
- return !IS_HAS_ERROR(rs);
- }
- BOOL GbkToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- int iOutBufLen = (int)(iDestLength * sizeof(WCHAR));
- BOOL isOK = CharsetConvert(CHARSET_GBK, SYSTEM_CHARSET_UNICODE, szSrc, iInBufLen, (char*)szDest, iOutBufLen);
- iDestLength = (int)(iOutBufLen / sizeof(WCHAR));
- return isOK;
- }
- BOOL UnicodeToGbkEx(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)(((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? wcslen(szSrc) + 1 : 0)) * sizeof(WCHAR));
- return CharsetConvert(SYSTEM_CHARSET_UNICODE, CHARSET_GBK, (LPCSTR)szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL Utf8ToUnicodeEx(const char szSrc[], int iSrcLength, WCHAR szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- int iOutBufLen = (int)(iDestLength * sizeof(WCHAR));
- BOOL isOK = CharsetConvert(CHARSET_UTF_8, SYSTEM_CHARSET_UNICODE, szSrc, iInBufLen, (char*)szDest, iOutBufLen);
- iDestLength = (int)(iOutBufLen / sizeof(WCHAR));
- return isOK;
- }
- BOOL UnicodeToUtf8Ex(const WCHAR szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)(((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? wcslen(szSrc) + 1 : 0)) * sizeof(WCHAR));
- return CharsetConvert(SYSTEM_CHARSET_UNICODE, CHARSET_UTF_8, (LPCSTR)szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL GbkToUtf8Ex(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- return CharsetConvert(CHARSET_GBK, CHARSET_UTF_8, szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL Utf8ToGbkEx(const char szSrc[], int iSrcLength, char szDest[], int& iDestLength)
- {
- int iInBufLen = (int)((iSrcLength > 0) ? iSrcLength : ((szSrc != nullptr) ? strlen(szSrc) + 1 : 0));
- return CharsetConvert(CHARSET_UTF_8, CHARSET_GBK, szSrc, iInBufLen, szDest, iDestLength);
- }
- BOOL GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
- {
- return GbkToUnicodeEx(szSrc, -1, szDest, iDestLength);
- }
- BOOL UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
- {
- return UnicodeToGbkEx(szSrc, -1, szDest, iDestLength);
- }
- BOOL Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
- {
- return Utf8ToUnicodeEx(szSrc, -1, szDest, iDestLength);
- }
- BOOL UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
- {
- return UnicodeToUtf8Ex(szSrc, -1, szDest, iDestLength);
- }
- BOOL GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
- {
- return GbkToUtf8Ex(szSrc, -1, szDest, iDestLength);
- }
- BOOL Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
- {
- return Utf8ToGbkEx(szSrc, -1, szDest, iDestLength);
- }
- #endif
|