Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

817 lines
26 KiB

  1. /*----------------------------------------------------------------------------
  2. * File: RTPRECV.C
  3. * Product: RTP/RTCP implementation
  4. * Description: Provides Receive Data Functionality.
  5. *
  6. * This listing is supplied under the terms
  7. * of a license agreement with Intel Corporation and
  8. * many not be copied nor disclosed except in accordance
  9. * with the terms of that agreement.
  10. * Copyright (c) 1995 Intel Corporation.
  11. *--------------------------------------------------------------------------*/
  12. #include "rrcm.h"
  13. /*---------------------------------------------------------------------------
  14. / Global Variables
  15. /--------------------------------------------------------------------------*/
  16. /*---------------------------------------------------------------------------
  17. / External Variables
  18. /--------------------------------------------------------------------------*/
  19. extern PRTP_CONTEXT pRTPContext;
  20. extern RRCM_WS RRCMws;
  21. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  22. //INTEROP
  23. extern LPInteropLogger RTPLogger;
  24. #endif
  25. /*----------------------------------------------------------------------------
  26. * Function : RTPReceiveCheck
  27. * Description: Called when a packet is received. Handles any statistical
  28. * processing required for RTCP.
  29. *
  30. * Input : hRTPSession: handle returned by CreateRTPSession
  31. RTPsocket: socket on which the packet was received
  32. char *pPacket: pointer to packet buffer
  33. * cbTransferred: Number of bytes in packet
  34. * pFrom: sender address
  35. * fromlen: sender address length
  36. *
  37. * !!! IMPORTANT NOTE !!!
  38. * Currently assumes CSRC = 0
  39. * !!! IMPORTANT NOTE !!!
  40. *
  41. * Return: Status indicating if the packet is OK or has a problem
  42. ---------------------------------------------------------------------------*/
  43. DWORD RTPReceiveCheck (
  44. HANDLE hRTPSession,
  45. SOCKET RTPsocket,
  46. char *pPacket,
  47. DWORD cbTransferred,
  48. PSOCKADDR pFrom,
  49. UINT fromlen
  50. )
  51. {
  52. PRTP_SESSION pRTPSession = (PRTP_SESSION) hRTPSession;
  53. RTP_HDR_T *pRTPHeader = (RTP_HDR_T *)pPacket;
  54. PSSRC_ENTRY pSSRC = NULL;
  55. DWORD dwSSRC;
  56. DWORD oldSSRC;
  57. PSSRC_ENTRY pMySSRC;
  58. DWORD dwStatus = 0;
  59. struct sockaddr_in *pSSRCadr;
  60. IN_OUT_STR ("RTP : Enter RTPReceiveCheck()\n");
  61. ASSERT (pRTPSession);
  62. // If Winsock error or runt packet(used to cancel recvs), signal completion to application
  63. // and do not repost.
  64. if (cbTransferred < RTP_HDR_MIN_LEN)
  65. {
  66. // don't report closeSocket() as an error when the application
  67. // have some pending buffers remaining
  68. // notify the user if an error occured, so he can free up
  69. // its receive resources. The byte count is set to 0
  70. return RTP_RUNT_PACKET;
  71. }
  72. // Perform validity checking
  73. ASSERT (pRTPHeader);
  74. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  75. if (RTPLogger)
  76. {
  77. //INTEROP
  78. InteropOutput (RTPLogger,
  79. (BYTE FAR*)(pRTPHeader),
  80. (int)cbTransferred,
  81. RTPLOG_RECEIVED_PDU | RTP_PDU);
  82. }
  83. #endif
  84. // Check RTP Headers for validity. If not valid, then repost buffers
  85. // to the network layer for a new receive.
  86. if (validateRTPHeader (pRTPHeader) )
  87. {
  88. // Get pointer to SSRC entry table for this session
  89. // If SSRC in packet is > 1/2 MAX_RANGE of DWORD, start search from
  90. // tail of SSRC list, otherwise, start from front
  91. RRCMws.ntohl (RTPsocket, pRTPHeader->ssrc, &dwSSRC);
  92. if (dwSSRC > MAX_DWORD/2)
  93. {
  94. pSSRC = searchforSSRCatTail (
  95. (PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.prev,
  96. dwSSRC);
  97. }
  98. else
  99. {
  100. pSSRC = searchforSSRCatHead (
  101. (PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.next,
  102. dwSSRC);
  103. }
  104. // get my own SSRC used for this stream
  105. pMySSRC = searchForMySSRC (
  106. (PSSRC_ENTRY)pRTPSession->pRTCPSession->XmtSSRCList.prev,
  107. RTPsocket);
  108. ASSERT (pMySSRC);
  109. // is this SSRC already known on the receive list ?
  110. if (pSSRC == NULL)
  111. {
  112. // don't create an entry for my own packet looping back on
  113. // a mcast group where loopback has not been turned off
  114. if (pMySSRC->SSRC != dwSSRC)
  115. {
  116. // new party heard from. Create an entry for it
  117. pSSRC = createSSRCEntry (dwSSRC,
  118. pRTPSession->pRTCPSession,
  119. pFrom,
  120. fromlen,
  121. FALSE);
  122. // notify application if interested
  123. RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, dwSSRC,
  124. pRTPHeader->pt);
  125. }
  126. else
  127. {
  128. // my own SSRC received back
  129. // A collision occurs if the SSRC in the rcvd packet is
  130. // equal to mine, and the network transport address is
  131. // different from mine.
  132. // A loop occurs if after a collision has been resolved the
  133. // SSRC collides again from the same source transport address
  134. pSSRCadr = (PSOCKADDR_IN)&pMySSRC->from;
  135. if (((PSOCKADDR_IN)pFrom)->sin_addr.S_un.S_addr !=
  136. pSSRCadr->sin_addr.S_un.S_addr)
  137. {
  138. // check if the source address is already in the
  139. // conflicting table. This identifes that somebody out
  140. // there is looping pckts back to me
  141. if (RRCMChkCollisionTable (pFrom, fromlen, pMySSRC))
  142. {
  143. RRCM_DBG_MSG ("RTP : Loop Detected ...", 0, NULL, 0,
  144. DBG_NOTIFY);
  145. // loop already known
  146. dwStatus |= SSRC_LOOP_DETECTED;
  147. }
  148. else
  149. {
  150. RRCM_DBG_MSG ("RTP : Collision Detected ...", 0, NULL, 0,
  151. DBG_NOTIFY);
  152. // create new entry in conflicting address table
  153. RRCMAddEntryToCollisionTable (pFrom, fromlen, pMySSRC);
  154. // send RTCP BYE packet w/ old SSRC
  155. RTCPsendBYE (pMySSRC, "Loop/collision detected");
  156. // select new SSRC
  157. oldSSRC = pMySSRC->SSRC;
  158. dwSSRC = getSSRC (pMySSRC->pRTCPses->RcvSSRCList,
  159. pMySSRC->pRTCPses->XmtSSRCList);
  160. EnterCriticalSection (&pMySSRC->critSect);
  161. pMySSRC->SSRC = dwSSRC;
  162. LeaveCriticalSection (&pMySSRC->critSect);
  163. // create new entry w/ old SSRC plus actual source
  164. // transport address in our receive list side, so the
  165. // packet actually en-route will be dealt with
  166. createSSRCEntry (oldSSRC,
  167. pRTPSession->pRTCPSession,
  168. pFrom,
  169. fromlen,
  170. FALSE);
  171. // notify application if interested
  172. RRCMnotification (RRCM_LOCAL_COLLISION_EVENT,
  173. pMySSRC, oldSSRC, 0);
  174. // loop already known
  175. dwStatus |= SSRC_COLLISION_DETECTED;
  176. }
  177. }
  178. else
  179. {
  180. // own packet looped back because the sender joined the
  181. // multicast group and loopback is not turned off
  182. dwStatus |= MCAST_LOOPBACK_NOT_OFF;
  183. }
  184. }
  185. }
  186. else if (pSSRC->dwSSRCStatus & THIRD_PARTY_COLLISION)
  187. {
  188. // this SSRC is marked as colliding. Reject the data
  189. dwStatus = THIRD_PARTY_COLLISION;
  190. }
  191. if (dwStatus == 0)
  192. {
  193. // do all the statistical updating stuff
  194. updateRTPStats (pRTPHeader, pSSRC, cbTransferred);
  195. // update the payload type for this SSRC
  196. pSSRC->PayLoadType = pRTPHeader->pt;
  197. } // SSRCList != NULL
  198. } // valid RTP Header
  199. else
  200. {
  201. dwStatus |= INVALID_RTP_HEADER;
  202. }
  203. IN_OUT_STR ("RTP : Exit RTPReceiveCallback()\n");
  204. return dwStatus;
  205. }
  206. /*----------------------------------------------------------------------------
  207. * Function : validateRTPHeader
  208. * Description: Performs basic checking of RTP Header (e.g., version number
  209. * and payload type range).
  210. *
  211. * Input : pRTPHeader: -> to an RTP header
  212. *
  213. * Return: TRUE, RTP Packet Header is valid
  214. * FALSE: Header is invalid
  215. ---------------------------------------------------------------------------*/
  216. BOOL validateRTPHeader(RTP_HDR_T *pRTPHeader)
  217. {
  218. BOOL bStatus = TRUE;
  219. IN_OUT_STR ("RTP : Enter validateRTPHeader()\n");
  220. if (! pRTPHeader)
  221. return FALSE;
  222. // Check version number is correct
  223. if (pRTPHeader->type != RTP_TYPE)
  224. bStatus = FALSE;
  225. // Next check that the Packet types look somewhat reasonable,
  226. // at least out of the RTCP range
  227. if (pRTPHeader->pt >= RTCP_SR)
  228. bStatus = FALSE;
  229. IN_OUT_STR ("RTP : Exit validateRTPHeader()\n");
  230. return bStatus;
  231. }
  232. #if 0
  233. /*----------------------------------------------------------------------------
  234. * Function : RTPRecvFrom
  235. * Description: Intercepts receive requests from app. Handles any statistical
  236. * processing required for RTCP. Copies completion routine
  237. * from app and substitutes its own. Apps completion routine
  238. * will be called after RTP's completion routine gets called.
  239. *
  240. * Input : RTPsocket: RTP socket descriptor
  241. * pBuffers: -> to WSAbuf structure
  242. * dwBufferCount: Buffer count in WSAbuf structure
  243. * pNumBytesRecvd: -> to number of bytes received
  244. * pFlags: -> to flags
  245. * pFrom: -> to the source address
  246. * pFromLen: -> to source address length
  247. * pOverlapped: -> to overlapped I/O structure
  248. * pCompletionRoutine: -> to completion routine
  249. *
  250. * Return: RRCM_NoError = OK.
  251. * Otherwise(!=0) = Check RRCM.h file for references.
  252. ---------------------------------------------------------------------------*/
  253. DWORD WINAPI RTPRecvFrom (SOCKET RTPsocket,
  254. LPWSABUF pBuffers,
  255. DWORD dwBufferCount,
  256. LPDWORD pNumBytesRecvd,
  257. LPDWORD pFlags,
  258. PSOCKADDR pFrom,
  259. LPINT pFromlen,
  260. LPWSAOVERLAPPED pOverlapped,
  261. LPWSAOVERLAPPED_COMPLETION_ROUTINE pCompletionRoutine)
  262. {
  263. int dwStatus = RRCM_NoError;
  264. int dwError;
  265. PRTP_SESSION pRTPSession;
  266. PRTP_BFR_LIST pRCVStruct;
  267. IN_OUT_STR ("RTP : Enter RTPRecvFrom()\n");
  268. // If RTP context doesn't exist, report error and return.
  269. if (pRTPContext == NULL)
  270. {
  271. RRCM_DBG_MSG ("RTP : ERROR - No RTP Instance", 0,
  272. __FILE__, __LINE__, DBG_CRITICAL);
  273. IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
  274. return (MAKE_RRCM_ERROR(RRCMError_RTPInvalid));
  275. }
  276. // Search for the proper session based on incoming socket
  277. pRTPSession = findSessionID(RTPsocket);
  278. if (pRTPSession == NULL)
  279. {
  280. RRCM_DBG_MSG ("RTP : ERROR - Invalid RTP session", 0,
  281. __FILE__, __LINE__, DBG_CRITICAL);
  282. IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
  283. return (MAKE_RRCM_ERROR(RRCMError_RTPInvalidSession));
  284. }
  285. // We need to associate a completionRoutine's lpOverlapped with a
  286. // session. We look at each buffer and associate a socket so when
  287. // the completion routine is called, we can pull out the socket.
  288. if (dwStatus = saveRCVWinsockContext(pOverlapped,
  289. pBuffers,
  290. pCompletionRoutine,
  291. pRTPSession,
  292. dwBufferCount,
  293. pNumBytesRecvd,
  294. pFlags,
  295. pFrom,
  296. pFromlen,
  297. RTPsocket) != RRCM_NoError)
  298. {
  299. RRCM_DBG_MSG ("RTP : ERROR - Out of resources...", 0,
  300. __FILE__, __LINE__, DBG_NOTIFY);
  301. IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
  302. return (MAKE_RRCM_ERROR(dwStatus));
  303. }
  304. // Forward to winsock, substituting our completion routine for the
  305. // one handed to us.
  306. dwStatus = RRCMws.recvFrom (RTPsocket,
  307. pBuffers,
  308. dwBufferCount,
  309. pNumBytesRecvd,
  310. pFlags,
  311. pFrom,
  312. pFromlen,
  313. pOverlapped,
  314. RTPReceiveCallback);
  315. // Check if Winsock Call succeeded
  316. if (dwStatus != 0)
  317. {
  318. // If serious error, the receive request won't proceed so
  319. // we must undo all our work
  320. dwError = GetLastError();
  321. if ((dwError != WSA_IO_PENDING) && (dwError != WSAEMSGSIZE))
  322. {
  323. // Reinstate the Apps WSAEVENT
  324. pRCVStruct = (PRTP_BFR_LIST)pOverlapped->hEvent;
  325. pOverlapped->hEvent = pRCVStruct->hEvent;
  326. RRCM_DBG_MSG ("RTP : ERROR - WSARecvFrom()", dwError,
  327. __FILE__, __LINE__, DBG_NOTIFY);
  328. // Return the struct to the free queue
  329. addToHeadOfList (&pRTPSession->pRTPFreeList,
  330. (PLINK_LIST)pRCVStruct,
  331. &pRTPSession->critSect);
  332. }
  333. }
  334. IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
  335. return (dwStatus);
  336. }
  337. /*----------------------------------------------------------------------------
  338. * Function : RTPReceiveCallback
  339. * Description: Callback routine from Winsock2 Handles any statistical
  340. * processing required for RTCP. Copies completion routine
  341. * from app and substitutes its own. Apps completion routine
  342. * will be called after RTP's completion routine gets called.
  343. *
  344. * Input : dwError: I/O completion error code
  345. * cbTransferred: Number of bytes transferred
  346. * pOverlapped: -> to overlapped I/O structure
  347. * dwFlags: Flags
  348. *
  349. * !!! IMPORTANT NOTE !!!
  350. * Currently assumes CSRC = 0
  351. * !!! IMPORTANT NOTE !!!
  352. *
  353. * Return: None
  354. ---------------------------------------------------------------------------*/
  355. void CALLBACK RTPReceiveCallback (DWORD dwError,
  356. DWORD cbTransferred,
  357. LPWSAOVERLAPPED pOverlapped,
  358. DWORD dwFlags)
  359. {
  360. PRTP_SESSION pRTPSession;
  361. RTP_HDR_T *pRTPHeader;
  362. PRTP_BFR_LIST pRCVStruct;
  363. PSSRC_ENTRY pSSRC = NULL;
  364. DWORD dwSSRC;
  365. DWORD oldSSRC;
  366. PSSRC_ENTRY pMySSRC;
  367. DWORD dwRequeue = 0;
  368. struct sockaddr_in *pSSRCadr;
  369. IN_OUT_STR ("RTP : Enter RTPReceiveCallback()\n");
  370. // GEORGEJ: catch Winsock 2 bug (94903) where I get a bogus callback
  371. // after WSARecv returns WSAEMSGSIZE.
  372. if (!dwError && ((int) cbTransferred < 0)) {
  373. RRCM_DBG_MSG ("RTP : RCV Callback : bad cbTransferred", cbTransferred,
  374. __FILE__, __LINE__, DBG_ERROR);
  375. return;
  376. }
  377. // The returning hEvent in the LPWSAOVERLAPPED struct contains the
  378. // information mapping the session and the buffer.
  379. pRCVStruct = (PRTP_BFR_LIST)pOverlapped->hEvent;
  380. // Search for the proper session based on incoming socket
  381. pRTPSession = (PRTP_SESSION)pRCVStruct->pSession;
  382. ASSERT (pRTPSession);
  383. // If Winsock error or runt packet(used to cancel recvs), signal completion to application
  384. // and do not repost.
  385. if (dwError || cbTransferred < RTP_HDR_MIN_LEN)
  386. {
  387. // don't report closeSocket() as an error when the application
  388. // have some pending buffers remaining
  389. if ((dwError != 65534) && (dwError == WSA_OPERATION_ABORTED))
  390. {
  391. RRCM_DBG_MSG ("RTP : RCV Callback", dwError,
  392. __FILE__, __LINE__, DBG_ERROR);
  393. }
  394. // notify the user if an error occured, so he can free up
  395. // its receive resources. The byte count is set to 0
  396. // Reinstate the AppSs WSAEVENT
  397. pOverlapped->hEvent = pRCVStruct->hEvent;
  398. // And call the apps completion routine
  399. pRCVStruct->pfnCompletionNotification (dwError,
  400. cbTransferred,
  401. pOverlapped,
  402. dwFlags);
  403. // Return the struct to the free queue
  404. addToHeadOfList (&pRTPSession->pRTPFreeList,
  405. (PLINK_LIST)pRCVStruct,
  406. &pRTPSession->critSect);
  407. IN_OUT_STR ("RTP : Exit RTPReceiveCallback()\n");
  408. return;
  409. }
  410. // Perform validity checking
  411. pRTPHeader = (RTP_HDR_T *)pRCVStruct->pBuffer->buf;
  412. ASSERT (pRTPHeader);
  413. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  414. if (RTPLogger)
  415. {
  416. //INTEROP
  417. InteropOutput (RTPLogger,
  418. (BYTE FAR*)(pRCVStruct->pBuffer->buf),
  419. (int)cbTransferred,
  420. RTPLOG_RECEIVED_PDU | RTP_PDU);
  421. }
  422. #endif
  423. // Check RTP Headers for validity. If not valid, then repost buffers
  424. // to the network layer for a new receive.
  425. if (validateRTPHeader (pRTPHeader) && (dwError == 0))
  426. {
  427. // Get pointer to SSRC entry table for this session
  428. // If SSRC in packet is > 1/2 MAX_RANGE of DWORD, start search from
  429. // tail of SSRC list, otherwise, start from front
  430. RRCMws.ntohl (pRCVStruct->RTPsocket, pRTPHeader->ssrc, &dwSSRC);
  431. if (dwSSRC > MAX_DWORD/2)
  432. {
  433. pSSRC = searchforSSRCatTail (
  434. (PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.prev,
  435. dwSSRC);
  436. }
  437. else
  438. {
  439. pSSRC = searchforSSRCatHead (
  440. (PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.next,
  441. dwSSRC);
  442. }
  443. // get my own SSRC used for this stream
  444. pMySSRC = searchForMySSRC (
  445. (PSSRC_ENTRY)pRTPSession->pRTCPSession->XmtSSRCList.prev,
  446. pRCVStruct->RTPsocket);
  447. ASSERT (pMySSRC);
  448. // is this SSRC already known on the receive list ?
  449. if (pSSRC == NULL)
  450. {
  451. // don't create an entry for my own packet looping back on
  452. // a mcast group where loopback has not been turned off
  453. if (pMySSRC->SSRC != dwSSRC)
  454. {
  455. // new party heard from. Create an entry for it
  456. pSSRC = createSSRCEntry (dwSSRC,
  457. pRTPSession->pRTCPSession,
  458. (PSOCKADDR)pRCVStruct->pFrom,
  459. (DWORD)*pRCVStruct->pFromlen,
  460. FALSE);
  461. // notify application if interested
  462. RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, dwSSRC,
  463. pRTPHeader->pt);
  464. }
  465. else
  466. {
  467. // my own SSRC received back
  468. // A collision occurs if the SSRC in the rcvd packet is
  469. // equal to mine, and the network transport address is
  470. // different from mine.
  471. // A loop occurs if after a collision has been resolved the
  472. // SSRC collides again from the same source transport address
  473. pSSRCadr = (PSOCKADDR_IN)&pMySSRC->from;
  474. if (((PSOCKADDR_IN)pRCVStruct->pFrom)->sin_addr.S_un.S_addr !=
  475. pSSRCadr->sin_addr.S_un.S_addr)
  476. {
  477. // check if the source address is already in the
  478. // conflicting table. This identifes that somebody out
  479. // there is looping pckts back to me
  480. if (RRCMChkCollisionTable ((PSOCKADDR)pRCVStruct->pFrom,*pRCVStruct->pFromlen, pMySSRC))
  481. {
  482. RRCM_DBG_MSG ("RTP : Loop Detected ...", 0, NULL, 0,
  483. DBG_NOTIFY);
  484. // loop already known
  485. dwRequeue |= SSRC_LOOP_DETECTED;
  486. }
  487. else
  488. {
  489. RRCM_DBG_MSG ("RTP : Collision Detected ...", 0, NULL, 0,
  490. DBG_NOTIFY);
  491. // create new entry in conflicting address table
  492. RRCMAddEntryToCollisionTable ((PSOCKADDR)pRCVStruct->pFrom,*pRCVStruct->pFromlen, pMySSRC);
  493. // send RTCP BYE packet w/ old SSRC
  494. RTCPsendBYE (pMySSRC, "Loop/collision detected");
  495. // select new SSRC
  496. oldSSRC = pMySSRC->SSRC;
  497. dwSSRC = getSSRC (pMySSRC->pRTCPses->RcvSSRCList,
  498. pMySSRC->pRTCPses->XmtSSRCList);
  499. EnterCriticalSection (&pMySSRC->critSect);
  500. pMySSRC->SSRC = dwSSRC;
  501. LeaveCriticalSection (&pMySSRC->critSect);
  502. // create new entry w/ old SSRC plus actual source
  503. // transport address in our receive list side, so the
  504. // packet actually en-route will be dealt with
  505. createSSRCEntry (oldSSRC,
  506. pRTPSession->pRTCPSession,
  507. (PSOCKADDR)pRCVStruct->pFrom,
  508. (DWORD)*pRCVStruct->pFromlen,
  509. FALSE);
  510. // notify application if interested
  511. RRCMnotification (RRCM_LOCAL_COLLISION_EVENT,
  512. pMySSRC, oldSSRC, 0);
  513. // loop already known
  514. dwRequeue |= SSRC_COLLISION_DETECTED;
  515. }
  516. }
  517. else
  518. {
  519. // own packet looped back because the sender joined the
  520. // multicast group and loopback is not turned off
  521. dwRequeue |= MCAST_LOOPBACK_NOT_OFF;
  522. }
  523. }
  524. }
  525. else if (pSSRC->dwSSRCStatus & THIRD_PARTY_COLLISION)
  526. {
  527. // this SSRC is marked as colliding. Reject the data
  528. dwRequeue = THIRD_PARTY_COLLISION;
  529. }
  530. if ((pSSRC != NULL) && (dwRequeue == 0))
  531. {
  532. // do all the statistical updating stuff
  533. updateRTPStats (pRTPHeader, pSSRC, cbTransferred);
  534. // update the payload type for this SSRC
  535. pSSRC->PayLoadType = pRTPHeader->pt;
  536. // Reinstate the AppSs WSAEVENT
  537. pOverlapped->hEvent = pRCVStruct->hEvent;
  538. // And call the apps completion routine
  539. pRCVStruct->pfnCompletionNotification (dwError,
  540. cbTransferred,
  541. pOverlapped,
  542. dwFlags);
  543. // Return the struct to the free queue
  544. addToHeadOfList (&pRTPSession->pRTPFreeList,
  545. (PLINK_LIST)pRCVStruct,
  546. &pRTPSession->critSect);
  547. } // SSRCList != NULL
  548. } // valid RTP Header
  549. else
  550. {
  551. dwRequeue |= INVALID_RTP_HEADER;
  552. }
  553. if (dwRequeue)
  554. {
  555. // The RTP packet was invalid for some reason
  556. RTPpostRecvBfr (dwError, cbTransferred, pOverlapped, dwFlags);
  557. }
  558. IN_OUT_STR ("RTP : Exit RTPReceiveCallback()\n");
  559. }
  560. /*----------------------------------------------------------------------------
  561. * Function : saveRCVWinsockContext
  562. * Description: Saves context for this buffer so that when a completion
  563. * routine returns with a handle, we know exactly what
  564. * buffer/stream this refers to.
  565. *
  566. * Input : pOverlapped : -> to overlapped structure
  567. * pBuffers : -> to WSA buffers
  568. * pFunc : -> to completion routine
  569. * pSession : -> to the RTP session
  570. * dwBufferCount : Number of WSA buffers
  571. * pNumBytesRecvd : -> to number of bytes received
  572. * pFlags : -> to flags
  573. * pFrom : -> to the From address field
  574. * pFromlen : -> to the from address field length
  575. * RTPsocket : RTP socket descriptor
  576. *
  577. * Return: RRCM_NoError = OK.
  578. * Otherwise(!=0) = Check RRCM.h file for references.
  579. ---------------------------------------------------------------------------*/
  580. DWORD CALLBACK saveRCVWinsockContext(LPWSAOVERLAPPED pOverlapped,
  581. LPWSABUF pBuffers,
  582. LPWSAOVERLAPPED_COMPLETION_ROUTINE pFunc,
  583. PRTP_SESSION pSession,
  584. DWORD dwBufferCount,
  585. LPDWORD pNumBytesRecvd,
  586. LPDWORD pFlags,
  587. LPVOID pFrom,
  588. LPINT pFromlen,
  589. SOCKET RTPsocket)
  590. {
  591. PRTP_BFR_LIST pNewCell;
  592. DWORD dwStatus = RRCM_NoError;
  593. DWORD numCells = NUM_FREE_CONTEXT_CELLS;
  594. IN_OUT_STR ("RTP : Enter saveRCVWinsockContext()\n");
  595. // Get a PRTP Buffer from the free list
  596. pNewCell = (PRTP_BFR_LIST)removePcktFromTail (
  597. (PLINK_LIST)&pSession->pRTPFreeList,
  598. &pSession->critSect);
  599. if (pNewCell == NULL)
  600. {
  601. // try to reallocate some free cells
  602. if (pSession->dwNumTimesFreeListAllocated <= MAXNUM_CONTEXT_CELLS_REALLOC)
  603. {
  604. // increment the number of reallocated times even if the realloc
  605. // fails next. Will avoid trying to realloc of a realloc problem
  606. pSession->dwNumTimesFreeListAllocated++;
  607. if (allocateLinkedList (&pSession->pRTPFreeList,
  608. pSession->hHeapFreeList,
  609. &numCells,
  610. sizeof(RTP_BFR_LIST),
  611. &pSession->critSect) == RRCM_NoError)
  612. {
  613. pNewCell = (PRTP_BFR_LIST)removePcktFromTail (
  614. (PLINK_LIST)&pSession->pRTPFreeList,
  615. &pSession->critSect);
  616. }
  617. }
  618. }
  619. if (pNewCell != NULL)
  620. {
  621. // Initialize the params
  622. pNewCell->hEvent = pOverlapped->hEvent;
  623. pNewCell->pBuffer = pBuffers;
  624. pNewCell->pSession = pSession;
  625. pNewCell->dwFlags = *pFlags;
  626. pNewCell->pFrom = pFrom;
  627. pNewCell->pFromlen = pFromlen;
  628. pNewCell->RTPsocket = RTPsocket;
  629. pNewCell->dwBufferCount = dwBufferCount;
  630. pNewCell->pfnCompletionNotification = pFunc;
  631. // Overwrite the hEvent handed down from app.
  632. // Will return the real one when the completion routine is called
  633. pOverlapped->hEvent = (WSAEVENT)pNewCell;
  634. }
  635. else
  636. dwStatus = RRCMError_RTPResources;
  637. IN_OUT_STR ("RTP : Exit saveRCVWinsockContext()\n");
  638. return (dwStatus);
  639. }
  640. /*----------------------------------------------------------------------------
  641. * Function : RTPpostRecvBfr
  642. * Description: RTP post a receive buffer to Winsock
  643. *
  644. * Input : dwError : Error code
  645. * cbTransferred : Bytes transferred
  646. * pOverlapped : -> to overlapped structure
  647. * dwFlags : Flags
  648. *
  649. * Return: None
  650. ---------------------------------------------------------------------------*/
  651. void RTPpostRecvBfr (DWORD dwError,
  652. DWORD cbTransferred,
  653. LPWSAOVERLAPPED pOverlapped,
  654. DWORD dwFlags)
  655. {
  656. DWORD dwStatus;
  657. PRTP_BFR_LIST pRCVStruct;
  658. PRTP_SESSION pRTPSession;
  659. IN_OUT_STR ("RTP : Enter RTPpostRecvBfr\n");
  660. // Reuse the packet with another receive
  661. pRCVStruct = (PRTP_BFR_LIST)pOverlapped->hEvent;
  662. // Corresponding RTP session
  663. pRTPSession = (PRTP_SESSION)pRCVStruct->pSession;
  664. dwStatus = RRCMws.recvFrom (pRCVStruct->RTPsocket,
  665. pRCVStruct->pBuffer,
  666. pRCVStruct->dwBufferCount,
  667. &cbTransferred,
  668. &pRCVStruct->dwFlags,
  669. (PSOCKADDR)pRCVStruct->pFrom,
  670. pRCVStruct->pFromlen,
  671. pOverlapped,
  672. RTPReceiveCallback);
  673. // Check if Winsock Call succeeded
  674. if (dwStatus == SOCKET_ERROR)
  675. {
  676. // If serious error, the receive request won't proceed
  677. dwStatus = GetLastError();
  678. if ((dwStatus != WSA_IO_PENDING) && (dwStatus != WSAEMSGSIZE))
  679. {
  680. RRCM_DBG_MSG ("RTP : ERROR - WSARecvFrom()", dwError,
  681. __FILE__, __LINE__, DBG_ERROR);
  682. // notify the user if an error occured, so he can free up
  683. // its receive resources. The byte count is set to 0
  684. // Reinstate the AppSs WSAEVENT
  685. pOverlapped->hEvent = pRCVStruct->hEvent;
  686. // And call the apps completion routine
  687. pRCVStruct->pfnCompletionNotification (dwStatus,
  688. 0,
  689. pOverlapped,
  690. dwFlags);
  691. // Return the receive structure to the free list
  692. addToHeadOfList (&pRTPSession->pRTPFreeList,
  693. (PLINK_LIST)pRCVStruct,
  694. &pRTPSession->critSect);
  695. }
  696. }
  697. IN_OUT_STR ("RTP : Exit RTPpostRecvBfr\n");
  698. }
  699. #endif
  700. // [EOF]