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.

457 lines
15 KiB

  1. /***************************************************************************
  2. *
  3. * File: h245wsrx.c
  4. *
  5. * INTEL Corporation Proprietary Information
  6. * Copyright (c) 1996 Intel Corporation.
  7. *
  8. * This listing is supplied under the terms of a license agreement
  9. * with INTEL Corporation and may not be used, copied, nor disclosed
  10. * except in accordance with the terms of that agreement.
  11. *
  12. ***************************************************************************
  13. *
  14. * $Workfile: h245wsrx.cpp $
  15. * $Revision: 2.4 $
  16. * $Modtime: 30 Jan 1997 17:15:58 $
  17. * $Log: S:/STURGEON/SRC/H245WS/VCS/h245wsrx.cpv $
  18. *
  19. * Rev 2.4 30 Jan 1997 17:17:16 EHOWARDX
  20. * Fixed bug in trace message - need to do trace before
  21. * calling shutdown() sent shutdown clears error retrieved
  22. * by WSAGetLastError().
  23. *
  24. * Rev 2.3 14 Jan 1997 15:48:04 EHOWARDX
  25. * Changed TryRecv() and TrySend() to check for WSAECONNRESET and
  26. * WSAECONNABORT return from recv() and send() and act accordingly.
  27. *
  28. * Rev 2.2 19 Dec 1996 18:54:54 SBELL1
  29. * took out tag comments
  30. *
  31. * Rev 2.1 Dec 13 1996 17:31:00 plantz
  32. * moved #ifdef _cplusplus to after include files
  33. //
  34. // Rev 1.1 13 Dec 1996 12:11:34 SBELL1
  35. // moved #ifdef _cplusplus to after include files
  36. //
  37. // Rev 1.0 11 Dec 1996 13:41:52 SBELL1
  38. // Initial revision.
  39. *
  40. * Rev 1.19 08 Jul 1996 19:27:44 unknown
  41. * Second experiment to try to fix Q.931 shutdown problem.
  42. *
  43. * Rev 1.18 01 Jul 1996 16:45:12 EHOWARDX
  44. *
  45. * Moved Call to SocketCloseEvent from TryRecv() to ProcessQueuedRecvs().
  46. * TryRecv() now returns LINK_RECV_CLOSED to trigger ProcessQueuedRecvs()
  47. * to call SocketCloseEvent().
  48. *
  49. * Rev 1.17 May 28 1996 18:14:36 plantz
  50. * Change error codes to use HRESULT. Propogate Winsock errors where appropriate
  51. *
  52. * Rev 1.16 17 May 1996 16:49:32 EHOWARDX
  53. * Shutdown fix.
  54. *
  55. * Rev 1.15 09 May 1996 18:33:16 EHOWARDX
  56. *
  57. * Changes to build with new LINKAPI.H.
  58. *
  59. * Rev 1.14 29 Apr 1996 16:53:16 EHOWARDX
  60. *
  61. * Added trace statement.
  62. *
  63. * Rev 1.13 Apr 29 1996 14:04:20 plantz
  64. * Call NotifyRead instead of ProcessQueuedRecvs.
  65. *
  66. * Rev 1.12 Apr 29 1996 12:14:06 plantz
  67. * Change tpkt header to include header size in packet length.
  68. * Assert that message length does not exceed INT_MAX.
  69. * .
  70. *
  71. * Rev 1.11 27 Apr 1996 14:07:32 EHOWARDX
  72. * Parenthesized return from TryRecv().
  73. *
  74. * Rev 1.10 Apr 25 1996 21:15:12 plantz
  75. * Check state of connection before attemting to call recv.
  76. *
  77. * Rev 1.9 Apr 24 1996 16:39:34 plantz
  78. * Merge 1.5.1.0 with 1.8 (changes for winsock 1)
  79. *
  80. * Rev 1.5.1.0 Apr 24 1996 16:23:00 plantz
  81. * Change to not use overlapped I/O (for winsock 1).
  82. *
  83. * Rev 1.5 01 Apr 1996 14:20:12 unknown
  84. * Shutdown redesign.
  85. *
  86. * Rev 1.4 19 Mar 1996 20:18:16 EHOWARDX
  87. *
  88. * Redesigned shutdown.
  89. *
  90. * Rev 1.3 18 Mar 1996 19:08:32 EHOWARDX
  91. * Fixed shutdown; eliminated TPKT/WSCB dependencies.
  92. * Define TPKT to put TPKT/WSCB dependencies back in.
  93. *
  94. * Rev 1.2 14 Mar 1996 17:01:58 EHOWARDX
  95. *
  96. * NT4.0 testing; got rid of HwsAssert(); got rid of TPKT/WSCB.
  97. *
  98. * Rev 1.1 09 Mar 1996 21:12:02 EHOWARDX
  99. * Fixes as result of testing.
  100. *
  101. * Rev 1.0 08 Mar 1996 20:20:18 unknown
  102. * Initial revision.
  103. *
  104. ***************************************************************************/
  105. #define LINKDLL_EXPORT
  106. #pragma warning ( disable : 4115 4201 4214 4514 )
  107. #undef _WIN32_WINNT // override bogus platform definition in our common build environment
  108. #include "precomp.h"
  109. #include <limits.h>
  110. //#include <winsock.h>
  111. #include "queue.h"
  112. #include "linkapi.h"
  113. #include "h245ws.h"
  114. #include "tstable.h"
  115. #if defined(__cplusplus)
  116. extern "C"
  117. {
  118. #endif // (__cplusplus)
  119. // If we are not using the Unicode version of the ISR display utility, then redefine
  120. // the __TEXT macro to do nothing.
  121. #ifndef UNICODE_TRACE
  122. #undef __TEXT
  123. #define __TEXT(x) x
  124. #endif
  125. extern TSTable<HWSINST>* gpInstanceTable; // global ptr to the instance table
  126. #define GetTpktLength(pReq) (((pReq)->req_TpktHeader[2] << 8) + (pReq)->req_TpktHeader[3])
  127. /*++
  128. Description:
  129. Start a receive
  130. Arguments:
  131. pHws - Pointer to context for "connection"
  132. pReq - Pointer to I/O request structure
  133. Return Value:
  134. SUCCESS - Successfully started receive.
  135. LINK_RECV_ERROR_WOULD_BLOCK -
  136. Winsock error
  137. --*/
  138. static HRESULT
  139. TryRecv(IN PHWSINST pHws, IN char *data, IN int length, IN OUT int *total_bytes_done)
  140. {
  141. int requested_length = length - *total_bytes_done;
  142. int recv_result = recv(pHws->hws_Socket, data+*total_bytes_done, requested_length, 0);
  143. if (recv_result == SOCKET_ERROR)
  144. {
  145. int err = WSAGetLastError();
  146. switch (err)
  147. {
  148. case WSAEWOULDBLOCK:
  149. return LINK_RECV_WOULD_BLOCK;
  150. case WSAECONNABORTED:
  151. case WSAECONNRESET:
  152. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
  153. __TEXT("TryRecv: recv() returned %s"),
  154. SocketErrorText());
  155. if (pHws->hws_uState == HWS_CONNECTED)
  156. {
  157. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE,
  158. __TEXT("TryRecv: calling shutdown"));
  159. if (shutdown(pHws->hws_Socket, 1) == SOCKET_ERROR)
  160. {
  161. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
  162. __TEXT("TryRecv: shutdown() returned %s"),
  163. SocketErrorText());
  164. }
  165. pHws->hws_uState = HWS_CLOSING;
  166. }
  167. return MAKE_WINSOCK_ERROR(err);
  168. default:
  169. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
  170. __TEXT("TryRecv: recv() returned %s"),
  171. SocketErrorText());
  172. return MAKE_WINSOCK_ERROR(err);
  173. } // switch
  174. }
  175. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("TryRecv: recv returned %d"), recv_result);
  176. if (recv_result == 0)
  177. {
  178. return LINK_RECV_CLOSED;
  179. }
  180. *total_bytes_done += recv_result;
  181. return (recv_result == requested_length) ? NOERROR : LINK_RECV_WOULD_BLOCK;
  182. }
  183. static HRESULT
  184. RecvStart(IN PHWSINST pHws, IN PREQUEST pReq)
  185. {
  186. HRESULT nResult = NOERROR;
  187. // Sanity checks
  188. HWSASSERT(pHws != NULL);
  189. HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
  190. HWSASSERT(pReq != NULL);
  191. HWSASSERT(pReq->req_dwMagic == RECV_REQUEST_MAGIC);
  192. HWSASSERT(pReq->req_pHws == pHws);
  193. // Get the header first; if that succeeds get the client data
  194. if (pReq->req_header_bytes_done < TPKT_HEADER_SIZE)
  195. {
  196. nResult = TryRecv(pHws,
  197. (char *)pReq->req_TpktHeader,
  198. TPKT_HEADER_SIZE,
  199. &pReq->req_header_bytes_done);
  200. }
  201. if (nResult == NOERROR)
  202. {
  203. long int tpkt_length = GetTpktLength(pReq) - TPKT_HEADER_SIZE;
  204. if (pReq->req_TpktHeader[0] != TPKT_VERSION || tpkt_length <= 0)
  205. {
  206. // Invalid header version
  207. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  208. __TEXT("RecvComplete: bad header version; available data discarded"));
  209. // Should this be reported to the client??
  210. // Read and discard all available data
  211. // The client's buffer is used as a temporary buffer.
  212. while (recv(pHws->hws_Socket, (char *)pReq->req_client_data, pReq->req_client_length, 0) > 0)
  213. ;
  214. // Mark the header for this request as unread; it
  215. // will be read again when additional data is received.
  216. pReq->req_header_bytes_done = 0;
  217. nResult = LINK_RECV_ERROR;
  218. }
  219. else if (tpkt_length > pReq->req_client_length)
  220. {
  221. // Packet too large
  222. int request_length;
  223. int result;
  224. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  225. __TEXT("RecvComplete: packet too large; packet discarded"));
  226. // Should this be reported to the client??
  227. // Read and discard the packet
  228. // The client's buffer is used as a temporary buffer.
  229. do {
  230. request_length = pReq->req_client_length;
  231. if (request_length > tpkt_length)
  232. request_length = tpkt_length;
  233. result = recv(pHws->hws_Socket, (char *)pReq->req_client_data, request_length, 0);
  234. } while (result > 0 && (tpkt_length -= result) > 0);
  235. if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
  236. {
  237. //TODO: packet too large handling
  238. // Adjust the header so that the rest of this packet will be read, but
  239. // flag it so that it is known to be an error and will not be returned
  240. // to the client.
  241. }
  242. else
  243. {
  244. // Mark the header for this request as unread; it
  245. // will be read again for the next packet received.
  246. pReq->req_header_bytes_done = 0;
  247. }
  248. nResult = LINK_RECV_ERROR;
  249. }
  250. else
  251. {
  252. // Normal case
  253. // The current implementation of TryRecv requires that the requested
  254. // size fit in a signed int (because that is what Winsock supports
  255. // in a single recv). This is guaranteed at this point regardless
  256. // of the originator of the packets, because we don't allow a buffer
  257. // to be posted that is larger than that (see ASSERT below). If the
  258. // packet were larger than the buffer, it would have been caught above.
  259. // If TryRecv is changed to remove the restriction on buffer size and
  260. // accept a parameter of type long int, this ASSERT may be removed.
  261. HWSASSERT(tpkt_length <= INT_MAX);
  262. nResult = TryRecv(pHws,
  263. (char *)pReq->req_client_data,
  264. (int)tpkt_length,
  265. &pReq->req_client_bytes_done);
  266. }
  267. }
  268. return nResult;
  269. } // RecvStart()
  270. void
  271. ProcessQueuedRecvs(IN PHWSINST pHws)
  272. {
  273. register PREQUEST pReq;
  274. register DWORD dwPhysicalId = pHws->hws_dwPhysicalId;
  275. HWSASSERT(pHws != NULL);
  276. HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
  277. HWSASSERT(pHws->hws_uState <= HWS_CLOSING);
  278. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("ProcessQueuedRecvs"));
  279. while ((pReq = (PREQUEST) QRemove(pHws->hws_pRecvQueue)) != NULL)
  280. {
  281. switch (RecvStart(pHws, pReq))
  282. {
  283. case NOERROR:
  284. // Call Recv callback
  285. pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,
  286. LINK_RECV_DATA,
  287. pReq->req_client_data,
  288. pReq->req_client_bytes_done);
  289. // Free the I/O request structure
  290. MemFree(pReq);
  291. // Check to see if callback deallocated our instance or state changed
  292. // Check to see if callback deallocated our instance - this can be done
  293. // by attempting a lock - which will now fail if the entry has been marked
  294. // for deletion. Thus, if the lock succeeds, then just unlock it (since we
  295. // already have a lock on it in a higher level function).
  296. if(gpInstanceTable->Lock(dwPhysicalId) == NULL)
  297. return;
  298. gpInstanceTable->Unlock(dwPhysicalId);
  299. if(pHws->hws_uState > HWS_CONNECTED)
  300. return;
  301. break;
  302. default:
  303. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_WARNING,
  304. __TEXT("ProcessQueuedRecvs: RecvStart() failed"));
  305. // Fall-through to next case is intentional
  306. case LINK_RECV_WOULD_BLOCK:
  307. // The receive would have blocked; we need to requeue the I/O request
  308. // and wait for a FD_READ network event.
  309. // If any part of the data was received, the bytes_done field has been updated.
  310. if (QInsertAtHead(pHws->hws_pRecvQueue, pReq) == FALSE)
  311. {
  312. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  313. __TEXT("ProcessQueuedRecvs: QInsertAtHead() failed"));
  314. }
  315. return;
  316. case LINK_RECV_CLOSED:
  317. if (QInsertAtHead(pHws->hws_pRecvQueue, pReq) == FALSE)
  318. {
  319. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  320. __TEXT("ProcessQueuedRecvs: QInsertAtHead() failed"));
  321. }
  322. SocketCloseEvent(pHws);
  323. return;
  324. } // switch
  325. } // while
  326. } // ProcessQueuedRecvs()
  327. /**************************************************************************
  328. ** Function : datalinkReceiveRequest
  329. ** Description : Fills header/tail of buffer and posts buffer to H.223
  330. ***************************************************************************/
  331. LINKDLL HRESULT datalinkReceiveRequest( DWORD dwPhysicalId,
  332. PBYTE pbyDataBuf,
  333. DWORD dwLength)
  334. {
  335. register PHWSINST pHws;
  336. register PREQUEST pReq;
  337. HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkReceiveRequest"));
  338. pHws = gpInstanceTable->Lock(dwPhysicalId);
  339. if (pHws == NULL)
  340. {
  341. HWSTRACE0(dwPhysicalId, HWS_ERROR,
  342. __TEXT("datalinkReceiveRequest: dwPhysicalId not found"));
  343. return LINK_INVALID_INSTANCE;
  344. }
  345. if (pHws->hws_uState > HWS_CONNECTED)
  346. {
  347. HWSTRACE1(dwPhysicalId, HWS_ERROR,
  348. __TEXT("datalinkReceiveRequest: state = %d"), pHws->hws_uState);
  349. gpInstanceTable->Unlock(dwPhysicalId);
  350. return LINK_INVALID_STATE;
  351. }
  352. // Allocate request structure
  353. pReq = (PREQUEST) MemAlloc(sizeof(*pReq));
  354. if (pReq == NULL)
  355. {
  356. HWSTRACE0(dwPhysicalId, HWS_WARNING,
  357. __TEXT("datalinkReceiveRequest: could not allocate request buffer"));
  358. gpInstanceTable->Unlock(dwPhysicalId);
  359. return LINK_MEM_FAILURE;
  360. }
  361. // The current implementation requires that the size of each message
  362. // fit in a signed int (because that is what Winsock supports in a
  363. // single recv). If it is necessary to receive larger messages,
  364. // TryRecv and RecvStart must be changed to limit the size in each
  365. // recv call, and loop until all the data is received.
  366. // This ASSERT could then be removed.
  367. HWSASSERT(dwLength <= INT_MAX);
  368. pReq->req_pHws = pHws;
  369. pReq->req_header_bytes_done= 0;
  370. pReq->req_client_data = pbyDataBuf;
  371. pReq->req_client_length = (int)dwLength;
  372. pReq->req_client_bytes_done= 0;
  373. pReq->req_dwMagic = RECV_REQUEST_MAGIC;
  374. if (QInsert(pHws->hws_pRecvQueue, pReq) == FALSE)
  375. {
  376. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  377. __TEXT("datalinkReceiveRequest: QInsert() failed"));
  378. gpInstanceTable->Unlock(dwPhysicalId);
  379. return LINK_RECV_NOBUFF;
  380. }
  381. if (pHws->hws_uState == HWS_CONNECTED)
  382. NotifyRead(pHws);
  383. HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkReceiveRequest: succeeded"));
  384. gpInstanceTable->Unlock(dwPhysicalId);
  385. return NOERROR;
  386. } // datalinkReceiveRequest()
  387. #if defined(__cplusplus)
  388. }
  389. #endif // (__cplusplus)