工具项目

UdpCast.cpp 16KB

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