Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

496 lines
22 KiB

/****************************************************************************/
// atdint.c
//
// Transport driver - portable internal functions.
//
// Copyright (C) 1997-1999 Microsoft Corporation
/****************************************************************************/
#include <adcg.h>
extern "C" {
#define TRC_FILE "atdint"
#define TRC_GROUP TRC_GROUP_NETWORK
#include <atrcapi.h>
#include <adcgfsm.h>
}
#include "autil.h"
#include "td.h"
#include "xt.h"
#include "cd.h"
#include "nl.h"
#include "wui.h"
/****************************************************************************/
/* TD FSM TABLE */
/* ============ */
/* */
/* EVENTS STATES */
/* 0 TD_EVT_TDINIT 0 TD_ST_NOTINIT */
/* 1 TD_EVT_TDTERM 1 TD_ST_DISCONNECTED */
/* 2 TD_EVT_TDCONNECT_IP 2 TD_ST_WAITFORDNS */
/* 3 TD_EVT_TDCONNECT_DNS 3 TD_ST_WAITFORSKT */
/* 4 TD_EVT_TDDISCONNECT 4 TD_ST_CONNECTED */
/* 5 TD_EVT_WMTIMER 5 TD_ST_WAITFORCLOSE */
/* 6 TD_EVT_OK */
/* 7 TD_EVT_ERROR */
/* 8 TD_EVT_CONNECTWITHENDPOINT */
/* */
/* Stt | 0 1 2 3 4 5 */
/* ==================================== */
/* Evt | */
/* 0 | 1A / / / / / (TD_EVT_TDINIT) */
/* | */
/* 1 | / 0X 0Z 0Z 0Z 0Z (TD_EVT_TDTERM) */
/* | */
/* 2 | / 3B / / / / (TD_EVT_TDCONNECT_IP) */
/* | */
/* 3 | / 2C / / / / (TD_EVT_TDCONNECT_DNS) */
/* | */
/* 4 | / / 1Y 1Y 5D 5- (TD_EVT_DISCONNECT) */
/* | */
/* 5 | 0- 1- 1Y 1Y 4- 1W (TD_EVT_WMTIMER) */
/* | */
/* 6 | 0- 1- 3B 4E 4- 1Y (TD_EVT_OK) */
/* | */
/* 7 | 0- 1- 1Y 1Y 1Y 1W (TD_EVT_ERROR) */
/* */
/* 8 | 0- Conn / / / / (ACT_CONNECTENDPOINT) */
/* */
/* 9 | / / 1W 1W 1W 1- (TD_EVT_DROPLINK) */
/* */
/* */
/* */
/* '/' = illegal event/state combination */
/* '-' = no action */
/* */
/****************************************************************************/
const FSM_ENTRY tdFSM[TD_FSM_INPUTS][TD_FSM_STATES] =
/* TD_EVT_TDINIT */
{{{TD_ST_DISCONNECTED, ACT_A},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO}},
/* TD_EVT_TDTERM */
{{STATE_INVALID, ACT_NO},
{TD_ST_NOTINIT, ACT_X},
{TD_ST_NOTINIT, ACT_Z},
{TD_ST_NOTINIT, ACT_Z},
{TD_ST_NOTINIT, ACT_Z},
{TD_ST_NOTINIT, ACT_Z}},
/* TD_EVT_TDCONNECT_IP */
{{STATE_INVALID, ACT_NO},
{TD_ST_WAITFORSKT, ACT_B},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO}},
/* TD_EVT_TDCONNECT_DNS */
{{STATE_INVALID, ACT_NO},
{TD_ST_WAITFORDNS, ACT_C},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO}},
/* TD_EVT_TDDISCONNECT */
{{STATE_INVALID, ACT_NO},
{TD_ST_DISCONNECTED, ACT_NO},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_WAITFORCLOSE, ACT_D},
{TD_ST_WAITFORCLOSE, ACT_NO}},
/* TD_EVT_WMTIMER */
{{TD_ST_NOTINIT, ACT_NO},
{TD_ST_DISCONNECTED, ACT_NO},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_CONNECTED, ACT_NO},
{TD_ST_DISCONNECTED, ACT_W}},
/* TD_EVT_OK */
{{TD_ST_NOTINIT, ACT_NO},
{TD_ST_DISCONNECTED, ACT_NO},
{TD_ST_WAITFORSKT, ACT_B},
{TD_ST_CONNECTED, ACT_E},
{TD_ST_CONNECTED, ACT_NO},
{TD_ST_DISCONNECTED, ACT_Y}},
/* TD_EVT_ERROR */
{{TD_ST_NOTINIT, ACT_NO},
{TD_ST_DISCONNECTED, ACT_NO},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_DISCONNECTED, ACT_Y},
{TD_ST_DISCONNECTED, ACT_W}},
/* TD_EVT_CONNECTWITHENDPOINT */
{{STATE_INVALID, ACT_NO},
{TD_ST_WAITFORSKT, ACT_CONNECTENDPOINT}, // TDBeginSktConnectWithConnectedEndpoint() will post
{STATE_INVALID, ACT_NO}, // itself a FD_CONNECT message to setups rest of data
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO},
{STATE_INVALID, ACT_NO}},
/* TD_EVT_DROPLINK */
{{STATE_INVALID, ACT_NO},
{TD_ST_DISCONNECTED, ACT_NO},
{TD_ST_DISCONNECTED, ACT_W},
{TD_ST_DISCONNECTED, ACT_W},
{TD_ST_DISCONNECTED, ACT_W},
{TD_ST_DISCONNECTED, ACT_NO}},
};
/****************************************************************************/
/* Name: TDConnectFSMProc */
/* */
/* Purpose: The TD connection FSM. */
/* */
/* Params: IN fsmEvent - an external event. */
/* IN eventData - four bytes of event related data. */
/****************************************************************************/
DCVOID DCINTERNAL CTD::TDConnectFSMProc(DCUINT fsmEvent, ULONG_PTR eventData)
{
DCUINT action;
DC_BEGIN_FN("TDConnectFSMProc");
/************************************************************************/
/* Run the FSM. */
/************************************************************************/
EXECUTE_FSM(tdFSM, fsmEvent, _TD.fsmState, action,tdEventText,tdStateText);
TRC_NRM((TB, _T("eventData:%p"), eventData));
/************************************************************************/
/* Now perform the action. */
/************************************************************************/
switch (action)
{
case ACT_A:
{
/****************************************************************/
/* Initialize _TD. Note that any errors in this function are */
/* fatal and are handled by directly calling the UT fatal */
/* error handler. */
/****************************************************************/
TDInit();
}
break;
case ACT_CONNECTENDPOINT:
{
/****************************************************************/
/* Socket connection pre-established */
/****************************************************************/
TDBeginSktConnectWithConnectedEndpoint();
}
break;
case ACT_B:
{
/****************************************************************/
/* Begin the socket connection process. */
/****************************************************************/
TDBeginSktConnect((u_long) eventData);
}
break;
case ACT_C:
{
/****************************************************************/
/* We need to perform a DNS lookup, so resolve the address and */
/* call the state machine again to check the result of the */
/* resolution call. */
/****************************************************************/
TDBeginDNSLookup((PDCACHAR) eventData);
}
break;
case ACT_D:
{
/****************************************************************/
/* Disconnect processing. First of all start the disconnect */
/* timer. Normally the server will respond to our graceful */
/* close attempt prior to this timer popping. However, just in */
/* the case the server decides to take a hike, we have this */
/* timer which ensures that we tidy up. */
/****************************************************************/
TDSetTimer(TD_DISCONNECTTIMEOUT);
/****************************************************************/
/* Set the flag to indicate that there is no more data */
/* available in _TD. */
/****************************************************************/
_TD.dataInTD = FALSE;
/****************************************************************/
/* Decouple to the sender thread and clear the send queue. */
/****************************************************************/
_pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CTD,TDClearSendQueue),
0);
/****************************************************************/
/* Initiate the graceful close by calling shutdown with */
/* SD_SEND specified. This lets the server know that we've */
/* finished sending. If it's feeling up to it, the server will */
/* shortly get back to us with an FD_CLOSE which signifies that */
/* the graceful close has completed. */
/* */
/* However just in case the server misses a beat, we've got a */
/* timer running as well. If it pops before the server gets */
/* back to us, we'll just pull everything down anyway. */
/****************************************************************/
TRC_NRM((TB, _T("Issue shutdown (SD_SEND)")));
if (shutdown(_TD.hSocket, SD_SEND) != 0)
{
TRC_ALT((TB, _T("Shutdown error: %d"), WSAGetLastError()));
}
/****************************************************************/
/* Now hang around waiting for the server to get back to us, */
/* or the timer to pop. */
/****************************************************************/
}
break;
case ACT_E:
{
/****************************************************************/
/* We're now connected - so get rid of the connection timeout */
/* timer. */
/****************************************************************/
TDKillTimer();
/****************************************************************/
/* Set the required options on this socket. We do the */
/* following: */
/* */
/* - set the receive buffer size to TD_WSRCVBUFSIZE */
/* - set the send buffer size to TD_WSSNDBUFSIZE */
/* - disable Keep Alives */
/* */
/* Note that these calls should not be made until the */
/* connection is established. */
/****************************************************************/
#ifndef OS_WINCE
TDSetSockOpt(SOL_SOCKET, SO_RCVBUF, TD_WSRCVBUFSIZE);
TDSetSockOpt(SOL_SOCKET, SO_SNDBUF, TD_WSSNDBUFSIZE);
#endif
TDSetSockOpt(SOL_SOCKET, SO_KEEPALIVE, 0);
_pXt->XT_OnTDConnected();
}
break;
case ACT_W:
{
/****************************************************************/
/* Disconnect has timed out or failed. Close the socket but */
/* don't pass an error indication to the user. */
/****************************************************************/
TRC_NRM((TB, _T("Disconnection timeout / failure")));
TDDisconnect();
_pXt->XT_OnTDDisconnected(NL_DISCONNECT_LOCAL);
}
break;
case ACT_X:
{
/****************************************************************/
/* Termination action - reverse of Action A. Just call TDTerm. */
/****************************************************************/
TDTerm();
}
break;
case ACT_Y:
{
/****************************************************************/
/* Begin tidying up. */
/****************************************************************/
TDDisconnect();
/****************************************************************/
/* Now call the layer above to let it know that we've */
/* disconnected. <eventData> contains the disconnect reason */
/* code which must be non-zero. */
/****************************************************************/
TRC_ASSERT((eventData != 0), (TB, _T("eventData is zero")));
TRC_ASSERT((HIWORD(eventData) == 0),
(TB, _T("disconnect reason code unexpectedly using 32 bits")));
_pXt->XT_OnTDDisconnected((DCUINT)eventData);
}
break;
case ACT_Z:
{
/****************************************************************/
/* Termination action. First of all tidy up. Then call */
/* TDTerm. */
/****************************************************************/
TDDisconnect();
TDTerm();
}
break;
case ACT_NO:
{
TRC_NRM((TB, _T("No action required")));
}
break;
default:
{
TRC_ABORT((TB, _T("Unknown action:%u"), action));
}
}
DC_END_FN();
} /* TDConnectFSMProc */
/****************************************************************************/
/* Name: TDAllocBuf */
/* */
/* Purpose: This function allocates the memory for a send buffer and then */
/* stores a pointer to this memory in the buffer information */
/* structure. */
/* */
/* Params: IN pSndBufInf - a pointer to send buffer info structure. */
/* IN size - the size of the buffer to allocate. */
/****************************************************************************/
DCVOID DCINTERNAL CTD::TDAllocBuf(PTD_SNDBUF_INFO pSndBufInf, DCUINT size)
{
DC_BEGIN_FN("TDAllocBuf");
/************************************************************************/
/* Allocate the memory for the send buffer. */
/************************************************************************/
pSndBufInf->pBuffer = (PDCUINT8) UT_Malloc( _pUt, size);
pSndBufInf->size = size;
/************************************************************************/
/* Check that the memory allocation succeeded. */
/************************************************************************/
if (NULL == pSndBufInf->pBuffer)
{
TRC_ERR((TB, _T("Failed to allocate %u bytes of memory"),
size));
_pUi->UI_FatalError(DC_ERR_OUTOFMEMORY);
}
TRC_NRM((TB, _T("SndBufInf:%p size:%u buffer:%p"),
pSndBufInf,
pSndBufInf->size,
pSndBufInf->pBuffer));
DC_END_FN();
} /* TDAllocBuf */
/****************************************************************************/
/* Name: TDInitBufInfo */
/* */
/* Purpose: This function initializes a buffer. */
/* */
/* Params: IN pSndBufInf - a pointer to send buffer info structure. */
/****************************************************************************/
DCVOID DCINTERNAL CTD::TDInitBufInfo(PTD_SNDBUF_INFO pSndBufInf)
{
DC_BEGIN_FN("TDInitBufInfo");
TRC_ASSERT((NULL != pSndBufInf), (TB, _T("pSndBufInf is NULL")));
/************************************************************************/
/* Initialize the buffer fields. */
/************************************************************************/
pSndBufInf->pNext = 0;
pSndBufInf->inUse = FALSE;
pSndBufInf->pDataLeftToSend = NULL;
pSndBufInf->bytesLeftToSend = 0;
DC_END_FN();
} /* TDInitBufInfo */
/****************************************************************************/
// TDClearSendQueue
//
// Called on sender context (via direct or decoupled call) to clear the
// send queue on disconnect.
/****************************************************************************/
void DCINTERNAL CTD::TDClearSendQueue(ULONG_PTR unused)
{
DCUINT i;
DC_BEGIN_FN("TDClearSendQueue");
DC_IGNORE_PARAMETER(unused);
TRC_NRM((TB, _T("Clearing the send queue - initial buffers:")));
TD_TRACE_SENDINFO(TRC_LEVEL_NRM);
_TD.pFQBuf = NULL;
// Buffers can get taken from the pool, but not added to the
// send queue. This happens when the call goes down between
// the get and the send. Answer? Mark all the buffers in the
// pools as not in use.
for (i = 0; i < TD_SNDBUF_PUBNUM; i++) {
TRC_DBG((TB, _T("Tidying pub buf:%u inUse:%s size:%u"),
i,
_TD.pubSndBufs[i].inUse ? "TRUE" : "FALSE",
_TD.pubSndBufs[i].size));
_TD.pubSndBufs[i].pNext = NULL;
_TD.pubSndBufs[i].inUse = FALSE;
_TD.pubSndBufs[i].bytesLeftToSend = 0;
_TD.pubSndBufs[i].pDataLeftToSend = NULL;
}
for (i = 0; i < TD_SNDBUF_PRINUM; i++) {
TRC_DBG((TB, _T("Tidying pri buf:%u inUse:%s size:%u"),
i,
_TD.priSndBufs[i].inUse ? "TRUE" : "FALSE",
_TD.priSndBufs[i].size));
_TD.priSndBufs[i].pNext = NULL;
_TD.priSndBufs[i].inUse = FALSE;
_TD.priSndBufs[i].bytesLeftToSend = 0;
_TD.priSndBufs[i].pDataLeftToSend = NULL;
}
TRC_NRM((TB, _T("Send queue cleared - final buffers:")));
TD_TRACE_SENDINFO(TRC_LEVEL_NRM);
DC_END_FN();
}
/****************************************************************************/
// TDSendError
//
// Called on receive thread (possibly decoupled) to notify a send error.
/****************************************************************************/
void DCINTERNAL CTD::TDSendError(ULONG_PTR unused)
{
DC_BEGIN_FN("TDSendError");
DC_IGNORE_PARAMETER(unused);
// Call the FSM with an error.
TDConnectFSMProc(TD_EVT_ERROR,
NL_MAKE_DISCONNECT_ERR(NL_ERR_TDONCALLTOSEND));
DC_END_FN();
}