|
|
#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_MSMCSTCP);
#include "tprtsec.h"
#include <tprtntfy.h>
#include "cnpcoder.h"
#include "plgxprt.h"
// #undef TRACE_OUT
// #define TRACE_OUT WARNING_OUT
/* Tprtctrl.cpp
* * Copyright (c) 1996 by Microsoft Corporation * * Abstract: * This module maintains the TCP transport and all connections. * */
/* External definitions */ extern HINSTANCE g_hDllInst; extern PTransportInterface g_Transport; extern SOCKET Listen_Socket; extern SOCKET Listen_Socket_Secure; extern CPluggableTransport *g_pPluggableTransport;
extern PController g_pMCSController; extern CCNPCoder *g_CNPCoder; extern HWND TCP_Window_Handle; extern BOOL g_bRDS;
BOOL FindSocketNumber(DWORD dwGCCID, SOCKET * socket_number);
/*
* The following array contains a template for the X.224 data header. * The 5 of the 7 bytes that it initializes are actually sent to the * wire. Bytes 3 and 4 will be set to contain the size of the PDU. * The array is only used when we encode a data PDU. */ extern UChar g_X224Header[];
// The external MCS Controller object
extern PController g_pMCSController;
// plugable transport prototypes
int X224Recv(PSocket pSocket, LPBYTE buffer, int length, PLUGXPRT_RESULT *pnLastError); int Q922Recv(PSocket pSocket, LPBYTE buffer, int length, PLUGXPRT_RESULT *pnLastError);
/*
* TransportError ConnectRequest ( TransportAddress transport_address, * BOOL fSecure * PTransportConnection pXprtConn) * * Functional Description: * This function initiates a connection. It passes the transport address * to the TCP transport. It will either deny the request or accept the * request and call us back when the physical connection is established. * * We return the transport connection handle in the transport_connection * address. Although we return this transport number to the user, it * is not ready for data transfer until the user receives the * TRANSPORT_CONNECT_INDICATION and responds with a ConnectResponse() call. * At that point, the transport connection is up and running. */ TransportError ConnectRequest (TransportAddress transport_address, BOOL fSecure, /* out */ PTransportConnection pXprtConn) { TransportError rc = TRANSPORT_NO_ERROR; PSocket pSocket; PSecurityContext pSC = NULL; ULong address; SOCKADDR_IN sin; CPluggableConnection *p = NULL;
// initialize transport connection
UINT nPluggableConnID = ::GetPluggableTransportConnID(transport_address); if (nPluggableConnID) { p = ::GetPluggableConnection(nPluggableConnID); if (NULL != p) { pXprtConn->eType = p->GetType(); pXprtConn->nLogicalHandle = nPluggableConnID; ASSERT(IS_PLUGGABLE(*pXprtConn)); } else { return TRANSPORT_NO_SUCH_CONNECTION; } } else { pXprtConn->eType = TRANSPORT_TYPE_WINSOCK; pXprtConn->nLogicalHandle = INVALID_SOCKET; }
// we are connecting X224...
::OnProtocolControl(*pXprtConn, PLUGXPRT_CONNECTING);
// Try to prepare a security context object if we're told to do so.
if ( fSecure ) { // If we're trying to connect securely but can't, fail
if ( NULL == g_Transport->pSecurityInterface ) { WARNING_OUT(("Placing secure call failed: no valid security interface")); return TRANSPORT_SECURITY_FAILED; }
DBG_SAVE_FILE_LINE if (NULL != (pSC = new SecurityContext(g_Transport->pSecurityInterface, transport_address))) { if ( TPRTSEC_NOERROR != pSC->Initialize(NULL,0)) { // If we can't init a security context, fail
delete pSC; pSC = NULL; WARNING_OUT(("Placing secure call failed: could not initialize security context")); return TRANSPORT_SECURITY_FAILED; } } }
/* Create and Initialize the Socket object */ pSocket = newSocket(*pXprtConn, pSC); if( pSocket == NULL ) return (TRANSPORT_MEMORY_FAILURE);
pSocket->SecState = ( NULL == pSC ) ? SC_NONSECURE : SC_SECURE;
if (IS_SOCKET(*pXprtConn)) { //
// LAURABU SALEM BUGBUG
// Change this to allow initializer to pass in the outbound
// port!
//
u_short uPort = DEFAULT_LISTEN_PORT; TCHAR szAddress[MAXIMUM_IP_ADDRESS_SIZE]; lstrcpyn(szAddress, transport_address, MAXIMUM_IP_ADDRESS_SIZE); LPTSTR pszSeparator = (LPTSTR)_StrChr(szAddress, _T(':')); if (NULL != pszSeparator) { uPort = (u_short)DecimalStringToUINT(CharNext(pszSeparator)); *pszSeparator = _T('\0'); }
/* Convert the ascii string into an Internet Address */ if ((address = inet_addr(szAddress)) == INADDR_NONE) { WARNING_OUT (("ConnectRequest: %s is an invalid host addr", szAddress)); rc = TRANSPORT_CONNECT_REQUEST_FAILED; goto Bail; }
lstrcpyn (pSocket->Remote_Address, transport_address, MAXIMUM_IP_ADDRESS_SIZE);
/*
* Load the socket control structure with the parameters necessary. * * - Internet socket * - Let it assign any address to this socket * - Assign our port number (depending on secure/nonsecure call!) */ sin.sin_family = AF_INET; sin.sin_addr.s_addr = address; sin.sin_port = htons (uPort);
/* Attempt a connection to the remote site */ TRACE_OUT (("ConnectRequest: Issuing connect: address = %s", transport_address)); if (::connect(pSocket->XprtConn.nLogicalHandle, (const struct sockaddr *) &sin, sizeof(sin)) == 0) { TRACE_OUT (("ConnectRequest: State = SOCKET_CONNECTED...")); /* Add socket to connection list */ // bugbug: we may fail to insert.
g_pSocketList->SafeAppend(pSocket); ::SendX224ConnectRequest(pSocket->XprtConn); } else if (WSAGetLastError() == WSAEWOULDBLOCK) { /* If the error message is WSAEWOULDBLOCK, we must wait for the FD_CONNECT. */ TRACE_OUT (("ConnectRequest: State = WAITING_FOR_CONNECTION...")); pSocket -> State = WAITING_FOR_CONNECTION; /* Add socket to connection list */ // bugbug: we may fail to insert.
g_pSocketList->SafeAppend(pSocket); // SendStatusMessage(pSocket -> Remote_Address, TSTATE_CONNECT_PENDING, IDS_NULL_STRING);
} else { WARNING_OUT (("ConnectRequest: Connect Failed error = %d",WSAGetLastError()));
/* The connect() call failed, close the socket and notify the owner */ // SendStatusMessage (pSocket -> Remote_Address, TSTATE_NOT_READY, IDS_NULL_STRING);
::ShutdownAndClose(pSocket->XprtConn, FALSE, 2); rc = TRANSPORT_CONNECT_REQUEST_FAILED; goto Bail; } } else { ASSERT(IS_PLUGGABLE(*pXprtConn)); g_pSocketList->SafeAppend(pSocket); if (IS_PLUGGABLE_X224(*pXprtConn)) { ::SendX224ConnectRequest(pSocket->XprtConn); } else if (IS_PLUGGABLE_PSTN(*pXprtConn)) { rc = p->TConnectRequest(); ASSERT(TRANSPORT_NO_ERROR == rc); } }
Bail:
ASSERT(NULL != pSocket); if (TRANSPORT_NO_ERROR == rc) { *pXprtConn = pSocket->XprtConn; } else { ::freeSocket(pSocket, *pXprtConn); }
return rc; }
/*
* BOOL ConnectResponse (TransportConnection XprtConn) * * Functional Description: * This function is called by the user in response to a * TRANSPORT_CONNECT_INDICATION callback from us. By making this call the * user is accepting the call. If the user does not want to accept the * call, he should call DisconnectRequest(); */ BOOL ConnectResponse (TransportConnection XprtConn) { PSocket pSocket;
TRACE_OUT (("ConnectResponse(%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle));
/* If this is an invalid handle, return error */ if(NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) { BOOL fRet; if (pSocket->State == SOCKET_CONNECTED) { /* We do not change this state in ANY other place BECAUSE it breaks the connect request*/ pSocket->State = X224_CONNECTED; fRet = TRUE; } else { ERROR_OUT(("ConnectResponse: Illegal ConnectResponse packet")); fRet = FALSE; } pSocket->Release(); return fRet; } return FALSE; }
#ifdef TSTATUS_INDICATION
/*
* Void SendStatusMessage ( PChar RemoteAddress, * TransportState State, * UInt message_id) * * Functional Description: * This function is called to send a status indication to the user. The * specific text of the message is contained in a string resource. */ Void SendStatusMessage( PChar RemoteAddress, TransportState state, UInt message_id) { TransportStatus transport_status; char sTransport[80] = ""; char message[80] = "";
if( message_id == IDS_NULL_STRING ) message[0] = '\000'; else LoadString( (HINSTANCE) g_hDllInst, (UINT) message_id, (LPSTR) message, (int) sizeof(message) );
/*
** We issue a callback to the user to notify him of the message */ transport_status.device_identifier = ""; transport_status.remote_address = RemoteAddress; transport_status.message = message; transport_status.state = state;
g_pMCSController->HandleTransportStatusIndication(&transport_status); } #endif
/*
* Void SendX224ConnectRequest(TransportConnection XprtConn) * * Functional Description: * This function is called upon receipt of the FD_CONNECT from Winsock. * It indicates that the physical connection is established, and sends * the X224 connection request packet. */ void SendX224ConnectRequest(TransportConnection XprtConn) { PSocket pSocket;
static X224_CR_FIXED cr_fixed = { { 3, 0, 0, UNK }, UNK, { CONNECTION_REQUEST_PACKET, UNK, UNK, UNK, UNK, 0 } // common info
};
TRACE_OUT(("SendX224ConnectRequest"));
CNPPDU cnp_pdu; ConnectRequestPDU_reliableSecurityProtocols_Element cnp_cr_rsp_element; LPBYTE pbToSendBuf = NULL; UINT cbToSendBuf = 0; LPBYTE encoded_pdu; UINT encoded_pdu_length;
TransportError error;
cnp_pdu.choice = connectRequest_chosen; cnp_pdu.u.connectRequest.bit_mask = 0; cnp_pdu.u.connectRequest.protocolIdentifier = t123AnnexBProtocolId; cnp_pdu.u.connectRequest.reconnectRequested = FALSE;
// Sanity check field sizes... these need to conform to protocol
ASSERT (sizeof(RFC_HEADER) == 4); ASSERT (sizeof(X224_DATA_PACKET) == 7); ASSERT (sizeof(X224_CONNECT_COMMON) == 6); ASSERT (sizeof(X224_TPDU_INFO) == 3);
/* If this is an invalid handle, return */ if (NULL == (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) return;
if (IS_SOCKET(pSocket->XprtConn)) { if (pSocket -> State != WAITING_FOR_CONNECTION) { ERROR_OUT (("SendX224ConnectRequest: Illegal Socket State")); goto MyExit; } } else { ASSERT(IS_PLUGGABLE(pSocket->XprtConn)); if (X224_CONNECTED == pSocket->State) { // after query remote, we need to reset the state back to socket connected
pSocket->State = SOCKET_CONNECTED; } if (SOCKET_CONNECTED != pSocket->State) { ERROR_OUT (("SendX224ConnectRequest: Illegal Socket State")); goto MyExit; } }
// If there is a security context associated with this socket, we
// are settting up for a secure call and will indicate that in the CNP
// portion of the packet
if (NULL != pSocket->pSC) { TRACE_OUT(("SendX224ConnectRequest: requesting secure connection"));
cnp_pdu.u.connectRequest.bit_mask |= reliableSecurityProtocols_present; cnp_cr_rsp_element.next = NULL; cnp_cr_rsp_element.value.choice = gssApiX224_chosen; cnp_pdu.u.connectRequest.reliableSecurityProtocols = &cnp_cr_rsp_element; } else { TRACE_OUT(("SendX224ConnectRequest: requesting NON-secure connection")); }
if (! g_CNPCoder->Encode((LPVOID) &cnp_pdu, CNPPDU_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("SendX224ConnectRequest: Can't encode cnp pdu")); goto MyExit; }
pSocket -> State = SOCKET_CONNECTED;
/* X224 header */ cr_fixed.conn.msbSrc = (UChar) (XprtConn.nLogicalHandle >> 8); cr_fixed.conn.lsbSrc = (UChar) XprtConn.nLogicalHandle;
cbToSendBuf = sizeof(X224_CR_FIXED)+sizeof(X224_TPDU_INFO)+sizeof(X224_VARIABLE_INFO)+encoded_pdu_length; cr_fixed.rfc.lsbPacketSize = (UChar)cbToSendBuf; cr_fixed.HeaderSize = (UChar)(sizeof(X224_CONNECT_COMMON)+sizeof(X224_TPDU_INFO)+sizeof(X224_VARIABLE_INFO)+encoded_pdu_length); ASSERT ( cbToSendBuf <= 128); DBG_SAVE_FILE_LINE pbToSendBuf = new BYTE[cbToSendBuf]; if (NULL == pbToSendBuf) { ERROR_OUT(("SendX224ConnectRequest: failed to allocate memory")); goto MyExit; }
{ LPBYTE pbTemp = pbToSendBuf; memcpy(pbTemp, (LPBYTE) &cr_fixed, sizeof(cr_fixed)); pbTemp += sizeof(cr_fixed);
{ X224_TPDU_INFO x224_tpdu_info = { TPDU_SIZE, 1, DEFAULT_TPDU_SIZE }; memcpy(pbTemp, (LPBYTE) &x224_tpdu_info, sizeof(x224_tpdu_info)); pbTemp += sizeof(x224_tpdu_info); }
{ X224_VARIABLE_INFO x224_var_info = { T_SELECTOR, (UChar)encoded_pdu_length }; memcpy(pbTemp, (LPBYTE) &x224_var_info, sizeof(x224_var_info)); // bug: error handling
pbTemp += sizeof(x224_var_info); memcpy(pbTemp, encoded_pdu, encoded_pdu_length); } }
g_CNPCoder->FreeEncoded(encoded_pdu);
/* Attempt to send data out the socket */ error = FlushSendBuffer(pSocket, pbToSendBuf, cbToSendBuf); ASSERT (TRANSPORT_NO_ERROR == error);
delete [] pbToSendBuf;
MyExit:
pSocket->Release(); }
/*
* Void SendX224ConnectConfirm (PSocket pSocket, unsigned int remote) * * Functional Description: * This function is called upon receipt of the X224 connection request * packet. It indicates that the remote side wants to establish a * logical connection, and sends the X224 connection response packet. * * Return value: * TRUE, if everything went ok. * FALSE, otherwise (this implies a Disconnect will be issued for the socket). */ // LONCHANC: "remote" is from the X.224 ConnectRequest
BOOL SendX224ConnectConfirm (PSocket pSocket, unsigned int remote) { //PUChar ptr;
LPBYTE pbToSendBuf = NULL; UINT cbToSendBuf = 0; LPBYTE encoded_pdu = NULL; UINT encoded_pdu_length = 0; CNPPDU cnp_pdu; BOOL fAcceptSecure = FALSE; BOOL fRequireSecure = FALSE;
TRACE_OUT(("SendX224ConnectConfirm"));
fAcceptSecure = TRUE;
static X224_CC_FIXED cc_fixed = { { 3, 0, 0, UNK }, // RFC1006 header
UNK, { CONNECTION_CONFIRM_PACKET, UNK, UNK, UNK, UNK, 0 } // common info
};
// Sanity check field sizes... these need to conform to protocol
ASSERT (sizeof(RFC_HEADER) == 4); ASSERT (sizeof(X224_DATA_PACKET) == 7); ASSERT (sizeof(X224_CONNECT_COMMON) == 6); ASSERT (sizeof(X224_TPDU_INFO) == 3);
/* X224 header */ cc_fixed.conn.msbDest = (UChar) (remote >> 8); cc_fixed.conn.lsbDest = (UChar) remote; cc_fixed.conn.msbSrc = (UChar) (pSocket->XprtConn.nLogicalHandle >> 8); cc_fixed.conn.lsbSrc = (UChar) pSocket->XprtConn.nLogicalHandle;
cnp_pdu.choice = connectConfirm_chosen; cnp_pdu.u.connectConfirm.bit_mask = 0; cnp_pdu.u.connectConfirm.protocolIdentifier = t123AnnexBProtocolId;
if ( pSocket->fExtendedX224 ) { TRACE_OUT(("SendX224ConnectConfirm reply using extended X224"));
if ( pSocket->fIncomingSecure ) { TRACE_OUT(("SendX224ConnectConfirm: reply to secure call request"));
// Security not even initialized?
if ( NULL == g_Transport->pSecurityInterface ) { WARNING_OUT(("Can't accept secure call: no sec interface")); } // Registry indicates no secure calls? If we're in the service
// then security is always 'on'.
else if ( !g_bRDS && !fAcceptSecure) { WARNING_OUT(("Can't accept secure call: security disabled")); } else // OK to take secure call
{ TRACE_OUT(("Creating security context for incoming call on socket (%d, %d).", pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle )); if ( NULL != (pSocket->pSC = new SecurityContext(g_Transport->pSecurityInterface, ""))) { // Indicate we're ready for a secure call in the CC packet
cnp_pdu.u.connectConfirm.bit_mask |= ConnectConfirmPDU_reliableSecurityProtocol_present; cnp_pdu.u.connectConfirm.reliableSecurityProtocol.choice = gssApiX224_chosen; pSocket->SecState = SC_SECURE; } else { ERROR_OUT(("Error creating sec context on received call")); // We will report no-support for security in our CC
pSocket->SecState = SC_NONSECURE; } } } else if ( // Incoming call is not secure, but not downlevel
// Running as a service?
g_bRDS || fRequireSecure) { if (g_bRDS) { WARNING_OUT(("Can't accept non-secure call in SERVICE")); } else { WARNING_OUT(("Can't accept non-secure call -- we require security")); } return FALSE; } else { pSocket->SecState = SC_NONSECURE; }
if (! g_CNPCoder->Encode((LPVOID) &cnp_pdu, CNPPDU_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("SendX224ConnectRequest: Can't encode cnp pdu")); return FALSE; }
cbToSendBuf = sizeof(X224_CC_FIXED)+sizeof(X224_VARIABLE_INFO)+encoded_pdu_length; cc_fixed.rfc.lsbPacketSize = (UChar)cbToSendBuf; cc_fixed.HeaderSize = (UChar)(sizeof(X224_CONNECT_COMMON) + sizeof(X224_VARIABLE_INFO) + encoded_pdu_length); ASSERT( cbToSendBuf <= 128 ); pbToSendBuf = new BYTE[cbToSendBuf]; if (NULL == pbToSendBuf) { ERROR_OUT(("SendX224ConnectConfirm: failed to allocate memory")); return FALSE; }
PBYTE pbTemp = pbToSendBuf; memcpy(pbTemp, (LPBYTE) &cc_fixed, sizeof(cc_fixed)); pbTemp += sizeof(cc_fixed);
X224_VARIABLE_INFO x224_var_info = { T_SELECTOR_2 /*0xc2*/, (UChar)encoded_pdu_length }; memcpy(pbTemp, (LPBYTE) &x224_var_info, sizeof(x224_var_info)); pbTemp += sizeof(x224_var_info);
memcpy(pbTemp, encoded_pdu, encoded_pdu_length);
g_CNPCoder->FreeEncoded(encoded_pdu); } else // Incoming call is downlevel
{ if ( g_bRDS || fRequireSecure) { WARNING_OUT(("Can't accept downlevel call in RDS or if security required")); return FALSE; }
pSocket->SecState = SC_NONSECURE;
// Downlevel: send packet w/out TSELECTOR variable portion
cc_fixed.rfc.lsbPacketSize = sizeof(X224_CC_FIXED); cc_fixed.HeaderSize = sizeof(X224_CONNECT_COMMON); cbToSendBuf = sizeof(X224_CC_FIXED); pbToSendBuf = new BYTE[cbToSendBuf]; memcpy(pbToSendBuf, (LPBYTE) &cc_fixed, sizeof(cc_fixed)); }
/* Attempt to send data out the socket */ #ifdef DEBUG
TransportError error = #endif // DEBUG
FlushSendBuffer(pSocket, pbToSendBuf, cbToSendBuf); #ifdef DEBUG
ASSERT (TRANSPORT_NO_ERROR == error); #endif // DEBUG
delete [] pbToSendBuf; return TRUE; }
BOOL SendX224DisconnectRequest(PSocket pSocket, unsigned int remote, USHORT usReason) { LPBYTE pbToSendBuf = NULL; UINT cbToSendBuf = 0; CNPPDU cnp_pdu; LPBYTE encoded_pdu = NULL; UINT encoded_pdu_length = 0;
TRACE_OUT(("SendX224DisconnectRequest"));
static X224_DR_FIXED dr_fixed = { { 3, 0, 0, UNK }, // RFC1006 header
UNK, { DISCONNECT_REQUEST_PACKET, UNK, UNK, UNK, UNK, 0 }, };
ASSERT (pSocket->fExtendedX224); ASSERT (sizeof(RFC_HEADER) == 4); ASSERT (sizeof(X224_DATA_PACKET) == 7);
::OnProtocolControl(pSocket->XprtConn, PLUGXPRT_DISCONNECTING);
dr_fixed.disconn.msbDest = (UChar) (remote >> 8); dr_fixed.disconn.lsbDest = (UChar) remote; dr_fixed.disconn.msbSrc = (UChar) (pSocket->XprtConn.nLogicalHandle >> 8); dr_fixed.disconn.lsbSrc = (UChar) pSocket->XprtConn.nLogicalHandle;
cnp_pdu.choice = disconnectRequest_chosen; cnp_pdu.u.disconnectRequest.bit_mask = 0; cnp_pdu.u.disconnectRequest.disconnectReason.choice = usReason;
if (! g_CNPCoder->Encode((LPVOID) &cnp_pdu, CNPPDU_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("SendX224DisconnectRequest: Can't encode cnp pdu")); return FALSE; }
cbToSendBuf = sizeof(X224_DR_FIXED) + sizeof(X224_VARIABLE_INFO) + encoded_pdu_length; dr_fixed.rfc.lsbPacketSize = (UChar)cbToSendBuf; dr_fixed.HeaderSize = (UChar)(sizeof(X224_DISCONN) + sizeof(X224_VARIABLE_INFO) + encoded_pdu_length); ASSERT( cbToSendBuf <= 128 ); pbToSendBuf = new BYTE[cbToSendBuf]; if (NULL == pbToSendBuf) { ERROR_OUT(("SendX224DisconnectRequest: failed to allocate memory")); return FALSE; } LPBYTE pbTemp = pbToSendBuf; memcpy(pbTemp, (LPBYTE) &dr_fixed, sizeof(dr_fixed)); pbTemp += sizeof(dr_fixed); X224_VARIABLE_INFO x224_var_info = { 0xe0, (UChar)encoded_pdu_length }; memcpy(pbTemp, (LPBYTE) &x224_var_info, sizeof(x224_var_info)); pbTemp += sizeof(x224_var_info); memcpy(pbTemp, encoded_pdu, encoded_pdu_length);
g_CNPCoder->FreeEncoded(encoded_pdu);
/* Attempt to send data out the socket */ #ifdef DEBUG
TransportError error = #endif // DEBUG
FlushSendBuffer(pSocket, pbToSendBuf, cbToSendBuf); #ifdef DEBUG
ASSERT (TRANSPORT_NO_ERROR == error); #endif // DEBUG
return TRUE; }
/*
* void ContinueAuthentication (PSocket pSocket) * * Functional Description: */ void ContinueAuthentication (PSocket pSocket) { ULong packet_size; PUChar Buffer; PSecurityContext pSC = pSocket->pSC;
if (NULL != pSC) {
TRACE_OUT(("ContinueAuthentication: sending data packet"));
ASSERT(NULL != pSC->GetTokenBuf()); ASSERT(0 != pSC->GetTokenSiz());
/* We send an X224 data */ packet_size = sizeof(X224_DATA_PACKET) + pSC->GetTokenSiz(); DBG_SAVE_FILE_LINE Buffer = new UChar[packet_size]; if (NULL != Buffer) { memcpy(Buffer + sizeof(X224_DATA_PACKET), pSC->GetTokenBuf(), pSC->GetTokenSiz());
/* X224 header */ memcpy (Buffer, g_X224Header, sizeof(X224_DATA_PACKET)); AddRFCSize (Buffer, packet_size);
/* Attempt to send data out the socket */ #ifdef DEBUG
TransportError error = FlushSendBuffer(pSocket, (LPBYTE) Buffer, packet_size); ASSERT (TRANSPORT_NO_ERROR == error); #else // DEBUG
FlushSendBuffer(pSocket, (LPBYTE) Buffer, packet_size); #endif // DEBUG
delete [] Buffer; } else { // bugbug: what do we need to do in case of a mem alloc failure?
WARNING_OUT (("ContinueAuthentication: memory allocation failure.")); } } else { ERROR_OUT(("ContinueAuthentication called w/ bad socket")); } }
/*
* The following function processes the variable part of incoming X.224 * CONNECT_REQUEST and CONNECT_CONFIRM PDUs. * For now, it can only process Max PDU size and security T_SELECTOR requests. */ BOOL ProcessX224ConnectPDU (PSocket pSocket, PUChar CP_ptr, UINT CP_length, ULONG *pNotify) { UChar length; BOOL bSecurityInfoFound = FALSE; PSecurityContext pSC = pSocket->pSC;
/* This structure must be accessed using byte-alignment */ #pragma pack(1)
X224_VARIABLE_INFO *pX224VarInfo; /* return to normal alignment */ #pragma pack()
while (CP_length > 0) { pX224VarInfo = (X224_VARIABLE_INFO *) CP_ptr;
/*
* Check the packet to see if it contains a valid TPDU_SIZE part. If it * does, we need to reset the max packet size for this socket. */ if (TPDU_SIZE == pX224VarInfo->InfoType) { /* This structure must be accessed using byte-alignment */ #pragma pack(1)
X224_TPDU_INFO *pX224TpduSize; /* return to normal alignment */ #pragma pack()
pX224TpduSize = (X224_TPDU_INFO *) CP_ptr; ASSERT (pX224TpduSize->InfoSize == 1); if (pX224TpduSize->Info != DEFAULT_TPDU_SIZE) {
// We do not accept too small PDU sizes
if ((pX224TpduSize->Info < LOWEST_TPDU_SIZE) && (pX224TpduSize->Info < HIGHEST_TPDU_SIZE)) { if (NULL != pNotify) *pNotify = TPRT_NOTIFY_INCOMPATIBLE_T120_TPDU; return FALSE; } pSocket->Max_Packet_Length = (1 << pX224TpduSize->Info); } } /*
* Check the packet to see if it contains a valid * TSELECTOR variable portion. If so, make sure it's security related * and include one in the reply */ else if (T_SELECTOR == pX224VarInfo->InfoType || T_SELECTOR_2 == pX224VarInfo->InfoType) { // Try to decode
LPVOID pdecoding_buf = NULL; UINT decoding_len = 0; LPBYTE pbEncoded_data = CP_ptr + sizeof(X224_VARIABLE_INFO); if ( g_CNPCoder->Decode (pbEncoded_data, pX224VarInfo->InfoSize, CNPPDU_PDU, PACKED_ENCODING_RULES, (LPVOID *) &pdecoding_buf, &decoding_len)) { bSecurityInfoFound = TRUE; /* This structure must be accessed using byte-alignment */ #pragma pack(1)
CNPPDU *pCnp_pdu; /* return to normal alignment */ #pragma pack()
pCnp_pdu = (CNPPDU *) pdecoding_buf; if (pSocket->Read_State == CONNECTION_REQUEST) { TRACE_OUT(("CR packet using TSELECTOR extension")); pSocket->fExtendedX224 = TRUE; if (pCnp_pdu->u.connectRequest.bit_mask & reliableSecurityProtocols_present) { PConnectRequestPDU_reliableSecurityProtocols pRSP = pCnp_pdu->u.connectRequest.reliableSecurityProtocols; if (gssApiX224_chosen == pRSP->value.choice) { pSocket->fIncomingSecure = TRUE; } } } else { ASSERT (pSocket->Read_State == CONNECTION_CONFIRM); if ((NULL != pSC) && (pSC->ContinueNeeded())) { ConnectConfirmPDU *pCnpCc = &pCnp_pdu->u.connectConfirm; if ((pCnpCc->bit_mask & ConnectConfirmPDU_reliableSecurityProtocol_present ) && gssApiX224_chosen == pCnpCc->reliableSecurityProtocol.choice) { // Everything is OK, we got an extended X224 response
// to our secure CR.
ContinueAuthentication(pSocket); } else { WARNING_OUT(("No-support response to secure call attempt")); if (NULL != pNotify) *pNotify = TPRT_NOTIFY_REMOTE_NO_SECURITY; return FALSE; } } } } g_CNPCoder->FreeDecoded(CNPPDU_PDU, pdecoding_buf); } else { ERROR_OUT (("ProcessX224ConnectPDU: Received X.224 Connect packet with unrecognizable parts.")); }
// Adjust the pointer and length and the X.224 CR packet.
length = pX224VarInfo->InfoSize + sizeof(X224_VARIABLE_INFO); CP_ptr += length; CP_length -= length; }
if (bSecurityInfoFound == FALSE) { if ((pSocket->Read_State == CONNECTION_CONFIRM) && (pSC != NULL) && pSC->ContinueNeeded()) { WARNING_OUT(("Downlevel response to secure call attempt")); if (NULL != pNotify) *pNotify = TPRT_NOTIFY_REMOTE_DOWNLEVEL_SECURITY; return FALSE; } }
return TRUE; }
void ProcessX224DisconnectPDU(PSocket pSocket, PUChar CP_ptr, UINT CP_length, ULONG *pNotify) { UChar length; BOOL bSecurityInfoFound = FALSE; PSecurityContext pSC = pSocket->pSC;
/* This structure must be accessed using byte-alignment */ #pragma pack(1)
X224_VARIABLE_INFO *pX224VarInfo; /* return to normal alignment */ #pragma pack()
while (CP_length > 0) { pX224VarInfo = (X224_VARIABLE_INFO *) CP_ptr; if ( 0xe0 == pX224VarInfo->InfoType) { LPVOID pdecoding_buf = NULL; UINT decoding_len = 0; LPBYTE pbEncoded_data = CP_ptr + sizeof(X224_VARIABLE_INFO); if ( g_CNPCoder->Decode (pbEncoded_data, pX224VarInfo->InfoSize, CNPPDU_PDU, PACKED_ENCODING_RULES, (LPVOID *) &pdecoding_buf, &decoding_len)) { #pragma pack(1)
CNPPDU *pCnp_pdu; /* return to normal alignment */ #pragma pack()
pCnp_pdu = (CNPPDU *) pdecoding_buf; if (disconnectRequest_chosen == pCnp_pdu->choice) { switch (pCnp_pdu->u.disconnectRequest.disconnectReason.choice) { case securityDenied_chosen: *pNotify = TPRT_NOTIFY_REMOTE_REQUIRE_SECURITY; break; default: *pNotify = TPRT_NOTIFY_OTHER_REASON; break; } } } g_CNPCoder->FreeDecoded(decoding_len, pdecoding_buf); } length = pX224VarInfo->InfoSize + sizeof(X224_VARIABLE_INFO); CP_ptr += length; CP_length -= length; } }
/*
* void DisconnectRequest (TransportConnection XprtConn) * * Functional Description: * This function closes the socket and deletes its connection node. */ void DisconnectRequest (TransportConnection XprtConn, ULONG ulNotify) { PSocket pSocket;
TRACE_OUT(("DisconnectRequest"));
/* If the transport connection handle is not registered, return error */ if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn, TRUE))) { // LONCHANC: cannot do Remove in the above line because PurgeRequest() uses it again.
::PurgeRequest(XprtConn);
// SendStatusMessage (pSocket -> Remote_Address, TSTATE_NOT_CONNECTED, IDS_NULL_STRING);
if (IS_PLUGGABLE_PSTN(XprtConn)) { CPluggableConnection *p = ::GetPluggableConnection(XprtConn.nLogicalHandle); if (NULL != p) { p->TDisconnectRequest(); } }
/* Free the structures and close the socket */ TransportConnection XprtConn2 = XprtConn; if (IS_SOCKET(XprtConn2)) { XprtConn2.nLogicalHandle = INVALID_SOCKET; } ::freeSocket(pSocket, XprtConn2);
// Notify the user
if (TPRT_NOTIFY_NONE != ulNotify) { TRACE_OUT (("TCP Callback: g_Transport->DisconnectIndication (%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle));
/* We issue a callback to the user to notify him of the message */ g_Transport->DisconnectIndication(XprtConn, ulNotify); } } else { WARNING_OUT(("DisconnectRequest: logical handle (%d, %d) not found", XprtConn.eType, XprtConn.nLogicalHandle)); }
::OnProtocolControl(XprtConn, PLUGXPRT_DISCONNECTED); }
typedef enum { RECVRET_CONTINUE = 0, RECVRET_NON_FATAL_ERROR, RECVRET_DISCONNECT, RECVRET_NO_PLUGGABLE_CONNECTION, } RecvReturn;
/* RecvReturn Call_recv (PSocket pSocket)
* * Functional Description: * This function calls recv once and checks for errors coming from the * recv call. It knows about the socket's state from the "pSocket" argument * and uses this info to create the arguments for the recv call. * * Return value: * Continue, if everything went ok and we have new data * Non_Fatal_Error, if no real error has happenned, but we did not recv all data we asked for * Disconnect, if a real error has occurred, or the other side has disconnected. */ RecvReturn Call_recv (PSocket pSocket) { PUChar buffer; int length; int bytes_received; BOOL bAllocationOK; RecvReturn rrCode = RECVRET_NON_FATAL_ERROR; PLUGXPRT_RESULT plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
TRACE_OUT(("Call_recv"));
if (READ_HEADER != pSocket->Read_State) { ASSERT ((pSocket->X224_Length) > 0 && (pSocket->X224_Length <= 8192));
// Compute how much data we have to read from this X.224 pkt.
length = pSocket->X224_Length - sizeof(X224_DATA_PACKET);
// Space allocation
if (! pSocket->bSpaceAllocated) { // We need to allocate the space for the recv call.
if (NULL == pSocket->Data_Indication_Buffer) { DBG_SAVE_FILE_LINE pSocket->Data_Memory = AllocateMemory ( NULL, pSocket->X224_Length, ((READ_DATA == pSocket->Read_State) ? RECV_PRIORITY : HIGHEST_PRIORITY)); // Leave space for the X.224 header in the newly allocated data buffer
pSocket->Data_Indication_Length = sizeof (X224_DATA_PACKET); bAllocationOK = (pSocket->Data_Memory != NULL); } else { // This is an MCS PDU broken up in many X.224 packets.
ASSERT (READ_DATA == pSocket->Read_State); bAllocationOK = ReAllocateMemory (&(pSocket->Data_Memory), length); }
// Check whether the allocations were successful.
if (bAllocationOK) { pSocket->bSpaceAllocated = TRUE; pSocket->Data_Indication_Buffer = pSocket->Data_Memory->GetPointer(); /*
* If this is an X.224 CONNECT_REQUEST or CONNECT_CONFIRM packet, * we need to copy the first 7 bytes into the buffer for the whole * packet. */ if (READ_DATA != pSocket->Read_State) { memcpy ((void *) pSocket->Data_Indication_Buffer, (void *) &(pSocket->X224_Header), sizeof(X224_DATA_PACKET)); } } else { /*
* We will retry the operation later. */ WARNING_OUT (("Call_recv: Buffer allocation failed.")); g_pMCSController->HandleTransportWaitUpdateIndication(TRUE); goto ExitLabel; } } buffer = pSocket->Data_Indication_Buffer + pSocket->Data_Indication_Length; } else { buffer = (PUChar) &(pSocket->X224_Header); length = sizeof(X224_DATA_PACKET); }
// Adjust "buffer" and "length" for data already read from the current X.224 pkt.
buffer += pSocket->Current_Length; length -= pSocket->Current_Length;
ASSERT (length > 0);
if (IS_SOCKET(pSocket->XprtConn)) { // Issue the recv call.
bytes_received = recv (pSocket->XprtConn.nLogicalHandle, (char *) buffer, length, 0); } else { bytes_received = ::X224Recv(pSocket, buffer, length, &plug_rc); }
if (bytes_received == length) { TRACE_OUT (("Call_recv: Received %d bytes on socket (%d, %d).", bytes_received, pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); // We have received the whole X.224 packet.
if (READ_HEADER != pSocket->Read_State) { pSocket->Data_Indication_Length += pSocket->X224_Length - sizeof(X224_DATA_PACKET); } // Reset the current length variable for the next Call_recv().
pSocket->Current_Length = 0; rrCode = RECVRET_CONTINUE; } // Handle errors
else if (bytes_received == SOCKET_ERROR) { if (IS_SOCKET(pSocket->XprtConn)) { if(WSAGetLastError() == WSAEWOULDBLOCK) { TRACE_OUT(("Call_recv: recv blocked on socket (%d, %d).", pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); } else { /* If the error is not WOULD BLOCK, we have a real error. */ WARNING_OUT (("Call_recv: Error %d on recv. Socket: (%d, %d). Disconnecting...", WSAGetLastError(), pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); rrCode = RECVRET_DISCONNECT; } } else { if (PLUGXPRT_RESULT_SUCCESSFUL == plug_rc) { // do nothing, treat it as WSAEWOULDBLOCK
} else { /* If the error is not WOULD BLOCK, we have a real error. */ WARNING_OUT (("Call_recv: Error %d on recv. Socket: (%d, %d). Disconnecting...", WSAGetLastError(), pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); rrCode = RECVRET_DISCONNECT; } } } else if (bytes_received > 0) { TRACE_OUT(("Call_recv: Received %d bytes out of %d bytes requested on socket (%d, %d).", bytes_received, length, pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); // We received only part of what we wanted. We retry later.
pSocket->Current_Length += bytes_received; } else { WARNING_OUT(("Call_recv: Socket (%d, %d) has been gracefully closed.", pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); rrCode = RECVRET_DISCONNECT; }
ExitLabel: return rrCode; }
int X224Recv(PSocket pSocket, LPBYTE buffer, int length, PLUGXPRT_RESULT *plug_rc) { TRACE_OUT(("X224Recv"));
if (IS_PLUGGABLE_X224(pSocket->XprtConn)) { return ::SubmitPluggableRead(pSocket, buffer, length, plug_rc); }
if (IS_PLUGGABLE_PSTN(pSocket->XprtConn)) { return Q922Recv(pSocket, buffer, length, plug_rc); }
ERROR_OUT(("X224Recv: invalid plugable type (%d, %d)", pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); return SOCKET_ERROR; }
int Q922Recv(PSocket pSocket, LPBYTE buffer, int length, PLUGXPRT_RESULT *plug_rc) { ERROR_OUT(("Q922Recv: NYI (%d, %d)", pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); return SOCKET_ERROR; }
typedef enum { FreeX224AndExit, ErrorExit, ImmediateExit } ExitWay;
/*
* void ReadRequest ( TransportConnection ) * * Functional Description: * This function will attempt to read and process a full X.224 packet. * However, it may only be able to read part of a packet or fail to * process it at this time. In this case, it must keep enough state * info for the next entrance into this function, to be able to handle * the partly-received or unprocessed X.224 packet. */ void ReadRequest (TransportConnection XprtConn) { PSocket pSocket; ExitWay ew = ImmediateExit; RecvReturn rrCode; ULONG ulNotify = TPRT_NOTIFY_OTHER_REASON;
TRACE_OUT(("ReadRequest"));
if (IS_PLUGGABLE_PSTN(XprtConn)) { ERROR_OUT(("ReadRequest: PSTN should not be here")); return; }
/* If the transport connection handle is not registered, return */ if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) { if (pSocket->State != WAITING_FOR_CONNECTION) { PSecurityContext pSC = pSocket->pSC; /*
* If we haven't read the header of the incoming packet yet, * we need to read it into the header space */ if (READ_HEADER == pSocket->Read_State) { rrCode = Call_recv (pSocket); if (RECVRET_CONTINUE == rrCode) { // We need to allocate the space for the rest of the X.224 packet.
pSocket->bSpaceAllocated = FALSE;
// Find the length of the X.224 packet.
pSocket->X224_Length = (pSocket->X224_Header.rfc.msbPacketSize << 8) + pSocket->X224_Header.rfc.lsbPacketSize; /*
* We have the whole X.224 header. Compute the next state, * based on the packet type. */ switch (pSocket->X224_Header.PacketType) { case DATA_PACKET: pSocket->Read_State = READ_DATA; break;
case CONNECTION_CONFIRM_PACKET: if (pSocket->State != X224_CONNECTED) { pSocket->Read_State = CONNECTION_CONFIRM; } else { ERROR_OUT (("ReadRequest: Received X.224 CONNECTION_CONFIRM packet while already connected!! Socket: (%d, %d).", XprtConn.eType, XprtConn.nLogicalHandle)); ew = ErrorExit; } break;
case CONNECTION_REQUEST_PACKET: // we just received a X224 Connect request
pSocket->Read_State = CONNECTION_REQUEST; ::OnProtocolControl(XprtConn, PLUGXPRT_CONNECTING); break;
case DISCONNECT_REQUEST_PACKET: // we just received a X224 Disconnect request
pSocket->Read_State = DISCONNECT_REQUEST; ::OnProtocolControl(XprtConn, PLUGXPRT_DISCONNECTING); break;
default: // We have lost sync with the remote side.
ERROR_OUT (("ReadRequest: Bad X.224 packet on socket (%d, %d). Disconnecting...", XprtConn.eType, XprtConn.nLogicalHandle)); ew = ErrorExit; break; } } else if (RECVRET_DISCONNECT == rrCode) { ew = ErrorExit; } }
if ((READ_DATA <= pSocket->Read_State) && (CONNECTION_REQUEST >= pSocket->Read_State)) { rrCode = Call_recv (pSocket); if (RECVRET_CONTINUE == rrCode) { // We now have the whole X.224 packet.
switch (pSocket->Read_State) { case READ_DATA: // Check whether this is the final X.224 packet
if (pSocket->X224_Header.FinalPacket & EOT_BIT) { // If we're waiting for a security data packet we will process
// this internally without passing it up to the transport
// client.
if (NULL != pSC) { if (pSC->WaitingForPacket()) { TransportSecurityError SecErr;
SecErr = pSC->AdvanceState((PBYTE) pSocket->Data_Indication_Buffer + sizeof(X224_DATA_PACKET), pSocket->Data_Indication_Length - sizeof(X224_DATA_PACKET));
if (TPRTSEC_NOERROR != SecErr) { // Something has gone wrong. Need to disconnect
delete pSC; pSocket->pSC = NULL; ulNotify = TPRT_NOTIFY_AUTHENTICATION_FAILED; ew = ErrorExit; break; }
if (pSC->ContinueNeeded()) { // We need to send out another token
// bugbug: what should we do if this fails?
ContinueAuthentication(pSocket); }
if (pSC->StateComplete()) { // We're connected... inform the client
TRACE_OUT(("deferred g_Transport->ConnectConfirm")); g_Transport->ConnectConfirm(XprtConn); } ew = FreeX224AndExit; break; }
// We must decrypt the data (in place)
TRACE_OUT(("Decrypting received data"));
if (! pSC->Decrypt(pSocket->Data_Indication_Buffer + sizeof(X224_DATA_PACKET), pSocket->Data_Indication_Length - sizeof(X224_DATA_PACKET))) { TRACE_OUT(("Sending %d bytes to application", pSocket->Data_Indication_Length - sizeof(X224_DATA_PACKET))); } else { ERROR_OUT(("Error decrypting packet")); ew = ErrorExit; break; } } pSocket->Read_State = DATA_READY; } else { // This and the next X.224 packets are part of a bigger MCS data PDU.
ASSERT (NULL == pSC); pSocket->Read_State = READ_HEADER; } break;
case CONNECTION_CONFIRM: { TRACE_OUT(("ReadRequest: X224 CONNECTION_CONFIRM_PACKET received")); BOOL bCallback = ((NULL == pSC) || (! pSC->ContinueNeeded()));
// Process the CC packet.
if (FALSE == ProcessX224ConnectPDU (pSocket, pSocket->Data_Indication_Buffer + sizeof(X224_CONNECT), pSocket->X224_Length - sizeof (X224_CONNECT), &ulNotify)) { ew = ErrorExit; break; }
// Issue the callback if the CC was not on a secure connection
// Otherwise, we don't notify the transport client yet... still need to
// exchange security information. TRANSPORT_CONNECT_CONFIRM will
// be sent when the final security data token is received and
// processed.
if (bCallback) { TRACE_OUT (("TCP Callback: g_Transport->ConnectConfirm (%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); /* We issue a callback to the user to notify him of the message */ g_Transport->ConnectConfirm(XprtConn); } pSocket->State = X224_CONNECTED; ::OnProtocolControl(XprtConn, PLUGXPRT_CONNECTED); ew = FreeX224AndExit; } break;
case CONNECTION_REQUEST: { UINT remote; /* This structure must be accessed using byte-alignment */ #pragma pack(1)
X224_CONNECT *pConnectRequest; /* return to normal alignment */ #pragma pack()
/* Grab the remote connection ID */ TRACE_OUT (("ReadRequest: X224 CONNECTION_REQUEST_PACKET received")); pConnectRequest = (X224_CONNECT *) pSocket->Data_Indication_Buffer; remote = ((unsigned int) pConnectRequest->conn.msbSrc) << 8; remote |= pConnectRequest->conn.lsbSrc;
if (FALSE == ProcessX224ConnectPDU (pSocket, (PUChar) (pConnectRequest + 1), pSocket->X224_Length - sizeof (X224_CONNECT), &ulNotify)) { ew = ErrorExit; break; }
if (::SendX224ConnectConfirm(pSocket, remote)) { // success
if (IS_PLUGGABLE(pSocket->XprtConn)) { pSocket->State = SOCKET_CONNECTED; g_Transport->ConnectIndication(XprtConn); ASSERT(X224_CONNECTED == pSocket->State); } ::OnProtocolControl(XprtConn, PLUGXPRT_CONNECTED); ew = FreeX224AndExit; } else { if (pSocket->fExtendedX224) { ::SendX224DisconnectRequest(pSocket, remote, securityDenied_chosen); } ew = ErrorExit; } } break;
case DISCONNECT_REQUEST: { UINT remote; X224_DR_FIXED *pX224_DR_fixed;
TRACE_OUT(("ReadRequest: X224 DISCONNECT_REQUEST_PACKET received")); pX224_DR_fixed = (X224_DR_FIXED *) pSocket->Data_Indication_Buffer; remote = ((unsigned int) pX224_DR_fixed->disconn.msbSrc) << 8; remote |= pX224_DR_fixed->disconn.lsbSrc;
ProcessX224DisconnectPDU(pSocket, pSocket->Data_Indication_Buffer + sizeof(X224_DR_FIXED), pSocket->X224_Length - sizeof(X224_DR_FIXED), &ulNotify); ew = ErrorExit; } break; } } else if (RECVRET_DISCONNECT == rrCode) { ew = ErrorExit; } }
if (DATA_READY == pSocket->Read_State) { TransportData transport_data;
// Fill in the callback structure.
transport_data.transport_connection = XprtConn; transport_data.user_data = pSocket->Data_Indication_Buffer; transport_data.user_data_length = pSocket->Data_Indication_Length; transport_data.memory = pSocket->Data_Memory;
/*
* If there is an incoming security context associated with this * socket, we must adjust pointer by header and overall size by header and * trailer. */ if (NULL != pSC) { transport_data.user_data += pSC->GetStreamHeaderSize(); transport_data.user_data_length -= (pSC->GetStreamHeaderSize() + pSC->GetStreamTrailerSize()); }
if (TRANSPORT_NO_ERROR == g_Transport->DataIndication(&transport_data)) { TRACE_OUT (("ReadRequest: %d bytes were accepted from socket (%d, %d)", transport_data.user_data_length, XprtConn.eType, XprtConn.nLogicalHandle)); // Prepare for the next X.224 packet
pSocket->Read_State = READ_HEADER; pSocket->Data_Indication_Buffer = NULL; pSocket->Data_Memory = NULL; } else { WARNING_OUT(("ReadRequest: Error on g_Transport->DataIndication from socket (%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); } } } else { WARNING_OUT (("ReadRequest: socket (%d, %d) is in WAITING_FOR_CONNECTION state.", XprtConn.eType, XprtConn.nLogicalHandle)); } } else { WARNING_OUT (("ReadRequest: socket (%d, %d) can not be found.", XprtConn.eType, XprtConn.nLogicalHandle)); }
switch (ew) { case FreeX224AndExit: if (NULL != pSocket) { // Free the buffers we have allocated.
pSocket->FreeTransportBuffer(); // Prepare for the next X.224 packet
pSocket->Read_State = READ_HEADER; } break;
case ErrorExit: // We get here only if we need to disconnect the socket (because of an error)
ASSERT(TPRT_NOTIFY_NONE != ulNotify); ::DisconnectRequest(XprtConn, ulNotify); break; }
if (NULL != pSocket) { pSocket->Release(); // offset the previous AddRef.
} }
/*
* TransportError FlushSendBuffer ( PSocket pSocket ) * * Functional Description: * This function sends any pending data through the transport. */ TransportError FlushSendBuffer(PSocket pSocket, LPBYTE buffer, UINT length) { int bytes_sent = SOCKET_ERROR; PLUGXPRT_RESULT plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
TRACE_OUT(("FlushSendBuffer"));
/* send the data */ if (IS_SOCKET(pSocket->XprtConn)) { bytes_sent = ::send(pSocket->XprtConn.nLogicalHandle, (PChar) buffer, (int) length, 0); } else if (IS_PLUGGABLE_X224(pSocket->XprtConn)) { bytes_sent = ::SubmitPluggableWrite(pSocket, buffer, length, &plug_rc); } else if (IS_PLUGGABLE_PSTN(pSocket->XprtConn)) { CPluggableConnection *p = ::GetPluggableConnection(pSocket); if (NULL != p) { bytes_sent = p->TDataRequest(buffer, length, &plug_rc); } else { plug_rc = PLUGXPRT_RESULT_WRITE_FAILED; } }
if (bytes_sent == SOCKET_ERROR) { if (IS_SOCKET(pSocket->XprtConn)) { /* If the error is not WOULD BLOCK, it is a real error! */ if (::WSAGetLastError() != WSAEWOULDBLOCK) { WARNING_OUT (("FlushSendBuffer: Error %d on write", ::WSAGetLastError()));
/* Notify the owner of the broken connection */ WARNING_OUT (("FlushSendBuffer: Sending up DISCONNECT_INDICATION")); // SendStatusMessage (pSocket -> Remote_Address, TSTATE_REMOVED, IDS_NULL_STRING);
::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_OTHER_REASON); return (TRANSPORT_WRITE_QUEUE_FULL); } } else { // do nothing if it is WSAEWOULDBLOCK
if (PLUGXPRT_RESULT_SUCCESSFUL != plug_rc) { /* Notify the owner of the broken connection */ WARNING_OUT (("FlushSendBuffer: Sending up DISCONNECT_INDICATION")); // SendStatusMessage (pSocket -> Remote_Address, TSTATE_REMOVED, IDS_NULL_STRING);
::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_OTHER_REASON); return (TRANSPORT_WRITE_QUEUE_FULL); } }
bytes_sent = 0; }
/* If the transport layer did not accept the data, its write buffers are full */ if (bytes_sent != (int) length) { ASSERT (bytes_sent == 0); TRACE_OUT(("FlushSendBuffer: returning TRANSPORT_WRITE_QUEUE_FULL")); return (TRANSPORT_WRITE_QUEUE_FULL); }
TRACE_OUT (("FlushSendBuffer: %d bytes sent on Socket (%d, %d).", length, pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle));
return (TRANSPORT_NO_ERROR); }
/*
* SegmentX224Data * * This function segments outgoing data into X.224 packets of the appropriate size. * It should not be called in a NM to NM call or in a call when we have negotiated an * X.224 max PDU size of at least the size of a max MCS PDU. NM attempts to negotiate * X.224 sizes of 8K, but will accept anything the other side proposes. * This function does memcpy's so it will slow us down sending data. * * The 2 buffers specified by "ptr1" and "ptr2" and their lengths are used to create * one stream of X.224 bytes. The function will return TRANSPORT_WRITE_QUEUE_FULL if * it fails to allocate the necessary amount of memory. */ TransportError SegmentX224Data (PSocket pSocket, LPBYTE *pPtr1, UINT *pLength1, LPBYTE Ptr2, UINT Length2) { TransportError TransError; UINT length; LPBYTE ptr1 = *pPtr1 + sizeof (X224_DATA_PACKET); UINT length1 = *pLength1 - sizeof (X224_DATA_PACKET); LPBYTE ptr; UINT max_pdu_length = pSocket->Max_Packet_Length; X224_DATA_PACKET l_X224Header = {3, 0, (UChar) (max_pdu_length >> 8), (UChar) (max_pdu_length & 0xFF), 2, DATA_PACKET, 0}; UINT last_length; /* This structure must be accessed using byte-alignment */ #pragma pack(1)
X224_DATA_PACKET *pX224Data; /* return to normal alignment */ #pragma pack()
ASSERT(! IS_PLUGGABLE_PSTN(pSocket->XprtConn));
// Calculate how much space we need.
length = *pLength1 + Length2; ASSERT (pSocket->Max_Packet_Length < length); ASSERT (pSocket->Max_Packet_Length > sizeof(X224_DATA_PACKET));
max_pdu_length -= sizeof (X224_DATA_PACKET); /*
* Calculate the space we need to allocate. Notice that the data already * contains one X.224 header. */ length += (length / max_pdu_length) * sizeof (X224_DATA_PACKET); *pPtr1 = Allocate (length);
if (*pPtr1 != NULL) { TransError = TRANSPORT_NO_ERROR; ptr = *pPtr1;
// Go through the 1st buffer.
while (length1 > 0) { // Copy the X.224 header.
memcpy (ptr, &l_X224Header, sizeof(X224_DATA_PACKET)); pX224Data = (X224_DATA_PACKET *) ptr; ptr += sizeof (X224_DATA_PACKET);
// Copy data
length = ((max_pdu_length > length1) ? length1 : max_pdu_length); memcpy (ptr, ptr1, length); last_length = length;
// Advance pointers
ptr1 += length; ptr += length; length1 -= length; }
// If there is space in the current X.224 PDU, we need to use it.
length = max_pdu_length - length; if (length > 0 && Length2 > 0) { if (length > Length2) length = Length2; memcpy (ptr, Ptr2, length); last_length += length; Ptr2 += length; ptr += length; Length2 -= length; }
// Go through the 2nd buffer.
while (Length2 > 0) { // Copy the X.224 header.
memcpy (ptr, &l_X224Header, sizeof(X224_DATA_PACKET)); pX224Data = (X224_DATA_PACKET *) ptr; ptr += sizeof (X224_DATA_PACKET);
// Copy data
length = ((max_pdu_length > Length2) ? Length2 : max_pdu_length); memcpy (ptr, Ptr2, length); last_length = length;
// Advance pointers
Ptr2 += length; ptr += length; Length2 -= length; }
// Prepare for return
*pLength1 = (UINT)(ptr - *pPtr1);
// Set the last X.224 header
last_length += sizeof(X224_DATA_PACKET); pX224Data->FinalPacket = EOT_BIT; pX224Data->rfc.msbPacketSize = (UChar) (last_length >> 8); pX224Data->rfc.lsbPacketSize = (UChar) (last_length & 0xFF); } else { ERROR_OUT (("SegmentX224Data: Failed to allocate memory of length %d.", length)); TransError = TRANSPORT_WRITE_QUEUE_FULL; }
return TransError; }
/*
* SendSecureData * * This function segments secure data into X.224 packets, if needed, and flushes them through * the transport. "pBuf" and "cbBuf" provide the encrypted data buffer and length. */ TransportError SendSecureData (PSocket pSocket, LPBYTE pBuf, UINT cbBuf) { TransportError TransError; LPBYTE pBuf_Copy = pBuf; UINT cbBuf_Copy = cbBuf;
// Do we need to segment the data into X.224 packets?
if (pSocket->Max_Packet_Length >= cbBuf) { TransError = TRANSPORT_NO_ERROR; } else { TransError = SegmentX224Data (pSocket, &pBuf, &cbBuf, NULL, 0); }
// Flush the data, if everything OK so far.
if (TRANSPORT_NO_ERROR == TransError) TransError = FlushSendBuffer (pSocket, pBuf, cbBuf);
// If we segmented the data, we need to free the segmented buffer.
if (pBuf != pBuf_Copy) Free(pBuf);
// If there are errors, we need to store the decrypted data for the next time, so don't free it.
if (TRANSPORT_NO_ERROR == TransError) { LocalFree(pBuf_Copy); }
return TransError; }
/*
* TransportError DataRequest ( TransportConnection XprtConn, * PSimplePacket packet) * * Functional Description: * This function is used to send a data packet to the remote site. * If the user_data_length is zero, and we have no pending data, * it sends a keep-alive (zero-length) packet. */ TransportError DataRequest (TransportConnection XprtConn, PSimplePacket packet) { PSocket pSocket; LPBYTE ptr1, ptr2; UINT length1, length2; TransportError TransError = TRANSPORT_NO_ERROR;
TRACE_OUT(("DataRequest: packet=0x%x", packet));
if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) { // First, we need to handle the retry operations.
if (NULL != pSocket->pSC) { LPBYTE lpBuf; /*
* Check to see whether we have already encrypted, but not sent * the last piece of data. */ lpBuf = pSocket->Retry_Info.sbiBufferInfo.lpBuffer; if (NULL != lpBuf) { TransError = SendSecureData (pSocket, lpBuf, pSocket->Retry_Info.sbiBufferInfo.uiLength);
if (TransError == TRANSPORT_NO_ERROR) { TRACE_OUT(("DataRequest: Sent previously-encrypted piece of data.")); pSocket->Retry_Info.sbiBufferInfo.lpBuffer = NULL; } } } else { PDataPacket pdpPacket = pSocket->Retry_Info.pUnfinishedPacket;
// Check to see whether we have half-sent the last packet.
if (NULL != pdpPacket) { /*
* We need to send the rest of the unfinished packet, * before we can go on. The 1st part of the packet * must have already been sent. */ // The packet's encoded data must be in 2 buffers.
ASSERT (TRUE == pdpPacket->IsEncodedDataBroken());
TransError = FlushSendBuffer (pSocket, pdpPacket->GetUserData(), pdpPacket->GetUserDataLength()); if (TransError == TRANSPORT_NO_ERROR) { pdpPacket->Unlock(); TRACE_OUT(("DataRequest: 2nd part of data packet was sent out in separate request")); pSocket->Retry_Info.pUnfinishedPacket = NULL; } } }
if ((TransError == TRANSPORT_NO_ERROR) && (packet != NULL)) {
// Now, let's try to send this new packet.
ptr1 = packet->GetEncodedData(); length1 = packet->GetEncodedDataLength();
/*
* We need to find out whether the packet to send is a * DataPacket or a Packet object. If it's a DataPacket, the * encoded data may not be contiguous (may be broken in 2 parts) */ if ((packet->IsDataPacket()) && ((PDataPacket) packet)->IsEncodedDataBroken()) { // the data to send is broken into 2 parts.
ptr2 = ((PDataPacket) packet)->GetUserData(); length2 = ((PDataPacket) packet)->GetUserDataLength(); } else { // the data to send is contiguous.
ptr2 = NULL; length2 = 0; }
if (NULL != pSocket->pSC) { LPBYTE pBuf; UINT cbBuf;
TRACE_OUT(("Encrypting %d bytes of outgoing data", (length1 + length2) - sizeof(X224_DATA_PACKET)));
if (!pSocket->pSC->Encrypt(ptr1 + sizeof(X224_DATA_PACKET), length1 - sizeof(X224_DATA_PACKET), ptr2, length2, &pBuf, &cbBuf)) {
ASSERT (TransError == TRANSPORT_NO_ERROR);
TransError = SendSecureData (pSocket, pBuf, cbBuf); if (TRANSPORT_NO_ERROR != TransError) { TRACE_OUT(("DataRequest: Failed to send encrypted data. Keeping buffer for retry.")); pSocket->Retry_Info.sbiBufferInfo.lpBuffer = pBuf; pSocket->Retry_Info.sbiBufferInfo.uiLength = cbBuf; // The caller needs to remove the packet from its queue.
TransError = TRANSPORT_NO_ERROR; } } else { WARNING_OUT (("DataRequest: Encryption failed. Disconnecting...")); ::DisconnectRequest(pSocket->XprtConn, TPRT_NOTIFY_OTHER_REASON); TransError = TRANSPORT_MEMORY_FAILURE; } } else { BOOL bNeedToFree = FALSE; // Do we need to segment the data into X.224 packets?
if (pSocket->Max_Packet_Length >= length1 + length2) ; else { TransError = SegmentX224Data (pSocket, &ptr1, &length1, ptr2, length2); if (TRANSPORT_NO_ERROR == TransError) { // The data is now contiguous
ptr2 = NULL; bNeedToFree = TRUE; } }
// Flush the data, if everything OK so far.
if (TRANSPORT_NO_ERROR == TransError) TransError = FlushSendBuffer (pSocket, ptr1, length1);
// Free the temporary X.224 buffer if we need to.
if (bNeedToFree) Free(ptr1);
if (TRANSPORT_NO_ERROR == TransError) { // If there is more, send it, too.
if (NULL != ptr2) { TransError = FlushSendBuffer (pSocket, ptr2, length2); if (TRANSPORT_NO_ERROR != TransError) { /*
* We need to keep the partial packet to send it later. * Notice we have already sent a part of this packet. */ ASSERT (pSocket->Retry_Info.pUnfinishedPacket == NULL); pSocket->Retry_Info.pUnfinishedPacket = (PDataPacket) packet; packet->Lock();
// Return success.
TransError = TRANSPORT_NO_ERROR; } } } } }
pSocket->Release(); } else { TransError = TRANSPORT_NO_SUCH_CONNECTION; WARNING_OUT (("DataRequest: Attempt to send to unknown transport connection (%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); }
return TransError; }
/*
* void PurgeRequest (TransportConnection XprtConn) * * Functional Description: * This function purges the outbound packets for the given transport * connection. */ void PurgeRequest (TransportConnection XprtConn) {
PSocket pSocket;
TRACE_OUT (("In PurgeRequest for transport connection (%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle));
if (IS_PLUGGABLE_PSTN(XprtConn)) { CPluggableConnection *p = ::GetPluggableConnection(XprtConn.nLogicalHandle); if (NULL != p) { p->TPurgeRequest(); } } else /* If the logical connection handle is not registered, return error */ if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) { /* Purge the pending data stored in the socket struct */ if (NULL != pSocket->pSC) { if (NULL != pSocket->Retry_Info.sbiBufferInfo.lpBuffer) { TRACE_OUT (("PurgeRequest: Purging data packet for secure connection")); LocalFree (pSocket->Retry_Info.sbiBufferInfo.lpBuffer); pSocket->Retry_Info.sbiBufferInfo.lpBuffer = NULL; } } pSocket->Release(); } }
/*
* void EnableReceiver (Void) * * Functional Description: * This function allows packets to be sent to the user application. */ void EnableReceiver (void) { PSocket pSocket;
::EnterCriticalSection(&g_csTransport); CSocketList Connection_List_Copy (*g_pSocketList); ::LeaveCriticalSection(&g_csTransport);
TRACE_OUT(("EnableReceiver"));
if (NULL != g_pLegacyTransport) { g_pLegacyTransport->TEnableReceiver(); }
/* Go thru all the sockets and enable receiving */ while (NULL != (pSocket = Connection_List_Copy.Get())) { /*
* If we had failed to deliver a data pkt to MCS before, we need * an extra ReadRequest to recv and keep the FD_READ msgs coming. */ if (DATA_READY == pSocket->Read_State) { ::ReadRequest(pSocket->XprtConn); }
TRACE_OUT (("EnableReceiver: Calling ReadRequestEx on socket (%d, %d)", pSocket->XprtConn.eType, pSocket->XprtConn.nLogicalHandle)); ::ReadRequestEx(pSocket->XprtConn); } }
/*
* TransportError ShutdownAndClose (TransportConnection , BOOL fShutdown, int how) * * Functional Description * This function shuts down the socket and closes it. * */ void ShutdownAndClose (TransportConnection XprtConn, BOOL fShutdown, int how) { if (IS_SOCKET(XprtConn)) { int error;
if (fShutdown) { error = ::shutdown(XprtConn.nLogicalHandle, how);
ASSERT(error != SOCKET_ERROR); #ifdef DEBUG
if(error == SOCKET_ERROR) { error = WSAGetLastError(); WARNING_OUT (("ShutdownAndClose: shutdown returned %d", error)); } #endif // DEBUG
}
error = ::closesocket(XprtConn.nLogicalHandle);
#ifdef DEBUG
if(error == SOCKET_ERROR) { WARNING_OUT(("ShutdownAndClose: closesocket returned %d", WSAGetLastError())); } #endif // DEBUG
} }
/*
* TransportError GetLocalAddress (TransportConnection XprtConn, * TransportAddress address, * int * size) * * Functional Description: * This function retrieves the local IP address associated with the given * connection. It returns TRANSPORT_NO_SUCH_CONNECTION if the address is * not available. If the address is available, the size parameter specifies * the size of the address buffer on entry, and it is filled in with the size * used for the address on exit. */ TransportError GetLocalAddress( TransportConnection XprtConn, TransportAddress address, int * size) { SOCKADDR_IN socket_control; PChar szTemp; int Length; TransportError error = TRANSPORT_NO_SUCH_CONNECTION;
if (NULL != g_pSocketList->FindByTransportConnection(XprtConn, TRUE)) { if (IS_SOCKET(XprtConn)) { /* Get the local name for the socket */ Length = sizeof(socket_control); if (getsockname(XprtConn.nLogicalHandle, (LPSOCKADDR) &socket_control, &Length) == 0) { /* Convert it to an IP address string */ szTemp = inet_ntoa(socket_control.sin_addr);
ASSERT (szTemp); Length = (int) strlen(szTemp) + 1;
ASSERT (*size >= Length); ASSERT (address);
/* Copy it to the buffer */ lstrcpyn((PChar)address, szTemp, Length); *size = Length;
error = TRANSPORT_NO_ERROR; } } else { ASSERT(IS_PLUGGABLE(XprtConn));
// string should look like "xprt: 1"
char szConnStr[T120_CONNECTION_ID_LENGTH]; Length = ::CreateConnString((UINT)XprtConn.nLogicalHandle, szConnStr); if (*size > ++Length) { ::lstrcpyn(address, szConnStr, Length+1); *size = Length; error = TRANSPORT_NO_ERROR; TRACE_OUT (("GetLocalAddress: plugable connection local address (%s)", address)); } else { ERROR_OUT(("GetLocalAddress: buffer too small, given=%d, required=%d", *size, Length)); error = TRANSPORT_BUFFER_TOO_SMALL; } } }
#ifdef DEBUG
if (error != TRANSPORT_NO_ERROR) WARNING_OUT (("GetLocalAddress: Failure to obtain local address (%d)", WSAGetLastError())); #endif // DEBUG
return (error); }
/*
* void AcceptCall (BOOL fSecure) * * Functional Description: * This function calls Winsock to answer an incoming call. */
void AcceptCall (TransportConnection XprtConn) { PSocket pSocket; PSecurityContext pSC = NULL; SOCKADDR_IN socket_control; int size;
TRACE_OUT(("AcceptCall"));
if (IS_SOCKET(XprtConn)) { ASSERT(XprtConn.nLogicalHandle == Listen_Socket); ASSERT (Listen_Socket != INVALID_SOCKET);
/* Call accept() to see if anyone is calling us */ size = sizeof (socket_control); XprtConn.nLogicalHandle = ::accept ( Listen_Socket, (struct sockaddr *) &socket_control, &size);
/* Note that we expect accept to complete immediately */ if (XprtConn.nLogicalHandle == INVALID_SOCKET) { ERROR_OUT (("AcceptCall: Error on accept = %d", WSAGetLastError())); // SendStatusMessage ("", TSTATE_NOT_READY, IDS_NULL_STRING);
return; } }
/* If the accept() received an incoming call, create a connection and notify our owner object. */ pSocket = newSocket(XprtConn, NULL); if( pSocket == NULL ) { /* Close the socket */ ::ShutdownAndClose(XprtConn, TRUE, 2); return; }
pSocket -> State = SOCKET_CONNECTED;
if (IS_SOCKET(XprtConn)) { /* Issue the getpeername() function to get the remote user's address */ size = sizeof (socket_control); if (::getpeername(XprtConn.nLogicalHandle, (LPSOCKADDR) &socket_control, &size) == 0) { lstrcpyn ( pSocket -> Remote_Address, inet_ntoa (socket_control.sin_addr), MAXIMUM_IP_ADDRESS_SIZE-1); pSocket -> Remote_Address[MAXIMUM_IP_ADDRESS_SIZE - 1] = NULL; }
// SendStatusMessage(pSocket -> Remote_Address, TSTATE_CONNECTED, IDS_NULL_STRING);
}
/* Add to connection list */ // bugbug: we fail to insert.
g_pSocketList->SafeAppend(pSocket);
/* Notify the user */ TRACE_OUT (("TCP Callback: g_Transport->ConnectIndication (%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); /* We issue a callback to the user to notify him of the message */ g_Transport->ConnectIndication(XprtConn); }
//
// ReadRequestEx() is for the plugable transport.
// Since we do not have the FD_ACCEPT notifcation, we try to make sure
// we have a valid transport connection for every read...
// The following piece of code is derived from AcceptCall().
//
void ReadRequestEx(TransportConnection XprtConn) { if (! IS_PLUGGABLE_PSTN(XprtConn)) { ::ReadRequest(XprtConn); } }
/*
* LRESULT WindowProcedure ( * HWND window_handle, * UINT message, * WPARAM wParam, * LPARAM lParam) * * Public * * Functional Description: * This function is called by Windows when we dispatch a TCP message from the * event loop above. It gives us a chance to process the incoming socket messages. */ LRESULT WindowProcedure (HWND window_handle, UINT message, WPARAM wParam, LPARAM lParam) { TransportConnection XprtConn; UShort error; UShort event; //PSocket pSocket;
switch (message) { #ifndef NO_TCP_TIMER
case WM_TIMER: { /*
** We are currently using a slow timer to keep reading even when ** FD_READ msgs get lost (this happens on Win95). ** */ if (NULL != g_Transport) { TRACE_OUT(("MSMCSTCP: WM_TIMER")); EnableReceiver (); } } break; #endif /* NO_TCP_TIMER */
case WM_SOCKET_NOTIFICATION: { /* This message is generated by WinSock */ event = WSAGETSELECTEVENT (lParam); error = WSAGETSELECTERROR (lParam);
SET_SOCKET_CONNECTION(XprtConn, wParam);
/* We disconnect whenever a socket command generates an error message */ if (error) { WARNING_OUT (("TCP: error %d on socket (%d). Event: %d", error, XprtConn.nLogicalHandle, event)); ::DisconnectRequest(XprtConn, TPRT_NOTIFY_OTHER_REASON); break; }
/* We get FD_CLOSE when the socket is closed by the remote site. */ if (event & FD_CLOSE) { TRACE_OUT (("TCP: FD_CLOSE(%d)", XprtConn.nLogicalHandle)); ::DisconnectRequest(XprtConn, TPRT_NOTIFY_OTHER_REASON); break; }
/* We get FD_READ when there is data available for us to read. */ if (event & FD_READ) { // TRACE_OUT(("MSMCSTCP: FD_READ(%d)", (UINT) wParam));
::ReadRequest(XprtConn); }
/* We get FD_ACCEPT when a remote site is connecting with us */ if (event & FD_ACCEPT) { TRACE_OUT (("TCP: FD_ACCEPT(%d)", XprtConn.nLogicalHandle));
/* Note that we always accept calls. Disconnect cancels them. */ TransportConnection XprtConn2; SET_SOCKET_CONNECTION(XprtConn2, Listen_Socket); ::AcceptCall(XprtConn2); }
/* We get FD_CONNECT when our connect completes */ if (event & FD_CONNECT) { TRACE_OUT (("TCP: FD_CONNECT(%d)", XprtConn.nLogicalHandle)); ::SendX224ConnectRequest(XprtConn); }
/* We get FD_WRITE when there is space available to write data to WinSock */ if (event & FD_WRITE) { /*
* We need to send a BUFFER_EMPTY_INDICATION to the connection associated * with the socket */ TRACE_OUT (("TCP: FD_WRITE(%d)", XprtConn.nLogicalHandle)); // We need to flush the socket's pending data first.
if (TRANSPORT_NO_ERROR == ::DataRequest(XprtConn, NULL)) { TRACE_OUT (("TCP: Sending BUFFER_EMPTY_INDICATION to transport.")); g_Transport->BufferEmptyIndication(XprtConn); } } } break;
case WM_PLUGGABLE_X224: // for low level read and write,
{ XprtConn.eType = (TransportType) PLUGXPRT_WPARAM_TO_TYPE(wParam); XprtConn.nLogicalHandle = PLUGXPRT_WPARAM_TO_ID(wParam); ASSERT(IS_PLUGGABLE(XprtConn));
event = PLUGXPRT_LPARAM_TO_EVENT(lParam); error = PLUGXPRT_LPARAM_TO_ERROR(lParam);
/* We disconnect whenever a socket command generates an error message */ if (error) { WARNING_OUT(("PluggableWndProc: error %d on socket (%d, %d). Event: %d", error, XprtConn.eType, XprtConn.nLogicalHandle, event)); ::DisconnectRequest(XprtConn, TPRT_NOTIFY_OTHER_REASON); ::PluggableShutdown(XprtConn); break; }
switch (event) { case PLUGXPRT_EVENT_READ: TRACE_OUT(("PluggableWndProc: READ(%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); ::ReadRequestEx(XprtConn); break;
case PLUGXPRT_EVENT_WRITE: TRACE_OUT(("PluggableWndProc: WRITE(%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); ::PluggableWriteTheFirst(XprtConn); break;
case PLUGXPRT_EVENT_CLOSE: TRACE_OUT(("PluggableWndProc: CLOSE(%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); ::DisconnectRequest(XprtConn, TPRT_NOTIFY_OTHER_REASON); break;
case PLUGXPRT_HIGH_LEVEL_READ: TRACE_OUT(("PluggableWndProc: READ_NEXT(%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); ::ReadRequestEx(XprtConn); break;
case PLUGXPRT_HIGH_LEVEL_WRITE: TRACE_OUT(("PluggableWndProc: WRITE_NEXT(%d, %d)", XprtConn.eType, XprtConn.nLogicalHandle)); // We need to flush the socket's pending data first.
if (TRANSPORT_NO_ERROR == ::DataRequest(XprtConn, NULL)) { TRACE_OUT(("PluggableWndProc: Sending BUFFER_EMPTY_INDICATION to transport.")); g_Transport->BufferEmptyIndication(XprtConn); } break;
default: ERROR_OUT(("PluggableWndProc: unknown event=%d.", event)); break; } } break;
case WM_PLUGGABLE_PSTN: { extern void HandlePSTNCallback(WPARAM wParam, LPARAM lParam); HandlePSTNCallback(wParam, lParam); } break;
default: { /*
** The message is not related to WinSock messages, so let ** the default window procedure handle it. */ return (DefWindowProc (window_handle, message, wParam, lParam)); } }
return (0); }
// GetSecurityInfo() takes a connection_handle and returns the security information associated with
// it.
//
// Returns TRUE if we can either find the information or we are not directly connected to the node
// represented by this connection handle.
//
// Returns FALSE if we are directly connected but for some reason could not get the info -- this
// result should be viewed as suspicious.
BOOL GetSecurityInfo(ConnectionHandle connection_handle, PBYTE pInfo, PDWORD pcbInfo) { PSocket pSocket; SOCKET socket_number;
if (g_pMCSController->FindSocketNumber(connection_handle, &socket_number)) { TransportConnection XprtConn; SET_SOCKET_CONNECTION(XprtConn, socket_number);
BOOL fRet = FALSE; if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) { if (NULL != pSocket->pSC) { fRet = pSocket->pSC->GetUserCert(pInfo, pcbInfo); } else { WARNING_OUT(("GetSecurityInfo: queried non-secure socket %d", socket_number)); }
pSocket->Release(); } else { WARNING_OUT(("GetSecurityInfo: socket %d not found", socket_number )); } return fRet; } // In this case we are not directly connected, so will return length of NOT_DIRECTLY_CONNECTED
// but positive return value.
*pcbInfo = NOT_DIRECTLY_CONNECTED; return TRUE; }
// GetSecurityInfoFromGCCID() takes a GCCID and returns the security information associated with
// it.
//
// Returns TRUE if either (1) we successfully retrieve the information from a transport-level
// connection, or (2) we find that we are not directly connected to the node with this GCCID.
//
// Returns FALSE if we are directly connected but cannot retrieve the info, or some other error
// occurs. A FALSE return value should be treated as a security violation.
BOOL WINAPI T120_GetSecurityInfoFromGCCID(DWORD dwGCCID, PBYTE pInfo, PDWORD pcbInfo) { PSocket pSocket;
SOCKET socket_number; if ( NULL != dwGCCID ) { // Get the user info for a remote connection
ConnectionHandle connection_handle; BOOL fConnected = FindSocketNumber(dwGCCID, &socket_number); if (fConnected == FALSE) { (* pcbInfo) = 0; return TRUE; }
TransportConnection XprtConn; SET_SOCKET_CONNECTION(XprtConn, socket_number);
BOOL fRet = FALSE; if (NULL != (pSocket = g_pSocketList->FindByTransportConnection(XprtConn))) { if (NULL != pSocket->pSC) { fRet = pSocket->pSC->GetUserCert(pInfo, pcbInfo); } else { WARNING_OUT(("GetSecurityInfoFromGCCID: queried non-secure socket %d", socket_number)); } pSocket->Release(); } else { ERROR_OUT(("GetSecurityInfoFromGCCID: socket %d not found", socket_number )); } return fRet; } else { // Get the user info for the local user
if ( NULL != g_Transport && NULL != g_Transport->pSecurityInterface ) return g_Transport->pSecurityInterface->GetUserCert( pInfo, pcbInfo ); else return FALSE; } }
|