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.

912 lines
26 KiB

  1. #include "precomp.h"
  2. DEBUG_FILEZONE(ZONE_T120_MSMCSTCP);
  3. /*
  4. * tptif.cpp
  5. *
  6. * Copyright (c) 1996-1997 by Microsoft Corporation, Redmond, WA
  7. *
  8. * Abstract:
  9. * This is the implementation module for the TCP TransportInterface class.
  10. * It implements the Win32 TCP transport stack.
  11. * This file contains all of the public functions needed to use
  12. * the TCP stack.
  13. *
  14. * It uses owner callbacks to forward transport events upward to interested
  15. * parties. It has one default callback to handle
  16. * events for unregistered transport connections (such as incoming connect
  17. * indications). It also maintains an array of callbacks so that events
  18. * for a particular transport connection can be routed appropriately.
  19. *
  20. * X.214 INTERFACE
  21. *
  22. * You will notice that many of the entry points to this DLL were taken
  23. * from the X.214 service definition. These entry points are consistent
  24. * with the DataBeam Transport DLLs. This gives the user application
  25. * a consistent interface.
  26. *
  27. * Protected Instance Variables:
  28. * m_TrnsprtConnCallbackList2
  29. * This is the dictionary containg the addresses of the callbacks for
  30. * each transport connection.
  31. *
  32. * Private Member Functions:
  33. * CreateConnectionCallback
  34. * This function creates a new entry in the callback list.
  35. * ConnectIndication
  36. * Handles TRANSPORT_CONNECT_INDICATION messages from the transport
  37. * layer.
  38. * ConnectConfirm
  39. * Handles TRANSPORT_CONNECT_CONFIRM messages from the transport
  40. * layer.
  41. * DisconnectIndication
  42. * Handles TRANSPORT_DISCONNECT_INDICATION messages from the transport
  43. * layer.
  44. * DataIndication
  45. * Handles TRANSPORT_DATA_INDICATION messages from the transport
  46. * layer.
  47. *
  48. * Global Variables:
  49. *
  50. * Transport - Address of this object (used by tprtctrl.cpp)
  51. * g_pSocketList - List of all active connection structures.
  52. * Listen_Socket - The listening socket number.
  53. *
  54. * Caveats:
  55. * This code is NOT portable. It is very specific to the Windows
  56. * operating system.
  57. *
  58. * Author:
  59. * Christos Tsollis
  60. */
  61. /*
  62. * External Interfaces
  63. */
  64. #include <tprtntfy.h>
  65. #include "plgxprt.h"
  66. #include <service.h>
  67. /* This is the number of the buckets for the socket dictionary */
  68. #define NUMBER_OF_SOCKET_BUCKETS 8
  69. PTransportInterface g_Transport = NULL;
  70. CSocketList *g_pSocketList = NULL; // key=socket_number, data=pSocket
  71. SOCKET Listen_Socket = INVALID_SOCKET;
  72. // The external MCS Controller object
  73. extern PController g_pMCSController;
  74. extern CPluggableTransport *g_pPluggableTransport;
  75. extern BOOL g_bRDS;
  76. /*
  77. * TransportInterface ()
  78. *
  79. * Public
  80. *
  81. * Functional Description:
  82. * This is the class constructor.
  83. *
  84. * Note that this version of the constructor is specific to 32-bit
  85. * Windows.
  86. */
  87. TransportInterface::TransportInterface (
  88. HANDLE transport_transmit_event,
  89. PTransportInterfaceError transport_interface_error) :
  90. Transport_Transmit_Event (transport_transmit_event),
  91. m_TrnsprtConnCallbackList2()
  92. {
  93. TransportInterfaceError tcp_error = TRANSPORT_INTERFACE_NO_ERROR;
  94. //WORD version_requested;
  95. //int error;
  96. WSADATA wsa_data;
  97. TRACE_OUT(("TCP Initialization..."));
  98. ASSERT(NULL == g_pSocketList);
  99. DBG_SAVE_FILE_LINE
  100. g_pSocketList = new CSocketList(NUMBER_OF_SOCKET_BUCKETS);
  101. if (g_pSocketList == NULL)
  102. {
  103. WARNING_OUT (("TransportInterface::TransportInterface: Unable to allocate socket dictionary."));
  104. tcp_error = TRANSPORT_INTERFACE_INITIALIZATION_FAILED;
  105. }
  106. if (tcp_error == TRANSPORT_INTERFACE_NO_ERROR) {
  107. /* WSAStartup() must be called to initialize WinSock */
  108. WORD version_requested = MAKEWORD (1,1);
  109. int error = WSAStartup (version_requested, &wsa_data);
  110. ASSERT(error == 0);
  111. if (error) {
  112. WARNING_OUT (("ThreadFunction: WSAStartup returned error %d", error));
  113. tcp_error = TRANSPORT_INTERFACE_INITIALIZATION_FAILED;
  114. }
  115. else {
  116. /* Print out the developer of this version of WinSock */
  117. TRACE_OUT (("TransportInterface::TransportInterface: WinSock implementation by %s", &wsa_data.szDescription));
  118. }
  119. }
  120. //
  121. // ALWAYS initialize security
  122. //
  123. DBG_SAVE_FILE_LINE
  124. pSecurityInterface = new SecurityInterface();
  125. if ( TPRTSEC_NOERROR != pSecurityInterface->Initialize())
  126. {
  127. WARNING_OUT(("Creating security interface failed!"));
  128. delete pSecurityInterface;
  129. pSecurityInterface = NULL;
  130. }
  131. /* Initialize the listen socket. This socket will wait for incoming calls */
  132. if (tcp_error == TRANSPORT_INTERFACE_NO_ERROR) {
  133. // Listen on standard socket
  134. Listen_Socket = CreateAndConfigureListenSocket();
  135. if ( INVALID_SOCKET == Listen_Socket ) {
  136. ERROR_OUT(("TransportInterface::TransportInterface: Error - could not initialize listen socket"));
  137. tcp_error = TRANSPORT_INTERFACE_INITIALIZATION_FAILED;
  138. }
  139. }
  140. *transport_interface_error = tcp_error;
  141. }
  142. void CloseListenSocket(void)
  143. {
  144. if (Listen_Socket != INVALID_SOCKET)
  145. {
  146. TransportConnection XprtConn;
  147. SET_SOCKET_CONNECTION(XprtConn, Listen_Socket);
  148. ::freeListenSocket(XprtConn);
  149. Listen_Socket = INVALID_SOCKET;
  150. }
  151. }
  152. /*
  153. * ~TransportInterface ()
  154. *
  155. * Public
  156. *
  157. * Functional Description:
  158. * This is the class destructor. It unloads the DLL (if necessary).
  159. */
  160. TransportInterface::~TransportInterface ()
  161. {
  162. PSocket pSocket;
  163. TRACE_OUT (("Cleaning up the TCP transport..."));
  164. /* Delete all of the Logical Connection Structures */
  165. if (g_pSocketList != NULL)
  166. {
  167. ::EnterCriticalSection(&g_csTransport);
  168. CSocketList Connection_List_Copy (*g_pSocketList);
  169. ::LeaveCriticalSection(&g_csTransport);
  170. while (NULL != (pSocket = Connection_List_Copy.Get()))
  171. {
  172. // LONCHANC: cannot remove pSocket out of the list now
  173. // because DisconnectRequest() uses it.
  174. /* Disconnect, trash packets, and delete the first connection in the list */
  175. ::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_NONE);
  176. }
  177. ::EnterCriticalSection(&g_csTransport);
  178. delete g_pSocketList;
  179. g_pSocketList = NULL;
  180. ::LeaveCriticalSection(&g_csTransport);
  181. }
  182. /* Close the listening socket */
  183. ::CloseListenSocket();
  184. delete pSecurityInterface;
  185. /* Force Winsock to cleanup immediately */
  186. WSACleanup();
  187. TRACE_OUT (("TCP Transport has been cleaned up."));
  188. }
  189. /*
  190. * TransportInterfaceError RegisterTransportConnection ()
  191. *
  192. * Public
  193. *
  194. * Functional Description:
  195. * This member function is used to register a callback for a particular
  196. * transport connection. This will usually be done for incoming
  197. * connections, when you know the transport connection handle BEFORE
  198. * registering the callback.
  199. */
  200. TransportInterfaceError TransportInterface::RegisterTransportConnection (
  201. TransportConnection XprtConn,
  202. PConnection owner_object,
  203. BOOL bNoNagle)
  204. {
  205. TransportInterfaceError return_value;
  206. /*
  207. * Check to see if the transport connection in question exists. If
  208. * it does, then remove it and add it again with the new owner.
  209. * If not, fail the call.
  210. */
  211. if (m_TrnsprtConnCallbackList2.RemoveEx(XprtConn))
  212. {
  213. /*
  214. * Get the address of the associated connection callback structure.
  215. * Then put the new callback information into it.
  216. */
  217. TRACE_OUT (("TransportInterface::RegisterTransportConnection: "
  218. "registering new owner"));
  219. m_TrnsprtConnCallbackList2.AppendEx(owner_object ? owner_object : (PConnection) LPVOID_NULL, XprtConn);
  220. if (IS_SOCKET(XprtConn))
  221. {
  222. if (bNoNagle)
  223. {
  224. // We need to disable the Nagle algorithm
  225. TRACE_OUT(("TransportInterface::RegisterTransportConnection: disabling Nagle for socket (%d, %d)",
  226. XprtConn.eType, XprtConn.nLogicalHandle));
  227. ::setsockopt(XprtConn.nLogicalHandle, IPPROTO_TCP, TCP_NODELAY,
  228. (const char *) &bNoNagle, sizeof(BOOL));
  229. }
  230. }
  231. return_value = TRANSPORT_INTERFACE_NO_ERROR;
  232. }
  233. else
  234. {
  235. /*
  236. * There is no entry in the callback list for the specified transport
  237. * connection. Since this function is only used to replace callback
  238. * information for existing connections, it is necessary to fail the
  239. * request.
  240. */
  241. WARNING_OUT (("TransportInterface::RegisterTransportConnection: "
  242. "no such connection"));
  243. return_value = TRANSPORT_INTERFACE_NO_SUCH_CONNECTION;
  244. }
  245. return (return_value);
  246. }
  247. #ifdef NM_RESET_DEVICE
  248. /*
  249. * TransportError ResetDevice ()
  250. *
  251. * Public
  252. *
  253. * Functional Description:
  254. * This member function merely makes the call to the transport DLL if the
  255. * library was successfully loaded.
  256. */
  257. TransportError TransportInterface::ResetDevice (
  258. PChar device_identifier)
  259. {
  260. PSocket pSocket;
  261. PChar Remote_Address;
  262. ::EnterCriticalSection(&g_csTransport);
  263. CSocketList Connection_List_Copy (*g_pSocketList);
  264. ::LeaveCriticalSection(&g_csTransport);
  265. while (NULL != (pSocket = Connection_List_Copy.Get()))
  266. {
  267. Remote_Address = pSocket->Remote_Address;
  268. if(Remote_Address && (strcmp(Remote_Address, device_identifier) == 0))
  269. {
  270. ::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_OTHER_REASON);
  271. break;
  272. }
  273. }
  274. return (TRANSPORT_NO_ERROR);
  275. }
  276. #endif // NM_RESET_DEVICE
  277. /*
  278. * TransportError ConnectRequest ()
  279. *
  280. * Public
  281. *
  282. * Functional Description:
  283. * After checking to make sure that the library was loaded properly, this
  284. * routine takes the steps required to create a new transport connection.
  285. */
  286. TransportError TransportInterface::ConnectRequest (
  287. TransportAddress transport_address,
  288. BOOL fSecure,
  289. BOOL bNoNagle,
  290. PConnection owner_object,
  291. PTransportConnection pXprtConn)
  292. {
  293. TransportError return_value;
  294. TransportInterfaceError transport_interface_error;
  295. TRACE_OUT (("TransportInterface::ConnectRequest"));
  296. /*
  297. * Issue a call to the Transport's ConnectRequest API routine. Note that
  298. * this MUST be done first since one of the return values is the
  299. * transport connection handle of the newly created connection.
  300. * Also note that this is a non-blocking call, so what we have done
  301. * is begun the process of forming a connection. The connection
  302. * cannot be used until a connect confirm is received.
  303. */
  304. return_value = ::ConnectRequest(transport_address, fSecure, pXprtConn);
  305. if (return_value == TRANSPORT_NO_ERROR) {
  306. /*
  307. * If the call to create the connection was successful, then
  308. * put a new entry into the callback list. This entry will
  309. * contain the callback information provided as parameters to
  310. * this routine.
  311. */
  312. transport_interface_error = CreateConnectionCallback (
  313. *pXprtConn, owner_object);
  314. if (IS_SOCKET(*pXprtConn))
  315. {
  316. if (bNoNagle)
  317. {
  318. // We need to disable the Nagle algorithm
  319. TRACE_OUT(("TransportInterface::ConnectRequest: disabling Nagle for socket (%d, %d)",
  320. pXprtConn->eType, pXprtConn->nLogicalHandle));
  321. ::setsockopt(pXprtConn->nLogicalHandle, IPPROTO_TCP, TCP_NODELAY,
  322. (const char *) &bNoNagle, sizeof(BOOL));
  323. }
  324. #ifdef DEBUG
  325. if (TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS ==
  326. transport_interface_error) {
  327. /*
  328. * The transport connection handle returned from the
  329. * transport layer is the same as one we already have
  330. * listed. We will therefore terminate the existing
  331. * connection (since its integrity appears to have been
  332. * compromised). We will also fail this request.
  333. */
  334. WARNING_OUT (("DLLTransportInterface::ConnectRequest: "
  335. "ERROR - duplicate connections"));
  336. // This should NOT be happenning!!!
  337. ASSERT (FALSE);
  338. }
  339. else {
  340. /*
  341. * Everything worked fine, so do nothing.
  342. */
  343. TRACE_OUT (("DLLTransportInterface::ConnectRequest: "
  344. "callback added to list"));
  345. }
  346. #endif // DEBUG
  347. }
  348. }
  349. else
  350. {
  351. /*
  352. * The call to TConnectRequest failed. Report it and let the
  353. * error fall through.
  354. */
  355. WARNING_OUT (("DLLTransportInterface::ConnectRequest: "
  356. "TConnectRequest failed"));
  357. }
  358. return (return_value);
  359. }
  360. /*
  361. * void DisconnectRequest ()
  362. *
  363. * Public
  364. *
  365. * Functional Description:
  366. * This member function is called to break an existing transport
  367. * connection. After checking to make sure that the transport connection
  368. * is valid, it passes the call onto the DLL and removes the transport
  369. * connection from the local callback list.
  370. */
  371. void TransportInterface::DisconnectRequest (TransportConnection transport_connection)
  372. {
  373. TRACE_OUT (("TransportInterface::DisconnectRequest"));
  374. if (m_TrnsprtConnCallbackList2.RemoveEx(transport_connection))
  375. {
  376. ::DisconnectRequest (transport_connection, TPRT_NOTIFY_NONE);
  377. }
  378. else
  379. {
  380. TRACE_OUT (("DLLTransportInterface::DisconnectRequest: the specified connection can not be found"));
  381. }
  382. }
  383. /*
  384. * BOOL GetSecurity ()
  385. *
  386. * Public
  387. *
  388. * Functional Description:
  389. */
  390. BOOL TransportInterface::GetSecurity (TransportConnection XprtConn)
  391. {
  392. PSocket pSocket;
  393. if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn)))
  394. {
  395. BOOL fRet = (pSocket->pSC != NULL);
  396. pSocket->Release();
  397. return fRet;
  398. }
  399. ERROR_OUT(("GetSecurity: could not find socket"));
  400. return FALSE; // Err on the safe side
  401. }
  402. /*
  403. * Void ReceiveBufferAvailable ()
  404. *
  405. * Public
  406. *
  407. * Functional Description:
  408. */
  409. Void TransportInterface::ReceiveBufferAvailable ()
  410. {
  411. TRACE_OUT(("TransportInterface::ReceiveBufferAvailable"));
  412. // Reset the controller's wait info
  413. g_pMCSController->HandleTransportWaitUpdateIndication(FALSE);
  414. TReceiveBufferAvailable();
  415. // Poll all the transport connections
  416. EnableReceiver ();
  417. }
  418. /*
  419. * Void ConnectIndication ()
  420. *
  421. * Private
  422. *
  423. * Functional Description:
  424. * This function handles the reception of a connect indication from the
  425. * transport layer. Normally this involves putting a new entry in the
  426. * callback list, and forwarding the connect indication to the default
  427. * owner object.
  428. *
  429. * Formal Parameters:
  430. * transport_identifier (i)
  431. * This is a pointer to a structure that contains information about
  432. * the new connection. This includes: the logical handle of the new
  433. * connection; and the handle of the physical connection which will
  434. * carry the new connection.
  435. *
  436. * Return Value:
  437. * None.
  438. *
  439. * Side Effects:
  440. * None.
  441. *
  442. * Caveats:
  443. * None.
  444. */
  445. Void TransportInterface::ConnectIndication (
  446. TransportConnection transport_connection)
  447. {
  448. TransportInterfaceError transport_interface_error;
  449. PConnection pConnection;
  450. /*
  451. * Put the new connection into the callback list.
  452. */
  453. transport_interface_error = CreateConnectionCallback (transport_connection,
  454. NULL);
  455. switch (transport_interface_error)
  456. {
  457. case TRANSPORT_INTERFACE_NO_ERROR:
  458. /*
  459. * Everything worked fine, so do forward the indication to the
  460. * default owner object.
  461. */
  462. TRACE_OUT (("DLLTransportInterface::ConnectIndication: "
  463. "calling ConnectResponse."));
  464. ::ConnectResponse (transport_connection);
  465. break;
  466. case TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS:
  467. /*
  468. * The transport connection handle sent by the transport layer is
  469. * the same as one we already have listed. We will therefore
  470. * terminate the existing connection (since its integrity appears
  471. * to have been compromised).
  472. */
  473. WARNING_OUT (("DLLTransportInterface::ConnectIndication: "
  474. "ERROR - duplicate connections. Connection: %d", transport_connection));
  475. ::DisconnectRequest (transport_connection, TPRT_NOTIFY_NONE);
  476. /*
  477. * Get the callback information for the previously existing
  478. * connection. Then delete it.
  479. */
  480. if (NULL != (pConnection = m_TrnsprtConnCallbackList2.RemoveEx(transport_connection)))
  481. {
  482. if (LPVOID_NULL != (LPVOID) pConnection)
  483. {
  484. /*
  485. * Let the former owner of the connection know that it has been
  486. * terminated.
  487. */
  488. ULONG ulReason = TPRT_NOTIFY_NONE;
  489. pConnection->HandleDisconnectIndication(transport_connection, &ulReason);
  490. }
  491. else
  492. {
  493. ERROR_OUT(("TransportInterface::ConnectIndication: null pConnection"));
  494. }
  495. }
  496. break;
  497. }
  498. }
  499. /*
  500. * Void ConnectConfirm ()
  501. *
  502. * Private
  503. *
  504. * Functional Description:
  505. * This function handles the reception of a connect confirm frmo the
  506. * transport layer. Assuming that the connect confirm is the result of
  507. * a previously outstanding connect request. everything will be processed
  508. * normally, and the confirm will forwarded to the object that originated
  509. * the request.
  510. *
  511. * Formal Parameters:
  512. * transport_identifier (i)
  513. * This is a pointer to a structure that contains information about
  514. * the connection being confirmed. This includes: the logical handle
  515. * of the connection; and the handle of the physical connection which
  516. * is carrying the connection.
  517. *
  518. * Return Value:
  519. * None.
  520. *
  521. * Side Effects:
  522. * None.
  523. *
  524. * Caveats:
  525. * None.
  526. */
  527. Void TransportInterface::ConnectConfirm (
  528. TransportConnection transport_connection)
  529. {
  530. PConnection connection;
  531. /*
  532. * Since a connect confirm should only result from an earlier connect
  533. * request, the transport connection handle SHOULD already be in the
  534. * callback list. If it is, then process this confirm normally.
  535. */
  536. if (NULL != (connection = m_TrnsprtConnCallbackList2.FindEx(transport_connection)))
  537. {
  538. /*
  539. * Get the address of the callback structure from the Connection List.
  540. * Then invoke the callback, passing the message and parameter to it.
  541. */
  542. TRACE_OUT (("DLLTransportInterface::ConnectConfirm: forwarding CONNECT_CONFIRM"));
  543. if (LPVOID_NULL != (LPVOID) connection)
  544. {
  545. // The owner is a Connection object.
  546. connection->HandleConnectConfirm(transport_connection);
  547. }
  548. }
  549. else
  550. {
  551. /*
  552. * This transport connection handle is invalid. It is therefore
  553. * necessary to terminate the connection, and otherwise ignore the
  554. * confirm.
  555. */
  556. WARNING_OUT (("DLLTransportInterface::ConnectConfirm: "
  557. "terminating unknown connection %d", transport_connection));
  558. // ::DisconnectRequest (transport_connection, TPRT_NOTIFY_NONE);
  559. }
  560. }
  561. /*
  562. * Void DisconnectIndication ()
  563. *
  564. * Private
  565. *
  566. * Functional Description:
  567. * This function handles the reception of a disconnect indication from the
  568. * transport layer. If the specified transport connection exists, it will
  569. * be removed, and the object that owns it will be informed of the loss.
  570. *
  571. * Formal Parameters:
  572. * transport_identifier (i)
  573. * This is a pointer to a structure that contains information about
  574. * the connection being disconnected. This includes: the logical
  575. * handle of the connection; and the handle of the physical connection
  576. * which carried the connection.
  577. *
  578. * Return Value:
  579. * None.
  580. *
  581. * Side Effects:
  582. * None.
  583. *
  584. * Caveats:
  585. * None.
  586. */
  587. Void TransportInterface::DisconnectIndication (
  588. TransportConnection transport_connection,
  589. ULONG ulReason)
  590. {
  591. PConnection connection;
  592. /*
  593. * It should only be possible to receive a disconnect on a transport
  594. * connection that we already know about. Therefore, the transport
  595. * connection handle SHOULD already be in the list. Check this.
  596. */
  597. if (NULL != (connection = m_TrnsprtConnCallbackList2.RemoveEx(transport_connection)))
  598. {
  599. /*
  600. * Get the address of the callback structure from the callback list.
  601. * Then delete it from the list.
  602. */
  603. TRACE_OUT (("DLLTransportInterface::DisconnectIndication: "
  604. "forwarding DISCONNECT_INDICATION"));
  605. if (LPVOID_NULL != (LPVOID) connection)
  606. {
  607. // The owner is a Connection object.
  608. connection->HandleDisconnectIndication(transport_connection, &ulReason);
  609. }
  610. else
  611. {
  612. // The owner is the MCS Controller
  613. g_pMCSController->HandleTransportDisconnectIndication(transport_connection, &ulReason);
  614. }
  615. }
  616. else
  617. {
  618. /*
  619. * We have received a disconnect indication on an unknown transport
  620. * connection. Ignore it.
  621. */
  622. WARNING_OUT (("DLLTransportInterface::DisconnectIndication: "
  623. "disconnect on unknown connection"));
  624. }
  625. }
  626. /*
  627. * TransportError DataIndication ()
  628. *
  629. * Private
  630. *
  631. * Functional Description:
  632. * This function handles the reception of a data indication from the
  633. * transport layer. If the transport connection is properly registered,
  634. * the data will be forwarded to the object that owns the connection.
  635. *
  636. * Formal Parameters:
  637. * transport_data (i)
  638. * This is the address of a structure that contains information about
  639. * the data in the indication. This includes what transport
  640. * connection the data was received on, as well as the address and
  641. * length of the data itself.
  642. *
  643. * Return Value:
  644. * TRANSPORT_NO_ERROR
  645. * This indicates that the data was processed.
  646. * TRANSPORT_READ_QUEUE_FULL
  647. * This means that the transport layer should try resending the data
  648. * during the next heartbeat.
  649. *
  650. * Side Effects:
  651. * None.
  652. *
  653. * Caveats:
  654. * None.
  655. */
  656. TransportError TransportInterface::DataIndication (PTransportData transport_data)
  657. {
  658. PConnection connection;
  659. TransportError return_value = TRANSPORT_NO_ERROR;
  660. /*
  661. * If the transport connection is in the callback list, then send the
  662. * data to the registered callback. If it is not in the Connection
  663. * List, then ignore the data (we have nowhere to send it).
  664. */
  665. if (NULL != (connection = m_TrnsprtConnCallbackList2.FindEx(transport_data->transport_connection)))
  666. {
  667. if (LPVOID_NULL != (LPVOID) connection)
  668. {
  669. // The owner is a Connection object.
  670. return_value = connection->HandleDataIndication(transport_data,
  671. transport_data->transport_connection);
  672. }
  673. else
  674. {
  675. // The owner is the MCS Controller
  676. g_pMCSController->HandleTransportDataIndication(transport_data);
  677. }
  678. /*
  679. * If we fail to deliver the data indication, we need to set the amount
  680. * of data available to be received and notify the controller to
  681. * retry the operation later.
  682. */
  683. if (TRANSPORT_NO_ERROR != return_value)
  684. {
  685. g_pMCSController->HandleTransportWaitUpdateIndication(TRUE);
  686. }
  687. }
  688. else
  689. {
  690. /*
  691. * We have received data on an unknown transport connection.
  692. * Ignore the indication.
  693. */
  694. WARNING_OUT (("TransportInterface::DataIndication: data on unknown connection"));
  695. return_value = TRANSPORT_NO_SUCH_CONNECTION;
  696. }
  697. return (return_value);
  698. }
  699. /*
  700. * Void BufferEmptyIndication ()
  701. *
  702. * Private
  703. *
  704. * Functional Description:
  705. * This function handles the reception of a buffer-empty indication from the
  706. * transport layer. If the specified transport connection exists, the object
  707. * that owns it will be notified that it can proceed sending data on the
  708. * transport connection.
  709. *
  710. * Formal Parameters:
  711. * transport_identifier (i)
  712. * This is a pointer to a structure that contains information about
  713. * the connection. This includes: the logical
  714. * handle of the connection; and the handle of the physical connection
  715. * which carried the connection.
  716. *
  717. * Return Value:
  718. * None.
  719. *
  720. * Side Effects:
  721. * None.
  722. *
  723. * Caveats:
  724. * None.
  725. */
  726. Void TransportInterface::BufferEmptyIndication (
  727. TransportConnection transport_connection)
  728. {
  729. PConnection connection;
  730. /*
  731. * It should only be possible to receive a disconnect on a transport
  732. * connection that we already know about. Therefore, the transport
  733. * connection handle SHOULD already be in the list. Check this.
  734. */
  735. if (NULL != (connection = m_TrnsprtConnCallbackList2.FindEx(transport_connection)))
  736. {
  737. /*
  738. * Get the address of the callback structure from the callback list.
  739. * Then delete it from the list.
  740. */
  741. TRACE_OUT(("DLLTransportInterface::BufferEmptyIndication: "
  742. "forwarding BUFFER_EMPTY_INDICATION"));
  743. /*
  744. * Forward the disconnect indication to the owner of this transport
  745. * connection.
  746. */
  747. if (LPVOID_NULL != (LPVOID) connection)
  748. {
  749. connection->HandleBufferEmptyIndication(transport_connection);
  750. }
  751. }
  752. else
  753. {
  754. /*
  755. * We have received a buffer empty indication on an unknown transport
  756. * connection. Ignore it.
  757. */
  758. TRACE_OUT (("TransportInterface::BufferEmptyIndication: "
  759. "indication on unknown connection"));
  760. }
  761. }
  762. /*
  763. * TransportInterfaceError CreateConnectionCallback ()
  764. *
  765. * Protected
  766. *
  767. * Functional Description:
  768. * This private member function is used to create new entries in the
  769. * callback list. Each entry consists of a pointer to a structure that
  770. * contains the address of the object that "owns" the transport connection,
  771. * as well as the message index to be used for the owner callbacks.
  772. *
  773. * This routine allocates the memory used to hold the callback information,
  774. * and puts it in the callback list if everything is successful.
  775. *
  776. * Formal Parameters:
  777. * transport_connection (i)
  778. * This is the transport connection for which the callback information
  779. * is to be associated.
  780. * owner_object (i)
  781. * This is the address of the object that is to receive all transport
  782. * layer events for the specified transport connection.
  783. *
  784. * Return Value:
  785. * TRANSPORT_INTERFACE_NO_ERROR
  786. * The operation completed successfully.
  787. * TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS
  788. * This value indicates that the request was unsuccessful because the
  789. * specified transport connection already exists in the callback list
  790. * (it is an error to try and create an entry for the same transport
  791. * connection more than once).
  792. *
  793. * Side Effects:
  794. * None.
  795. *
  796. * Caveats:
  797. * None.
  798. */
  799. TransportInterfaceError TransportInterface::CreateConnectionCallback (
  800. TransportConnection transport_connection,
  801. PConnection owner_object)
  802. {
  803. TransportInterfaceError return_value;
  804. /*
  805. * See if there is already an entry in the callback list for the specified
  806. * transport connection. If there is, then abort this request before
  807. * doing anything.
  808. */
  809. if (m_TrnsprtConnCallbackList2.FindEx(transport_connection) == FALSE)
  810. {
  811. /*
  812. * Put the callback information into the newly allocated
  813. * structure. Then put the structure into the callback list.
  814. */
  815. TRACE_OUT (("TransportInterface::CreateConnectionCallback: "
  816. "adding new callback object"));
  817. m_TrnsprtConnCallbackList2.AppendEx(owner_object ? owner_object : (PConnection) LPVOID_NULL, transport_connection);
  818. return_value = TRANSPORT_INTERFACE_NO_ERROR;
  819. }
  820. else
  821. {
  822. /*
  823. * There is already an entry in the callback list for the specified
  824. * transport connection. It is therefore necessary to fail this
  825. * request.
  826. */
  827. WARNING_OUT (("TransportInterface::CreateConnectionCallback: "
  828. "callback already exists"));
  829. return_value = TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS;
  830. }
  831. return (return_value);
  832. }