UdpClient.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  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. #include "stdafx.h"
  25. #include "UdpClient.h"
  26. #include "../../Common/Src/WaitFor.h"
  27. #include <process.h>
  28. BOOL CUdpClient::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress)
  29. {
  30. if(!CheckParams() || !CheckStarting())
  31. return FALSE;
  32. PrepareStart();
  33. m_ccContext.Reset();
  34. BOOL isOK = FALSE;
  35. m_bAsyncConnect = bAsyncConnect;
  36. if(CreateClientSocket())
  37. {
  38. if(BindClientSocket(lpszBindAddress))
  39. {
  40. if(FirePrepareConnect(m_soClient) != HR_ERROR)
  41. {
  42. if(ConnectToServer(lpszRemoteAddress, usPort))
  43. {
  44. if(CreateWorkerThread())
  45. {
  46. if(CreateDetectorThread())
  47. isOK = TRUE;
  48. else
  49. SetLastError(SE_DETECT_THREAD_CREATE, __FUNCTION__, ERROR_CREATE_FAILED);
  50. }
  51. else
  52. SetLastError(SE_WORKER_THREAD_CREATE, __FUNCTION__, ERROR_CREATE_FAILED);
  53. }
  54. else
  55. SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ::WSAGetLastError());
  56. }
  57. else
  58. SetLastError(SE_SOCKET_PREPARE, __FUNCTION__, ERROR_CANCELLED);
  59. }
  60. else
  61. SetLastError(SE_SOCKET_BIND, __FUNCTION__, ::WSAGetLastError());
  62. }
  63. else
  64. SetLastError(SE_SOCKET_CREATE, __FUNCTION__, ::WSAGetLastError());
  65. if(!isOK)
  66. {
  67. m_ccContext.Reset(FALSE);
  68. Stop();
  69. }
  70. return isOK;
  71. }
  72. BOOL CUdpClient::CheckParams()
  73. {
  74. if (((int)m_dwMaxDatagramSize > 0) &&
  75. ((int)m_dwFreeBufferPoolSize >= 0) &&
  76. ((int)m_dwFreeBufferPoolHold >= 0) &&
  77. ((int)m_dwDetectAttempts >= 0) &&
  78. ((int)m_dwDetectInterval >= 0) )
  79. return TRUE;
  80. SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
  81. return FALSE;
  82. }
  83. void CUdpClient::PrepareStart()
  84. {
  85. m_itPool.SetItemCapacity((int)m_dwMaxDatagramSize);
  86. m_itPool.SetPoolSize((int)m_dwFreeBufferPoolSize);
  87. m_itPool.SetPoolHold((int)m_dwFreeBufferPoolHold);
  88. m_itPool.Prepare();
  89. }
  90. BOOL CUdpClient::CheckStarting()
  91. {
  92. CSpinLock locallock(m_csState);
  93. if(m_enState == SS_STOPPED)
  94. m_enState = SS_STARTING;
  95. else
  96. {
  97. SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_OPERATION);
  98. return FALSE;
  99. }
  100. return TRUE;
  101. }
  102. BOOL CUdpClient::CheckStoping(DWORD dwCurrentThreadID)
  103. {
  104. if(m_enState == SS_STOPPED)
  105. return FALSE;
  106. CSpinLock locallock(m_csState);
  107. if(HasStarted())
  108. {
  109. m_enState = SS_STOPPING;
  110. return TRUE;
  111. }
  112. else if(m_enState == SS_STOPPING)
  113. {
  114. if(dwCurrentThreadID != m_dwWorkerID && dwCurrentThreadID != m_dwDetectorID)
  115. {
  116. while(m_enState != SS_STOPPED)
  117. ::Sleep(30);
  118. }
  119. SetLastError(SE_ILLEGAL_STATE, __FUNCTION__, ERROR_INVALID_OPERATION);
  120. }
  121. return FALSE;
  122. }
  123. BOOL CUdpClient::CreateClientSocket()
  124. {
  125. m_soClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  126. if(m_soClient != INVALID_SOCKET)
  127. {
  128. VERIFY(::SSO_UDP_ConnReset(m_soClient, FALSE) == NO_ERROR);
  129. m_evSocket = ::WSACreateEvent();
  130. ASSERT(m_evSocket != WSA_INVALID_EVENT);
  131. return TRUE;
  132. }
  133. return FALSE;
  134. }
  135. BOOL CUdpClient::BindClientSocket(LPCTSTR lpszBindAddress)
  136. {
  137. if(lpszBindAddress)
  138. {
  139. SOCKADDR_IN bindAddr;
  140. if(!::sockaddr_A_2_IN(AF_INET, lpszBindAddress, 0, bindAddr))
  141. {
  142. ::WSASetLastError(WSAEADDRNOTAVAIL);
  143. return FALSE;
  144. }
  145. if(::bind(m_soClient, (struct sockaddr*)&bindAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
  146. return FALSE;
  147. }
  148. m_dwConnID = ::GenerateConnectionID();
  149. return TRUE;
  150. }
  151. BOOL CUdpClient::ConnectToServer(LPCTSTR lpszRemoteAddress, USHORT usPort)
  152. {
  153. TCHAR szAddress[40];
  154. int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
  155. if(!::GetIPAddress(lpszRemoteAddress, szAddress, iAddressLen))
  156. return FALSE;
  157. SOCKADDR_IN addr;
  158. if(!::sockaddr_A_2_IN(AF_INET, szAddress, usPort, addr))
  159. {
  160. ::WSASetLastError(WSAEADDRNOTAVAIL);
  161. return FALSE;
  162. }
  163. BOOL isOK = FALSE;
  164. if(m_bAsyncConnect)
  165. {
  166. if(::WSAEventSelect(m_soClient, m_evSocket, FD_CONNECT | FD_CLOSE) != SOCKET_ERROR)
  167. {
  168. int rc = ::connect(m_soClient, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
  169. isOK = (rc == NO_ERROR || (rc == SOCKET_ERROR && ::WSAGetLastError() == WSAEWOULDBLOCK));
  170. }
  171. }
  172. else
  173. {
  174. if(::connect(m_soClient, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)) != SOCKET_ERROR)
  175. {
  176. if(::WSAEventSelect(m_soClient, m_evSocket, FD_READ | FD_WRITE | FD_CLOSE) != SOCKET_ERROR)
  177. {
  178. if(FireConnect() != HR_ERROR)
  179. {
  180. VERIFY(NeedDetectorThread() || DetectConnection() == NO_ERROR);
  181. m_enState = SS_STARTED;
  182. isOK = TRUE;
  183. }
  184. }
  185. }
  186. }
  187. return isOK;
  188. }
  189. BOOL CUdpClient::CreateWorkerThread()
  190. {
  191. m_hWorker = (HANDLE)_beginthreadex(nullptr, 0, WorkerThreadProc, (LPVOID)this, 0, &m_dwWorkerID);
  192. return m_hWorker != nullptr;
  193. }
  194. UINT WINAPI CUdpClient::WorkerThreadProc(LPVOID pv)
  195. {
  196. TRACE("---------------> Client Worker Thread 0x%08X started <---------------\n", ::GetCurrentThreadId());
  197. BOOL bCallStop = TRUE;
  198. CUdpClient* pClient = (CUdpClient*)pv;
  199. HANDLE hEvents[] = {pClient->m_evSocket, pClient->m_evBuffer, pClient->m_evWorker};
  200. pClient->m_rcBuffer.Malloc(pClient->m_dwMaxDatagramSize);
  201. while(pClient->HasStarted())
  202. {
  203. DWORD retval = ::WSAWaitForMultipleEvents(3, hEvents, FALSE, WSA_INFINITE, FALSE);
  204. if(retval == WSA_WAIT_EVENT_0)
  205. {
  206. if(!pClient->ProcessNetworkEvent())
  207. break;
  208. }
  209. else if(retval == WSA_WAIT_EVENT_0 + 1)
  210. {
  211. if(!pClient->SendData())
  212. break;
  213. }
  214. else if(retval == WSA_WAIT_EVENT_0 + 2)
  215. {
  216. bCallStop = FALSE;
  217. break;
  218. }
  219. else
  220. ASSERT(FALSE);
  221. }
  222. pClient->OnWorkerThreadEnd(::GetCurrentThreadId());
  223. if(bCallStop && pClient->HasStarted())
  224. pClient->Stop();
  225. TRACE("---------------> Client Worker Thread 0x%08X stoped <---------------\n", ::GetCurrentThreadId());
  226. return 0;
  227. }
  228. BOOL CUdpClient::ProcessNetworkEvent()
  229. {
  230. BOOL bContinue = TRUE;
  231. WSANETWORKEVENTS events;
  232. int rc = ::WSAEnumNetworkEvents(m_soClient, m_evSocket, &events);
  233. if(rc == SOCKET_ERROR)
  234. bContinue = HandleError(events);
  235. if(m_bAsyncConnect && bContinue && events.lNetworkEvents & FD_CONNECT)
  236. bContinue = HandleConnect(events);
  237. if(bContinue && events.lNetworkEvents & FD_READ)
  238. bContinue = HandleRead(events);
  239. if(bContinue && events.lNetworkEvents & FD_WRITE)
  240. bContinue = HandleWrite(events);
  241. if(bContinue && events.lNetworkEvents & FD_CLOSE)
  242. bContinue = HandleClose(events);
  243. return bContinue;
  244. }
  245. BOOL CUdpClient::HandleError(WSANETWORKEVENTS& events)
  246. {
  247. int iCode = ::WSAGetLastError();
  248. EnSocketOperation enOperation = SO_UNKNOWN;
  249. if(events.lNetworkEvents & FD_CONNECT)
  250. enOperation = SO_CONNECT;
  251. else if(events.lNetworkEvents & FD_CLOSE)
  252. enOperation = SO_CLOSE;
  253. else if(events.lNetworkEvents & FD_READ)
  254. enOperation = SO_RECEIVE;
  255. else if(events.lNetworkEvents & FD_WRITE)
  256. enOperation = SO_SEND;
  257. VERIFY(::WSAResetEvent(m_evSocket));
  258. m_ccContext.Reset(TRUE, enOperation, iCode);
  259. return FALSE;
  260. }
  261. BOOL CUdpClient::HandleRead(WSANETWORKEVENTS& events)
  262. {
  263. BOOL bContinue = TRUE;
  264. int iCode = events.iErrorCode[FD_READ_BIT];
  265. if(iCode == 0)
  266. bContinue = ReadData();
  267. else
  268. {
  269. m_ccContext.Reset(TRUE, SO_RECEIVE, iCode);
  270. bContinue = FALSE;
  271. }
  272. return bContinue;
  273. }
  274. BOOL CUdpClient::HandleWrite(WSANETWORKEVENTS& events)
  275. {
  276. BOOL bContinue = TRUE;
  277. int iCode = events.iErrorCode[FD_WRITE_BIT];
  278. if(iCode == 0)
  279. bContinue = SendData();
  280. else
  281. {
  282. m_ccContext.Reset(TRUE, SO_SEND, iCode);
  283. bContinue = FALSE;
  284. }
  285. return bContinue;
  286. }
  287. BOOL CUdpClient::HandleConnect(WSANETWORKEVENTS& events)
  288. {
  289. BOOL bContinue = TRUE;
  290. int iCode = events.iErrorCode[FD_CONNECT_BIT];
  291. if(iCode == 0)
  292. {
  293. if(::WSAEventSelect(m_soClient, m_evSocket, FD_READ | FD_WRITE | FD_CLOSE) != SOCKET_ERROR)
  294. {
  295. if(FireConnect() != HR_ERROR)
  296. {
  297. VERIFY(NeedDetectorThread() || DetectConnection() == NO_ERROR);
  298. m_enState = SS_STARTED;
  299. }
  300. else
  301. iCode = ERROR_CANCELLED;
  302. }
  303. else
  304. iCode = ::WSAGetLastError();
  305. }
  306. if(iCode != 0)
  307. {
  308. if(iCode != ERROR_CANCELLED)
  309. m_ccContext.Reset(TRUE, SO_CONNECT, iCode);
  310. else
  311. m_ccContext.Reset(FALSE);
  312. bContinue = FALSE;
  313. }
  314. return bContinue;
  315. }
  316. BOOL CUdpClient::HandleClose(WSANETWORKEVENTS& events)
  317. {
  318. int iCode = events.iErrorCode[FD_CLOSE_BIT];
  319. if(iCode == 0)
  320. m_ccContext.Reset(TRUE, SO_CLOSE, SE_OK);
  321. else
  322. m_ccContext.Reset(TRUE, SO_CLOSE, iCode);
  323. return FALSE;
  324. }
  325. BOOL CUdpClient::ReadData()
  326. {
  327. while(TRUE)
  328. {
  329. int rc = recv(m_soClient, (char*)(BYTE*)m_rcBuffer, m_dwMaxDatagramSize, 0);
  330. if(rc > 0)
  331. {
  332. if(FireReceive(m_rcBuffer, rc) == HR_ERROR)
  333. {
  334. TRACE("<C-CNNID: %Iu> OnReceive() event return 'HR_ERROR', connection will be closed !\n", m_dwConnID);
  335. m_ccContext.Reset(TRUE, SO_RECEIVE, ERROR_CANCELLED);
  336. return FALSE;
  337. }
  338. }
  339. else if(rc == SOCKET_ERROR)
  340. {
  341. int code = ::WSAGetLastError();
  342. if(code == WSAEWOULDBLOCK)
  343. break;
  344. else
  345. {
  346. m_ccContext.Reset(TRUE, SO_RECEIVE, code);
  347. return FALSE;
  348. }
  349. }
  350. else if(rc == 0)
  351. {
  352. m_dwDetectFails = 0;
  353. TRACE("<C-CNNID: %Iu> recv 0 bytes (detect package)\n", m_dwConnID);
  354. }
  355. else
  356. ASSERT(FALSE);
  357. }
  358. return TRUE;
  359. }
  360. BOOL CUdpClient::SendData()
  361. {
  362. while(TRUE)
  363. {
  364. TItemPtr itPtr(m_itPool, GetSendBuffer());
  365. if(itPtr.IsValid())
  366. {
  367. ASSERT(!itPtr->IsEmpty());
  368. int rc = 0;
  369. {
  370. CCriSecLock locallock(m_csSend);
  371. rc = send(m_soClient, (char*)itPtr->Ptr(), itPtr->Size(), 0);
  372. if(rc > 0) m_iPending -= rc;
  373. }
  374. if(rc > 0)
  375. {
  376. ASSERT(rc == itPtr->Size());
  377. if(FireSend(itPtr->Ptr(), rc) == HR_ERROR)
  378. {
  379. TRACE("<C-CNNID: %Iu> OnSend() event should not return 'HR_ERROR' !!\n", m_dwConnID);
  380. ASSERT(FALSE);
  381. }
  382. }
  383. else if(rc == SOCKET_ERROR)
  384. {
  385. int iCode = ::WSAGetLastError();
  386. if(iCode == WSAEWOULDBLOCK)
  387. {
  388. CCriSecLock locallock(m_csSend);
  389. m_lsSend.PushFront(itPtr.Detach());
  390. break;
  391. }
  392. else
  393. {
  394. m_ccContext.Reset(TRUE, SO_SEND, iCode);
  395. return FALSE;
  396. }
  397. }
  398. else
  399. ASSERT(FALSE);
  400. }
  401. else
  402. break;
  403. }
  404. return TRUE;
  405. }
  406. TItem* CUdpClient::GetSendBuffer()
  407. {
  408. TItem* pItem = nullptr;
  409. if(m_lsSend.Size() > 0)
  410. {
  411. CCriSecLock locallock(m_csSend);
  412. if(m_lsSend.Size() > 0)
  413. pItem = m_lsSend.PopFront();
  414. }
  415. return pItem;
  416. }
  417. int CUdpClient::DetectConnection()
  418. {
  419. int result = NO_ERROR;
  420. if(send(m_soClient, nullptr, 0, 0) == SOCKET_ERROR)
  421. {
  422. result = ::WSAGetLastError();
  423. if(result == WSAEWOULDBLOCK)
  424. result = NO_ERROR;
  425. }
  426. TRACE("<C-CNNID: %Iu> send 0 bytes (detect package)\n", m_dwConnID);
  427. return result;
  428. }
  429. BOOL CUdpClient::CreateDetectorThread()
  430. {
  431. BOOL isOK = TRUE;
  432. if(NeedDetectorThread())
  433. {
  434. m_hDetector = (HANDLE)_beginthreadex(nullptr, 0, DetecotrThreadProc, (LPVOID)this, 0, &m_dwDetectorID);
  435. isOK = m_hDetector != nullptr;
  436. }
  437. return isOK;
  438. }
  439. UINT WINAPI CUdpClient::DetecotrThreadProc(LPVOID pv)
  440. {
  441. TRACE("---------------> Client Detecotr Thread 0x%08X started <---------------\n", ::GetCurrentThreadId());
  442. CUdpClient* pClient = (CUdpClient*)pv;
  443. DWORD retval = WAIT_TIMEOUT;
  444. ASSERT(pClient->NeedDetectorThread());
  445. while(pClient->HasStarted())
  446. {
  447. retval = ::WaitForSingleObject(pClient->m_evDetector, pClient->m_dwDetectInterval * 1000L);
  448. ASSERT(retval == WAIT_TIMEOUT || retval == WAIT_OBJECT_0);
  449. if(retval == WAIT_OBJECT_0)
  450. break;
  451. int iCode = NO_ERROR;
  452. if(pClient->m_dwDetectFails++ < pClient->m_dwDetectAttempts)
  453. iCode = pClient->DetectConnection();
  454. else
  455. iCode = WSAECONNRESET;
  456. if(iCode != NO_ERROR)
  457. {
  458. pClient->m_ccContext.Reset(TRUE, SO_CLOSE, WSAECONNRESET);
  459. pClient->Stop();
  460. break;
  461. }
  462. }
  463. TRACE("---------------> Client Detecotr Thread 0x%08X stoped <---------------\n", ::GetCurrentThreadId());
  464. return 0;
  465. }
  466. BOOL CUdpClient::Stop()
  467. {
  468. DWORD dwCurrentThreadID = ::GetCurrentThreadId();
  469. if(!CheckStoping(dwCurrentThreadID))
  470. return FALSE;
  471. WaitForDetectorThreadEnd(dwCurrentThreadID);
  472. WaitForWorkerThreadEnd(dwCurrentThreadID);
  473. if(m_ccContext.bFireOnClose)
  474. FireClose(m_ccContext.enOperation, m_ccContext.iErrorCode);
  475. if(m_evSocket != nullptr)
  476. {
  477. ::WSACloseEvent(m_evSocket);
  478. m_evSocket = nullptr;
  479. }
  480. if(m_soClient != INVALID_SOCKET)
  481. {
  482. shutdown(m_soClient, SD_SEND);
  483. closesocket(m_soClient);
  484. m_soClient = INVALID_SOCKET;
  485. }
  486. Reset();
  487. return TRUE;
  488. }
  489. void CUdpClient::Reset()
  490. {
  491. CCriSecLock locallock(m_csSend);
  492. m_rcBuffer.Free();
  493. m_evBuffer.Reset();
  494. m_evWorker.Reset();
  495. m_evDetector.Reset();
  496. m_lsSend.Clear();
  497. m_itPool.Clear();
  498. m_iPending = 0;
  499. m_dwDetectFails = 0;
  500. m_enState = SS_STOPPED;
  501. }
  502. void CUdpClient::WaitForWorkerThreadEnd(DWORD dwCurrentThreadID)
  503. {
  504. if(m_hWorker != nullptr)
  505. {
  506. if(dwCurrentThreadID != m_dwWorkerID)
  507. {
  508. m_evWorker.Set();
  509. VERIFY(::WaitForSingleObject(m_hWorker, INFINITE) == WAIT_OBJECT_0);
  510. }
  511. ::CloseHandle(m_hWorker);
  512. m_hWorker = nullptr;
  513. m_dwWorkerID = 0;
  514. }
  515. }
  516. void CUdpClient::WaitForDetectorThreadEnd(DWORD dwCurrentThreadID)
  517. {
  518. if(m_hDetector != nullptr)
  519. {
  520. if(dwCurrentThreadID != m_dwDetectorID)
  521. {
  522. m_evDetector.Set();
  523. VERIFY(::WaitForSingleObject(m_hDetector, INFINITE) == WAIT_OBJECT_0);
  524. }
  525. ::CloseHandle(m_hDetector);
  526. m_hDetector = nullptr;
  527. m_dwDetectorID = 0;
  528. }
  529. }
  530. BOOL CUdpClient::Send(const BYTE* pBuffer, int iLength, int iOffset)
  531. {
  532. int result = NO_ERROR;
  533. ASSERT(pBuffer && iLength > 0 && iLength <= (int)m_dwMaxDatagramSize);
  534. if(pBuffer && iLength > 0 && iLength <= (int)m_dwMaxDatagramSize)
  535. {
  536. if(iOffset != 0) pBuffer += iOffset;
  537. result = SendInternal(pBuffer, iLength);
  538. }
  539. else
  540. result = ERROR_INVALID_PARAMETER;
  541. if(result != NO_ERROR)
  542. ::SetLastError(result);
  543. return (result == NO_ERROR);
  544. }
  545. BOOL CUdpClient::SendPackets(const WSABUF pBuffers[], int iCount)
  546. {
  547. int result = NO_ERROR;
  548. ASSERT(pBuffers && iCount > 0);
  549. if(pBuffers && iCount > 0)
  550. {
  551. int iLength = 0;
  552. int iMaxLen = (int)m_dwMaxDatagramSize;
  553. TItemPtr itPtr(m_itPool, m_itPool.PickFreeItem());
  554. for(int i = 0; i < iCount; i++)
  555. {
  556. int iBufLen = pBuffers[i].len;
  557. if(iBufLen > 0)
  558. {
  559. BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
  560. ASSERT(pBuffer);
  561. iLength += iBufLen;
  562. if(iLength <= iMaxLen)
  563. itPtr->Cat(pBuffer, iBufLen);
  564. else
  565. break;
  566. }
  567. }
  568. if(iLength > 0 && iLength <= iMaxLen)
  569. result = SendInternal(itPtr->Ptr(), iLength);
  570. else
  571. result = ERROR_INCORRECT_SIZE;
  572. }
  573. else
  574. result = ERROR_INVALID_PARAMETER;
  575. if(result != NO_ERROR)
  576. ::SetLastError(result);
  577. return (result == NO_ERROR);
  578. }
  579. int CUdpClient::SendInternal(const BYTE* pBuffer, int iLength)
  580. {
  581. int result = NO_ERROR;
  582. if(HasStarted())
  583. {
  584. CCriSecLock locallock(m_csSend);
  585. if(HasStarted())
  586. {
  587. ASSERT(m_iPending >= 0);
  588. BOOL isPending = m_iPending > 0;
  589. TItem* pItem = m_itPool.PickFreeItem();
  590. pItem->Cat(pBuffer, iLength);
  591. m_lsSend.PushBack(pItem);
  592. m_iPending += iLength;
  593. if(!isPending) m_evBuffer.Set();
  594. }
  595. else
  596. result = ERROR_INVALID_STATE;
  597. }
  598. else
  599. result = ERROR_INVALID_STATE;
  600. return result;
  601. }
  602. void CUdpClient::SetLastError(EnSocketError code, LPCSTR func, int ec)
  603. {
  604. TRACE("%s --> Error: %d, EC: %d\n", func, code, ec);
  605. m_enLastError = code;
  606. ::SetLastError(ec);
  607. }
  608. BOOL CUdpClient::GetLocalAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
  609. {
  610. ASSERT(lpszAddress != nullptr && iAddressLen > 0);
  611. return ::GetSocketLocalAddress(m_soClient, lpszAddress, iAddressLen, usPort);
  612. }