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.

529 lines
17 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. #ifndef STRICT
  106. #define STRICT
  107. #endif // not defined STRICT
  108. #define LINKDLL_EXPORT
  109. #pragma warning ( disable : 4115 4201 4214 4514 )
  110. #undef _WIN32_WINNT // override bogus platform definition in our common build environment
  111. #include <nt.h>
  112. #include <ntrtl.h>
  113. #include <nturtl.h>
  114. #include <limits.h>
  115. //#include <winsock.h>
  116. #include <windows.h>
  117. #include "queue.h"
  118. #include "linkapi.h"
  119. #include "h245ws.h"
  120. #include "tstable.h"
  121. #if defined(__cplusplus)
  122. extern "C"
  123. {
  124. #endif // (__cplusplus)
  125. // If we are not using the Unicode version of the ISR display utility, then redefine
  126. // the __TEXT macro to do nothing.
  127. #ifndef UNICODE_TRACE
  128. #undef __TEXT
  129. #define __TEXT(x) x
  130. #endif
  131. extern TSTable<HWSINST>* gpInstanceTable; // global ptr to the instance table
  132. #define GetTpktLength(pReq) (((pReq)->req_TpktHeader[2] << 8) + (pReq)->req_TpktHeader[3])
  133. HRESULT Q931Hangup(
  134. DWORD hQ931Call,
  135. BYTE bReason);
  136. /*++
  137. Description:
  138. Start a receive
  139. Arguments:
  140. pHws - Pointer to context for "connection"
  141. pReq - Pointer to I/O request structure
  142. Return Value:
  143. SUCCESS - Successfully started receive.
  144. LINK_RECV_ERROR_WOULD_BLOCK -
  145. Winsock error
  146. --*/
  147. static HRESULT
  148. TryRecv(IN PHWSINST pHws, IN char *data, IN int length, IN OUT int *total_bytes_done)
  149. {
  150. int requested_length = length - *total_bytes_done;
  151. int recv_result = recv(pHws->hws_Socket, data+*total_bytes_done, requested_length, 0);
  152. if (recv_result == SOCKET_ERROR)
  153. {
  154. int err = WSAGetLastError();
  155. switch (err)
  156. {
  157. case WSAEWOULDBLOCK:
  158. return LINK_RECV_WOULD_BLOCK;
  159. case WSAECONNABORTED:
  160. case WSAECONNRESET:
  161. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
  162. __TEXT("TryRecv: recv() returned %s"),
  163. SocketErrorText());
  164. if (pHws->hws_uState == HWS_CONNECTED)
  165. {
  166. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE,
  167. __TEXT("TryRecv: calling shutdown"));
  168. if (shutdown(pHws->hws_Socket, 1) == SOCKET_ERROR)
  169. {
  170. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
  171. __TEXT("TryRecv: shutdown() returned %s"),
  172. SocketErrorText());
  173. }
  174. else
  175. {
  176. Q931Hangup( pHws->hws_dwH245Instance, CC_REJECT_UNDEFINED_REASON );
  177. }
  178. pHws->hws_uState = HWS_CLOSING;
  179. }
  180. return MAKE_WINSOCK_ERROR(err);
  181. default:
  182. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
  183. __TEXT("TryRecv: recv() returned %s"),
  184. SocketErrorText());
  185. return MAKE_WINSOCK_ERROR(err);
  186. } // switch
  187. }
  188. HWSTRACE1(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("TryRecv: recv returned %d"), recv_result);
  189. if (recv_result == 0)
  190. {
  191. return LINK_RECV_CLOSED;
  192. }
  193. *total_bytes_done += recv_result;
  194. return (recv_result == requested_length) ? NOERROR : LINK_RECV_WOULD_BLOCK;
  195. }
  196. static HRESULT
  197. RecvStart(IN PHWSINST pHws, IN PREQUEST pReq)
  198. {
  199. HRESULT nResult = NOERROR;
  200. // Sanity checks
  201. HWSASSERT(pHws != NULL);
  202. HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
  203. HWSASSERT(pReq != NULL);
  204. HWSASSERT(pReq->req_dwMagic == RECV_REQUEST_MAGIC);
  205. HWSASSERT(pReq->req_pHws == pHws);
  206. // Get the header first; if that succeeds get the client data
  207. if (pReq->req_header_bytes_done < TPKT_HEADER_SIZE)
  208. {
  209. nResult = TryRecv(pHws,
  210. (char *)pReq->req_TpktHeader,
  211. TPKT_HEADER_SIZE,
  212. &pReq->req_header_bytes_done);
  213. }
  214. if (nResult == NOERROR)
  215. {
  216. long int tpkt_length = GetTpktLength(pReq) - TPKT_HEADER_SIZE;
  217. if (pReq->req_TpktHeader[0] != TPKT_VERSION || tpkt_length <= 0)
  218. {
  219. // Invalid header version
  220. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  221. __TEXT("RecvComplete: bad header version; available data discarded"));
  222. // Should this be reported to the client??
  223. // Read and discard all available data
  224. // The client's buffer is used as a temporary buffer.
  225. while (recv(pHws->hws_Socket, (char *)pReq->req_client_data, pReq->req_client_length, 0) != SOCKET_ERROR)
  226. ;
  227. // Mark the header for this request as unread; it
  228. // will be read again when additional data is received.
  229. pReq->req_header_bytes_done = 0;
  230. nResult = LINK_RECV_ERROR;
  231. }
  232. else if (tpkt_length > pReq->req_client_length)
  233. {
  234. // Packet too large
  235. int request_length;
  236. int result;
  237. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  238. __TEXT("RecvComplete: packet too large; packet discarded"));
  239. // Should this be reported to the client??
  240. // Read and discard the packet
  241. // The client's buffer is used as a temporary buffer.
  242. do {
  243. request_length = pReq->req_client_length;
  244. if (request_length > tpkt_length)
  245. request_length = tpkt_length;
  246. result = recv(pHws->hws_Socket, (char *)pReq->req_client_data, request_length, 0);
  247. } while (result != SOCKET_ERROR && (tpkt_length -= result) > 0);
  248. if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
  249. {
  250. //TODO: packet too large handling
  251. // Adjust the header so that the rest of this packet will be read, but
  252. // flag it so that it is known to be an error and will not be returned
  253. // to the client.
  254. }
  255. else
  256. {
  257. // Mark the header for this request as unread; it
  258. // will be read again for the next packet received.
  259. pReq->req_header_bytes_done = 0;
  260. }
  261. nResult = LINK_RECV_ERROR;
  262. }
  263. else
  264. {
  265. // Normal case
  266. // The current implementation of TryRecv requires that the requested
  267. // size fit in a signed int (because that is what Winsock supports
  268. // in a single recv). This is guaranteed at this point regardless
  269. // of the originator of the packets, because we don't allow a buffer
  270. // to be posted that is larger than that (see ASSERT below). If the
  271. // packet were larger than the buffer, it would have been caught above.
  272. // If TryRecv is changed to remove the restriction on buffer size and
  273. // accept a parameter of type long int, this assert may be removed.
  274. HWSASSERT(tpkt_length <= INT_MAX);
  275. nResult = TryRecv(pHws,
  276. (char *)pReq->req_client_data,
  277. (int)tpkt_length,
  278. &pReq->req_client_bytes_done);
  279. }
  280. }
  281. return nResult;
  282. } // RecvStart()
  283. void
  284. ProcessQueuedRecvs(IN PHWSINST pHws)
  285. {
  286. register PREQUEST pReq;
  287. register DWORD dwPhysicalId = pHws->hws_dwPhysicalId;
  288. HWSASSERT(pHws != NULL);
  289. HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
  290. HWSASSERT(pHws->hws_uState <= HWS_CLOSING);
  291. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("ProcessQueuedRecvs"));
  292. while ((pReq = (PREQUEST) QRemove(pHws->hws_pRecvQueue)) != NULL)
  293. {
  294. switch (RecvStart(pHws, pReq))
  295. {
  296. case NOERROR:
  297. // Call Recv callback
  298. pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,
  299. LINK_RECV_DATA,
  300. pReq->req_client_data,
  301. pReq->req_client_bytes_done);
  302. // Free the I/O request structure
  303. HWSFREE(pReq);
  304. // Check to see if callback deallocated our instance or state changed
  305. // Check to see if callback deallocated our instance - this can be done
  306. // by attempting a lock - which will now fail if the entry has been marked
  307. // for deletion. Thus, if the lock succeeds, then just unlock it (since we
  308. // already have a lock on it in a higher level function).
  309. if(gpInstanceTable->Lock(dwPhysicalId) == NULL)
  310. return;
  311. gpInstanceTable->Unlock(dwPhysicalId);
  312. if(pHws->hws_uState > HWS_CONNECTED)
  313. return;
  314. break;
  315. default:
  316. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_WARNING,
  317. __TEXT("ProcessQueuedRecvs: RecvStart() failed"));
  318. // Fall-through to next case is intentional
  319. case LINK_RECV_WOULD_BLOCK:
  320. // The receive would have blocked; we need to requeue the I/O request
  321. // and wait for a FD_READ network event.
  322. // If any part of the data was received, the bytes_done field has been updated.
  323. if (QInsertAtHead(pHws->hws_pRecvQueue, pReq) == FALSE)
  324. {
  325. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  326. __TEXT("ProcessQueuedRecvs: QInsertAtHead() failed"));
  327. }
  328. return;
  329. case LINK_RECV_CLOSED:
  330. if (QInsertAtHead(pHws->hws_pRecvQueue, pReq) == FALSE)
  331. {
  332. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  333. __TEXT("ProcessQueuedRecvs: QInsertAtHead() failed"));
  334. }
  335. SocketCloseEvent(pHws);
  336. return;
  337. } // switch
  338. } // while
  339. } // ProcessQueuedRecvs()
  340. /**************************************************************************
  341. ** Function : datalinkReceiveRequest
  342. ** Description : Fills header/tail of buffer and posts buffer to H.223
  343. ***************************************************************************/
  344. LINKDLL HRESULT datalinkReceiveRequest( DWORD dwPhysicalId,
  345. PBYTE pbyDataBuf,
  346. DWORD dwLength)
  347. {
  348. register PHWSINST pHws;
  349. register PREQUEST pReq;
  350. HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkReceiveRequest"));
  351. pHws = gpInstanceTable->Lock(dwPhysicalId);
  352. if (pHws == NULL)
  353. {
  354. HWSTRACE0(dwPhysicalId, HWS_ERROR,
  355. __TEXT("datalinkReceiveRequest: dwPhysicalId not found"));
  356. return LINK_INVALID_INSTANCE;
  357. }
  358. if (pHws->hws_uState > HWS_CONNECTED)
  359. {
  360. HWSTRACE1(dwPhysicalId, HWS_ERROR,
  361. __TEXT("datalinkReceiveRequest: state = %d"), pHws->hws_uState);
  362. gpInstanceTable->Unlock(dwPhysicalId);
  363. return LINK_INVALID_STATE;
  364. }
  365. // Allocate request structure
  366. pReq = (PREQUEST) HWSMALLOC(sizeof(*pReq));
  367. if (pReq == NULL)
  368. {
  369. HWSTRACE0(dwPhysicalId, HWS_WARNING,
  370. __TEXT("datalinkReceiveRequest: could not allocate request buffer"));
  371. gpInstanceTable->Unlock(dwPhysicalId);
  372. return LINK_MEM_FAILURE;
  373. }
  374. // The current implementation requires that the size of each message
  375. // fit in a signed int (because that is what Winsock supports in a
  376. // single recv). If it is necessary to receive larger messages,
  377. // TryRecv and RecvStart must be changed to limit the size in each
  378. // recv call, and loop until all the data is received.
  379. // This assert could then be removed.
  380. HWSASSERT(dwLength <= INT_MAX);
  381. pReq->req_pHws = pHws;
  382. pReq->req_header_bytes_done= 0;
  383. pReq->req_client_data = pbyDataBuf;
  384. pReq->req_client_length = (int)dwLength;
  385. pReq->req_client_bytes_done= 0;
  386. pReq->req_dwMagic = RECV_REQUEST_MAGIC;
  387. if (QInsert(pHws->hws_pRecvQueue, pReq) == FALSE)
  388. {
  389. HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
  390. __TEXT("datalinkReceiveRequest: QInsert() failed"));
  391. gpInstanceTable->Unlock(dwPhysicalId);
  392. return LINK_RECV_NOBUFF;
  393. }
  394. if (pHws->hws_uState == HWS_CONNECTED)
  395. NotifyRead(pHws);
  396. HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkReceiveRequest: succeeded"));
  397. gpInstanceTable->Unlock(dwPhysicalId);
  398. return NOERROR;
  399. } // datalinkReceiveRequest()
  400. /**************************************************************************
  401. ** Function : datalinkCancelReceiveRequest
  402. ** Description : remove buffer from the request queue.
  403. ***************************************************************************/
  404. LINKDLL HRESULT datalinkCancelReceiveRequest(
  405. IN DWORD dwPhysicalId,
  406. IN PBYTE pbyDataBuf
  407. )
  408. {
  409. register PHWSINST pHws;
  410. register PREQUEST pReq;
  411. HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkCancelReceiveRequest"));
  412. pHws = gpInstanceTable->Lock(dwPhysicalId);
  413. if (pHws == NULL)
  414. {
  415. HWSTRACE0(dwPhysicalId, HWS_ERROR,
  416. __TEXT("datalinkCancelReceiveRequest: dwPhysicalId not found"));
  417. return LINK_INVALID_INSTANCE;
  418. }
  419. if (pHws->hws_uState > HWS_CONNECTED)
  420. {
  421. HWSTRACE1(dwPhysicalId, HWS_ERROR,
  422. __TEXT("datalinkCancelReceiveRequest: state = %d"), pHws->hws_uState);
  423. gpInstanceTable->Unlock(dwPhysicalId);
  424. return LINK_INVALID_STATE;
  425. }
  426. if (pHws->hws_pRecvQueue == NULL)
  427. {
  428. HWSTRACE0(dwPhysicalId, HWS_ERROR,
  429. __TEXT("datalinkCancelReceiveRequest: RecvQueue is NULL"));
  430. gpInstanceTable->Unlock(dwPhysicalId);
  431. return LINK_INVALID_INSTANCE;
  432. }
  433. // Remove the request that contains the receive buffer.
  434. QLock(pHws->hws_pRecvQueue);
  435. pReq = (PREQUEST) QFirstItem(pHws->hws_pRecvQueue);
  436. while (pReq != NULL)
  437. {
  438. if (pReq->req_client_data == pbyDataBuf)
  439. {
  440. QRemoveCurrentItem(pHws->hws_pRecvQueue);
  441. // Free the I/O request structure
  442. HWSFREE(pReq);
  443. break;
  444. }
  445. pReq = (PREQUEST) QNextItem(pHws->hws_pRecvQueue);
  446. }
  447. QUnlock(pHws->hws_pRecvQueue);
  448. gpInstanceTable->Unlock(dwPhysicalId);
  449. return NOERROR;
  450. }
  451. #if defined(__cplusplus)
  452. }
  453. #endif // (__cplusplus)