Source code of Windows XP (NT5)
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.

353 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 1998 - 2000 Microsoft Corporation
  3. Module Name:
  4. emrecv.cpp
  5. Abstract:
  6. Contains all the event manager routines which
  7. manage the overlapped recv operations
  8. Revision History:
  9. 1. created
  10. Ajay Chitturi (ajaych) 12-Jun-1998
  11. --*/
  12. #include "stdafx.h"
  13. #include "cbridge.h"
  14. #include "ovioctx.h"
  15. static
  16. PSendRecvContext
  17. EventMgrCreateRecvContext(
  18. IN SOCKET sock,
  19. IN OVERLAPPED_PROCESSOR & rOvProcessor
  20. )
  21. {
  22. PSendRecvContext pRecvContext;
  23. // IO Context part - make this a separate inline function
  24. pRecvContext = (PSendRecvContext) HeapAlloc (GetProcessHeap (),
  25. 0, // No Flags
  26. sizeof(SendRecvContext));
  27. if (!pRecvContext)
  28. return NULL;
  29. memset(pRecvContext, 0, sizeof(SendRecvContext));
  30. pRecvContext->ioCtxt.reqType = EMGR_OV_IO_REQ_RECV;
  31. pRecvContext->ioCtxt.pOvProcessor = &rOvProcessor;
  32. // Recv Context part
  33. pRecvContext->sock = sock;
  34. pRecvContext->dwTpktHdrBytesDone = 0;
  35. pRecvContext->dwDataLen = 0;
  36. pRecvContext->pbData = NULL;
  37. pRecvContext->dwDataBytesDone = 0;
  38. return pRecvContext;
  39. }
  40. // If you do not want to free the event manager context
  41. // set it to NULL before calling this function.
  42. void
  43. EventMgrFreeRecvContext (
  44. PSendRecvContext pRecvCtxt
  45. )
  46. {
  47. // Socket and OvProcessor are owned by the
  48. // Call Bridge Machine
  49. if (pRecvCtxt->pbData != NULL)
  50. { EM_FREE(pRecvCtxt->pbData);
  51. }
  52. HeapFree (GetProcessHeap (),
  53. 0, // no flags
  54. pRecvCtxt);
  55. }
  56. /*
  57. * Call ReadFile to start an overlapped request
  58. * on a socket. Make sure we handle errors
  59. * that are recoverable.
  60. *
  61. * pRecvCtxt is not freed in case of an error
  62. */
  63. static
  64. HRESULT
  65. EventMgrIssueRecvHelperFn(
  66. PSendRecvContext pRecvCtxt
  67. )
  68. {
  69. int i = 0;
  70. BOOL bResult;
  71. int err;
  72. DWORD dwNumRead, dwToRead;
  73. PBYTE pbReadBuf;
  74. _ASSERTE(pRecvCtxt);
  75. if (pRecvCtxt ->ioCtxt.pOvProcessor->IsSocketValid())
  76. {
  77. if (pRecvCtxt->dwTpktHdrBytesDone < TPKT_HEADER_SIZE)
  78. {
  79. dwToRead = TPKT_HEADER_SIZE - pRecvCtxt->dwTpktHdrBytesDone;
  80. pbReadBuf = pRecvCtxt->pbTpktHdr + pRecvCtxt->dwTpktHdrBytesDone;
  81. }
  82. else
  83. {
  84. dwToRead = pRecvCtxt->dwDataLen - pRecvCtxt->dwDataBytesDone;
  85. pbReadBuf = pRecvCtxt->pbData + pRecvCtxt->dwDataBytesDone;
  86. }
  87. // Kick off the first read
  88. while (++i)
  89. {
  90. memset(&pRecvCtxt->ioCtxt.ov, 0, sizeof(OVERLAPPED));
  91. // make an overlapped IO Request
  92. // XXX The socket may not be valid at this point
  93. pRecvCtxt->ioCtxt.pOvProcessor->GetCallBridge().AddRef();
  94. bResult = ReadFile((HANDLE)pRecvCtxt->sock,
  95. pbReadBuf,
  96. dwToRead,
  97. &dwNumRead,
  98. &pRecvCtxt->ioCtxt.ov
  99. );
  100. // It succeeded immediately, but do not process it
  101. // here, wait for the completion packet.
  102. if (bResult)
  103. return S_OK;
  104. err = GetLastError();
  105. // This is what we want to happen, its not an error
  106. if (err == ERROR_IO_PENDING)
  107. return S_OK;
  108. pRecvCtxt->ioCtxt.pOvProcessor->GetCallBridge().Release ();
  109. // Handle recoverable error
  110. if ( err == ERROR_INVALID_USER_BUFFER ||
  111. err == ERROR_NOT_ENOUGH_QUOTA ||
  112. err == ERROR_NOT_ENOUGH_MEMORY )
  113. {
  114. if (i <= 5) // I just picked a number
  115. {
  116. Sleep(50); // Wait around and try later
  117. continue;
  118. }
  119. DebugF (_T("H323: System ran out of non-paged space.\n"));
  120. }
  121. // This means this is an unrecoverable error
  122. // one possibility is that that Call bridge could have closed
  123. // the socket some time in between
  124. break;
  125. }//while(++i)
  126. DebugF (_T("H323: ReadFile failed error: %d.\n"), err);
  127. return E_FAIL;
  128. } else {
  129. DebugF (_T("H323: 0x%x overlapped processor %x had invalid socket.\n"),
  130. &pRecvCtxt ->ioCtxt.pOvProcessor -> GetCallBridge (),
  131. pRecvCtxt ->ioCtxt.pOvProcessor);
  132. return E_ABORT;
  133. }
  134. return S_OK;
  135. } //EventMgrIssueRecv()
  136. /*
  137. * The Call Bridge Machine calls this function to issue asynchronous
  138. * receive requests
  139. *
  140. */
  141. HRESULT
  142. EventMgrIssueRecv(
  143. IN SOCKET sock,
  144. IN OVERLAPPED_PROCESSOR & rOvProcessor
  145. )
  146. {
  147. PSendRecvContext pRecvCtxt =
  148. EventMgrCreateRecvContext(sock, rOvProcessor);
  149. if (!pRecvCtxt)
  150. {
  151. return E_OUTOFMEMORY;
  152. }
  153. HRESULT hRes = EventMgrIssueRecvHelperFn(pRecvCtxt);
  154. if (FAILED(hRes))
  155. {
  156. EventMgrFreeRecvContext(pRecvCtxt);
  157. }
  158. return hRes;
  159. }
  160. /*
  161. * Make the error callback.
  162. *
  163. * Since this is called only in case of an error this need not be an
  164. * inline function
  165. *
  166. */
  167. void
  168. MakeErrorRecvCallback(
  169. HRESULT hRes,
  170. PSendRecvContext pRecvCtxt
  171. )
  172. {
  173. DebugF (_T("Q931: 0x%x error 0x%x on receive callback.\n"),
  174. &pRecvCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
  175. hRes);
  176. pRecvCtxt->ioCtxt.pOvProcessor->ReceiveCallback(hRes, NULL, NULL);
  177. }
  178. // This function passes the decoded PDUs to the Call bridge Machine.
  179. // This function frees the PDUs after the callback function returns.
  180. // The PDUs are allocated by the ASN1 library and the corresponding
  181. // functions need to be used to free the PDUs.
  182. /*
  183. * This function is called by the event loop when a recv I/O completes.
  184. * The Call Bridge Machine's recv call back function is called.
  185. *
  186. * This function does not return any error code. In case of an error,
  187. * the call bridge machine is notified about the error in the callback.
  188. *
  189. * This function always frees pRecvCtxt if another Recv is not issued
  190. */
  191. void
  192. HandleRecvCompletion(
  193. PSendRecvContext pRecvCtxt,
  194. DWORD dwNumRead,
  195. DWORD status
  196. )
  197. {
  198. HRESULT hRes;
  199. if (status != NO_ERROR || dwNumRead == 0)
  200. {
  201. // This means an error occured in the read operation
  202. // We need to call the callback with the error status
  203. if (status == NO_ERROR && dwNumRead == 0)
  204. {
  205. DebugF (_T("H323: 0x%x transport connection was closed by peer.\n"),
  206. &pRecvCtxt -> ioCtxt.pOvProcessor -> GetCallBridge ());
  207. hRes = HRESULT_FROM_WIN32 (WSAECONNRESET);
  208. }
  209. else
  210. {
  211. hRes = HRESULT_FROM_WIN32_ERROR_CODE(status);
  212. }
  213. // make callback
  214. MakeErrorRecvCallback(hRes, pRecvCtxt);
  215. EventMgrFreeRecvContext(pRecvCtxt);
  216. return;
  217. }
  218. if (pRecvCtxt->dwTpktHdrBytesDone < TPKT_HEADER_SIZE)
  219. {
  220. // This means we are still reading the TPKT header
  221. pRecvCtxt->dwTpktHdrBytesDone += dwNumRead;
  222. }
  223. else
  224. {
  225. // This means we are reading the data
  226. pRecvCtxt->dwDataBytesDone += dwNumRead;
  227. }
  228. // If the TPKT header has been read completely we need to
  229. // extract the packet size, set it appropriately
  230. // and allocate the data buffer
  231. if (pRecvCtxt->dwDataLen == 0 &&
  232. pRecvCtxt->dwTpktHdrBytesDone == TPKT_HEADER_SIZE)
  233. {
  234. hRes = S_OK;
  235. pRecvCtxt->dwDataLen = GetPktLenFromTPKTHdr(pRecvCtxt->pbTpktHdr);
  236. // The length of the PDU fits in 2 bytes
  237. _ASSERTE(pRecvCtxt->dwDataLen < (1L << 16));
  238. pRecvCtxt->pbData = (PBYTE) EM_MALLOC(pRecvCtxt->dwDataLen);
  239. if (!pRecvCtxt->pbData)
  240. {
  241. DebugF (_T ("H323: 0x%x HandleRecvCompletion(): Could not allocate pbData.\n"),
  242. &pRecvCtxt -> ioCtxt.pOvProcessor -> GetCallBridge ());
  243. MakeErrorRecvCallback(E_OUTOFMEMORY, pRecvCtxt);
  244. EventMgrFreeRecvContext(pRecvCtxt);
  245. return;
  246. }
  247. memset(pRecvCtxt->pbData, 0, pRecvCtxt->dwDataLen);
  248. hRes = EventMgrIssueRecvHelperFn(pRecvCtxt);
  249. if (hRes != S_OK)
  250. {
  251. MakeErrorRecvCallback(hRes, pRecvCtxt);
  252. EventMgrFreeRecvContext(pRecvCtxt);
  253. return;
  254. }
  255. else
  256. {
  257. // Succeeded in making an overlapped recv request
  258. return;
  259. }
  260. }
  261. if (pRecvCtxt->dwTpktHdrBytesDone < TPKT_HEADER_SIZE ||
  262. pRecvCtxt->dwDataBytesDone < pRecvCtxt->dwDataLen)
  263. {
  264. hRes = S_OK;
  265. hRes = EventMgrIssueRecvHelperFn(pRecvCtxt);
  266. if (hRes != S_OK)
  267. {
  268. MakeErrorRecvCallback(hRes, pRecvCtxt);
  269. EventMgrFreeRecvContext(pRecvCtxt);
  270. return;
  271. }
  272. else
  273. {
  274. // Succeeded in making an overlapped recv request
  275. return;
  276. }
  277. }
  278. // Received a complete PDU
  279. // need to decode the packet and call the appropriate callback
  280. // and free pRecvCtxt
  281. pRecvCtxt->ioCtxt.pOvProcessor->ReceiveCallback(S_OK,
  282. pRecvCtxt->pbData,
  283. pRecvCtxt->dwDataLen);
  284. // It is the responsibility of the callback function to free the buffer.
  285. pRecvCtxt->pbData = NULL;
  286. pRecvCtxt->dwDataLen = 0;
  287. // Clean up Recv context structure
  288. EventMgrFreeRecvContext(pRecvCtxt);
  289. }