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.
 
 
 
 
 
 

679 lines
30 KiB

/****************************************************************************/
/* tdapi.c */
/* */
/* Transport driver - portable specific API */
/* */
/* Copyright (C) 1997-1999 Microsoft Corporation */
/****************************************************************************/
#include <adcg.h>
extern "C" {
#define TRC_FILE "tdapi"
#define TRC_GROUP TRC_GROUP_NETWORK
#include <atrcapi.h>
}
#include "autil.h"
#include "td.h"
#include "xt.h"
#include "nl.h"
CTD::CTD(CObjs* objs)
{
_pClientObjects = objs;
}
CTD::~CTD()
{
}
/****************************************************************************/
/* Name: TD_Init */
/* */
/* Purpose: Initializes the transport driver. This is called on the */
/* receiver thread. */
/****************************************************************************/
DCVOID DCAPI CTD::TD_Init(DCVOID)
{
DC_BEGIN_FN("TD_Init");
_pNl = _pClientObjects->_pNlObject;
_pUt = _pClientObjects->_pUtObject;
_pXt = _pClientObjects->_pXTObject;
_pUi = _pClientObjects->_pUiObject;
_pCd = _pClientObjects->_pCdObject;
/************************************************************************/
/* Initialize the global data and set the initial FSM state. */
/************************************************************************/
DC_MEMSET(&_TD, 0, sizeof(_TD));
_TD.fsmState = TD_ST_NOTINIT;
/************************************************************************/
/* Call the FSM. */
/************************************************************************/
TDConnectFSMProc(TD_EVT_TDINIT, 0);
DC_END_FN();
} /* TD_Init */
/****************************************************************************/
/* Name: TD_Term */
/* */
/* Purpose: Terminates the transport driver. This is called on the */
/* receiver thread. */
/****************************************************************************/
DCVOID DCAPI CTD::TD_Term(DCVOID)
{
DC_BEGIN_FN("TD_Term");
/************************************************************************/
/* Call the FSM. */
/************************************************************************/
TDConnectFSMProc(TD_EVT_TDTERM, 0);
DC_END_FN();
} /* TD_Term */
/****************************************************************************/
/* Name: TD_Connect */
/* */
/* Purpose: Connects to a remote server. Called on the receiver thread. */
/* */
/* Params: */
/* IN bInitateConnect : TRUE if we are making connection, */
/* FALSE if connect with already connected socket */
/* */
/****************************************************************************/
DCVOID DCAPI CTD::TD_Connect(BOOL bInitateConnect, PDCTCHAR pServerAddress)
{
DCUINT i;
DCUINT errorCode;
u_long addr;
DCUINT nextEvent;
ULONG_PTR eventData;
DCACHAR ansiBuffer[256];
DC_BEGIN_FN("TD_Connect");
/************************************************************************/
/* Check that the string is not null. */
/************************************************************************/
if( bInitateConnect )
{
TRC_ASSERT((0 != *pServerAddress),
(TB, _T("Server address is NULL")));
}
/************************************************************************/
/* Check that all the buffers are not in-use. */
/************************************************************************/
for (i = 0; i < TD_SNDBUF_PUBNUM; i++)
{
if (_TD.pubSndBufs[i].inUse)
{
TD_TRACE_SENDINFO(TRC_LEVEL_ERR);
TRC_ABORT((TB, _T("Public buffer %u still in-use"), i));
}
}
for (i = 0; i < TD_SNDBUF_PRINUM; i++)
{
if (_TD.priSndBufs[i].inUse)
{
TD_TRACE_SENDINFO(TRC_LEVEL_ERR);
TRC_ABORT((TB, _T("Private buffer %u still in-use"), i));
}
}
/************************************************************************/
/* Trace out the send buffer information. */
/************************************************************************/
TD_TRACE_SENDINFO(TRC_LEVEL_NRM);
if( FALSE == bInitateConnect )
{
TDConnectFSMProc(TD_EVT_CONNECTWITHENDPOINT, NULL);
DC_QUIT; // all we need is the buffer.
}
#ifdef UNICODE
/************************************************************************/
/* WinSock 1.1 only supports ANSI, so we need to convert any Unicode */
/* strings at this point. */
/************************************************************************/
if (!WideCharToMultiByte(CP_ACP,
0,
pServerAddress,
-1,
ansiBuffer,
256,
NULL,
NULL))
{
/********************************************************************/
/* Conversion failed */
/********************************************************************/
TRC_ERR((TB, _T("Failed to convert address to ANSI")));
/********************************************************************/
/* Generate the error code. */
/********************************************************************/
errorCode = NL_MAKE_DISCONNECT_ERR(NL_ERR_TDANSICONVERT);
TRC_ASSERT((HIWORD(errorCode) == 0),
(TB, _T("disconnect reason code unexpectedly using 32 bits")));
_pXt->XT_OnTDDisconnected(errorCode);
}
#else
DC_ASTRCPY(ansiBuffer, pServerAddress);
#endif /* UNICODE */
/************************************************************************/
/* Check that the address is not the limited broadcast address */
/* (255.255.255.255). */
/************************************************************************/
if (0 == DC_ASTRCMP(ansiBuffer, TD_LIMITED_BROADCAST_ADDRESS))
{
TRC_ALT((TB, _T("Cannot connect to the limited broadcast address")));
/********************************************************************/
/* Generate the error code. */
/********************************************************************/
errorCode = NL_MAKE_DISCONNECT_ERR(NL_ERR_TDBADIPADDRESS);
TRC_ASSERT((HIWORD(errorCode) == 0),
(TB, _T("disconnect reason code unexpectedly using 32 bits")));
_pXt->XT_OnTDDisconnected(errorCode);
DC_QUIT;
}
/************************************************************************/
/* Now determine whether a DNS lookup is required. */
/************************************************************************/
TRC_NRM((TB, _T("ServerAddress:%s"), ansiBuffer));
/************************************************************************/
/* Check that we have a string and that the address is not the limited */
/* broadcast address. */
/************************************************************************/
TRC_ASSERT((NULL != ansiBuffer), (TB, _T("ansiBuffer is NULL")));
TRC_ASSERT(('\0' != ansiBuffer[0]),
(TB, _T("Empty server address string")));
TRC_ASSERT((0 != DC_ASTRCMP(ansiBuffer, TD_LIMITED_BROADCAST_ADDRESS)),
(TB, _T("Cannot connect to the limited broadcast address")));
/************************************************************************/
/* Check for a dotted-IP address string. */
/************************************************************************/
addr = inet_addr(ansiBuffer);
TRC_NRM((TB, _T("Address returned is %#lx"), addr));
/************************************************************************/
/* Now determine whether this is an address string or a host name. */
/* Note that inet_addr doesn't distinguish between an invalid IP */
/* address and the limited broadcast address (255.255.255.255). */
/* However since we don't allow the limited broadcast address and have */
/* already checked explicitly for it we don't need to worry about this */
/* case. */
/************************************************************************/
if (INADDR_NONE == addr)
{
/********************************************************************/
/* This looks like a host name so call the FSM with the current */
/* address. */
/********************************************************************/
TRC_NRM((TB, _T("%s looks like a hostname - need DNS lookup"),
ansiBuffer));
nextEvent = TD_EVT_TDCONNECT_DNS;
eventData = (ULONG_PTR) ansiBuffer;
}
else
{
/********************************************************************/
/* If we get here then it appears to be a dotted-IP address. Call */
/* the FSM with the updated address. */
/********************************************************************/
TRC_NRM((TB, _T("%s looks like a dotted-IP address:%lu"),
ansiBuffer,
addr));
nextEvent = TD_EVT_TDCONNECT_IP;
eventData = addr;
}
/************************************************************************/
/* Now call the FSM with the appropriate parameters. */
/************************************************************************/
TDConnectFSMProc(nextEvent, eventData);
DC_EXIT_POINT:
DC_END_FN();
} /* TD_Connect */
/****************************************************************************/
/* Name: TD_Disconnect */
/* */
/* Purpose: Disconnects from the server. This is called on the receiver */
/* thread. */
/****************************************************************************/
DCVOID DCAPI CTD::TD_Disconnect(DCVOID)
{
DC_BEGIN_FN("TD_Disconnect");
/************************************************************************/
/* Call the FSM. We pass NL_DISCONNECT_LOCAL which will be used as the */
/* return code to XT in the cases where we are waiting for the DNS */
/* lookup to return or the socket to connect. */
/************************************************************************/
TDConnectFSMProc(TD_EVT_TDDISCONNECT, NL_DISCONNECT_LOCAL);
DC_END_FN();
} /* TD_Disconnect */
//
// TD_DropLink - drops the link immediately (ungracefully)
//
VOID
CTD::TD_DropLink(DCVOID)
{
DC_BEGIN_FN("TD_DropLink");
TDConnectFSMProc(TD_EVT_DROPLINK, NL_DISCONNECT_LOCAL);
DC_END_FN();
}
/****************************************************************************/
/* Name: TD_GetPublicBuffer */
/* */
/* Purpose: Attempts to allocate a buffer from the public TD buffer pool. */
/* */
/* Returns: If the allocation succeeds then this function returns TRUE */
/* otherwise it returns FALSE. */
/* */
/* Params: IN dataLength - length of the buffer requested. */
/* OUT ppBuffer - a pointer to a pointer to the buffer. */
/* OUT pBufHandle - a pointer to a buffer handle. */
/****************************************************************************/
DCBOOL DCAPI CTD::TD_GetPublicBuffer(DCUINT dataLength,
PPDCUINT8 ppBuffer,
PTD_BUFHND pBufHandle)
{
DCUINT i;
DCBOOL rc = FALSE;
DCUINT lastfree = TD_SNDBUF_PUBNUM;
PDCUINT8 pbOldBuffer;
DCUINT cbOldBuffer;
DC_BEGIN_FN("TD_GetPublicBuffer");
// Check that we're in the correct state. If we're disconnected
// then fail the call. Note that the FSM state is maintained by the
// receiver thread - but we're on the sender thread.
if (_TD.fsmState == TD_ST_CONNECTED) {
TRC_DBG((TB, _T("Searching for a buffer big enough for %u bytes"),
dataLength));
// Trace out the send buffer information.
TD_TRACE_SENDINFO(TRC_LEVEL_DBG);
// Search the array of buffers looking for the first free one that is
// large enough.
for (i = 0; i < TD_SNDBUF_PUBNUM; i++) {
TRC_DBG((TB, _T("Trying buf:%u inUse:%s size:%u"),
i,
_TD.pubSndBufs[i].inUse ? "TRUE" : "FALSE",
_TD.pubSndBufs[i].size));
if(!_TD.pubSndBufs[i].inUse)
{
lastfree = i;
}
if ((!(_TD.pubSndBufs[i].inUse)) &&
(_TD.pubSndBufs[i].size >= dataLength)) {
TRC_DBG((TB, _T("bufHandle:%p (idx:%u) free - size:%u (req:%u)"),
&_TD.pubSndBufs[i], i, _TD.pubSndBufs[i].size,
dataLength));
// Now mark this buffer as being in use and set up the return
// values. The handle is just a pointer to the buffer
// information structure.
_TD.pubSndBufs[i].inUse = TRUE;
*ppBuffer = _TD.pubSndBufs[i].pBuffer;
*pBufHandle = (TD_BUFHND) (PDCVOID)&_TD.pubSndBufs[i];
// Set a good return code.
rc = TRUE;
// Check that the other fields are set correctly.
TRC_ASSERT((_TD.pubSndBufs[i].pNext == NULL),
(TB, _T("Buf:%u next non-zero"), i));
TRC_ASSERT((_TD.pubSndBufs[i].bytesLeftToSend == 0),
(TB, _T("Buf:%u bytesLeftToSend non-zero"), i));
TRC_ASSERT((_TD.pubSndBufs[i].pDataLeftToSend == NULL),
(TB, _T("Buf:%u pDataLeftToSend non-null"), i));
// Update the performance counter.
PRF_INC_COUNTER(PERF_PKTS_ALLOCATED);
// That's all we need to do so just quit.
DC_QUIT;
}
}
// check if we need to re-allocate
if(lastfree < TD_SNDBUF_PUBNUM)
{
pbOldBuffer = _TD.pubSndBufs[lastfree].pBuffer;
cbOldBuffer = _TD.pubSndBufs[lastfree].size;
// reallocate space
TDAllocBuf(
&_TD.pubSndBufs[lastfree],
dataLength
);
// TDAllocBuf() return DCVOID with UI_FatalError()
if( NULL != _TD.pubSndBufs[lastfree].pBuffer )
{
UT_Free( _pUt, pbOldBuffer );
// Now mark this buffer as being in use and set up the return
// values. The handle is just a pointer to the buffer
// information structure.
_TD.pubSndBufs[lastfree].inUse = TRUE;
*ppBuffer = _TD.pubSndBufs[lastfree].pBuffer;
*pBufHandle = (TD_BUFHND) (PDCVOID)&_TD.pubSndBufs[lastfree];
// Set a good return code.
rc = TRUE;
// Update the performance counter.
PRF_INC_COUNTER(PERF_PKTS_ALLOCATED);
// That's all we need to do so just quit.
DC_QUIT;
}
else
{
// restore pointer and size.
_TD.pubSndBufs[lastfree].pBuffer = pbOldBuffer;
_TD.pubSndBufs[lastfree].size = cbOldBuffer;
}
}
// We failed to find a free buffer. Trace the send buffer info.
_TD.getBufferFailed = TRUE;
TRC_ALT((TB, _T("Failed to find a free buffer (req dataLength:%u) Bufs:"),
dataLength));
TD_TRACE_SENDINFO(TRC_LEVEL_ALT);
}
else {
TRC_NRM((TB, _T("Not connected therefore fail get buffer call")));
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
} /* TD_GetPublicBuffer */
/****************************************************************************/
/* Name: TD_GetPrivateBuffer */
/* */
/* Purpose: Attempts to allocate a buffer from the private TD buffer */
/* pool. */
/* */
/* Returns: If the allocation succeeds then this function returns TRUE */
/* otherwise it returns FALSE. */
/* */
/* Params: IN dataLength - length of the buffer requested. */
/* OUT ppBuffer - a pointer to a pointer to the buffer. */
/* OUT pBufHandle - a pointer to a buffer handle. */
/* */
/* Operation: This function should always return a buffer - it it up to */
/* the network layer to ensure that it does not allocate more */
/* buffers than are available in the private list. */
/****************************************************************************/
DCBOOL DCAPI CTD::TD_GetPrivateBuffer(DCUINT dataLength,
PPDCUINT8 ppBuffer,
PTD_BUFHND pBufHandle)
{
DCUINT i;
DCBOOL rc = FALSE;
DC_BEGIN_FN("TD_GetPrivateBuffer");
// Check that we're in the correct state. If we're disconnected
// then fail the call. Note that the FSM state is maintained by the
// receiver thread - but we're on the sender thread.
if (_TD.fsmState == TD_ST_CONNECTED) {
TRC_DBG((TB, _T("Searching for a buffer big enough for %u bytes"),
dataLength));
// Trace out the send buffer information.
TD_TRACE_SENDINFO(TRC_LEVEL_DBG);
// Search the array of buffers looking for the first free one that is
// large enough.
for (i = 0; i < TD_SNDBUF_PRINUM; i++) {
TRC_DBG((TB, _T("Trying buf:%u inUse:%s size:%u"),
i,
_TD.priSndBufs[i].inUse ? "TRUE" : "FALSE",
_TD.priSndBufs[i].size));
if ((!(_TD.priSndBufs[i].inUse)) &&
(_TD.priSndBufs[i].size >= dataLength)) {
TRC_DBG((TB, _T("bufHandle:%p (idx:%u) free - size:%u (req:%u)"),
&_TD.priSndBufs[i], i, _TD.priSndBufs[i].size,
dataLength));
// Now mark this buffer as being in use and set up the return
// values. The handle is just a pointer to the buffer
// information structure.
_TD.priSndBufs[i].inUse = TRUE;
*ppBuffer = _TD.priSndBufs[i].pBuffer;
*pBufHandle = (TD_BUFHND) (PDCVOID)&_TD.priSndBufs[i];
// Set a good return code.
rc = TRUE;
// Check that the other fields are set correctly.
TRC_ASSERT((_TD.priSndBufs[i].pNext == NULL),
(TB, _T("Buf:%u next non-zero"), i));
TRC_ASSERT((_TD.priSndBufs[i].bytesLeftToSend == 0),
(TB, _T("Buf:%u bytesLeftToSend non-zero"), i));
TRC_ASSERT((_TD.priSndBufs[i].pDataLeftToSend == NULL),
(TB, _T("Buf:%u pDataLeftToSend non-null"), i));
// That's all we need to do so just quit.
DC_QUIT;
}
}
// We failed to find a free buffer - flag this internal error by
// tracing out the entire buffer structure and then aborting.
TD_TRACE_SENDINFO(TRC_LEVEL_ERR);
TRC_ABORT((TB, _T("Failed to find a free buffer (req dataLength:%u)"),
dataLength));
}
else {
TRC_NRM((TB, _T("Not connected therefore fail get buffer call")));
}
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* TD_GetPrivateBuffer */
/****************************************************************************/
/* Name: TD_SendBuffer */
/* */
/* Purpose: Sends a buffer. The buffer is added to the end of the */
/* pending queue and all data on the pending queue is then */
/* sent. */
/* */
/* Params: IN pData - pointer to the start of the data. */
/* IN dataLength - amount of the buffer used. */
/* IN bufHandle - handle to a buffer. */
/****************************************************************************/
DCVOID DCAPI CTD::TD_SendBuffer(PDCUINT8 pData,
DCUINT dataLength,
TD_BUFHND bufHandle)
{
PTD_SNDBUF_INFO pNext;
PTD_SNDBUF_INFO pHandle = (PTD_SNDBUF_INFO) bufHandle;
DC_BEGIN_FN("TD_SendBuffer");
// Trace out the function parameters.
TRC_DBG((TB, _T("bufHandle:%p dataLength:%u pData:%p"), bufHandle,
dataLength, pData));
// Check that the handle is valid.
TRC_ASSERT((((pHandle >= &_TD.pubSndBufs[0]) &&
(pHandle <= &_TD.pubSndBufs[TD_SNDBUF_PUBNUM - 1])) ||
((pHandle >= &_TD.priSndBufs[0]) &&
(pHandle <= &_TD.priSndBufs[TD_SNDBUF_PRINUM - 1]))),
(TB, _T("Invalid buffer handle:%p"), bufHandle));
// Verify buffer contents.
TRC_ASSERT((0 == pHandle->bytesLeftToSend),
(TB, _T("pHandle->bytesLeftToSend non-zero (pHandle:%p)"), pHandle));
TRC_ASSERT((NULL == pHandle->pDataLeftToSend),
(TB, _T("pHandle->pDataLeftToSend non NULL (pHandle:%p)"), pHandle));
TRC_ASSERT((NULL != pHandle->pBuffer),
(TB, _T("pHandle->pBuffer is NULL (pHandle:%p)"), pHandle));
TRC_ASSERT((NULL == pHandle->pNext),
(TB, _T("pHandle->pNext (pHandle:%p) non NULL"), pHandle));
TRC_ASSERT((pHandle->inUse), (TB, _T("pHandle %p is not in-use"), pHandle));
// Check that pData lies within the buffer and pData+dataLength does not
// overrun the end.
TRC_ASSERT(((pData >= pHandle->pBuffer) &&
(pData < (pHandle->pBuffer + pHandle->size))),
(TB, _T("pData lies outwith range")));
TRC_ASSERT(((pData + dataLength) <= (pHandle->pBuffer + pHandle->size)),
(TB, _T("pData + dataLength over the end of the buffer")));
//
// Update the fields in the buffer information structure and add to the
// pending buffer queue.
//
pHandle->pDataLeftToSend = pData;
pHandle->bytesLeftToSend = dataLength;
if (NULL == _TD.pFQBuf) {
TRC_DBG((TB, _T("Inserted buffer:%p at queue head"), pHandle));
_TD.pFQBuf = pHandle;
}
else {
// OK - the queue is not empty. We need to scan through the queue
// looking for the first empty slot to insert this buffer in at.
pNext = _TD.pFQBuf;
while (NULL != pNext->pNext)
pNext = pNext->pNext;
// Update the next field of the this buffer information structure.
pNext->pNext = pHandle;
TRC_DBG((TB, _T("Inserted buffer:%p"), pHandle));
}
// Finally attempt to flush the send queue.
TDFlushSendQueue(0);
DC_END_FN();
} /* TD_SendBuffer */
/****************************************************************************/
/* Name: TD_FreeBuffer */
/* */
/* Purpose: Frees the passed buffer. */
/****************************************************************************/
DCVOID DCAPI CTD::TD_FreeBuffer(TD_BUFHND bufHandle)
{
PTD_SNDBUF_INFO pHandle = (PTD_SNDBUF_INFO) bufHandle;
DC_BEGIN_FN("TD_FreeBuffer");
// Trace out the function parameters.
TRC_DBG((TB, _T("bufHandle:%p"), bufHandle));
// Check that the handle is valid.
TRC_ASSERT((((pHandle >= &_TD.pubSndBufs[0]) &&
(pHandle <= &_TD.pubSndBufs[TD_SNDBUF_PUBNUM - 1])) ||
((pHandle >= &_TD.priSndBufs[0]) &&
(pHandle <= &_TD.priSndBufs[TD_SNDBUF_PRINUM - 1]))),
(TB, _T("Invalid buffer handle:%p"), bufHandle));
// Verify the buffer contents. InUse does not matter, we can legitimately
// free a non-in-use buffer.
TRC_ASSERT((0 == pHandle->bytesLeftToSend),
(TB, _T("pHandle->bytesLeftToSend non-zero (pHandle:%p)"), pHandle));
TRC_ASSERT((NULL == pHandle->pDataLeftToSend),
(TB, _T("pHandle->pDataLeftToSend non NULL (pHandle:%p)"), pHandle));
TRC_ASSERT((NULL != pHandle->pBuffer),
(TB, _T("pHandle->pBuffer is NULL (pHandle:%p)"), pHandle));
TRC_ASSERT((NULL == pHandle->pNext),
(TB, _T("pHandle->pNext (pHandle:%p) non NULL"), pHandle));
// Free the buffer.
pHandle->inUse = FALSE;
// Update the performance counter.
PRF_INC_COUNTER(PERF_PKTS_FREED);
DC_END_FN();
} /* TD_FreeBuffer */
#ifdef DC_DEBUG
/****************************************************************************/
/* Name: TD_SetBufferOwner */
/* */
/* Purpose: Note the owner of a TD buffer */
/* */
/* Params: bufHandle - handle to the buffer */
/* pOwner - name of the 'owner' */
/****************************************************************************/
DCVOID DCAPI CTD::TD_SetBufferOwner(TD_BUFHND bufHandle, PDCTCHAR pOwner)
{
PTD_SNDBUF_INFO pHandle = (PTD_SNDBUF_INFO) bufHandle;
DC_BEGIN_FN("TD_SetBufferOwner");
/************************************************************************/
/* Trace out the function parameters. */
/************************************************************************/
TRC_DBG((TB, _T("bufHandle:%p owner %s"), bufHandle, pOwner));
/************************************************************************/
/* Check that the handle is valid. */
/************************************************************************/
TRC_ASSERT((((pHandle >= &_TD.pubSndBufs[0]) &&
(pHandle <= &_TD.pubSndBufs[TD_SNDBUF_PUBNUM - 1])) ||
((pHandle >= &_TD.priSndBufs[0]) &&
(pHandle <= &_TD.priSndBufs[TD_SNDBUF_PRINUM - 1]))),
(TB, _T("Invalid buffer handle:%p"), bufHandle));
/************************************************************************/
/* Save the owner */
/************************************************************************/
pHandle->pOwner = pOwner;
DC_END_FN();
} /* TD_SetBufferOwner */
#endif/* DC_DEBUG */