913 lines
26 KiB
C++
913 lines
26 KiB
C++
#include "precomp.h"
|
|
DEBUG_FILEZONE(ZONE_T120_MSMCSTCP);
|
|
/*
|
|
* tptif.cpp
|
|
*
|
|
* Copyright (c) 1996-1997 by Microsoft Corporation, Redmond, WA
|
|
*
|
|
* Abstract:
|
|
* This is the implementation module for the TCP TransportInterface class.
|
|
* It implements the Win32 TCP transport stack.
|
|
* This file contains all of the public functions needed to use
|
|
* the TCP stack.
|
|
*
|
|
* It uses owner callbacks to forward transport events upward to interested
|
|
* parties. It has one default callback to handle
|
|
* events for unregistered transport connections (such as incoming connect
|
|
* indications). It also maintains an array of callbacks so that events
|
|
* for a particular transport connection can be routed appropriately.
|
|
*
|
|
* X.214 INTERFACE
|
|
*
|
|
* You will notice that many of the entry points to this DLL were taken
|
|
* from the X.214 service definition. These entry points are consistent
|
|
* with the DataBeam Transport DLLs. This gives the user application
|
|
* a consistent interface.
|
|
*
|
|
* Protected Instance Variables:
|
|
* m_TrnsprtConnCallbackList2
|
|
* This is the dictionary containg the addresses of the callbacks for
|
|
* each transport connection.
|
|
*
|
|
* Private Member Functions:
|
|
* CreateConnectionCallback
|
|
* This function creates a new entry in the callback list.
|
|
* ConnectIndication
|
|
* Handles TRANSPORT_CONNECT_INDICATION messages from the transport
|
|
* layer.
|
|
* ConnectConfirm
|
|
* Handles TRANSPORT_CONNECT_CONFIRM messages from the transport
|
|
* layer.
|
|
* DisconnectIndication
|
|
* Handles TRANSPORT_DISCONNECT_INDICATION messages from the transport
|
|
* layer.
|
|
* DataIndication
|
|
* Handles TRANSPORT_DATA_INDICATION messages from the transport
|
|
* layer.
|
|
*
|
|
* Global Variables:
|
|
*
|
|
* Transport - Address of this object (used by tprtctrl.cpp)
|
|
* g_pSocketList - List of all active connection structures.
|
|
* Listen_Socket - The listening socket number.
|
|
*
|
|
* Caveats:
|
|
* This code is NOT portable. It is very specific to the Windows
|
|
* operating system.
|
|
*
|
|
* Author:
|
|
* Christos Tsollis
|
|
*/
|
|
|
|
/*
|
|
* External Interfaces
|
|
*/
|
|
|
|
#include <tprtntfy.h>
|
|
#include "plgxprt.h"
|
|
#include <service.h>
|
|
|
|
/* This is the number of the buckets for the socket dictionary */
|
|
#define NUMBER_OF_SOCKET_BUCKETS 8
|
|
|
|
PTransportInterface g_Transport = NULL;
|
|
CSocketList *g_pSocketList = NULL; // key=socket_number, data=pSocket
|
|
SOCKET Listen_Socket = INVALID_SOCKET;
|
|
|
|
// The external MCS Controller object
|
|
extern PController g_pMCSController;
|
|
extern CPluggableTransport *g_pPluggableTransport;
|
|
extern BOOL g_bRDS;
|
|
|
|
/*
|
|
* TransportInterface ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the class constructor.
|
|
*
|
|
* Note that this version of the constructor is specific to 32-bit
|
|
* Windows.
|
|
*/
|
|
TransportInterface::TransportInterface (
|
|
HANDLE transport_transmit_event,
|
|
PTransportInterfaceError transport_interface_error) :
|
|
Transport_Transmit_Event (transport_transmit_event),
|
|
m_TrnsprtConnCallbackList2()
|
|
{
|
|
TransportInterfaceError tcp_error = TRANSPORT_INTERFACE_NO_ERROR;
|
|
//WORD version_requested;
|
|
//int error;
|
|
WSADATA wsa_data;
|
|
|
|
TRACE_OUT(("TCP Initialization..."));
|
|
|
|
ASSERT(NULL == g_pSocketList);
|
|
DBG_SAVE_FILE_LINE
|
|
g_pSocketList = new CSocketList(NUMBER_OF_SOCKET_BUCKETS);
|
|
if (g_pSocketList == NULL)
|
|
{
|
|
WARNING_OUT (("TransportInterface::TransportInterface: Unable to allocate socket dictionary."));
|
|
tcp_error = TRANSPORT_INTERFACE_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
if (tcp_error == TRANSPORT_INTERFACE_NO_ERROR) {
|
|
/* WSAStartup() must be called to initialize WinSock */
|
|
WORD version_requested = MAKEWORD (1,1);
|
|
int error = WSAStartup (version_requested, &wsa_data);
|
|
ASSERT(error == 0);
|
|
if (error) {
|
|
WARNING_OUT (("ThreadFunction: WSAStartup returned error %d", error));
|
|
tcp_error = TRANSPORT_INTERFACE_INITIALIZATION_FAILED;
|
|
}
|
|
else {
|
|
/* Print out the developer of this version of WinSock */
|
|
TRACE_OUT (("TransportInterface::TransportInterface: WinSock implementation by %s", &wsa_data.szDescription));
|
|
}
|
|
}
|
|
|
|
//
|
|
// ALWAYS initialize security
|
|
//
|
|
DBG_SAVE_FILE_LINE
|
|
pSecurityInterface = new SecurityInterface();
|
|
|
|
if ( TPRTSEC_NOERROR != pSecurityInterface->Initialize())
|
|
{
|
|
WARNING_OUT(("Creating security interface failed!"));
|
|
delete pSecurityInterface;
|
|
pSecurityInterface = NULL;
|
|
}
|
|
|
|
/* Initialize the listen socket. This socket will wait for incoming calls */
|
|
if (tcp_error == TRANSPORT_INTERFACE_NO_ERROR) {
|
|
|
|
// Listen on standard socket
|
|
Listen_Socket = CreateAndConfigureListenSocket();
|
|
|
|
if ( INVALID_SOCKET == Listen_Socket ) {
|
|
ERROR_OUT(("TransportInterface::TransportInterface: Error - could not initialize listen socket"));
|
|
tcp_error = TRANSPORT_INTERFACE_INITIALIZATION_FAILED;
|
|
}
|
|
}
|
|
|
|
*transport_interface_error = tcp_error;
|
|
}
|
|
|
|
|
|
void CloseListenSocket(void)
|
|
{
|
|
if (Listen_Socket != INVALID_SOCKET)
|
|
{
|
|
TransportConnection XprtConn;
|
|
SET_SOCKET_CONNECTION(XprtConn, Listen_Socket);
|
|
::freeListenSocket(XprtConn);
|
|
Listen_Socket = INVALID_SOCKET;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ~TransportInterface ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the class destructor. It unloads the DLL (if necessary).
|
|
*/
|
|
TransportInterface::~TransportInterface ()
|
|
{
|
|
PSocket pSocket;
|
|
|
|
TRACE_OUT (("Cleaning up the TCP transport..."));
|
|
|
|
/* Delete all of the Logical Connection Structures */
|
|
if (g_pSocketList != NULL)
|
|
{
|
|
::EnterCriticalSection(&g_csTransport);
|
|
CSocketList Connection_List_Copy (*g_pSocketList);
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
|
|
while (NULL != (pSocket = Connection_List_Copy.Get()))
|
|
{
|
|
// LONCHANC: cannot remove pSocket out of the list now
|
|
// because DisconnectRequest() uses it.
|
|
|
|
/* Disconnect, trash packets, and delete the first connection in the list */
|
|
::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_NONE);
|
|
}
|
|
|
|
::EnterCriticalSection(&g_csTransport);
|
|
delete g_pSocketList;
|
|
g_pSocketList = NULL;
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
}
|
|
|
|
/* Close the listening socket */
|
|
::CloseListenSocket();
|
|
|
|
delete pSecurityInterface;
|
|
|
|
/* Force Winsock to cleanup immediately */
|
|
WSACleanup();
|
|
|
|
TRACE_OUT (("TCP Transport has been cleaned up."));
|
|
|
|
}
|
|
|
|
/*
|
|
* TransportInterfaceError RegisterTransportConnection ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This member function is used to register a callback for a particular
|
|
* transport connection. This will usually be done for incoming
|
|
* connections, when you know the transport connection handle BEFORE
|
|
* registering the callback.
|
|
*/
|
|
TransportInterfaceError TransportInterface::RegisterTransportConnection (
|
|
TransportConnection XprtConn,
|
|
PConnection owner_object,
|
|
BOOL bNoNagle)
|
|
{
|
|
TransportInterfaceError return_value;
|
|
|
|
/*
|
|
* Check to see if the transport connection in question exists. If
|
|
* it does, then remove it and add it again with the new owner.
|
|
* If not, fail the call.
|
|
*/
|
|
if (m_TrnsprtConnCallbackList2.RemoveEx(XprtConn))
|
|
{
|
|
/*
|
|
* Get the address of the associated connection callback structure.
|
|
* Then put the new callback information into it.
|
|
*/
|
|
TRACE_OUT (("TransportInterface::RegisterTransportConnection: "
|
|
"registering new owner"));
|
|
|
|
m_TrnsprtConnCallbackList2.AppendEx(owner_object ? owner_object : (PConnection) LPVOID_NULL, XprtConn);
|
|
|
|
if (IS_SOCKET(XprtConn))
|
|
{
|
|
if (bNoNagle)
|
|
{
|
|
// We need to disable the Nagle algorithm
|
|
TRACE_OUT(("TransportInterface::RegisterTransportConnection: disabling Nagle for socket (%d, %d)",
|
|
XprtConn.eType, XprtConn.nLogicalHandle));
|
|
::setsockopt(XprtConn.nLogicalHandle, IPPROTO_TCP, TCP_NODELAY,
|
|
(const char *) &bNoNagle, sizeof(BOOL));
|
|
}
|
|
}
|
|
return_value = TRANSPORT_INTERFACE_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* There is no entry in the callback list for the specified transport
|
|
* connection. Since this function is only used to replace callback
|
|
* information for existing connections, it is necessary to fail the
|
|
* request.
|
|
*/
|
|
WARNING_OUT (("TransportInterface::RegisterTransportConnection: "
|
|
"no such connection"));
|
|
return_value = TRANSPORT_INTERFACE_NO_SUCH_CONNECTION;
|
|
}
|
|
|
|
return (return_value);
|
|
}
|
|
|
|
#ifdef NM_RESET_DEVICE
|
|
/*
|
|
* TransportError ResetDevice ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This member function merely makes the call to the transport DLL if the
|
|
* library was successfully loaded.
|
|
*/
|
|
TransportError TransportInterface::ResetDevice (
|
|
PChar device_identifier)
|
|
{
|
|
PSocket pSocket;
|
|
PChar Remote_Address;
|
|
|
|
::EnterCriticalSection(&g_csTransport);
|
|
CSocketList Connection_List_Copy (*g_pSocketList);
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
|
|
while (NULL != (pSocket = Connection_List_Copy.Get()))
|
|
{
|
|
Remote_Address = pSocket->Remote_Address;
|
|
if(Remote_Address && (strcmp(Remote_Address, device_identifier) == 0))
|
|
{
|
|
::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_OTHER_REASON);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (TRANSPORT_NO_ERROR);
|
|
}
|
|
#endif // NM_RESET_DEVICE
|
|
|
|
/*
|
|
* TransportError ConnectRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* After checking to make sure that the library was loaded properly, this
|
|
* routine takes the steps required to create a new transport connection.
|
|
*/
|
|
TransportError TransportInterface::ConnectRequest (
|
|
TransportAddress transport_address,
|
|
BOOL fSecure,
|
|
BOOL bNoNagle,
|
|
PConnection owner_object,
|
|
PTransportConnection pXprtConn)
|
|
{
|
|
TransportError return_value;
|
|
TransportInterfaceError transport_interface_error;
|
|
|
|
TRACE_OUT (("TransportInterface::ConnectRequest"));
|
|
/*
|
|
* Issue a call to the Transport's ConnectRequest API routine. Note that
|
|
* this MUST be done first since one of the return values is the
|
|
* transport connection handle of the newly created connection.
|
|
* Also note that this is a non-blocking call, so what we have done
|
|
* is begun the process of forming a connection. The connection
|
|
* cannot be used until a connect confirm is received.
|
|
*/
|
|
return_value = ::ConnectRequest(transport_address, fSecure, pXprtConn);
|
|
|
|
if (return_value == TRANSPORT_NO_ERROR) {
|
|
/*
|
|
* If the call to create the connection was successful, then
|
|
* put a new entry into the callback list. This entry will
|
|
* contain the callback information provided as parameters to
|
|
* this routine.
|
|
*/
|
|
transport_interface_error = CreateConnectionCallback (
|
|
*pXprtConn, owner_object);
|
|
if (IS_SOCKET(*pXprtConn))
|
|
{
|
|
if (bNoNagle)
|
|
{
|
|
// We need to disable the Nagle algorithm
|
|
TRACE_OUT(("TransportInterface::ConnectRequest: disabling Nagle for socket (%d, %d)",
|
|
pXprtConn->eType, pXprtConn->nLogicalHandle));
|
|
::setsockopt(pXprtConn->nLogicalHandle, IPPROTO_TCP, TCP_NODELAY,
|
|
(const char *) &bNoNagle, sizeof(BOOL));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS ==
|
|
transport_interface_error) {
|
|
/*
|
|
* The transport connection handle returned from the
|
|
* transport layer is the same as one we already have
|
|
* listed. We will therefore terminate the existing
|
|
* connection (since its integrity appears to have been
|
|
* compromised). We will also fail this request.
|
|
*/
|
|
WARNING_OUT (("DLLTransportInterface::ConnectRequest: "
|
|
"ERROR - duplicate connections"));
|
|
|
|
// This should NOT be happenning!!!
|
|
ASSERT (FALSE);
|
|
|
|
}
|
|
else {
|
|
/*
|
|
* Everything worked fine, so do nothing.
|
|
*/
|
|
TRACE_OUT (("DLLTransportInterface::ConnectRequest: "
|
|
"callback added to list"));
|
|
}
|
|
#endif // DEBUG
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The call to TConnectRequest failed. Report it and let the
|
|
* error fall through.
|
|
*/
|
|
WARNING_OUT (("DLLTransportInterface::ConnectRequest: "
|
|
"TConnectRequest failed"));
|
|
}
|
|
|
|
return (return_value);
|
|
}
|
|
|
|
/*
|
|
* void DisconnectRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This member function is called to break an existing transport
|
|
* connection. After checking to make sure that the transport connection
|
|
* is valid, it passes the call onto the DLL and removes the transport
|
|
* connection from the local callback list.
|
|
*/
|
|
void TransportInterface::DisconnectRequest (TransportConnection transport_connection)
|
|
{
|
|
TRACE_OUT (("TransportInterface::DisconnectRequest"));
|
|
|
|
if (m_TrnsprtConnCallbackList2.RemoveEx(transport_connection))
|
|
{
|
|
::DisconnectRequest (transport_connection, TPRT_NOTIFY_NONE);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT (("DLLTransportInterface::DisconnectRequest: the specified connection can not be found"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* BOOL GetSecurity ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
*/
|
|
BOOL TransportInterface::GetSecurity (TransportConnection XprtConn)
|
|
{
|
|
PSocket pSocket;
|
|
|
|
if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn)))
|
|
{
|
|
BOOL fRet = (pSocket->pSC != NULL);
|
|
pSocket->Release();
|
|
return fRet;
|
|
}
|
|
ERROR_OUT(("GetSecurity: could not find socket"));
|
|
return FALSE; // Err on the safe side
|
|
}
|
|
|
|
/*
|
|
* Void ReceiveBufferAvailable ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
*/
|
|
Void TransportInterface::ReceiveBufferAvailable ()
|
|
{
|
|
TRACE_OUT(("TransportInterface::ReceiveBufferAvailable"));
|
|
|
|
// Reset the controller's wait info
|
|
g_pMCSController->HandleTransportWaitUpdateIndication(FALSE);
|
|
|
|
TReceiveBufferAvailable();
|
|
|
|
// Poll all the transport connections
|
|
EnableReceiver ();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Void ConnectIndication ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function handles the reception of a connect indication from the
|
|
* transport layer. Normally this involves putting a new entry in the
|
|
* callback list, and forwarding the connect indication to the default
|
|
* owner object.
|
|
*
|
|
* Formal Parameters:
|
|
* transport_identifier (i)
|
|
* This is a pointer to a structure that contains information about
|
|
* the new connection. This includes: the logical handle of the new
|
|
* connection; and the handle of the physical connection which will
|
|
* carry the new connection.
|
|
*
|
|
* Return Value:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*/
|
|
Void TransportInterface::ConnectIndication (
|
|
TransportConnection transport_connection)
|
|
{
|
|
TransportInterfaceError transport_interface_error;
|
|
PConnection pConnection;
|
|
|
|
/*
|
|
* Put the new connection into the callback list.
|
|
*/
|
|
transport_interface_error = CreateConnectionCallback (transport_connection,
|
|
NULL);
|
|
|
|
switch (transport_interface_error)
|
|
{
|
|
case TRANSPORT_INTERFACE_NO_ERROR:
|
|
/*
|
|
* Everything worked fine, so do forward the indication to the
|
|
* default owner object.
|
|
*/
|
|
TRACE_OUT (("DLLTransportInterface::ConnectIndication: "
|
|
"calling ConnectResponse."));
|
|
::ConnectResponse (transport_connection);
|
|
break;
|
|
|
|
case TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS:
|
|
/*
|
|
* The transport connection handle sent by the transport layer is
|
|
* the same as one we already have listed. We will therefore
|
|
* terminate the existing connection (since its integrity appears
|
|
* to have been compromised).
|
|
*/
|
|
WARNING_OUT (("DLLTransportInterface::ConnectIndication: "
|
|
"ERROR - duplicate connections. Connection: %d", transport_connection));
|
|
::DisconnectRequest (transport_connection, TPRT_NOTIFY_NONE);
|
|
|
|
/*
|
|
* Get the callback information for the previously existing
|
|
* connection. Then delete it.
|
|
*/
|
|
if (NULL != (pConnection = m_TrnsprtConnCallbackList2.RemoveEx(transport_connection)))
|
|
{
|
|
if (LPVOID_NULL != (LPVOID) pConnection)
|
|
{
|
|
/*
|
|
* Let the former owner of the connection know that it has been
|
|
* terminated.
|
|
*/
|
|
ULONG ulReason = TPRT_NOTIFY_NONE;
|
|
pConnection->HandleDisconnectIndication(transport_connection, &ulReason);
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("TransportInterface::ConnectIndication: null pConnection"));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void ConnectConfirm ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function handles the reception of a connect confirm frmo the
|
|
* transport layer. Assuming that the connect confirm is the result of
|
|
* a previously outstanding connect request. everything will be processed
|
|
* normally, and the confirm will forwarded to the object that originated
|
|
* the request.
|
|
*
|
|
* Formal Parameters:
|
|
* transport_identifier (i)
|
|
* This is a pointer to a structure that contains information about
|
|
* the connection being confirmed. This includes: the logical handle
|
|
* of the connection; and the handle of the physical connection which
|
|
* is carrying the connection.
|
|
*
|
|
* Return Value:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*/
|
|
Void TransportInterface::ConnectConfirm (
|
|
TransportConnection transport_connection)
|
|
{
|
|
PConnection connection;
|
|
|
|
/*
|
|
* Since a connect confirm should only result from an earlier connect
|
|
* request, the transport connection handle SHOULD already be in the
|
|
* callback list. If it is, then process this confirm normally.
|
|
*/
|
|
if (NULL != (connection = m_TrnsprtConnCallbackList2.FindEx(transport_connection)))
|
|
{
|
|
/*
|
|
* Get the address of the callback structure from the Connection List.
|
|
* Then invoke the callback, passing the message and parameter to it.
|
|
*/
|
|
TRACE_OUT (("DLLTransportInterface::ConnectConfirm: forwarding CONNECT_CONFIRM"));
|
|
|
|
if (LPVOID_NULL != (LPVOID) connection)
|
|
{
|
|
// The owner is a Connection object.
|
|
connection->HandleConnectConfirm(transport_connection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This transport connection handle is invalid. It is therefore
|
|
* necessary to terminate the connection, and otherwise ignore the
|
|
* confirm.
|
|
*/
|
|
WARNING_OUT (("DLLTransportInterface::ConnectConfirm: "
|
|
"terminating unknown connection %d", transport_connection));
|
|
// ::DisconnectRequest (transport_connection, TPRT_NOTIFY_NONE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void DisconnectIndication ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function handles the reception of a disconnect indication from the
|
|
* transport layer. If the specified transport connection exists, it will
|
|
* be removed, and the object that owns it will be informed of the loss.
|
|
*
|
|
* Formal Parameters:
|
|
* transport_identifier (i)
|
|
* This is a pointer to a structure that contains information about
|
|
* the connection being disconnected. This includes: the logical
|
|
* handle of the connection; and the handle of the physical connection
|
|
* which carried the connection.
|
|
*
|
|
* Return Value:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*/
|
|
Void TransportInterface::DisconnectIndication (
|
|
TransportConnection transport_connection,
|
|
ULONG ulReason)
|
|
{
|
|
PConnection connection;
|
|
|
|
/*
|
|
* It should only be possible to receive a disconnect on a transport
|
|
* connection that we already know about. Therefore, the transport
|
|
* connection handle SHOULD already be in the list. Check this.
|
|
*/
|
|
if (NULL != (connection = m_TrnsprtConnCallbackList2.RemoveEx(transport_connection)))
|
|
{
|
|
/*
|
|
* Get the address of the callback structure from the callback list.
|
|
* Then delete it from the list.
|
|
*/
|
|
TRACE_OUT (("DLLTransportInterface::DisconnectIndication: "
|
|
"forwarding DISCONNECT_INDICATION"));
|
|
|
|
if (LPVOID_NULL != (LPVOID) connection)
|
|
{
|
|
// The owner is a Connection object.
|
|
connection->HandleDisconnectIndication(transport_connection, &ulReason);
|
|
}
|
|
else
|
|
{
|
|
// The owner is the MCS Controller
|
|
g_pMCSController->HandleTransportDisconnectIndication(transport_connection, &ulReason);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We have received a disconnect indication on an unknown transport
|
|
* connection. Ignore it.
|
|
*/
|
|
WARNING_OUT (("DLLTransportInterface::DisconnectIndication: "
|
|
"disconnect on unknown connection"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* TransportError DataIndication ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function handles the reception of a data indication from the
|
|
* transport layer. If the transport connection is properly registered,
|
|
* the data will be forwarded to the object that owns the connection.
|
|
*
|
|
* Formal Parameters:
|
|
* transport_data (i)
|
|
* This is the address of a structure that contains information about
|
|
* the data in the indication. This includes what transport
|
|
* connection the data was received on, as well as the address and
|
|
* length of the data itself.
|
|
*
|
|
* Return Value:
|
|
* TRANSPORT_NO_ERROR
|
|
* This indicates that the data was processed.
|
|
* TRANSPORT_READ_QUEUE_FULL
|
|
* This means that the transport layer should try resending the data
|
|
* during the next heartbeat.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*/
|
|
TransportError TransportInterface::DataIndication (PTransportData transport_data)
|
|
{
|
|
PConnection connection;
|
|
TransportError return_value = TRANSPORT_NO_ERROR;
|
|
|
|
/*
|
|
* If the transport connection is in the callback list, then send the
|
|
* data to the registered callback. If it is not in the Connection
|
|
* List, then ignore the data (we have nowhere to send it).
|
|
*/
|
|
if (NULL != (connection = m_TrnsprtConnCallbackList2.FindEx(transport_data->transport_connection)))
|
|
{
|
|
if (LPVOID_NULL != (LPVOID) connection)
|
|
{
|
|
// The owner is a Connection object.
|
|
return_value = connection->HandleDataIndication(transport_data,
|
|
transport_data->transport_connection);
|
|
}
|
|
else
|
|
{
|
|
// The owner is the MCS Controller
|
|
g_pMCSController->HandleTransportDataIndication(transport_data);
|
|
}
|
|
|
|
/*
|
|
* If we fail to deliver the data indication, we need to set the amount
|
|
* of data available to be received and notify the controller to
|
|
* retry the operation later.
|
|
*/
|
|
if (TRANSPORT_NO_ERROR != return_value)
|
|
{
|
|
g_pMCSController->HandleTransportWaitUpdateIndication(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We have received data on an unknown transport connection.
|
|
* Ignore the indication.
|
|
*/
|
|
WARNING_OUT (("TransportInterface::DataIndication: data on unknown connection"));
|
|
return_value = TRANSPORT_NO_SUCH_CONNECTION;
|
|
}
|
|
|
|
return (return_value);
|
|
}
|
|
|
|
/*
|
|
* Void BufferEmptyIndication ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function handles the reception of a buffer-empty indication from the
|
|
* transport layer. If the specified transport connection exists, the object
|
|
* that owns it will be notified that it can proceed sending data on the
|
|
* transport connection.
|
|
*
|
|
* Formal Parameters:
|
|
* transport_identifier (i)
|
|
* This is a pointer to a structure that contains information about
|
|
* the connection. This includes: the logical
|
|
* handle of the connection; and the handle of the physical connection
|
|
* which carried the connection.
|
|
*
|
|
* Return Value:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*/
|
|
Void TransportInterface::BufferEmptyIndication (
|
|
TransportConnection transport_connection)
|
|
{
|
|
PConnection connection;
|
|
|
|
/*
|
|
* It should only be possible to receive a disconnect on a transport
|
|
* connection that we already know about. Therefore, the transport
|
|
* connection handle SHOULD already be in the list. Check this.
|
|
*/
|
|
if (NULL != (connection = m_TrnsprtConnCallbackList2.FindEx(transport_connection)))
|
|
{
|
|
/*
|
|
* Get the address of the callback structure from the callback list.
|
|
* Then delete it from the list.
|
|
*/
|
|
TRACE_OUT(("DLLTransportInterface::BufferEmptyIndication: "
|
|
"forwarding BUFFER_EMPTY_INDICATION"));
|
|
|
|
/*
|
|
* Forward the disconnect indication to the owner of this transport
|
|
* connection.
|
|
*/
|
|
if (LPVOID_NULL != (LPVOID) connection)
|
|
{
|
|
connection->HandleBufferEmptyIndication(transport_connection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We have received a buffer empty indication on an unknown transport
|
|
* connection. Ignore it.
|
|
*/
|
|
TRACE_OUT (("TransportInterface::BufferEmptyIndication: "
|
|
"indication on unknown connection"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* TransportInterfaceError CreateConnectionCallback ()
|
|
*
|
|
* Protected
|
|
*
|
|
* Functional Description:
|
|
* This private member function is used to create new entries in the
|
|
* callback list. Each entry consists of a pointer to a structure that
|
|
* contains the address of the object that "owns" the transport connection,
|
|
* as well as the message index to be used for the owner callbacks.
|
|
*
|
|
* This routine allocates the memory used to hold the callback information,
|
|
* and puts it in the callback list if everything is successful.
|
|
*
|
|
* Formal Parameters:
|
|
* transport_connection (i)
|
|
* This is the transport connection for which the callback information
|
|
* is to be associated.
|
|
* owner_object (i)
|
|
* This is the address of the object that is to receive all transport
|
|
* layer events for the specified transport connection.
|
|
*
|
|
* Return Value:
|
|
* TRANSPORT_INTERFACE_NO_ERROR
|
|
* The operation completed successfully.
|
|
* TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS
|
|
* This value indicates that the request was unsuccessful because the
|
|
* specified transport connection already exists in the callback list
|
|
* (it is an error to try and create an entry for the same transport
|
|
* connection more than once).
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*/
|
|
TransportInterfaceError TransportInterface::CreateConnectionCallback (
|
|
TransportConnection transport_connection,
|
|
PConnection owner_object)
|
|
{
|
|
TransportInterfaceError return_value;
|
|
|
|
/*
|
|
* See if there is already an entry in the callback list for the specified
|
|
* transport connection. If there is, then abort this request before
|
|
* doing anything.
|
|
*/
|
|
if (m_TrnsprtConnCallbackList2.FindEx(transport_connection) == FALSE)
|
|
{
|
|
/*
|
|
* Put the callback information into the newly allocated
|
|
* structure. Then put the structure into the callback list.
|
|
*/
|
|
TRACE_OUT (("TransportInterface::CreateConnectionCallback: "
|
|
"adding new callback object"));
|
|
|
|
m_TrnsprtConnCallbackList2.AppendEx(owner_object ? owner_object : (PConnection) LPVOID_NULL, transport_connection);
|
|
|
|
return_value = TRANSPORT_INTERFACE_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* There is already an entry in the callback list for the specified
|
|
* transport connection. It is therefore necessary to fail this
|
|
* request.
|
|
*/
|
|
WARNING_OUT (("TransportInterface::CreateConnectionCallback: "
|
|
"callback already exists"));
|
|
return_value = TRANSPORT_INTERFACE_CONNECTION_ALREADY_EXISTS;
|
|
}
|
|
|
|
return (return_value);
|
|
}
|
|
|
|
|