工具项目

UdpClient.cpp 16KB

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