开源的socket服务端客户端,支持C# C++

UdpClient.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 4.1.3
  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. SetRemoteHost(lpszRemoteAddress, usPort);
  164. BOOL isOK = FALSE;
  165. if(m_bAsyncConnect)
  166. {
  167. if(::WSAEventSelect(m_soClient, m_evSocket, FD_CONNECT | FD_CLOSE) != SOCKET_ERROR)
  168. {
  169. int rc = ::connect(m_soClient, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
  170. isOK = (rc == NO_ERROR || (rc == SOCKET_ERROR && ::WSAGetLastError() == WSAEWOULDBLOCK));
  171. }
  172. }
  173. else
  174. {
  175. if(::connect(m_soClient, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)) != SOCKET_ERROR)
  176. {
  177. if(::WSAEventSelect(m_soClient, m_evSocket, FD_READ | FD_WRITE | FD_CLOSE) != SOCKET_ERROR)
  178. {
  179. if(FireConnect() != HR_ERROR)
  180. {
  181. VERIFY(NeedDetectorThread() || DetectConnection() == NO_ERROR);
  182. m_enState = SS_STARTED;
  183. isOK = TRUE;
  184. }
  185. }
  186. }
  187. }
  188. return isOK;
  189. }
  190. BOOL CUdpClient::CreateWorkerThread()
  191. {
  192. m_hWorker = (HANDLE)_beginthreadex(nullptr, 0, WorkerThreadProc, (LPVOID)this, 0, &m_dwWorkerID);
  193. return m_hWorker != nullptr;
  194. }
  195. UINT WINAPI CUdpClient::WorkerThreadProc(LPVOID pv)
  196. {
  197. TRACE("---------------> Client Worker Thread 0x%08X started <---------------\n", ::GetCurrentThreadId());
  198. BOOL bCallStop = TRUE;
  199. CUdpClient* pClient = (CUdpClient*)pv;
  200. HANDLE hEvents[] = {pClient->m_evSocket, pClient->m_evBuffer, pClient->m_evWorker};
  201. pClient->m_rcBuffer.Malloc(pClient->m_dwMaxDatagramSize);
  202. while(pClient->HasStarted())
  203. {
  204. DWORD retval = ::WSAWaitForMultipleEvents(3, hEvents, FALSE, WSA_INFINITE, FALSE);
  205. if(retval == WSA_WAIT_EVENT_0)
  206. {
  207. if(!pClient->ProcessNetworkEvent())
  208. break;
  209. }
  210. else if(retval == WSA_WAIT_EVENT_0 + 1)
  211. {
  212. if(!pClient->SendData())
  213. break;
  214. }
  215. else if(retval == WSA_WAIT_EVENT_0 + 2)
  216. {
  217. bCallStop = FALSE;
  218. break;
  219. }
  220. else if(retval == WSA_WAIT_FAILED)
  221. {
  222. pClient->m_ccContext.Reset(TRUE, SO_UNKNOWN, ::WSAGetLastError());
  223. break;
  224. }
  225. else
  226. VERIFY(FALSE);
  227. }
  228. pClient->OnWorkerThreadEnd(::GetCurrentThreadId());
  229. if(bCallStop && pClient->HasStarted())
  230. pClient->Stop();
  231. TRACE("---------------> Client Worker Thread 0x%08X stoped <---------------\n", ::GetCurrentThreadId());
  232. return 0;
  233. }
  234. BOOL CUdpClient::ProcessNetworkEvent()
  235. {
  236. BOOL bContinue = TRUE;
  237. WSANETWORKEVENTS events;
  238. int rc = ::WSAEnumNetworkEvents(m_soClient, m_evSocket, &events);
  239. if(rc == SOCKET_ERROR)
  240. bContinue = HandleError(events);
  241. if(m_bAsyncConnect && bContinue && events.lNetworkEvents & FD_CONNECT)
  242. bContinue = HandleConnect(events);
  243. if(bContinue && events.lNetworkEvents & FD_READ)
  244. bContinue = HandleRead(events);
  245. if(bContinue && events.lNetworkEvents & FD_WRITE)
  246. bContinue = HandleWrite(events);
  247. if(bContinue && events.lNetworkEvents & FD_CLOSE)
  248. bContinue = HandleClose(events);
  249. return bContinue;
  250. }
  251. BOOL CUdpClient::HandleError(WSANETWORKEVENTS& events)
  252. {
  253. int iCode = ::WSAGetLastError();
  254. EnSocketOperation enOperation = SO_UNKNOWN;
  255. if(events.lNetworkEvents & FD_CONNECT)
  256. enOperation = SO_CONNECT;
  257. else if(events.lNetworkEvents & FD_CLOSE)
  258. enOperation = SO_CLOSE;
  259. else if(events.lNetworkEvents & FD_READ)
  260. enOperation = SO_RECEIVE;
  261. else if(events.lNetworkEvents & FD_WRITE)
  262. enOperation = SO_SEND;
  263. VERIFY(::WSAResetEvent(m_evSocket));
  264. m_ccContext.Reset(TRUE, enOperation, iCode);
  265. return FALSE;
  266. }
  267. BOOL CUdpClient::HandleRead(WSANETWORKEVENTS& events)
  268. {
  269. BOOL bContinue = TRUE;
  270. int iCode = events.iErrorCode[FD_READ_BIT];
  271. if(iCode == 0)
  272. bContinue = ReadData();
  273. else
  274. {
  275. m_ccContext.Reset(TRUE, SO_RECEIVE, iCode);
  276. bContinue = FALSE;
  277. }
  278. return bContinue;
  279. }
  280. BOOL CUdpClient::HandleWrite(WSANETWORKEVENTS& events)
  281. {
  282. BOOL bContinue = TRUE;
  283. int iCode = events.iErrorCode[FD_WRITE_BIT];
  284. if(iCode == 0)
  285. bContinue = SendData();
  286. else
  287. {
  288. m_ccContext.Reset(TRUE, SO_SEND, iCode);
  289. bContinue = FALSE;
  290. }
  291. return bContinue;
  292. }
  293. BOOL CUdpClient::HandleConnect(WSANETWORKEVENTS& events)
  294. {
  295. BOOL bContinue = TRUE;
  296. int iCode = events.iErrorCode[FD_CONNECT_BIT];
  297. if(iCode == 0)
  298. {
  299. if(::WSAEventSelect(m_soClient, m_evSocket, FD_READ | FD_WRITE | FD_CLOSE) != SOCKET_ERROR)
  300. {
  301. if(FireConnect() != HR_ERROR)
  302. {
  303. VERIFY(NeedDetectorThread() || DetectConnection() == NO_ERROR);
  304. m_enState = SS_STARTED;
  305. }
  306. else
  307. iCode = ERROR_CANCELLED;
  308. }
  309. else
  310. iCode = ::WSAGetLastError();
  311. }
  312. if(iCode != 0)
  313. {
  314. if(iCode != ERROR_CANCELLED)
  315. m_ccContext.Reset(TRUE, SO_CONNECT, iCode);
  316. else
  317. m_ccContext.Reset(FALSE);
  318. bContinue = FALSE;
  319. }
  320. return bContinue;
  321. }
  322. BOOL CUdpClient::HandleClose(WSANETWORKEVENTS& events)
  323. {
  324. int iCode = events.iErrorCode[FD_CLOSE_BIT];
  325. if(iCode == 0)
  326. m_ccContext.Reset(TRUE, SO_CLOSE, SE_OK);
  327. else
  328. m_ccContext.Reset(TRUE, SO_CLOSE, iCode);
  329. return FALSE;
  330. }
  331. BOOL CUdpClient::ReadData()
  332. {
  333. while(TRUE)
  334. {
  335. int rc = recv(m_soClient, (char*)(BYTE*)m_rcBuffer, m_dwMaxDatagramSize, 0);
  336. if(rc > 0)
  337. {
  338. if(FireReceive(m_rcBuffer, rc) == HR_ERROR)
  339. {
  340. TRACE("<C-CNNID: %Iu> OnReceive() event return 'HR_ERROR', connection will be closed !\n", m_dwConnID);
  341. m_ccContext.Reset(TRUE, SO_RECEIVE, ERROR_CANCELLED);
  342. return FALSE;
  343. }
  344. }
  345. else if(rc == SOCKET_ERROR)
  346. {
  347. int code = ::WSAGetLastError();
  348. if(code == WSAEWOULDBLOCK)
  349. break;
  350. else
  351. {
  352. m_ccContext.Reset(TRUE, SO_RECEIVE, code);
  353. return FALSE;
  354. }
  355. }
  356. else if(rc == 0)
  357. {
  358. m_dwDetectFails = 0;
  359. TRACE("<C-CNNID: %Iu> recv 0 bytes (detect package)\n", m_dwConnID);
  360. }
  361. else
  362. ASSERT(FALSE);
  363. }
  364. return TRUE;
  365. }
  366. BOOL CUdpClient::SendData()
  367. {
  368. while(TRUE)
  369. {
  370. TItemPtr itPtr(m_itPool, GetSendBuffer());
  371. if(itPtr.IsValid())
  372. {
  373. ASSERT(!itPtr->IsEmpty());
  374. int rc = 0;
  375. {
  376. CCriSecLock locallock(m_csSend);
  377. rc = send(m_soClient, (char*)itPtr->Ptr(), itPtr->Size(), 0);
  378. if(rc > 0) m_iPending -= rc;
  379. }
  380. if(rc > 0)
  381. {
  382. ASSERT(rc == itPtr->Size());
  383. if(FireSend(itPtr->Ptr(), rc) == HR_ERROR)
  384. {
  385. TRACE("<C-CNNID: %Iu> OnSend() event should not return 'HR_ERROR' !!\n", m_dwConnID);
  386. ASSERT(FALSE);
  387. }
  388. }
  389. else if(rc == SOCKET_ERROR)
  390. {
  391. int iCode = ::WSAGetLastError();
  392. if(iCode == WSAEWOULDBLOCK)
  393. {
  394. CCriSecLock locallock(m_csSend);
  395. m_lsSend.PushFront(itPtr.Detach());
  396. break;
  397. }
  398. else
  399. {
  400. m_ccContext.Reset(TRUE, SO_SEND, iCode);
  401. return FALSE;
  402. }
  403. }
  404. else
  405. ASSERT(FALSE);
  406. }
  407. else
  408. break;
  409. }
  410. return TRUE;
  411. }
  412. TItem* CUdpClient::GetSendBuffer()
  413. {
  414. TItem* pItem = nullptr;
  415. if(m_lsSend.Size() > 0)
  416. {
  417. CCriSecLock locallock(m_csSend);
  418. if(m_lsSend.Size() > 0)
  419. pItem = m_lsSend.PopFront();
  420. }
  421. return pItem;
  422. }
  423. int CUdpClient::DetectConnection()
  424. {
  425. int result = NO_ERROR;
  426. if(send(m_soClient, nullptr, 0, 0) == SOCKET_ERROR)
  427. {
  428. result = ::WSAGetLastError();
  429. if(result == WSAEWOULDBLOCK)
  430. result = NO_ERROR;
  431. }
  432. TRACE("<C-CNNID: %Iu> send 0 bytes (detect package)\n", m_dwConnID);
  433. return result;
  434. }
  435. BOOL CUdpClient::CreateDetectorThread()
  436. {
  437. BOOL isOK = TRUE;
  438. if(NeedDetectorThread())
  439. {
  440. m_hDetector = (HANDLE)_beginthreadex(nullptr, 0, DetecotrThreadProc, (LPVOID)this, 0, &m_dwDetectorID);
  441. isOK = m_hDetector != nullptr;
  442. }
  443. return isOK;
  444. }
  445. UINT WINAPI CUdpClient::DetecotrThreadProc(LPVOID pv)
  446. {
  447. TRACE("---------------> Client Detecotr Thread 0x%08X started <---------------\n", ::GetCurrentThreadId());
  448. CUdpClient* pClient = (CUdpClient*)pv;
  449. DWORD retval = WAIT_TIMEOUT;
  450. ASSERT(pClient->NeedDetectorThread());
  451. while(pClient->HasStarted())
  452. {
  453. retval = ::WaitForSingleObject(pClient->m_evDetector, pClient->m_dwDetectInterval * 1000L);
  454. ASSERT(retval == WAIT_TIMEOUT || retval == WAIT_OBJECT_0);
  455. if(retval == WAIT_OBJECT_0)
  456. break;
  457. int iCode = NO_ERROR;
  458. if(pClient->m_dwDetectFails++ < pClient->m_dwDetectAttempts)
  459. iCode = pClient->DetectConnection();
  460. else
  461. iCode = WSAECONNRESET;
  462. if(iCode != NO_ERROR)
  463. {
  464. pClient->m_ccContext.Reset(TRUE, SO_CLOSE, WSAECONNRESET);
  465. pClient->Stop();
  466. break;
  467. }
  468. }
  469. TRACE("---------------> Client Detecotr Thread 0x%08X stoped <---------------\n", ::GetCurrentThreadId());
  470. return 0;
  471. }
  472. BOOL CUdpClient::Stop()
  473. {
  474. DWORD dwCurrentThreadID = ::GetCurrentThreadId();
  475. if(!CheckStoping(dwCurrentThreadID))
  476. return FALSE;
  477. WaitForDetectorThreadEnd(dwCurrentThreadID);
  478. WaitForWorkerThreadEnd(dwCurrentThreadID);
  479. if(m_ccContext.bFireOnClose)
  480. FireClose(m_ccContext.enOperation, m_ccContext.iErrorCode);
  481. if(m_evSocket != nullptr)
  482. {
  483. ::WSACloseEvent(m_evSocket);
  484. m_evSocket = nullptr;
  485. }
  486. if(m_soClient != INVALID_SOCKET)
  487. {
  488. shutdown(m_soClient, SD_SEND);
  489. closesocket(m_soClient);
  490. m_soClient = INVALID_SOCKET;
  491. }
  492. Reset();
  493. return TRUE;
  494. }
  495. void CUdpClient::Reset()
  496. {
  497. CCriSecLock locallock(m_csSend);
  498. m_rcBuffer.Free();
  499. m_evBuffer.Reset();
  500. m_evWorker.Reset();
  501. m_evDetector.Reset();
  502. m_lsSend.Clear();
  503. m_itPool.Clear();
  504. m_strHost.Empty();
  505. m_usPort = 0;
  506. m_iPending = 0;
  507. m_dwDetectFails = 0;
  508. m_enState = SS_STOPPED;
  509. }
  510. void CUdpClient::WaitForWorkerThreadEnd(DWORD dwCurrentThreadID)
  511. {
  512. if(m_hWorker != nullptr)
  513. {
  514. if(dwCurrentThreadID != m_dwWorkerID)
  515. {
  516. m_evWorker.Set();
  517. VERIFY(::WaitForSingleObject(m_hWorker, INFINITE) == WAIT_OBJECT_0);
  518. }
  519. ::CloseHandle(m_hWorker);
  520. m_hWorker = nullptr;
  521. m_dwWorkerID = 0;
  522. }
  523. }
  524. void CUdpClient::WaitForDetectorThreadEnd(DWORD dwCurrentThreadID)
  525. {
  526. if(m_hDetector != nullptr)
  527. {
  528. if(dwCurrentThreadID != m_dwDetectorID)
  529. {
  530. m_evDetector.Set();
  531. VERIFY(::WaitForSingleObject(m_hDetector, INFINITE) == WAIT_OBJECT_0);
  532. }
  533. ::CloseHandle(m_hDetector);
  534. m_hDetector = nullptr;
  535. m_dwDetectorID = 0;
  536. }
  537. }
  538. BOOL CUdpClient::Send(const BYTE* pBuffer, int iLength, int iOffset)
  539. {
  540. int result = NO_ERROR;
  541. ASSERT(pBuffer && iLength > 0 && iLength <= (int)m_dwMaxDatagramSize);
  542. if(pBuffer && iLength > 0 && iLength <= (int)m_dwMaxDatagramSize)
  543. {
  544. if(iOffset != 0) pBuffer += iOffset;
  545. result = SendInternal(pBuffer, iLength);
  546. }
  547. else
  548. result = ERROR_INVALID_PARAMETER;
  549. if(result != NO_ERROR)
  550. ::SetLastError(result);
  551. return (result == NO_ERROR);
  552. }
  553. BOOL CUdpClient::SendPackets(const WSABUF pBuffers[], int iCount)
  554. {
  555. int result = NO_ERROR;
  556. ASSERT(pBuffers && iCount > 0);
  557. if(pBuffers && iCount > 0)
  558. {
  559. int iLength = 0;
  560. int iMaxLen = (int)m_dwMaxDatagramSize;
  561. TItemPtr itPtr(m_itPool, m_itPool.PickFreeItem());
  562. for(int i = 0; i < iCount; i++)
  563. {
  564. int iBufLen = pBuffers[i].len;
  565. if(iBufLen > 0)
  566. {
  567. BYTE* pBuffer = (BYTE*)pBuffers[i].buf;
  568. ASSERT(pBuffer);
  569. iLength += iBufLen;
  570. if(iLength <= iMaxLen)
  571. itPtr->Cat(pBuffer, iBufLen);
  572. else
  573. break;
  574. }
  575. }
  576. if(iLength > 0 && iLength <= iMaxLen)
  577. result = SendInternal(itPtr->Ptr(), iLength);
  578. else
  579. result = ERROR_INCORRECT_SIZE;
  580. }
  581. else
  582. result = ERROR_INVALID_PARAMETER;
  583. if(result != NO_ERROR)
  584. ::SetLastError(result);
  585. return (result == NO_ERROR);
  586. }
  587. int CUdpClient::SendInternal(const BYTE* pBuffer, int iLength)
  588. {
  589. int result = NO_ERROR;
  590. if(HasStarted())
  591. {
  592. CCriSecLock locallock(m_csSend);
  593. if(HasStarted())
  594. {
  595. ASSERT(m_iPending >= 0);
  596. BOOL isPending = m_iPending > 0;
  597. TItem* pItem = m_itPool.PickFreeItem();
  598. pItem->Cat(pBuffer, iLength);
  599. m_lsSend.PushBack(pItem);
  600. m_iPending += iLength;
  601. if(!isPending) m_evBuffer.Set();
  602. }
  603. else
  604. result = ERROR_INVALID_STATE;
  605. }
  606. else
  607. result = ERROR_INVALID_STATE;
  608. return result;
  609. }
  610. void CUdpClient::SetLastError(EnSocketError code, LPCSTR func, int ec)
  611. {
  612. TRACE("%s --> Error: %d, EC: %d\n", func, code, ec);
  613. m_enLastError = code;
  614. ::SetLastError(ec);
  615. }
  616. BOOL CUdpClient::GetLocalAddress(TCHAR lpszAddress[], int& iAddressLen, USHORT& usPort)
  617. {
  618. ASSERT(lpszAddress != nullptr && iAddressLen > 0);
  619. return ::GetSocketLocalAddress(m_soClient, lpszAddress, iAddressLen, usPort);
  620. }
  621. void CUdpClient::SetRemoteHost(LPCTSTR lpszHost, USHORT usPort)
  622. {
  623. m_strHost = lpszHost;
  624. m_usPort = usPort;
  625. }
  626. BOOL CUdpClient::GetRemoteHost(TCHAR lpszHost[], int& iHostLen, USHORT& usPort)
  627. {
  628. BOOL isOK = FALSE;
  629. if(m_strHost.IsEmpty())
  630. return isOK;
  631. int iLen = m_strHost.GetLength() + 1;
  632. if(iHostLen >= iLen)
  633. {
  634. memcpy(lpszHost, CA2CT(m_strHost), iLen * sizeof(TCHAR));
  635. usPort = m_usPort;
  636. isOK = TRUE;
  637. }
  638. iHostLen = iLen;
  639. return isOK;
  640. }
  641. BOOL CUdpClient::GetRemoteHost(LPCSTR* lpszHost, USHORT* pusPort)
  642. {
  643. *lpszHost = m_strHost;
  644. if(pusPort != nullptr)
  645. *pusPort = m_usPort;
  646. return !m_strHost.IsEmpty();
  647. }