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.

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