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.

1366 lines
59 KiB

  1. /****************************************************************************/
  2. // wtdint.cpp
  3. //
  4. // Transport driver - Windows specific internal functions.
  5. //
  6. // Copyright (C) 1997-1999 Microsoft Corp.
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. extern "C" {
  10. #define TRC_FILE "wtdint"
  11. #define TRC_GROUP TRC_GROUP_NETWORK
  12. #include <atrcapi.h>
  13. }
  14. #include "autil.h"
  15. #include "td.h"
  16. #include "xt.h"
  17. #include "nl.h"
  18. #include "wui.h"
  19. #include "objs.h"
  20. /****************************************************************************/
  21. /* Name: TDInit */
  22. /* */
  23. /* Purpose: Initializes _TD. This function allocates the send buffers, */
  24. /* creates the TD window and then initializes WinSock. */
  25. /* */
  26. /* Operation: On error this function calls the UT fatal error handler. */
  27. /****************************************************************************/
  28. DCVOID DCINTERNAL CTD::TDInit(DCVOID)
  29. {
  30. DCUINT i;
  31. DCUINT pubSndBufSizes[TD_SNDBUF_PUBNUM] = TD_SNDBUF_PUBSIZES;
  32. DCUINT priSndBufSizes[TD_SNDBUF_PRINUM] = TD_SNDBUF_PRISIZES;
  33. WORD versionRequested;
  34. WSADATA wsaData;
  35. int intRC;
  36. DC_BEGIN_FN("TDInit");
  37. /************************************************************************/
  38. /* Allocate a buffer into which data will be recieved from Winsock. */
  39. /************************************************************************/
  40. _TD.recvBuffer.pData = (PDCUINT8)UT_Malloc( _pUt, TD_RECV_BUFFER_SIZE);
  41. if (NULL != _TD.recvBuffer.pData)
  42. {
  43. // Got the buffer memory. Record the buffer size. Note we need to
  44. // record slightly less than the allocated size to account for
  45. // the fact that the current MPPC decompression code looks ahead one
  46. // byte, which means that a fault can occur if this lookahead goes
  47. // over the page boundary of this buffer. Leaving a couple of bytes
  48. // at the end of the buffer prevents this. This does not seriously
  49. // affect decoding efficiency -- the server itself sends less than
  50. // a full 8K buffer per send.
  51. TRC_NRM((TB, _T("Allocated %u bytes for recv buffer"),
  52. TD_RECV_BUFFER_SIZE));
  53. _TD.recvBuffer.size = TD_RECV_BUFFER_SIZE - 2;
  54. }
  55. else
  56. {
  57. /********************************************************************/
  58. /* Didn't get the memory. We can live without it, just keep the */
  59. /* size set at zero. */
  60. /********************************************************************/
  61. TRC_ALT((TB, _T("Failed to alloc %u bytes for recv buffer"),
  62. TD_RECV_BUFFER_SIZE));
  63. }
  64. /************************************************************************/
  65. /* Now loop through the public send buffer array and initialize the */
  66. /* array members. */
  67. /************************************************************************/
  68. for (i = 0; i < TD_SNDBUF_PUBNUM; i++)
  69. {
  70. /********************************************************************/
  71. /* Initialize the buffer information structure and allocate memory */
  72. /* for the actual buffer. */
  73. /********************************************************************/
  74. TDInitBufInfo(&_TD.pubSndBufs[i]);
  75. TDAllocBuf(&_TD.pubSndBufs[i], pubSndBufSizes[i]);
  76. TRC_DBG((TB, _T("Initialised public buffer:%u size:%u"),
  77. i,
  78. pubSndBufSizes[i]));
  79. }
  80. /************************************************************************/
  81. /* Loop through the private send buffer array and initialize the array */
  82. /* members. */
  83. /************************************************************************/
  84. for (i = 0; i < TD_SNDBUF_PRINUM; i++)
  85. {
  86. /********************************************************************/
  87. /* Initialize the buffer. */
  88. /********************************************************************/
  89. TDInitBufInfo(&_TD.priSndBufs[i]);
  90. TDAllocBuf(&_TD.priSndBufs[i], priSndBufSizes[i]);
  91. TRC_DBG((TB, _T("Initialised private buffer:%u size:%u"),
  92. i,
  93. priSndBufSizes[i]));
  94. }
  95. /************************************************************************/
  96. /* Create the TD window. */
  97. /************************************************************************/
  98. TDCreateWindow();
  99. #ifdef OS_WINCE
  100. #if (_WIN32_WCE > 300)
  101. if (NULL == (_TD.hevtAddrChange = CreateEvent(NULL, TRUE, FALSE, NULL)))
  102. {
  103. TRC_ABORT((TB, _T("Failed to create addr change notify event:%d"), GetLastError()));
  104. _pUi->UI_FatalError(DC_ERR_OUTOFMEMORY);
  105. DC_QUIT;
  106. }
  107. #endif
  108. #endif
  109. /************************************************************************/
  110. /* We want to use version 1.1 of WinSock. */
  111. /************************************************************************/
  112. versionRequested = MAKEWORD(1, 1);
  113. /************************************************************************/
  114. /* Initialize WinSock. */
  115. /************************************************************************/
  116. intRC = WSAStartup(versionRequested, &wsaData);
  117. if (intRC != 0)
  118. {
  119. /********************************************************************/
  120. // Trace out the error code - note that we can't use WSAGetLastError
  121. // at this point as WinSock has failed to initialize and so
  122. // WSAGetLastError will just fail.
  123. /********************************************************************/
  124. TRC_ABORT((TB, _T("Failed to initialize WinSock rc:%d"), intRC));
  125. _pUi->UI_FatalError(DC_ERR_WINSOCKINITFAILED);
  126. DC_QUIT;
  127. }
  128. /************************************************************************/
  129. /* Now confirm that this WinSock supports version 1.1. Note that if */
  130. /* the DLL supports versions greater than 1.1 in addition to 1.1 then */
  131. /* it will still return 1.1 in the version information as that is the */
  132. /* version requested. */
  133. /************************************************************************/
  134. if ((LOBYTE(wsaData.wVersion) != 1) ||
  135. (HIBYTE(wsaData.wVersion) != 1))
  136. {
  137. /********************************************************************/
  138. /* Oops - this WinSock doesn't support version 1.1. */
  139. /********************************************************************/
  140. WSACleanup();
  141. TRC_ABORT((TB, _T("This WinSock doesn't support version 1.1")));
  142. _pUi->UI_FatalError(DC_ERR_WINSOCKINITFAILED);
  143. DC_QUIT;
  144. }
  145. TRC_NRM((TB, _T("WinSock init version %u:%u"),
  146. HIBYTE(wsaData.wVersion),
  147. LOBYTE(wsaData.wVersion)));
  148. TRC_NRM((TB, _T("TD successfully initialized")));
  149. DC_EXIT_POINT:
  150. DC_END_FN();
  151. } /* TDInit */
  152. /****************************************************************************/
  153. /* Name: TDTerm */
  154. /* */
  155. /* Purpose: Terminates _TD. It frees the send buffers, cleans up WinSock, */
  156. /* destroys the TD window and then unregisters the TD window */
  157. /* class. */
  158. /****************************************************************************/
  159. DCVOID DCINTERNAL CTD::TDTerm(DCVOID)
  160. {
  161. DCUINT i;
  162. int intRC;
  163. DC_BEGIN_FN("TDTerm");
  164. /************************************************************************/
  165. /* Loop through the public and private send buffers and free the */
  166. /* memory. */
  167. /************************************************************************/
  168. for (i = 0; i < TD_SNDBUF_PUBNUM; i++)
  169. {
  170. UT_Free( _pUt, _TD.pubSndBufs[i].pBuffer);
  171. }
  172. for (i = 0; i < TD_SNDBUF_PRINUM; i++)
  173. {
  174. UT_Free( _pUt, _TD.priSndBufs[i].pBuffer);
  175. }
  176. /************************************************************************/
  177. /* Cleanup WinSock. */
  178. /************************************************************************/
  179. intRC = WSACleanup();
  180. if (SOCKET_ERROR == intRC)
  181. {
  182. TRC_ALT((TB, _T("Failed to cleanup WinSock:%d"), WSAGetLastError()));
  183. }
  184. #ifdef OS_WINCE
  185. #if (_WIN32_WCE > 300)
  186. TRC_ASSERT((_TD.hevtAddrChange), (TB, _T("hevtAddrChange is null")));
  187. CloseHandle(_TD.hevtAddrChange);
  188. _TD.hevtAddrChange = NULL;
  189. #endif
  190. #endif
  191. /************************************************************************/
  192. /* Destroy the window. */
  193. /************************************************************************/
  194. intRC = DestroyWindow(_TD.hWnd);
  195. _TD.hWnd = NULL;
  196. if (0 == intRC)
  197. {
  198. TRC_SYSTEM_ERROR("Destroy Window");
  199. }
  200. /************************************************************************/
  201. /* Unregister the class. */
  202. /************************************************************************/
  203. UnregisterClass(TD_WNDCLASSNAME, _pUi->UI_GetInstanceHandle());
  204. /************************************************************************/
  205. /* Release the recv buffer (if allocated). */
  206. /************************************************************************/
  207. if (0 != _TD.recvBuffer.size)
  208. {
  209. TRC_ASSERT((!IsBadWritePtr(_TD.recvBuffer.pData, _TD.recvBuffer.size)),
  210. (TB, _T("recv buffer %p size %u is invalid"),
  211. _TD.recvBuffer.pData,
  212. _TD.recvBuffer.size));
  213. UT_Free( _pUt, _TD.recvBuffer.pData);
  214. _TD.recvBuffer.pData = NULL;
  215. }
  216. TRC_NRM((TB, _T("TD successfully terminated")));
  217. DC_END_FN();
  218. } /* TDTerm */
  219. LRESULT CALLBACK CTD::StaticTDWndProc(HWND hwnd,
  220. UINT message,
  221. WPARAM wParam,
  222. LPARAM lParam)
  223. {
  224. CTD* pTD = (CTD*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  225. if(WM_CREATE == message)
  226. {
  227. //pull out the this pointer and stuff it in the window class
  228. LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
  229. pTD = (CTD*)lpcs->lpCreateParams;
  230. SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pTD);
  231. }
  232. //
  233. // Delegate the message to the appropriate instance
  234. //
  235. return pTD->TDWndProc(hwnd, message, wParam, lParam);
  236. }
  237. /****************************************************************************/
  238. /* Name: TDWndProc */
  239. /* */
  240. /* Purpose: The TD window procedure. */
  241. /* */
  242. /* Params: See Windows documentation. */
  243. /****************************************************************************/
  244. LRESULT CALLBACK CTD::TDWndProc(HWND hWnd,
  245. UINT uMsg,
  246. WPARAM wParam,
  247. LPARAM lParam)
  248. {
  249. LRESULT rc = 0;
  250. WORD eventWSA;
  251. WORD errorWSA;
  252. u_long address;
  253. DC_BEGIN_FN("TDWndProc");
  254. // Trace the interesting parameters.
  255. TRC_DBG((TB, _T("uMsg:%u wP:%u lP:%lu"), uMsg, wParam, lParam));
  256. // Special-case FD_READ (most important) and FD_WRITE (happens often).
  257. if (uMsg == TD_WSA_ASYNC) {
  258. if (WSAGETSELECTEVENT(lParam) == FD_READ) {
  259. TRC_DBG((TB, _T("FD_READ recvd")));
  260. // Check for an error.
  261. if (WSAGETSELECTERROR(lParam) == 0) {
  262. // If we're no longer connected, we just ignore the data.
  263. if (_TD.fsmState == TD_ST_CONNECTED) {
  264. // There is now some data available so set the
  265. // global variable.
  266. _TD.dataInTD = TRUE;
  267. #ifdef OS_WINCE
  268. // Enable Winsock receive. We perform only one
  269. // WinSock recv per FD_READ.
  270. TD_EnableWSRecv();
  271. #endif // OS_WINCE
  272. // Tell XT.
  273. _pXt->XT_OnTDDataAvailable();
  274. }
  275. else {
  276. TRC_NRM((TB, _T("FD_READ when not connected")));
  277. }
  278. }
  279. else {
  280. TRC_ALT((TB, _T("WSA_ASYNC error:%hu"),
  281. WSAGETSELECTERROR(lParam)));
  282. }
  283. DC_QUIT;
  284. }
  285. else if (WSAGETSELECTEVENT(lParam) == FD_WRITE) {
  286. TRC_NRM((TB, _T("FD_WRITE received")));
  287. // Check for an error.
  288. if (WSAGETSELECTERROR(lParam) == 0) {
  289. // Make sure we're still connected.
  290. if (_TD.fsmState == TD_ST_CONNECTED) {
  291. // We're on the receiver thread, notify sender
  292. // thread to flush the send queue.
  293. _pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
  294. CD_NOTIFICATION_FUNC(CTD,TDFlushSendQueue), 0);
  295. // Call up to XT to inform the higher layers
  296. // that the back pressure situation has been
  297. // relieved.
  298. _pXt->XT_OnTDBufferAvailable();
  299. }
  300. else {
  301. TRC_ALT((TB, _T("FD_WRITE when not connected")));
  302. }
  303. }
  304. else {
  305. TRC_ALT((TB, _T("WSA_ASYNC error:%hu"),
  306. WSAGETSELECTERROR(lParam)));
  307. }
  308. DC_QUIT;
  309. }
  310. }
  311. // Now switch on the message type for other messages.
  312. switch (uMsg) {
  313. case WM_TIMER:
  314. /****************************************************************/
  315. /* Check that the ID of the timer is as expected. */
  316. /****************************************************************/
  317. if (TD_TIMERID == wParam)
  318. {
  319. /************************************************************/
  320. /* OK it is our connection time out timer, so call the */
  321. /* state machine. */
  322. /************************************************************/
  323. TRC_NRM((TB, _T("WM_TIMER recvd")));
  324. TDConnectFSMProc(TD_EVT_WMTIMER,
  325. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDTIMEOUT));
  326. }
  327. #ifdef DC_DEBUG
  328. else if (TD_THROUGHPUTTIMERID == wParam)
  329. {
  330. /************************************************************/
  331. /* This is the throughput throttling timer. Reset the */
  332. /* byte counts. */
  333. /************************************************************/
  334. TRC_DBG((TB, _T("Throughput timer, reset byte counts to:%u"),
  335. _TD.currentThroughput));
  336. _TD.periodSendBytesLeft = _TD.currentThroughput;
  337. _TD.periodRecvBytesLeft = _TD.currentThroughput;
  338. /************************************************************/
  339. /* If we're connected then generate FD_READ and FD_WRITE */
  340. /* messages to get the network layer running along. */
  341. /************************************************************/
  342. if (TD_ST_CONNECTED == _TD.fsmState)
  343. {
  344. PostMessage(_TD.hWnd,
  345. TD_WSA_ASYNC,
  346. (WPARAM)0,
  347. (LPARAM)MAKELONG(FD_READ, 0));
  348. PostMessage(_TD.hWnd,
  349. TD_WSA_ASYNC,
  350. (WPARAM)0,
  351. (LPARAM)MAKELONG(FD_WRITE, 0));
  352. }
  353. }
  354. #endif /* DC_DEBUG */
  355. else
  356. {
  357. TRC_ALT((TB, _T("Unexpected timer message id:%u"), wParam));
  358. }
  359. break;
  360. case TD_WSA_ASYNC:
  361. /****************************************************************/
  362. /* We've received a WSAAsyncSelect() FD_x notification message. */
  363. /* Parse the message to extract the FD_ value and error value */
  364. /* (if there is one). */
  365. /****************************************************************/
  366. eventWSA = WSAGETSELECTEVENT(lParam);
  367. errorWSA = WSAGETSELECTERROR(lParam);
  368. TRC_DBG((TB, _T("WSA_ASYNC event:%#hx error:%hu"),
  369. eventWSA,
  370. errorWSA));
  371. /****************************************************************/
  372. /* Everything is OK so now switch on the event. */
  373. /****************************************************************/
  374. switch (eventWSA) {
  375. case FD_CONNECT:
  376. TRC_NRM((TB, _T("FD_CONNECT recvd")));
  377. /********************************************************/
  378. /* Under some circumstances, we can receive FD_CONNECT */
  379. /* for a socket which we have lost interest in. */
  380. /********************************************************/
  381. if (wParam != _TD.hSocket)
  382. {
  383. TRC_ALT((TB, _T("FD_CONNECT for socket %d, using %d"),
  384. wParam, _TD.hSocket));
  385. DC_QUIT;
  386. }
  387. /********************************************************/
  388. /* Check for an error. */
  389. /********************************************************/
  390. if (0 != errorWSA)
  391. {
  392. TRC_ALT((TB, _T("WSA_ASYNC error:%hu"), errorWSA));
  393. TDConnectFSMProc(TD_EVT_ERROR,
  394. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDSKTCONNECTFAILED));
  395. DC_QUIT;
  396. }
  397. /********************************************************/
  398. /* Advance the state machine. */
  399. /********************************************************/
  400. TDConnectFSMProc(TD_EVT_OK, 0);
  401. break;
  402. case FD_CLOSE:
  403. {
  404. DCBOOL keepOnReceiving = TRUE;
  405. int intRC;
  406. TRC_NRM((TB, _T("FD_CLOSE recvd")));
  407. /********************************************************/
  408. /* Check for the remote system aborting the connection. */
  409. /********************************************************/
  410. if (0 != errorWSA)
  411. {
  412. /****************************************************/
  413. /* The server sends a TCP RST instead of a FIN, */
  414. /* even when a clean disconnection is made. */
  415. /* However, this is handled by the UI (see */
  416. /* UIGoDisconnected). */
  417. /****************************************************/
  418. TRC_ALT((TB, _T("Abortive server close:%hu"), errorWSA));
  419. TDConnectFSMProc(TD_EVT_ERROR,
  420. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDFDCLOSE));
  421. DC_QUIT;
  422. }
  423. /********************************************************/
  424. /* If we get here then this a response to a graceful */
  425. /* close (i.e. we made a call to shutdown(SD_SEND) */
  426. /* earlier). */
  427. /* */
  428. /* All of the data should have already been read from */
  429. /* the socket before WinSock posted the FD_CLOSE, but */
  430. /* to be safe we loop on recv. */
  431. /********************************************************/
  432. while (keepOnReceiving)
  433. {
  434. intRC = recv(_TD.hSocket,
  435. (char *)_TD.priSndBufs[0].pBuffer,
  436. _TD.priSndBufs[0].size,
  437. 0);
  438. if ((0 == intRC) || (SOCKET_ERROR == intRC))
  439. {
  440. keepOnReceiving = FALSE;
  441. TRC_ALT((TB, _T("No more data in WS (rc:%d)"),
  442. intRC));
  443. }
  444. else
  445. {
  446. TRC_ALT((TB, _T("Throwing away %d bytes from WS"),
  447. intRC));
  448. }
  449. }
  450. /********************************************************/
  451. /* Finally call the FSM. */
  452. /********************************************************/
  453. TDConnectFSMProc(TD_EVT_OK, NL_DISCONNECT_LOCAL);
  454. }
  455. break;
  456. default:
  457. TRC_ALT((TB, _T("Unknown FD event %hu recvd"), eventWSA));
  458. break;
  459. }
  460. break;
  461. case TD_WSA_GETHOSTBYNAME:
  462. /****************************************************************/
  463. /* We've received the result of a WSAAsyncGetHostByName */
  464. /* operation. Split the message apart and call the FSM. */
  465. /****************************************************************/
  466. errorWSA = WSAGETASYNCERROR(lParam);
  467. if (0 != errorWSA)
  468. {
  469. TRC_ALT((TB, _T("GHBN failed:%hu"), errorWSA));
  470. /************************************************************/
  471. /* Call the state machine with the error event. */
  472. /************************************************************/
  473. TDConnectFSMProc(TD_EVT_ERROR,
  474. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDGHBNFAILED));
  475. break;
  476. }
  477. /****************************************************************/
  478. /* Now get the primary interface address. */
  479. /****************************************************************/
  480. address = *((u_long DCPTR)
  481. (((struct hostent DCPTR)_TD.priSndBufs[0].pBuffer)->h_addr));
  482. TRC_ASSERT((address != 0),
  483. (TB, _T("GetHostByName returned success but 0 address")));
  484. TRC_NRM((TB, _T("GHBN - address is:%#lx"), address));
  485. TDConnectFSMProc(TD_EVT_OK, (DCUINT32)address);
  486. break;
  487. #if (defined(OS_WINCE) && (_WIN32_WCE > 300))
  488. case TD_WSA_NETDOWN:
  489. TRC_NRM((TB, _T("TD_WSA_NETDOWN recvd")));
  490. TDConnectFSMProc(TD_EVT_ERROR, NL_MAKE_DISCONNECT_ERR(NL_ERR_TDONCALLTOSEND));
  491. break;
  492. #endif
  493. default:
  494. rc = DefWindowProc(hWnd, uMsg, wParam, lParam);
  495. break;
  496. }
  497. DC_EXIT_POINT:
  498. DC_END_FN();
  499. return(rc);
  500. } /* TDWndProc */
  501. /****************************************************************************/
  502. /* Name: TDCreateWindow */
  503. /* */
  504. /* Purpose: Creates the TD window. This function registers the TD */
  505. /* window class and then creates a window of that class. On */
  506. /* error it calls UI_FatalError. */
  507. /****************************************************************************/
  508. DCVOID DCINTERNAL CTD::TDCreateWindow(DCVOID)
  509. {
  510. WNDCLASS wc;
  511. WNDCLASS tmpWndClass;
  512. ATOM intRC;
  513. DC_BEGIN_FN("TDCreateWindow");
  514. if(!GetClassInfo(_pUi->UI_GetInstanceHandle(),TD_WNDCLASSNAME, &tmpWndClass))
  515. {
  516. /************************************************************************/
  517. /* Fill in the class structure. */
  518. /************************************************************************/
  519. wc.style = 0;
  520. wc.lpfnWndProc = StaticTDWndProc;
  521. wc.cbClsExtra = 0;
  522. wc.cbWndExtra = sizeof(void*); //for instance pointer
  523. wc.hInstance = _pUi->UI_GetInstanceHandle();
  524. wc.hIcon = NULL;
  525. wc.hCursor = NULL;
  526. wc.hbrBackground = NULL;
  527. wc.lpszMenuName = NULL;
  528. wc.lpszClassName = TD_WNDCLASSNAME;
  529. /************************************************************************/
  530. /* Register the class used by the TD window. */
  531. /************************************************************************/
  532. intRC = RegisterClass(&wc);
  533. if (0 == intRC)
  534. {
  535. TRC_ERR((TB, _T("Failed to register WinSock window class")));
  536. _pUi->UI_FatalError(DC_ERR_CLASSREGISTERFAILED);
  537. DC_QUIT;
  538. }
  539. }
  540. /************************************************************************/
  541. /* Now create the window. */
  542. /************************************************************************/
  543. _TD.hWnd = CreateWindow(TD_WNDCLASSNAME, /* class name */
  544. NULL, /* window title */
  545. 0, /* window style */
  546. 0, /* x-pos */
  547. 0, /* y-pos */
  548. 0, /* width */
  549. 0, /* height */
  550. NULL, /* parent */
  551. NULL, /* menu */
  552. _pUi->UI_GetInstanceHandle(), /* instance */
  553. this); /* ptr to creation data */
  554. if (NULL == _TD.hWnd)
  555. {
  556. TRC_ERR((TB, _T("Failed to create TD window")));
  557. _pUi->UI_FatalError(DC_ERR_WINDOWCREATEFAILED);
  558. DC_QUIT;
  559. }
  560. TRC_NRM((TB, _T("Created window:%p"), _TD.hWnd));
  561. DC_EXIT_POINT:
  562. DC_END_FN();
  563. } /* TDCreateWindow */
  564. /****************************************************************************/
  565. /* Name: TDBeginDNSLookup */
  566. /* */
  567. /* Purpose: Starts the address resolution process. On error this */
  568. /* function calls into the state machine with an error code. */
  569. /* */
  570. /* Params: IN pServerAddress - pointer to the server address name. */
  571. /****************************************************************************/
  572. DCVOID DCINTERNAL CTD::TDBeginDNSLookup(PDCACHAR pServerAddress)
  573. {
  574. DC_BEGIN_FN("TDBeginDNSLookup");
  575. /************************************************************************/
  576. /* This is an asynchronous operation and will result in us getting a */
  577. /* callback sometime later. We need to provide a buffer which can be */
  578. /* filled in with DNS information, so we make use of the first private */
  579. /* send buffer. */
  580. /************************************************************************/
  581. TRC_ASSERT((_TD.priSndBufs[0].size >= MAXGETHOSTSTRUCT),
  582. (TB, _T("Private snd buf size (%u) too small for DNS lookup (need:%u)"),
  583. _TD.priSndBufs[0].size,
  584. MAXGETHOSTSTRUCT));
  585. /************************************************************************/
  586. /* Issue the call. */
  587. /************************************************************************/
  588. _TD.hGHBN = WSAAsyncGetHostByName(_TD.hWnd,
  589. TD_WSA_GETHOSTBYNAME,
  590. pServerAddress,
  591. (char DCPTR) _TD.priSndBufs[0].pBuffer,
  592. MAXGETHOSTSTRUCT);
  593. if (0 == _TD.hGHBN)
  594. {
  595. /********************************************************************/
  596. /* We failed to initiate the operation - so find out what went */
  597. /* wrong. */
  598. /********************************************************************/
  599. TRC_ALT((TB, _T("Failed to initiate GetHostByName - GLE:%d"),
  600. WSAGetLastError()));
  601. /********************************************************************/
  602. /* Call the state machine with an error. */
  603. /********************************************************************/
  604. TDConnectFSMProc(TD_EVT_ERROR,
  605. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDDNSLOOKUPFAILED));
  606. DC_QUIT;
  607. }
  608. TRC_NRM((TB, _T("Initiated GetHostByName OK")));
  609. DC_EXIT_POINT:
  610. DC_END_FN();
  611. } /* TDBeginDNSLookup */
  612. /****************************************************************************/
  613. /* Name: TDBeginSktConnectWithConnectedEndpoint */
  614. /* */
  615. /* Purpose: Establish connection with server already connect */
  616. /* on some socket */
  617. /* */
  618. /* Params: */
  619. /* */
  620. /****************************************************************************/
  621. DCVOID DCINTERNAL CTD::TDBeginSktConnectWithConnectedEndpoint()
  622. {
  623. DCBOOL failure = FALSE;
  624. #ifndef OS_WINCE
  625. int lastError;
  626. #endif
  627. int intRC;
  628. DC_BEGIN_FN("TDBeginSktConnectWithConnectedEndpoint");
  629. /************************************************************************/
  630. /* Socket already connect, setup FD_XXX event with our window */
  631. /* we are assuming mstscax client already make necessary error checking */
  632. /************************************************************************/
  633. _TD.hSocket = _pUi->UI_GetTDSocket();
  634. TRC_ASSERT(
  635. (_TD.hSocket != INVALID_SOCKET),
  636. (TB, _T("Connected socket not setup properly")) );
  637. if( INVALID_SOCKET == _TD.hSocket )
  638. {
  639. failure = TRUE;
  640. DC_QUIT;
  641. }
  642. /************************************************************************/
  643. /* Set the required options on this socket. We do the following: */
  644. /* */
  645. /* - disable the NAGLE algorithm. */
  646. /* - enable the don't linger option. This means the closesocket call */
  647. /* will return immediately while any data queued for transmission */
  648. /* will be sent, if possible, before the underlying socket is */
  649. /* closed. */
  650. /* */
  651. /* Note that further options are set when the connection is */
  652. /* established. */
  653. /************************************************************************/
  654. TDSetSockOpt(IPPROTO_TCP, TCP_NODELAY, 1);
  655. TDSetSockOpt(SOL_SOCKET, SO_DONTLINGER, 1);
  656. /************************************************************************/
  657. /* Now request async notifications for all events on this socket. */
  658. /************************************************************************/
  659. intRC = WSAAsyncSelect(_TD.hSocket,
  660. _TD.hWnd,
  661. TD_WSA_ASYNC,
  662. FD_READ | FD_WRITE | FD_CLOSE);
  663. if (SOCKET_ERROR == intRC)
  664. {
  665. TRC_ERR((TB, _T("Failed to select async - GLE:%d"), WSAGetLastError()));
  666. failure = TRUE;
  667. DC_QUIT;
  668. }
  669. DC_EXIT_POINT:
  670. if (failure)
  671. {
  672. TRC_ALT((TB, _T("Failed to begin socket connection process")));
  673. /********************************************************************/
  674. /* Call the FSM. */
  675. /********************************************************************/
  676. TDConnectFSMProc(TD_EVT_ERROR,
  677. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDSKTCONNECTFAILED));
  678. }
  679. else
  680. {
  681. // use existing code path to setup rest.
  682. PostMessage(_TD.hWnd,
  683. TD_WSA_ASYNC,
  684. (WPARAM) _TD.hSocket,
  685. (LPARAM)MAKELONG(FD_CONNECT, 0));
  686. }
  687. DC_END_FN();
  688. } /* TDBeginSktConnectWithConnectedEndpoint */
  689. /****************************************************************************/
  690. /* Name: TDBeginSktConnect */
  691. /* */
  692. /* Purpose: Issues a connect at the WinSock socket level. */
  693. /* */
  694. /* Params: IN address - the address to call (this is a numeric value */
  695. /* in network (big-endian) byte order). */
  696. /****************************************************************************/
  697. DCVOID DCINTERNAL CTD::TDBeginSktConnect(u_long address)
  698. {
  699. DCBOOL failure = FALSE;
  700. int intRC;
  701. int lastError;
  702. SOCKADDR_IN stDstAddr;
  703. DC_BEGIN_FN("TDBeginSktConnect");
  704. /************************************************************************/
  705. /* First of all get a socket. */
  706. /************************************************************************/
  707. _TD.hSocket = socket(AF_INET, SOCK_STREAM, 0);
  708. if (INVALID_SOCKET == _TD.hSocket)
  709. {
  710. TRC_ERR((TB, _T("Failed to get a socket - GLE:%d"), WSAGetLastError()));
  711. DC_QUIT;
  712. }
  713. _pUi->UI_SetTDSocket(_TD.hSocket);
  714. TRC_NRM((TB, _T("Acquired socket:%#x"), _TD.hSocket));
  715. /************************************************************************/
  716. /* Set the required options on this socket. We do the following: */
  717. /* */
  718. /* - disable the NAGLE algorithm. */
  719. /* - enable the don't linger option. This means the closesocket call */
  720. /* will return immediately while any data queued for transmission */
  721. /* will be sent, if possible, before the underlying socket is */
  722. /* closed. */
  723. /* */
  724. /* Note that further options are set when the connection is */
  725. /* established. */
  726. /************************************************************************/
  727. TDSetSockOpt(IPPROTO_TCP, TCP_NODELAY, 1);
  728. TDSetSockOpt(SOL_SOCKET, SO_DONTLINGER, 1);
  729. /************************************************************************/
  730. /* Now request async notifications for all events on this socket. */
  731. /************************************************************************/
  732. intRC = WSAAsyncSelect(_TD.hSocket,
  733. _TD.hWnd,
  734. TD_WSA_ASYNC,
  735. FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);
  736. if (SOCKET_ERROR == intRC)
  737. {
  738. TRC_ERR((TB, _T("Failed to select async - GLE:%d"), WSAGetLastError()));
  739. failure = TRUE;
  740. DC_QUIT;
  741. }
  742. /************************************************************************/
  743. /* Now kick off a timer - if the connect does not complete before we */
  744. /* get the WM_TIMER message then we'll abort the connection attempt. */
  745. /************************************************************************/
  746. /* _TD.hTimer = TDSetTimer(TD_CONNECTTIMEOUT);
  747. if (0 == _TD.hTimer)
  748. {
  749. failure = TRUE;
  750. DC_QUIT;
  751. }
  752. */
  753. /************************************************************************/
  754. /* Fill in the address of the remote system we want to connect to. */
  755. /************************************************************************/
  756. stDstAddr.sin_family = PF_INET;
  757. stDstAddr.sin_port = htons(_pUi->UI_GetMCSPort());
  758. stDstAddr.sin_addr.s_addr = (u_long) address;
  759. #ifdef OS_WINCE
  760. #if (_WIN32_WCE > 300)
  761. TRC_ASSERT((_TD.hevtAddrChange), (TB, _T("hevtAddrChange is null")));
  762. TRC_ASSERT((_TD.hAddrChangeThread == NULL), (TB, _T("hAddrChangeThread is not null")));
  763. _TD.hAddrChangeThread = CreateThread(NULL, 0, TDAddrChangeProc, &_TD, 0, NULL);
  764. if (_TD.hAddrChangeThread == NULL)
  765. {
  766. TRC_ERR((TB, _T("CreatThread failed - GLE:%d"), GetLastError()));
  767. failure = TRUE;
  768. DC_QUIT;
  769. }
  770. #endif
  771. #endif
  772. /************************************************************************/
  773. /* We're now in a state where we can try to connect to the remote */
  774. /* system so issue the connect now. We expect this call to fail with */
  775. /* an error code of WSAEWOULDBLOCK - any other error code is a genuine */
  776. /* problem. */
  777. /************************************************************************/
  778. intRC = connect(_TD.hSocket,
  779. (struct sockaddr DCPTR) &stDstAddr,
  780. sizeof(stDstAddr));
  781. if (SOCKET_ERROR == intRC)
  782. {
  783. /********************************************************************/
  784. /* Get the last error. */
  785. /********************************************************************/
  786. lastError = WSAGetLastError();
  787. /********************************************************************/
  788. /* We expect the connect to return an error of WSAEWOULDBLOCK - */
  789. /* anything else indicates a genuine error. */
  790. /********************************************************************/
  791. if (lastError != WSAEWOULDBLOCK)
  792. {
  793. TRC_ERR((TB, _T("Connect failed - GLE:%d"), lastError));
  794. failure = TRUE;
  795. DC_QUIT;
  796. }
  797. }
  798. /************************************************************************/
  799. /* We've done as much as we can at this point - all we can do now is */
  800. /* wait for the socket connection to complete. */
  801. /************************************************************************/
  802. TRC_NRM((TB, _T("Waiting for connect to complete...")));
  803. DC_EXIT_POINT:
  804. if (failure)
  805. {
  806. TRC_ALT((TB, _T("Failed to begin socket connection process")));
  807. /********************************************************************/
  808. /* Call the FSM. */
  809. /********************************************************************/
  810. TDConnectFSMProc(TD_EVT_ERROR,
  811. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDSKTCONNECTFAILED));
  812. }
  813. DC_END_FN();
  814. } /* TDBeginSktConnect */
  815. /****************************************************************************/
  816. /* Name: TDSetSockOpt */
  817. /* */
  818. /* Purpose: Sets a given WinSock socket option. Note that this function */
  819. /* does not return an error if it fails to set the option as */
  820. /* TD can still continue successfully despite failing to set */
  821. /* the options to the desired values. */
  822. /* */
  823. /* Params: IN level - the level at which the option is defined (see */
  824. /* docs for setsockopt). */
  825. /* IN optName - the socket option for which the value is to be */
  826. /* set. */
  827. /* IN value - the value to set the option to. */
  828. /****************************************************************************/
  829. DCVOID DCINTERNAL CTD::TDSetSockOpt(DCINT level, DCINT optName, DCINT value)
  830. {
  831. int intRC;
  832. DCINT size = sizeof(DCINT);
  833. #ifdef DC_DEBUG
  834. DCINT oldVal;
  835. DCINT newVal;
  836. #endif /* DC_DEBUG */
  837. DC_BEGIN_FN("TDSetSockOpt");
  838. #ifdef DC_DEBUG
  839. /************************************************************************/
  840. /* For the debug build trace out the current value of the option */
  841. /* before setting it. */
  842. /************************************************************************/
  843. getsockopt(_TD.hSocket, level, optName, (char DCPTR) &oldVal, &size);
  844. #endif /* DC_DEBUG */
  845. /************************************************************************/
  846. /* Now set the option. */
  847. /************************************************************************/
  848. intRC = setsockopt(_TD.hSocket, level, optName, (char DCPTR) &value, size);
  849. if (SOCKET_ERROR == intRC)
  850. {
  851. TRC_ALT((TB, _T("Failed to set socket option:%d rc:%d (level:%d val:%d)"),
  852. optName,
  853. WSAGetLastError(),
  854. level,
  855. value));
  856. DC_QUIT;
  857. }
  858. #ifdef DC_DEBUG
  859. /************************************************************************/
  860. /* Get the new value of the option. */
  861. /************************************************************************/
  862. getsockopt(_TD.hSocket, level, optName, (char DCPTR) &newVal, &size);
  863. TRC_NRM((TB, _T("Mod socket option %d:%d from %d to %d"),
  864. level,
  865. optName,
  866. oldVal,
  867. newVal));
  868. #endif /* DC_DEBUG */
  869. DC_EXIT_POINT:
  870. DC_END_FN();
  871. } /* TDSetSockOpt */
  872. /****************************************************************************/
  873. /* Name: TDDisconnect */
  874. /* */
  875. /* Purpose: Disconnects the transport driver. */
  876. /****************************************************************************/
  877. DCVOID DCINTERNAL CTD::TDDisconnect(DCVOID)
  878. {
  879. int intRC;
  880. SOCKET socket;
  881. DC_BEGIN_FN("TDDisconnect");
  882. /************************************************************************/
  883. /* Kill the timer. */
  884. /************************************************************************/
  885. TDKillTimer();
  886. /************************************************************************/
  887. /* Ensure the data-in-TD flag is cleared. */
  888. /************************************************************************/
  889. _TD.dataInTD = FALSE;
  890. /************************************************************************/
  891. /* Cancel the outstanding DNS lookup. We can't be sure that the async */
  892. /* operation has completed already and the message is already sitting */
  893. /* on our queue (or being processed by the receive thread). If that is */
  894. /* the case then WSACancelAsyncRequest will fail, but it doesn't */
  895. /* matter. */
  896. /************************************************************************/
  897. intRC = WSACancelAsyncRequest(_TD.hGHBN);
  898. if (SOCKET_ERROR == intRC) {
  899. TRC_NRM((TB, _T("Failed to cancel async DNS request")));
  900. }
  901. /************************************************************************/
  902. /* Decouple to the sender thread and clear the send queue. */
  903. /************************************************************************/
  904. _pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT, this,
  905. CD_NOTIFICATION_FUNC(CTD,TDClearSendQueue), 0);
  906. #ifdef OS_WINCE
  907. #if (_WIN32_WCE > 300)
  908. SetEvent(_TD.hevtAddrChange);
  909. if (_TD.hAddrChangeThread)
  910. {
  911. WaitForSingleObject(_TD.hAddrChangeThread, INFINITE);
  912. CloseHandle(_TD.hAddrChangeThread);
  913. _TD.hAddrChangeThread = NULL;
  914. }
  915. ResetEvent(_TD.hevtAddrChange);
  916. #endif
  917. #endif
  918. if (INVALID_SOCKET == _TD.hSocket)
  919. {
  920. TRC_NRM((TB, _T("_TD.hSocket is NULL so just quit")));
  921. DC_QUIT;
  922. }
  923. /************************************************************************/
  924. /* Now close the socket. */
  925. /************************************************************************/
  926. TRC_NRM((TB, _T("Close the socket")));
  927. socket = _TD.hSocket;
  928. _TD.hSocket = INVALID_SOCKET;
  929. intRC = closesocket(socket);
  930. if (SOCKET_ERROR == intRC)
  931. {
  932. TRC_ALT((TB, _T("closesocket rc:%d"), WSAGetLastError()));
  933. }
  934. DC_EXIT_POINT:
  935. DC_END_FN();
  936. } /* TDDisconnect */
  937. /****************************************************************************/
  938. /* Name: TDSetTimer */
  939. /* */
  940. /* Purpose: Sets the timer. */
  941. /* */
  942. /* Returns: TRUE on success and FALSE otherwise. */
  943. /* */
  944. /* Params: IN timeInterval - the time interval of the timer. */
  945. /****************************************************************************/
  946. DCBOOL DCINTERNAL CTD::TDSetTimer(DCUINT timeInterval)
  947. {
  948. DCBOOL rc;
  949. DC_BEGIN_FN("TDSetTimer");
  950. /************************************************************************/
  951. /* Set the timer with the passed time interval. */
  952. /************************************************************************/
  953. _TD.hTimer = SetTimer(_TD.hWnd, TD_TIMERID, timeInterval, NULL);
  954. if (_TD.hTimer != 0) {
  955. // Everything went OK, so set a successful return code.
  956. rc = TRUE;
  957. TRC_NRM((TB, _T("Set timer with interval:%u"), timeInterval));
  958. }
  959. else {
  960. TRC_SYSTEM_ERROR("SetTimer");
  961. rc = FALSE;
  962. }
  963. DC_END_FN();
  964. return rc;
  965. } /* TDSetTimer */
  966. /****************************************************************************/
  967. /* Name: TDKillTimer */
  968. /* */
  969. /* Purpose: Cleans up the timer which is used to time-out connect */
  970. /* and disconnect attempts. */
  971. /****************************************************************************/
  972. DCVOID DCINTERNAL CTD::TDKillTimer(DCVOID)
  973. {
  974. BOOL rc;
  975. DC_BEGIN_FN("TDKillTimer");
  976. /************************************************************************/
  977. /* Destroy the connection timeout timer. If we fail to get rid of this */
  978. /* timer then there's not much we can do - we'll continue to get */
  979. /* WM_TIMER messages which we'll ignore in retail and assert on in the */
  980. /* debug version. */
  981. /************************************************************************/
  982. if (_TD.hTimer != 0)
  983. {
  984. rc = KillTimer(_TD.hWnd, TD_TIMERID);
  985. _TD.hTimer = 0;
  986. TRC_NRM((TB, _T("Timer has %s been killed"), rc ? _T("") : _T(" NOT")));
  987. }
  988. else
  989. {
  990. TRC_NRM((TB, _T("Timer has not been set")));
  991. }
  992. DC_END_FN();
  993. } /* TDKillTimer */
  994. /****************************************************************************/
  995. // TDFlushSendQueue
  996. //
  997. // Tries to send all the packets which are waiting in the send queue.
  998. // Must be called on the sender thread, Can be called through direct calls
  999. // or through a CD_Decouple call.
  1000. /****************************************************************************/
  1001. void DCINTERNAL CTD::TDFlushSendQueue(ULONG_PTR unused)
  1002. {
  1003. DCUINT bytesSent;
  1004. PTD_SNDBUF_INFO pOldBuf;
  1005. int bytesToSend;
  1006. DCBOOL sentABuffer = FALSE;
  1007. int WSAErr;
  1008. DC_BEGIN_FN("TDFlushSendQueue");
  1009. DC_IGNORE_PARAMETER(unused);
  1010. // Check for rare re-entrancy.
  1011. if (!_TD.inFlushSendQueue) {
  1012. _TD.inFlushSendQueue = TRUE;
  1013. // Check that there are some buffers waiting to be sent.
  1014. if (_TD.pFQBuf != NULL) {
  1015. // Run along the send queue and try to send the data.
  1016. // Check for buffers that are inUse because ClearSendQueue could
  1017. // potentially clear some buffers before this call comes in
  1018. //
  1019. while (NULL != _TD.pFQBuf &&
  1020. _TD.pFQBuf->inUse) {
  1021. // Check that the buffer is in use and that the count of
  1022. // bytes waiting to be sent is more than zero.
  1023. TRC_ASSERT((_TD.pFQBuf->inUse), (TB, _T("Buffer is not in use")));
  1024. TRC_ASSERT((_TD.pFQBuf->bytesLeftToSend > 0),
  1025. (TB, _T("No bytes waiting to be sent")));
  1026. // Trace out the send buffer information.
  1027. TD_TRACE_SENDINFO(TRC_LEVEL_DBG);
  1028. TRC_DBG((TB, _T("Sending buffer:%p (waiting:%u)"),
  1029. _TD.pFQBuf,
  1030. _TD.pFQBuf->bytesLeftToSend));
  1031. // Call WinSock to send the buffer. We expect the call to:
  1032. // - succeed and send all the bytes requested. In this case
  1033. // there is little for us to do.
  1034. // - send some of the bytes we asked to be sent. This
  1035. // indicates that WinSock is applying back-pressure to us,
  1036. // so we update our count of bytes sent for this buffer
  1037. // and then quit. We will get a FD_WRITE later and retry
  1038. // the send.
  1039. // - send none of the bytes that we asked to be sent and
  1040. // return SOCKET_ERROR instead. We then use
  1041. // WSAGetLastError to determine why the call failed. If
  1042. // the reason is WSAEWOULDBLOCK then WinSock has decided
  1043. // to fail the call due to back-pressure - this is fine
  1044. // by us, so we just quit. Once again we will get an
  1045. // FD_WRITE to tell us that back-pressure has been
  1046. // relieved. Any other reason code is a genuine error
  1047. // so we decouple a call into the state table with an
  1048. // error code.
  1049. #ifdef DC_DEBUG
  1050. // Calculate how many bytes we can send and then decrement
  1051. // the count of bytes left to send in this period.
  1052. if (0 == _TD.hThroughputTimer) {
  1053. bytesToSend = (int)_TD.pFQBuf->bytesLeftToSend;
  1054. }
  1055. else {
  1056. bytesToSend = (int) DC_MIN(_TD.pFQBuf->bytesLeftToSend,
  1057. _TD.periodSendBytesLeft);
  1058. TRC_DBG((TB, _T("periodSendBytesLeft:%u"),
  1059. _TD.periodSendBytesLeft));
  1060. if (0 == bytesToSend) {
  1061. TRC_ALT((TB, _T("Constrained SEND network throughput")));
  1062. }
  1063. _TD.periodSendBytesLeft -= bytesToSend;
  1064. }
  1065. #else
  1066. bytesToSend = (int)_TD.pFQBuf->bytesLeftToSend;
  1067. #endif
  1068. bytesSent = (DCUINT)send(_TD.hSocket,
  1069. (char *)_TD.pFQBuf->pDataLeftToSend, bytesToSend, 0);
  1070. if (SOCKET_ERROR != bytesSent) {
  1071. TRC_DBG((TB, _T("Sent %u bytes of %u waiting"), bytesSent,
  1072. _TD.pFQBuf->bytesLeftToSend));
  1073. // Update the performance counter.
  1074. PRF_ADD_COUNTER(PERF_BYTES_SENT, bytesSent);
  1075. // Update the count of bytesWaiting and shuffle the
  1076. // pointer to the data along as well.
  1077. _TD.pFQBuf->pDataLeftToSend += bytesSent;
  1078. _TD.pFQBuf->bytesLeftToSend -= bytesSent;
  1079. // Check to determine if we managed to send all the data.
  1080. if (_TD.pFQBuf->bytesLeftToSend == 0) {
  1081. // We managed to send all the data in this buffer -
  1082. // so it is no longer in use. Get a pointer to this
  1083. // buffer.
  1084. pOldBuf = _TD.pFQBuf;
  1085. // Now update the head of the send queue with the
  1086. // next buffer and reset the next field of the buffer
  1087. // we've just sent.
  1088. _TD.pFQBuf = pOldBuf->pNext;
  1089. // Finally update the fields in the old buffer.
  1090. pOldBuf->pNext = NULL;
  1091. pOldBuf->inUse = FALSE;
  1092. pOldBuf->pDataLeftToSend = NULL;
  1093. sentABuffer = TRUE;
  1094. // Update the performance counter.
  1095. PRF_INC_COUNTER(PERF_PKTS_FREED);
  1096. TRC_DBG((TB, _T("Sent buffer completely - move to next")));
  1097. }
  1098. else {
  1099. // We didn't manage to send all the data so trace and
  1100. // quit.
  1101. TRC_NRM((TB, _T("Didn't send all data in buffer - quit")));
  1102. DC_QUIT;
  1103. }
  1104. }
  1105. else {
  1106. WSAErr = WSAGetLastError();
  1107. if (WSAErr == WSAEWOULDBLOCK || WSAErr == WSAENOBUFS) {
  1108. // WSAEWOULDBLOCK means that the network system is out
  1109. // of buffer space so we should wait until we receive
  1110. // a FD_WRITE notification indicating that more buffer
  1111. // space is available.
  1112. //
  1113. // WSAENOBUFS means that no buffer space is available
  1114. // and indicates a shortage of resources on the
  1115. // system.
  1116. bytesSent = 0;
  1117. PRF_INC_COUNTER(PERF_WINSOCK_SEND_FAIL);
  1118. TRC_NRM((TB, _T("WinSock send returns WSAEWOULDBLOCK")));
  1119. // We haven't sent any data, time to get out.
  1120. DC_QUIT;
  1121. }
  1122. else {
  1123. bytesSent = 0;
  1124. // If this is not a WSAEWOULDBLOCK and it is not a
  1125. // WSAENOBUFS error then call the FSM to begin
  1126. // disconnect processing.
  1127. // Trace out the buffer structure.
  1128. TD_TRACE_SENDINFO(TRC_LEVEL_ALT);
  1129. // We failed to send any data and the socket returned
  1130. // an error. The connection has probably failed or
  1131. // ended.
  1132. TRC_ALT((TB, _T("Failed to send any data, rc:%d"),
  1133. WSAErr));
  1134. // Decouple across to the recv side event handler at
  1135. // this point. It will call the TD FSM.
  1136. _pCd->CD_DecoupleSimpleNotification(CD_RCV_COMPONENT, this,
  1137. CD_NOTIFICATION_FUNC(CTD,TDSendError), 0);
  1138. DC_QUIT;
  1139. }
  1140. }
  1141. }
  1142. }
  1143. else {
  1144. TRC_NRM((TB, _T("No buffers waiting to be sent")));
  1145. }
  1146. }
  1147. else {
  1148. TRC_ABORT((TB, _T("Re-entered TDFlushSendQueue")));
  1149. goto RealExit;
  1150. }
  1151. DC_EXIT_POINT:
  1152. _TD.inFlushSendQueue = FALSE;
  1153. // If we previously failed TD_GetPublicBuffer, and we just
  1154. // succeeded in sending a buffer, call the OnBufferAvailable
  1155. // callbacks now.
  1156. TRC_DBG((TB, _T("Sent a buffer? %d, GetBuffer failed? %d"),
  1157. sentABuffer, _TD.getBufferFailed));
  1158. if (sentABuffer && _TD.getBufferFailed) {
  1159. TRC_NRM((TB, _T("Signal buffer available")));
  1160. _pXt->XT_OnTDBufferAvailable();
  1161. _TD.getBufferFailed = FALSE;
  1162. }
  1163. RealExit:
  1164. DC_END_FN();
  1165. } /* TDFlushSendQueue */