HttpHelper.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 3.6.1
  5. * Author : Bruce Liang
  6. * Website : http://www.jessma.org
  7. * Project : https://github.com/ldcsaa
  8. * Blog : http://www.cnblogs.com/ldcsaa
  9. * Wiki : http://www.oschina.net/p/hp-socket
  10. * QQ Group : 75375912
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. #pragma once
  25. #include "SocketHelper.h"
  26. #include "../../Common/Src/http/http_parser.h"
  27. /************************************************************************
  28. 名称:HTTP 全局常量
  29. 描述:声明 HTTP 组件的公共全局常量
  30. ************************************************************************/
  31. #define CRLF "\r\n"
  32. #define NV_SEPARATOR_CHAR '='
  33. #define HEADER_SEPARATOR ": "
  34. #define COOKIE_TOKENIZE "; "
  35. #define STR_HTTP_1_0 "HTTP/1.0"
  36. #define STR_HTTP_1_1 "HTTP/1.1"
  37. #define HOST_HEADER "Host"
  38. #define COOKIE_HEADER "Cookie"
  39. #define SET_COOKIE_HEADER "Set-Cookie"
  40. #define CONTENT_TYPE_HEADER "Content-Type"
  41. #define CONTENT_LENGTH_HEADER "Content-Length"
  42. #define TRANSFER_ENCODING_HEADER "Transfer-Encoding"
  43. #define UPGRADE_HEADER "Upgrade"
  44. #define WEB_SOCKET_HEADER_VALUE "WebSocket"
  45. #define HTTP_METHOD_POST "POST"
  46. #define HTTP_METHOD_PUT "PUT"
  47. #define HTTP_METHOD_PATCH "PATCH"
  48. #define HTTP_METHOD_GET "GET"
  49. #define HTTP_METHOD_DELETE "DELETE"
  50. #define HTTP_METHOD_HEAD "HEAD"
  51. #define HTTP_METHOD_TRACE "TRACE"
  52. #define HTTP_METHOD_OPTIONS "OPTIONS"
  53. #define HTTP_METHOD_CONNECT "CONNECT"
  54. extern const DWORD MIN_HTTP_RELEASE_CHECK_INTERVAL;
  55. extern const DWORD MIN_HTTP_RELEASE_DELAY;
  56. extern const DWORD MAX_HTTP_RELEASE_DELAY;
  57. extern const DWORD DEFAULT_HTTP_RELEASE_DELAY;
  58. extern const EnHttpVersion DEFAULT_HTTP_VERSION;
  59. struct TDyingConnection
  60. {
  61. CONNID connID;
  62. DWORD killTime;
  63. TDyingConnection(CONNID id, DWORD kt = 0)
  64. : connID (id)
  65. , killTime (kt == 0 ? ::TimeGetTime() : kt)
  66. {
  67. }
  68. static TDyingConnection* Construct(CONNID id, DWORD kt = 0) {return new TDyingConnection(id, kt);}
  69. static void Destruct(TDyingConnection* pObj) {if(pObj) delete pObj;}
  70. };
  71. struct str_hash_func
  72. {
  73. struct hash
  74. {
  75. size_t operator() (const char* p) const
  76. {
  77. return hash_value(p);
  78. }
  79. };
  80. struct equal_to
  81. {
  82. bool operator () (const char* p1, const char* p2) const
  83. {
  84. return strcmp(p1, p2) == 0;
  85. }
  86. };
  87. };
  88. struct cstringa_hash_func
  89. {
  90. struct hash
  91. {
  92. size_t operator() (const CStringA& str) const
  93. {
  94. size_t s = hash_value((LPCSTR)str);
  95. return s;
  96. }
  97. };
  98. struct equal_to
  99. {
  100. bool operator () (const CStringA& strA, const CStringA& strB) const
  101. {
  102. return strA == strB;
  103. }
  104. };
  105. };
  106. typedef unordered_multimap<CStringA, CStringA,
  107. cstringa_hash_func::hash, cstringa_hash_func::equal_to> THeaderMap;
  108. typedef THeaderMap::const_iterator THeaderMapCI;
  109. typedef THeaderMap::iterator THeaderMapI;
  110. typedef unordered_map<CStringA, CStringA,
  111. cstringa_hash_func::hash, cstringa_hash_func::equal_to> TCookieMap;
  112. typedef TCookieMap::const_iterator TCookieMapCI;
  113. typedef TCookieMap::iterator TCookieMapI;
  114. /* Http 缓冲区结构 */
  115. template<class T, class S> struct THttpObjT
  116. {
  117. public:
  118. EnHandleResult Execute(const BYTE* pData, int iLength)
  119. {
  120. ASSERT(pData != nullptr && iLength > 0);
  121. if(m_parser.upgrade)
  122. return m_pContext->DoFireSuperReceive(m_pSocket, pData, iLength);
  123. EnHandleResult hr = HR_OK;
  124. int iPased = (int)::http_parser_execute(&m_parser, &sm_settings, (LPCSTR)pData, iLength);
  125. if(m_parser.upgrade)
  126. hr = Upgrade(pData, iLength, iPased);
  127. else if(m_parser.http_errno != HPE_OK)
  128. {
  129. m_pContext->FireParseError(m_pSocket, m_parser.http_errno, ::http_errno_description(HTTP_PARSER_ERRNO(&m_parser)));
  130. hr = HR_ERROR;
  131. }
  132. else
  133. ASSERT(iPased == iLength);
  134. return hr;
  135. }
  136. static int on_message_begin(http_parser* p)
  137. {
  138. THttpObjT* pSelf = Self(p);
  139. pSelf->ResetHeaderState();
  140. return pSelf->m_pContext->FireMessageBegin(pSelf->m_pSocket);
  141. }
  142. static int on_url(http_parser* p, const char* at, size_t length)
  143. {
  144. EnHttpParseResult hpr = HPR_OK;
  145. THttpObjT* pSelf = Self(p);
  146. pSelf->AppendBuffer(at, length);
  147. if(p->state != s_req_http_start)
  148. return hpr;
  149. hpr = pSelf->ParseUrl();
  150. if(hpr == HPR_OK)
  151. hpr = pSelf->m_pContext->FireRequestLine(pSelf->m_pSocket, ::http_method_str((http_method)p->method), pSelf->GetBuffer());
  152. pSelf->ResetBuffer();
  153. return hpr;
  154. }
  155. static int on_status(http_parser* p, const char* at, size_t length)
  156. {
  157. EnHttpParseResult hpr = HPR_OK;
  158. THttpObjT* pSelf = Self(p);
  159. pSelf->AppendBuffer(at, length);
  160. if(p->state != s_res_line_almost_done)
  161. return hpr;
  162. hpr = pSelf->m_pContext->FireStatusLine(pSelf->m_pSocket, p->status_code, pSelf->GetBuffer());
  163. pSelf->ResetBuffer();
  164. return hpr;
  165. }
  166. static int on_header_field(http_parser* p, const char* at, size_t length)
  167. {
  168. EnHttpParseResult hpr = HPR_OK;
  169. THttpObjT* pSelf = Self(p);
  170. pSelf->AppendBuffer(at, length);
  171. if(p->state != s_header_value_discard_ws)
  172. return hpr;
  173. pSelf->m_strCurHeader = pSelf->GetBuffer();
  174. pSelf->ResetBuffer();
  175. return hpr;
  176. }
  177. static int on_header_value(http_parser* p, const char* at, size_t length)
  178. {
  179. EnHttpParseResult hpr = HPR_OK;
  180. THttpObjT* pSelf = Self(p);
  181. pSelf->AppendBuffer(at, length);
  182. if(p->state != s_header_almost_done)
  183. return hpr;
  184. if(pSelf->m_bRequest && pSelf->m_strCurHeader == COOKIE_HEADER)
  185. hpr = pSelf->ParseCookie();
  186. else
  187. {
  188. pSelf->m_headers.emplace(move(THeaderMap::value_type(pSelf->m_strCurHeader, pSelf->GetBuffer())));
  189. hpr = pSelf->m_pContext->FireHeader(pSelf->m_pSocket, pSelf->m_strCurHeader, pSelf->GetBuffer());
  190. }
  191. pSelf->ResetBuffer();
  192. return hpr;
  193. }
  194. static int on_headers_complete(http_parser* p)
  195. {
  196. THttpObjT* pSelf = Self(p);
  197. pSelf->CheckUpgrade();
  198. pSelf->ResetHeaderBuffer();
  199. return pSelf->m_pContext->FireHeadersComplete(pSelf->m_pSocket);
  200. }
  201. static int on_body(http_parser* p, const char* at, size_t length)
  202. {
  203. THttpObjT* pSelf = Self(p);
  204. return pSelf->m_pContext->FireBody(pSelf->m_pSocket, (const BYTE*)at, (int)length);
  205. }
  206. static int on_chunk_header(http_parser* p)
  207. {
  208. THttpObjT* pSelf = Self(p);
  209. if(p->state == s_chunk_data || p->state == s_header_field_start)
  210. return pSelf->m_pContext->FireChunkHeader(pSelf->m_pSocket, (int)p->content_length);
  211. return HPR_OK;
  212. }
  213. static int on_chunk_complete(http_parser* p)
  214. {
  215. THttpObjT* pSelf = Self(p);
  216. if(p->state == s_headers_done || p->state == s_message_done)
  217. return pSelf->m_pContext->FireChunkComplete(pSelf->m_pSocket);
  218. return HPR_OK;
  219. }
  220. static int on_message_complete(http_parser* p)
  221. {
  222. THttpObjT* pSelf = Self(p);
  223. EnHttpParseResult hpr = pSelf->m_pContext->FireMessageComplete(pSelf->m_pSocket);
  224. return hpr;
  225. }
  226. private:
  227. EnHandleResult Upgrade(const BYTE* pData, int iLength, int iPased)
  228. {
  229. ASSERT(m_parser.upgrade);
  230. if(m_pContext->FireUpgrade(m_pSocket, m_enUpgrade) != HPR_OK)
  231. return HR_ERROR;
  232. ResetHeaderState();
  233. if(iPased < iLength)
  234. return Execute(pData + iPased, iLength - iPased);
  235. return HR_OK;
  236. }
  237. void CheckUpgrade()
  238. {
  239. if(!m_parser.upgrade)
  240. return;
  241. if(m_bRequest && m_parser.method == HTTP_CONNECT)
  242. m_enUpgrade = HUT_HTTP_TUNNEL;
  243. else
  244. {
  245. LPCSTR lpszValue;
  246. if(GetHeader(UPGRADE_HEADER, &lpszValue) && _stricmp(WEB_SOCKET_HEADER_VALUE, lpszValue) == 0)
  247. m_enUpgrade = HUT_WEB_SOCKET;
  248. else
  249. m_enUpgrade = HUT_UNKNOWN;
  250. }
  251. }
  252. EnHttpParseResult ParseUrl()
  253. {
  254. http_parser_url url = {0};
  255. BOOL isConnect = m_parser.method == HTTP_CONNECT;
  256. int rs = ::http_parser_parse_url(m_strBuffer, m_strBuffer.GetLength(), isConnect, &url);
  257. if(rs != HPE_OK)
  258. {
  259. m_parser.http_errno = HPE_INVALID_URL;
  260. return HPR_ERROR;
  261. }
  262. m_usUrlFieldSet = url.field_set;
  263. LPCSTR lpszBuffer = (LPCSTR)m_strBuffer;
  264. for(int i = 0; i < UF_MAX; i++)
  265. {
  266. if((url.field_set & (1 << i)) != 0)
  267. m_pstrUrlFileds[i].SetString((lpszBuffer + url.field_data[i].off), url.field_data[i].len);
  268. }
  269. return HPR_OK;
  270. }
  271. EnHttpParseResult ParseCookie()
  272. {
  273. int i = 0;
  274. do
  275. {
  276. CStringA tk = m_strBuffer.Tokenize(COOKIE_TOKENIZE, i);
  277. if(i != -1)
  278. {
  279. int j = tk.Find(NV_SEPARATOR_CHAR);
  280. if(j <= 0)
  281. {
  282. m_parser.http_errno = HPE_INVALID_HEADER_TOKEN;
  283. return HPR_ERROR;
  284. }
  285. m_cookies.emplace(move(TCookieMap::value_type(tk.Left(j), tk.Mid(j + 1))));
  286. }
  287. } while(i != -1);
  288. return HPR_OK;
  289. }
  290. public:
  291. BOOL IsUpgrade() {return m_parser.upgrade;}
  292. BOOL IsKeepAlive() {return ::http_should_keep_alive(&m_parser);}
  293. USHORT GetVersion() {return MAKEWORD(m_parser.http_major, m_parser.http_minor);}
  294. ULONGLONG GetContentLength() {return m_parser.content_length;}
  295. LPCSTR GetMethod() {return ::http_method_str((http_method)(m_parser.method));}
  296. USHORT GetUrlFieldSet() {return m_usUrlFieldSet;}
  297. USHORT GetStatusCode() {return m_parser.status_code;}
  298. EnHttpUpgradeType GetUpgradeType() {return m_enUpgrade;}
  299. THeaderMap& GetHeaderMap() {return m_headers;}
  300. TCookieMap& GetCookieMap() {return m_cookies;}
  301. BOOL HasReleased() {return m_bReleased;}
  302. void Release() {m_bReleased = TRUE;}
  303. LPCSTR GetContentType()
  304. {
  305. LPCSTR lpszValue = nullptr;
  306. GetHeader(CONTENT_TYPE_HEADER, &lpszValue);
  307. return lpszValue;
  308. }
  309. USHORT GetParseErrorCode(LPCSTR* lpszErrorDesc = nullptr)
  310. {
  311. if(lpszErrorDesc)
  312. *lpszErrorDesc = ::http_errno_description(HTTP_PARSER_ERRNO(&m_parser));
  313. return m_parser.http_errno;
  314. }
  315. LPCSTR GetUrlField(EnHttpUrlField enField)
  316. {
  317. ASSERT(m_pstrUrlFileds && enField < HUF_MAX);
  318. if(m_pstrUrlFileds && enField < HUF_MAX)
  319. return (LPCSTR)m_pstrUrlFileds[enField];
  320. return nullptr;
  321. }
  322. BOOL GetHeader(LPCSTR lpszName, LPCSTR* lpszValue)
  323. {
  324. ASSERT(lpszName);
  325. BOOL isOK = FALSE;
  326. THeaderMapCI it = m_headers.find(lpszName);
  327. if(it != m_headers.end())
  328. {
  329. *lpszValue = it->second;
  330. isOK = TRUE;
  331. }
  332. return isOK;
  333. }
  334. BOOL GetHeaders(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
  335. {
  336. ASSERT(lpszName);
  337. if(lpszValue == nullptr || dwCount == 0)
  338. {
  339. dwCount = (DWORD)m_headers.count(lpszName);
  340. return FALSE;
  341. }
  342. pair<THeaderMapCI, THeaderMapCI> range = m_headers.equal_range(lpszName);
  343. THeaderMapCI it = range.first;
  344. DWORD dwIndex = 0;
  345. while(it != range.second)
  346. {
  347. if(dwIndex < dwCount)
  348. lpszValue[dwIndex] = it->second;
  349. ++dwIndex;
  350. ++it;
  351. }
  352. BOOL isOK = (dwIndex > 0 && dwIndex <= dwCount);
  353. dwCount = dwIndex;
  354. return isOK;
  355. }
  356. BOOL GetAllHeaders(THeader lpHeaders[], DWORD& dwCount)
  357. {
  358. DWORD dwSize = (DWORD)m_headers.size();
  359. if(lpHeaders == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
  360. {
  361. dwCount = dwSize;
  362. return FALSE;
  363. }
  364. DWORD dwIndex = 0;
  365. for(THeaderMapCI it = m_headers.begin(), end = m_headers.end(); it != end; ++it, ++dwIndex)
  366. {
  367. lpHeaders[dwIndex].name = it->first;
  368. lpHeaders[dwIndex].value = it->second;
  369. }
  370. dwCount = dwSize;
  371. return TRUE;
  372. }
  373. BOOL GetAllHeaderNames(LPCSTR lpszName[], DWORD& dwCount)
  374. {
  375. DWORD dwSize = (DWORD)m_headers.size();
  376. if(lpszName == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
  377. {
  378. dwCount = dwSize;
  379. return FALSE;
  380. }
  381. DWORD dwIndex = 0;
  382. for(THeaderMapCI it = m_headers.begin(), end = m_headers.end(); it != end; ++it, ++dwIndex)
  383. lpszName[dwIndex] = it->first;
  384. dwCount = dwSize;
  385. return TRUE;
  386. }
  387. BOOL AddCookie(LPCSTR lpszName, LPCSTR lpszValue, BOOL bRelpace = TRUE)
  388. {
  389. ASSERT(lpszName);
  390. if(bRelpace)
  391. DeleteCookie(lpszName);
  392. return m_cookies.emplace(TCookieMap::value_type(lpszName, lpszValue)).second;
  393. }
  394. BOOL DeleteCookie(LPCSTR lpszName)
  395. {
  396. ASSERT(lpszName);
  397. return m_cookies.erase(lpszName) > 0;
  398. }
  399. void DeleteAllCookies()
  400. {
  401. m_cookies.clear();
  402. }
  403. BOOL GetCookie(LPCSTR lpszName, LPCSTR* lpszValue)
  404. {
  405. ASSERT(lpszName);
  406. BOOL isOK = FALSE;
  407. TCookieMapCI it = m_cookies.find(lpszName);
  408. if(it != m_cookies.end())
  409. {
  410. *lpszValue = it->second;
  411. isOK = TRUE;
  412. }
  413. return isOK;
  414. }
  415. BOOL GetAllCookies(TCookie lpCookies[], DWORD& dwCount)
  416. {
  417. DWORD dwSize = (DWORD)m_cookies.size();
  418. if(lpCookies == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
  419. {
  420. dwCount = dwSize;
  421. return FALSE;
  422. }
  423. DWORD dwIndex = 0;
  424. for(TCookieMapCI it = m_cookies.begin(), end = m_cookies.end(); it != end; ++it, ++dwIndex)
  425. {
  426. lpCookies[dwIndex].name = it->first;
  427. lpCookies[dwIndex].value = it->second;
  428. }
  429. dwCount = dwSize;
  430. return TRUE;
  431. }
  432. public:
  433. THttpObjT (BOOL bRequest, T* pContext, S* pSocket)
  434. : m_pContext (pContext)
  435. , m_pSocket (pSocket)
  436. , m_bRequest (bRequest)
  437. , m_bReleased (FALSE)
  438. , m_usUrlFieldSet (0)
  439. , m_pstrUrlFileds (nullptr)
  440. , m_enUpgrade (HUT_NONE)
  441. {
  442. if(m_bRequest)
  443. m_pstrUrlFileds = new CStringA[HUF_MAX];
  444. ResetParser();
  445. }
  446. ~THttpObjT()
  447. {
  448. if(m_pstrUrlFileds)
  449. delete[] m_pstrUrlFileds;
  450. }
  451. static THttpObjT* Construct(BOOL bRequest, T* pContext, S* pSocket)
  452. {return new THttpObjT(bRequest, pContext, pSocket);}
  453. static void Destruct(THttpObjT* pHttpObj)
  454. {if(pHttpObj) delete pHttpObj;}
  455. void Reset()
  456. {
  457. ResetParser();
  458. ResetHeaderState();
  459. }
  460. private:
  461. void ResetParser()
  462. {
  463. ::http_parser_init(&m_parser, m_bRequest ? HTTP_REQUEST : HTTP_RESPONSE);
  464. m_parser.data = this;
  465. }
  466. void ResetHeaderState()
  467. {
  468. if(m_pstrUrlFileds && m_usUrlFieldSet != 0)
  469. {
  470. m_usUrlFieldSet = 0;
  471. for(int i = 0; i < HUF_MAX; i++)
  472. m_pstrUrlFileds[i].Empty();
  473. }
  474. if(m_bRequest)
  475. DeleteAllCookies();
  476. m_headers.clear();
  477. ResetHeaderBuffer();
  478. }
  479. void ResetHeaderBuffer()
  480. {
  481. ResetBuffer();
  482. m_strCurHeader.Empty();
  483. }
  484. void AppendBuffer(const char* at, size_t length) {m_strBuffer.Append(at, (int)length);}
  485. void ResetBuffer() {m_strBuffer.Empty();}
  486. LPCSTR GetBuffer() {return m_strBuffer;}
  487. static THttpObjT* Self(http_parser* p) {return (THttpObjT*)(p->data);}
  488. static T* SelfContext(http_parser* p) {return Self(p)->m_pContext;}
  489. static S* SelfSocketObj(http_parser* p) {return Self(p)->m_pSocket;}
  490. private:
  491. BOOL m_bRequest;
  492. BOOL m_bReleased;
  493. T* m_pContext;
  494. S* m_pSocket;
  495. http_parser m_parser;
  496. THeaderMap m_headers;
  497. TCookieMap m_cookies;
  498. CStringA m_strBuffer;
  499. CStringA m_strCurHeader;
  500. USHORT m_usUrlFieldSet;
  501. CStringA* m_pstrUrlFileds;
  502. EnHttpUpgradeType m_enUpgrade;
  503. static http_parser_settings sm_settings;
  504. };
  505. template<class T, class S> http_parser_settings THttpObjT<T, S>::sm_settings =
  506. {
  507. on_message_begin,
  508. on_url,
  509. on_status,
  510. on_header_field,
  511. on_header_value,
  512. on_headers_complete,
  513. on_body,
  514. on_message_complete,
  515. on_chunk_header,
  516. on_chunk_complete
  517. };
  518. extern CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult);
  519. extern LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode);
  520. extern void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue);
  521. extern void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue);
  522. extern void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, TCookieMap* pCookies, int iBodyLength, BOOL bRequest, CStringA& strValue);
  523. extern void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2]);