mirror of https://github.com/lianthony/NT4.0
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.
816 lines
22 KiB
816 lines
22 KiB
/**********************************************************************/
|
|
/** Microsoft Windows **/
|
|
/** Copyright(c) Microsoft Corp., 1994 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
|
|
Sockets.c
|
|
|
|
Vxd sockets routines
|
|
|
|
|
|
FILE HISTORY:
|
|
Johnl 12-Nov-1993 Created
|
|
|
|
*/
|
|
|
|
#include <dhcpcli.h>
|
|
#include <vxdprocs.h>
|
|
#include <debug.h>
|
|
#include <dhcp.h>
|
|
#include "local.h"
|
|
|
|
//
|
|
// Tdi Vxd dispatch table
|
|
//
|
|
TDIDispatchTable * TdiDispatch ;
|
|
|
|
//
|
|
// Last error that occurred, returned by WSAGetLastError
|
|
//
|
|
int wserrno ;
|
|
|
|
//
|
|
// The timeout specified by the last select call. In theory this should
|
|
// be on a per-socket basis but the code only does one recvfrom at a
|
|
// time so this is OK. Necessitated because select creates new socket thus
|
|
// we have no context for which VXDSOCKET being referred to.
|
|
//
|
|
ULONG Timeout ; // recvfrom timeout (in milliseconds)
|
|
extern BOOL fInInit ;
|
|
|
|
//
|
|
// For testing purposes, this simulates sends and/or receives failing
|
|
//
|
|
#ifdef DEBUG
|
|
#define FAIL_SENDS 0x02
|
|
#define FAIL_RECV 0x01
|
|
BOOL FailNetwork = FALSE ;
|
|
#endif
|
|
|
|
//
|
|
// Socket context information
|
|
//
|
|
|
|
typedef struct _VXDSOCKET
|
|
{
|
|
TDI_CONNECTION_INFORMATION TdiInfo ;
|
|
TA_IP_ADDRESS TAIP ;
|
|
HANDLE hAddress ;
|
|
NDIS_BUFFER ndisbuff ;
|
|
CTEBlockStruc * pBlock ;
|
|
CTEBlockStruc * pSendBlock;
|
|
int flags ;
|
|
CTETimer Timer ; // recvfrom timer
|
|
char * buf ; // recvfrom destination buffer
|
|
int len ; // recvfrom buffer len
|
|
CTEBlockStruc ReceiveDatagramBlock ;
|
|
CTEBlockStruc SendDatagramBlock;
|
|
DEFINE_LOCK_STRUCTURE(lock)
|
|
|
|
} VXDSOCKET, * PVXDSOCKET ;
|
|
|
|
#define PROCESSING_RCV 0x01 // Have possible candidate dgram
|
|
#define RCV_TIMEDOUT 0x02 // The timer has timed out
|
|
|
|
|
|
//
|
|
// Datagram buffering structures. The buffering algorithm is simple. New
|
|
// datagrams are always received into BuffPrimary. If it's an acceptable
|
|
// datagram (hardware address matches a DHCP address) then it's marked as
|
|
// valid. If another datagram arrives while BuffPrimary is still valid,
|
|
// BuffPrimary is copied to BuffSecondary. Subsequent datagrams will be lost.
|
|
//
|
|
// This code assumes DHCP only deals with a single address at a time.
|
|
//
|
|
typedef struct _DG_BUFFER
|
|
{
|
|
BOOL fValid ;
|
|
int Len ;
|
|
BYTE Data[DHCP_MESSAGE_SIZE] ; // Must be in line
|
|
} DG_BUFFER, * PDG_BUFFER ;
|
|
|
|
EventRcvBuffer evrcvbuf ;
|
|
NDIS_BUFFER ndisPrimary ;
|
|
DG_BUFFER BuffPrimary ;
|
|
DG_BUFFER BuffSecondary ;
|
|
CTEBlockStruc * pCurrentRecvBlock;
|
|
CTEBlockStruc * pCurrentSendBlock;
|
|
CTETimer * pCurrentCTETimer;
|
|
|
|
//
|
|
// Retrieves the oldest received datagram or NULL if we haven't received
|
|
// any
|
|
//
|
|
#define GetOldestDgram() \
|
|
(BuffSecondary.fValid ? &BuffSecondary : \
|
|
(BuffPrimary.fValid ? &BuffPrimary : NULL ))
|
|
|
|
//
|
|
// Local prototypes
|
|
//
|
|
TDI_STATUS
|
|
TdiRcvDatagramHandler(
|
|
IN PVOID pDgramEventContext,
|
|
IN int SourceAddressLength,
|
|
IN PVOID pSourceAddress,
|
|
IN int OptionsLength,
|
|
IN PVOID pOptions,
|
|
IN UINT Flags,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *pBytesTaken,
|
|
IN PVOID pData,
|
|
OUT EventRcvBuffer * * ppBuffer ) ;
|
|
|
|
VOID CompletionRcv( PVOID pContext, TDI_STATUS tdistatus, UINT Bytes ) ;
|
|
VOID CompletionSend( PVOID pContext, TDI_STATUS tdistatus, UINT Bytes ) ;
|
|
VOID ReceiveTimeout( CTEEvent * pCTEEvent, PVOID pContext ) ;
|
|
VOID ReleaseBlockedSockets(VOID);
|
|
|
|
//******************* Pageable Routine Declarations ****************
|
|
#ifdef ALLOC_PRAGMA
|
|
//
|
|
// This is a hack to stop compiler complaining about the routines already
|
|
// being in a segment!!!
|
|
//
|
|
#pragma code_seg()
|
|
|
|
#pragma CTEMakePageable(PAGEDHCP, socket )
|
|
#pragma CTEMakePageable(PAGEDHCP, closesocket )
|
|
#pragma CTEMakePageable(PAGEDHCP, bind )
|
|
#pragma CTEMakePageable(PAGEDHCP, sendto )
|
|
#pragma CTEMakePageable(PAGEDHCP, select )
|
|
#pragma CTEMakePageable(PAGEDHCP, ReleaseBlockedSockets )
|
|
#endif ALLOC_PRAGMA
|
|
//******************************************************************
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: socket
|
|
|
|
SYNOPSIS: Allocates socket data structure suitable only for data gram
|
|
sends and receives
|
|
|
|
********************************************************************/
|
|
|
|
SOCKET PASCAL FAR socket( int af, int type, int protocol )
|
|
{
|
|
PVXDSOCKET psock ;
|
|
ASSERT( af == PF_INET ) ;
|
|
ASSERT( type == SOCK_DGRAM ) ;
|
|
ASSERT( protocol == IPPROTO_UDP ) ;
|
|
ASSERT( sizeof( SOCKET ) == sizeof( PVXDSOCKET )) ;
|
|
|
|
if( TdiDispatch == NULL )
|
|
{
|
|
wserrno = WSAENETDOWN;
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
if ( psock = DhcpAllocateMemory( sizeof( VXDSOCKET )) )
|
|
{
|
|
memset( psock, 0, sizeof( VXDSOCKET ) ) ;
|
|
return (SOCKET) psock ;
|
|
}
|
|
|
|
wserrno = WSAENOBUFS ;
|
|
return INVALID_SOCKET ;
|
|
}
|
|
|
|
int PASCAL FAR closesocket( SOCKET s )
|
|
{
|
|
PVXDSOCKET psock = (PVXDSOCKET) s ;
|
|
|
|
if ( psock->hAddress && TdiDispatch )
|
|
{
|
|
TDI_REQUEST TdiRequest ;
|
|
|
|
TdiRequest.Handle.AddressHandle = psock->hAddress ;
|
|
REQUIRE( !TdiVxdCloseAddress( &TdiRequest )) ;
|
|
}
|
|
|
|
DhcpFreeMemory( (PVOID) s ) ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: bind
|
|
|
|
SYNOPSIS: Simulates a sockets bind
|
|
|
|
NOTES:
|
|
|
|
********************************************************************/
|
|
|
|
char DhcpOptions[2] = { TDI_ADDRESS_OPTION_DHCP, 0 } ;
|
|
|
|
int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen)
|
|
{
|
|
PVXDSOCKET psock = (PVXDSOCKET) s ;
|
|
struct sockaddr_in * paddr = (struct sockaddr_in *) addr ;
|
|
TDI_STATUS tdistatus ;
|
|
TDI_REQUEST TdiRequest ;
|
|
|
|
ASSERT( paddr->sin_family == PF_INET ) ;
|
|
|
|
if( TdiDispatch == NULL )
|
|
{
|
|
wserrno = WSAENETDOWN;
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
InitIPAddress( &psock->TAIP,
|
|
paddr->sin_port,
|
|
paddr->sin_addr.s_addr );
|
|
|
|
#define UDP_PORT 17
|
|
switch ( TdiVxdOpenAddress( &TdiRequest,
|
|
(TRANSPORT_ADDRESS*) &psock->TAIP,
|
|
UDP_PORT,
|
|
DhcpOptions ))
|
|
{
|
|
case TDI_SUCCESS:
|
|
psock->hAddress = TdiRequest.Handle.AddressHandle ;
|
|
REQUIRE(!TdiVxdSetEventHandler( psock->hAddress,
|
|
TDI_EVENT_RECEIVE_DATAGRAM,
|
|
TdiRcvDatagramHandler,
|
|
psock )) ;
|
|
return 0 ;
|
|
|
|
case TDI_PENDING:
|
|
default:
|
|
ASSERT( FALSE ) ; // This really shouldn't fail or return pending
|
|
wserrno = WSAENOBUFS ;
|
|
break ;
|
|
}
|
|
|
|
return SOCKET_ERROR ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: sendto
|
|
|
|
SYNOPSIS: Does a datagram send to the requested address and port
|
|
|
|
ENTRY: Same as winsock sendto
|
|
|
|
RETURN: Number of bytes sent or SOCKET_ERROR if an error occurred
|
|
|
|
NOTES: There's the possibility that a garbage datagram may get
|
|
sent if the first send fails (for example on an ARP timeout),
|
|
a second send is initiated (uses same buffer) and succeeds.
|
|
It's a remote possibility and it should be innocuous.
|
|
|
|
********************************************************************/
|
|
|
|
int PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags,
|
|
const struct sockaddr FAR *to, int tolen)
|
|
{
|
|
TDI_REQUEST TdiRequest ;
|
|
ULONG SentLength = 0 ;
|
|
TDI_STATUS tdistatus ;
|
|
PVXDSOCKET psock = (PVXDSOCKET) s ;
|
|
struct sockaddr_in * pto = (struct sockaddr_in *) to ;
|
|
CTELockHandle hLock;
|
|
|
|
|
|
CTEGetLock( &psock->lock, &hLock );
|
|
|
|
CDbgPrint( DEBUG_MISC, ("sendto entered\r\n")) ;
|
|
|
|
if( TdiDispatch == NULL )
|
|
{
|
|
wserrno = WSAENETDOWN;
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if ( FailNetwork & FAIL_SENDS )
|
|
{
|
|
wserrno = WSAENOBUFS ;
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
|
|
return SOCKET_ERROR ;
|
|
}
|
|
#endif
|
|
InitNDISBuff( &psock->ndisbuff, (void *)buf, len, NULL ) ;
|
|
InitIPTDIConnectInfo( &psock->TdiInfo,
|
|
&psock->TAIP,
|
|
pto->sin_port,
|
|
pto->sin_addr.s_addr ) ;
|
|
|
|
TdiRequest.RequestNotifyObject = CompletionSend ;
|
|
TdiRequest.RequestContext = psock ;
|
|
TdiRequest.Handle.AddressHandle= psock->hAddress ;
|
|
|
|
ASSERT( pCurrentSendBlock == NULL );
|
|
ASSERT( !psock->pSendBlock );
|
|
CTEInitBlockStruc( &psock->SendDatagramBlock );
|
|
pCurrentSendBlock = psock->pSendBlock = &psock->SendDatagramBlock ;
|
|
|
|
tdistatus = TdiVxdSendDatagram( &TdiRequest,
|
|
&psock->TdiInfo,
|
|
len,
|
|
&SentLength,
|
|
&psock->ndisbuff ) ;
|
|
|
|
switch ( tdistatus )
|
|
{
|
|
case TDI_PENDING:
|
|
CTEBlock1( &psock->SendDatagramBlock ) ;
|
|
SentLength = psock->SendDatagramBlock.cbs_status;
|
|
break;
|
|
|
|
case TDI_SUCCESS:
|
|
break;
|
|
|
|
case TDI_NO_RESOURCES:
|
|
wserrno = WSAENOBUFS ;
|
|
SentLength = SOCKET_ERROR;
|
|
break ;
|
|
|
|
default:
|
|
DhcpPrint((DEBUG_ERRORS, "sendto: Unexpected error from TdiVxdSendDatagram\r\n")) ;
|
|
wserrno = WSAENOBUFS ;
|
|
SentLength = SOCKET_ERROR;
|
|
break ;
|
|
}
|
|
|
|
pCurrentSendBlock = NULL;
|
|
psock->pSendBlock = NULL;
|
|
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
return SentLength ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: recvfrom
|
|
|
|
SYNOPSIS: Simulates a socket recvfrom call (only for datagrams)
|
|
|
|
RETURN: Number of bytes received or SOCKET_ERROR if an error occurred
|
|
|
|
NOTES:
|
|
|
|
********************************************************************/
|
|
|
|
int PASCAL FAR recvfrom (SOCKET s, char FAR * buf, int len, int flags,
|
|
struct sockaddr FAR *from, int FAR * fromlen)
|
|
{
|
|
TDI_REQUEST TdiRequest ;
|
|
TDI_STATUS tdistatus ;
|
|
PVXDSOCKET psock = (PVXDSOCKET) s ;
|
|
PDG_BUFFER pdgbuf ;
|
|
CTELockHandle hLock;
|
|
|
|
CDbgPrint( DEBUG_MISC, ("recvfrom entered\r\n")) ;
|
|
CTEGetLock( &psock->lock, &hLock );
|
|
|
|
#ifdef DEBUG
|
|
if ( FailNetwork & FAIL_RECV )
|
|
{
|
|
wserrno = ERROR_SEM_TIMEOUT ;
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
|
|
return SOCKET_ERROR ;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Do we have a buffered DHCP message?
|
|
//
|
|
if ( pdgbuf = GetOldestDgram() )
|
|
{
|
|
int BytesToCopy = min( len, sizeof(pdgbuf->Data) ) ;
|
|
memcpy( buf, pdgbuf->Data, BytesToCopy ) ;
|
|
pdgbuf->fValid = FALSE ;
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
|
|
return BytesToCopy ;
|
|
}
|
|
|
|
CTEInitBlockStruc( &psock->ReceiveDatagramBlock ) ;
|
|
CTEInitTimer( &psock->Timer ) ;
|
|
psock->buf = buf ;
|
|
psock->len = len ;
|
|
|
|
psock->flags &= ~RCV_TIMEDOUT ;
|
|
if ( !CTEStartTimer( &psock->Timer,
|
|
Timeout,
|
|
ReceiveTimeout,
|
|
psock ))
|
|
{
|
|
DhcpPrint((DEBUG_ERRORS, "recvfrom: Warning - Failed to start timer!!\r\n")) ;
|
|
wserrno = WSAENOBUFS ;
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
|
|
return SOCKET_ERROR ;
|
|
}
|
|
DhcpPrint(( DEBUG_MISC, "recvfrom - Datagram receive timeout set at %d seconds", Timeout/1000 ));
|
|
|
|
//
|
|
// Let the handler there's an active client
|
|
//
|
|
|
|
ASSERT( pCurrentRecvBlock == NULL );
|
|
ASSERT( pCurrentCTETimer == NULL );
|
|
pCurrentRecvBlock = psock->pBlock = &psock->ReceiveDatagramBlock ;
|
|
pCurrentCTETimer = &psock->Timer;
|
|
CTEBlock1( &psock->ReceiveDatagramBlock ) ;
|
|
pCurrentCTETimer = NULL;
|
|
pCurrentRecvBlock = NULL;
|
|
|
|
//
|
|
// Check how many bytes were retrieved (0 if we timed out or another
|
|
// error occurred)
|
|
//
|
|
if ( psock->ReceiveDatagramBlock.cbs_status )
|
|
{
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
|
|
return psock->ReceiveDatagramBlock.cbs_status ;
|
|
}
|
|
|
|
//
|
|
// A minor hack - GetSpecifiedDhcpMessage uses select to timeout, which
|
|
// would be more painful to support so we just timeout here and return
|
|
// a non WSA error that works correctly in this instance
|
|
//
|
|
wserrno = ERROR_SEM_TIMEOUT ;
|
|
CTEFreeLock( &psock->lock, hLock );
|
|
|
|
return SOCKET_ERROR ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: select
|
|
|
|
SYNOPSIS: Stub select Winsock API
|
|
|
|
********************************************************************/
|
|
|
|
int PASCAL FAR select (int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
|
|
fd_set FAR *exceptfds, const struct timeval FAR *timeout)
|
|
{
|
|
//
|
|
// Shorten the timeout if we're not in initialization. This prevents
|
|
// blocking the current vdm for an extended amount of time. Even if
|
|
// we don't get the response within the timeout, if it comes in later,
|
|
// we'll still get it the next time we call recvfrom.
|
|
//
|
|
|
|
#if defined(CHICAGO)
|
|
Timeout = timeout->tv_sec * 1000 + timeout->tv_usec ;
|
|
#else
|
|
if ( fInInit )
|
|
Timeout = timeout->tv_sec * 1000 + timeout->tv_usec ;
|
|
else
|
|
Timeout = 1000 ;
|
|
#endif // CHICAGO
|
|
|
|
|
|
//
|
|
// Don't return 0 (means data not available) unless we change to use
|
|
// a receive handler and buffer the datagrams
|
|
//
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: WSAGetLastError
|
|
|
|
SYNOPSIS: Returns the last Winsock error
|
|
|
|
********************************************************************/
|
|
|
|
int PASCAL FAR WSAGetLastError(void)
|
|
{
|
|
return wserrno ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: setsockopt
|
|
|
|
SYNOPSIS: Stub setsockopt winsock API
|
|
|
|
********************************************************************/
|
|
|
|
int PASCAL FAR setsockopt (SOCKET s, int level, int optname,
|
|
const char FAR * optval, int optlen)
|
|
{
|
|
//
|
|
// Nothing to fail
|
|
//
|
|
return 0 ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ReleaseBlockedSockets
|
|
|
|
SYNOPSIS: Releases any sockets blocked on I/O.
|
|
|
|
********************************************************************/
|
|
VOID
|
|
ReleaseBlockedSockets(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Unblock the worker thread if currently blocked.
|
|
//
|
|
|
|
if( pCurrentCTETimer )
|
|
{
|
|
CTEStopTimer( pCurrentCTETimer );
|
|
pCurrentCTETimer = NULL;
|
|
}
|
|
|
|
if( pCurrentRecvBlock )
|
|
{
|
|
CTESignal( pCurrentRecvBlock, 0 );
|
|
pCurrentRecvBlock = NULL;
|
|
}
|
|
|
|
if( pCurrentSendBlock )
|
|
{
|
|
CTESignal( pCurrentSendBlock, 0 );
|
|
pCurrentSendBlock = 0;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: TdiRcvDatagramHandler
|
|
|
|
SYNOPSIS: Examines incoming datagrams for DHCP server responses
|
|
|
|
NOTES:
|
|
|
|
********************************************************************/
|
|
|
|
TDI_STATUS
|
|
TdiRcvDatagramHandler(
|
|
IN PVOID pDgramEventContext,
|
|
IN int SourceAddressLength,
|
|
IN PVOID pSourceAddress,
|
|
IN int OptionsLength,
|
|
IN PVOID pOptions,
|
|
IN UINT Flags,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *pBytesTaken,
|
|
IN PVOID pData,
|
|
OUT EventRcvBuffer * * ppBuffer )
|
|
{
|
|
PVXDSOCKET psock = (PVXDSOCKET) pDgramEventContext ;
|
|
TA_IP_ADDRESS * pTAIP = (TA_IP_ADDRESS*) pSourceAddress ;
|
|
PDHCP_CONTEXT pDhcpContext ;
|
|
HARDWARE_ADDRESS HardwareAddress ;
|
|
|
|
*ppBuffer = NULL ;
|
|
*pBytesTaken = 0 ;
|
|
|
|
//
|
|
// Make sure this is a reasonable candidate before accepting it
|
|
//
|
|
if ( SourceAddressLength < sizeof( TA_IP_ADDRESS ) ||
|
|
pTAIP->Address[0].Address[0].sin_port != htons( DHCP_SERVR_PORT )||
|
|
BytesAvailable < sizeof( DHCP_MESSAGE ))
|
|
{
|
|
DbgPrint("Received datagram that is too short or from wrong port\n") ;
|
|
return TDI_NOT_ACCEPTED ;
|
|
}
|
|
|
|
//
|
|
// If we already had a valid datagram, then save it because the new
|
|
// one very well may *not* be valid (DHCP msgs sent to broadcast).
|
|
//
|
|
if ( BuffPrimary.fValid )
|
|
{
|
|
memcpy( &BuffSecondary, &BuffPrimary, sizeof( BuffSecondary )) ;
|
|
BuffPrimary.fValid = FALSE ;
|
|
}
|
|
|
|
//
|
|
// Get the whole datagram then check its hardware address
|
|
//
|
|
InitNDISBuff( &ndisPrimary,
|
|
BuffPrimary.Data,
|
|
sizeof(BuffPrimary.Data),
|
|
NULL ) ;
|
|
evrcvbuf.erb_rtn = CompletionRcv ;
|
|
evrcvbuf.erb_size = BytesAvailable ;
|
|
evrcvbuf.erb_context = psock ;
|
|
evrcvbuf.erb_buffer = &ndisPrimary ;
|
|
evrcvbuf.erb_flags = NULL ;
|
|
|
|
*ppBuffer = &evrcvbuf ;
|
|
|
|
//
|
|
// If we timeout before the completion routine is called, let the
|
|
// timeout routine know that we have a potential candidate so don't
|
|
// error out just yet.
|
|
//
|
|
psock->flags |= PROCESSING_RCV ;
|
|
|
|
// DhcpPrint(( DEBUG_MISC, "TdiRcvDatagramHandler - Accepting a DHCP datagram\r\n")) ;
|
|
return TDI_MORE_PROCESSING ;
|
|
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CompletionRcv
|
|
|
|
SYNOPSIS: Filters the received datagram on its hardware address then
|
|
unblocks a the recvfrom if psock->pBlock is non-NULL
|
|
|
|
********************************************************************/
|
|
|
|
VOID CompletionRcv( PVOID pContext, TDI_STATUS tdistatus, UINT Bytes )
|
|
{
|
|
PVXDSOCKET psock = (PVXDSOCKET) pContext ;
|
|
HARDWARE_ADDRESS HardwareAddress ;
|
|
PDHCP_MESSAGE pDhcpMsg = (PDHCP_MESSAGE) BuffPrimary.Data ;
|
|
PDHCP_CONTEXT pDhcpContext ;
|
|
|
|
ASSERT( psock ) ;
|
|
|
|
psock->flags &= ~PROCESSING_RCV ;
|
|
|
|
if ( tdistatus )
|
|
{
|
|
// DhcpPrint(( DEBUG_ERRORS, "CompletionRcv: tdistatus %d from send/recv", tdistatus)) ;
|
|
|
|
wserrno = tdistatus ;
|
|
|
|
if ( psock->pBlock )
|
|
{
|
|
CTESignal( psock->pBlock, 0 ) ;
|
|
psock->pBlock = NULL ;
|
|
}
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Check the DHCP message's hardware address and see if it originated
|
|
// with us
|
|
//
|
|
|
|
HardwareAddress.Length = pDhcpMsg->HardwareAddressLength ;
|
|
memcpy( HardwareAddress.Address,
|
|
pDhcpMsg->HardwareAddress,
|
|
pDhcpMsg->HardwareAddressLength ) ;
|
|
|
|
if ( !(pDhcpContext = LocalFindDhcpContextOnList( &DhcpGlobalNICList, &HardwareAddress )))
|
|
goto Cleanup ;
|
|
|
|
BuffPrimary.fValid = TRUE ;
|
|
BuffPrimary.Len = Bytes ;
|
|
|
|
//
|
|
// If we are actually in recvfrom (as opposed to just buffering) then
|
|
// copy the message now
|
|
//
|
|
|
|
if ( psock->pBlock )
|
|
{
|
|
PDG_BUFFER pdgbuf = GetOldestDgram() ;
|
|
|
|
ASSERT( pdgbuf ) ;
|
|
ASSERT( pdgbuf->Len <= psock->len ) ;
|
|
|
|
Bytes = pdgbuf->Len ;
|
|
memcpy( psock->buf, pdgbuf->Data, Bytes ) ;
|
|
pdgbuf->fValid = FALSE ;
|
|
CTEStopTimer( &psock->Timer ) ;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( !pDhcpContext && psock->flags & RCV_TIMEDOUT )
|
|
{
|
|
//
|
|
// The candidate failed and the timer fired so let the client know the
|
|
// recvfrom timedout if they are in a recvfrom
|
|
//
|
|
Bytes = 0 ;
|
|
}
|
|
|
|
if ( psock->pBlock &&
|
|
(pDhcpContext || !Bytes) )
|
|
{
|
|
CTESignal( psock->pBlock, Bytes ) ;
|
|
psock->pBlock = NULL ;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CompletionSend
|
|
|
|
SYNOPSIS: Unblocks the sendto call
|
|
|
|
********************************************************************/
|
|
|
|
VOID CompletionSend( PVOID pContext, TDI_STATUS tdistatus, UINT Bytes )
|
|
{
|
|
PVXDSOCKET psock = (PVXDSOCKET) pContext;
|
|
DWORD dwStatus;
|
|
|
|
ASSERT( psock );
|
|
|
|
if ( psock->pSendBlock )
|
|
{
|
|
|
|
if ( tdistatus )
|
|
{
|
|
// an error occurred
|
|
wserrno = tdistatus;
|
|
dwStatus = SOCKET_ERROR;
|
|
}
|
|
else
|
|
dwStatus = Bytes;
|
|
|
|
CTESignal( psock->pSendBlock, dwStatus );
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ReceiveTimeout
|
|
|
|
SYNOPSIS: This is the recvfrom timeout completion routine
|
|
|
|
********************************************************************/
|
|
|
|
VOID ReceiveTimeout( CTEEvent * pCTEEvent, PVOID pContext )
|
|
{
|
|
// DbgPrint("ReceiveTimeout - Warning - Timing out receive datagram\r\n") ;
|
|
|
|
//
|
|
// If we are looking at a potential candidate, delay erroring out
|
|
//
|
|
if ( ((PVXDSOCKET)pContext)->flags & PROCESSING_RCV )
|
|
((PVXDSOCKET)pContext)->flags |= RCV_TIMEDOUT ;
|
|
else
|
|
CompletionRcv( pContext, TDI_TIMED_OUT, 0 ) ;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
//
|
|
// Defn. from private\inc\sockets\netinet\in.h
|
|
//
|
|
|
|
u_long PASCAL FAR htonl (u_long x)
|
|
{
|
|
return((((x) >> 24) & 0x000000FFL) |
|
|
(((x) >> 8) & 0x0000FF00L) |
|
|
(((x) << 8) & 0x00FF0000L) |
|
|
(((x) << 24) & 0xFF000000L));
|
|
}
|
|
|
|
u_short PASCAL FAR htons (u_short x)
|
|
{
|
|
return ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00)) ;
|
|
}
|
|
|
|
u_long PASCAL FAR ntohl (u_long netlong)
|
|
{
|
|
return htonl( netlong ) ;
|
|
}
|
|
|
|
u_short PASCAL FAR ntohs (u_short netshort)
|
|
{
|
|
return htons( netshort ) ;
|
|
}
|
|
|
|
#ifdef DEBUG // Only used for trace output
|
|
|
|
char buff[128] ; // Making this static puts it in the _BSS segment for
|
|
// some reason which the windows loader chokes on
|
|
|
|
char * PASCAL inet_ntoa( struct in_addr in )
|
|
{
|
|
uchar * p = (uchar *) &in ;
|
|
|
|
VxdSprintf( buff, "%u.%u.%u.%u", (uint) p[0], (uint) p[1], (uint) p[2], (uint) p[3] ) ;
|
|
|
|
return buff ;
|
|
}
|
|
|
|
#endif
|
|
|