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.
1690 lines
43 KiB
1690 lines
43 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nbltsvr.c
|
|
|
|
Abstract:
|
|
|
|
This is the server side loadable transport module for NetBIOS.
|
|
|
|
Author:
|
|
|
|
tony chan (tonychan) 20-Jan-1995
|
|
|
|
Revision History:
|
|
|
|
tony chan (tonychan) 20-Jan-1995 using winsock to support NetBIOS
|
|
|
|
tony chan (tonychan) 5-Apr-1995 Fix to work with multiple Network Cards
|
|
|
|
Comments:
|
|
|
|
This server DLL works with both new and old NetBIOS client DLL.
|
|
|
|
In order to be compatible with the old NetBIOS client transport,
|
|
On ReceiveAny, server first check on new connection of the new client.
|
|
If the first DWORD of the packet is 0, we know that it's a old NetBIOS
|
|
client connection. Therefore, we will take away the seq # and return only
|
|
the data to the runtime.
|
|
|
|
If the first DWORD of the first message is not 0, it's actually is the
|
|
runtime message_header RPC_version #, so we hand the whole buffer to the
|
|
runtime.
|
|
|
|
On the client side.
|
|
If we are dealing with old server, on all subsequence Send, we need to
|
|
prepend seq_number, and we need to take away sequence # on all recv from
|
|
old client
|
|
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
// Includes
|
|
//
|
|
//
|
|
//
|
|
#include <stdlib.h>
|
|
#include "sysinc.h"
|
|
#include "rpc.h"
|
|
#include "rpcerrp.h"
|
|
#include "rpcdcep.h"
|
|
#include "rpctran.h"
|
|
#include "winbase.h"
|
|
#include <winsock.h>
|
|
#include "wsnetbs.h"
|
|
#include "reg.h" /* registry lookup rountine */
|
|
|
|
//
|
|
//
|
|
// Debugging code...
|
|
//
|
|
//
|
|
|
|
|
|
|
|
#if DBG
|
|
#define OPTIONAL_STATIC
|
|
#else
|
|
#define OPTIONAL_STATIC static
|
|
#endif
|
|
|
|
|
|
OPTIONAL_STATIC CRITICAL_SECTION TransCritSec;
|
|
|
|
//
|
|
// Data Structures
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
#define INITIAL_MASK_SIZE 10
|
|
|
|
typedef struct fd_big_set
|
|
{
|
|
u_int fd_count; /* how many are SET? */
|
|
SOCKET fd_array[0]; /* an array of SOCKETs */
|
|
} fd_big_set;
|
|
|
|
|
|
|
|
//
|
|
// This code is stolen from winsock.h. It does the same thing as FD_SET()
|
|
// except that it assumes the fd_array is large enough. AddConnection()
|
|
// grows the Masks as needed, so this better always be true.
|
|
//
|
|
|
|
#define FD_BIG_SET(fd, address) do { \
|
|
ASSERT((address)->MaskSize > (address)->MasterMask->fd_count); \
|
|
(address)->MasterMask->fd_array[(address)->MasterMask->fd_count++]=(fd);\
|
|
} while(0)
|
|
|
|
|
|
//
|
|
//
|
|
// Defines
|
|
//
|
|
//
|
|
#define INITIAL_MAPSIZE 32
|
|
#define ENDPOINT_LEN 3
|
|
#define NETADDR_LEN 16
|
|
|
|
#define MAX_HOSTNAME_LEN 15
|
|
#define MAX_NUM_ENDPOINT 256
|
|
#define LAN_MAN_PORT 32
|
|
|
|
|
|
typedef struct
|
|
{
|
|
SOCKET Sock;
|
|
void *Conn;
|
|
} SOCKMAP, *PSOCKMAP;
|
|
|
|
typedef struct
|
|
{
|
|
int MaxEntries;
|
|
int LastEntry;
|
|
int StartEntry;
|
|
} MAPINFO;
|
|
|
|
typedef struct
|
|
{ /* now we have 1 sock map for data sockets */
|
|
/* 1 for listening sockets */
|
|
int NumConnections;
|
|
int ListenSockReady;
|
|
unsigned int MaskSize;
|
|
fd_big_set *MasterMask;
|
|
fd_big_set *Mask;
|
|
PSOCKMAP DataMap;
|
|
MAPINFO DataMapInfo;
|
|
PSOCKMAP ListenSockMap;
|
|
MAPINFO ListenMapInfo;
|
|
} ADDRESS, *PADDRESS;
|
|
|
|
typedef struct
|
|
{
|
|
SOCKET ConnSock;
|
|
int ConnSockClosed;
|
|
PADDRESS Address;
|
|
unsigned int ReceiveDirectFlag;
|
|
int old_client;
|
|
DWORD seq_num;
|
|
} SCONNECTION, *PSCONNECTION;
|
|
|
|
/* 0 means 1 card, 1 means 2 cards */
|
|
extern int NumCards; /* defined in reg.h */
|
|
|
|
#define FD_BIG_SET(fd, address) do { \
|
|
ASSERT((address)->MaskSize > (address)->MasterMask->fd_count); \
|
|
(address)->MasterMask->fd_array[(address)->MasterMask->fd_count++]=(fd);\
|
|
} while(0)
|
|
|
|
|
|
void CloseAllListenSock(PADDRESS Address, int j)
|
|
|
|
{
|
|
|
|
/* close listening all sockets */
|
|
|
|
int i;
|
|
/* start from 1 because ListenSockMap[0]
|
|
= -1 */
|
|
for(i = 1 ; i <= j; i++)
|
|
{
|
|
if(Address->ListenSockMap)
|
|
{
|
|
closesocket(Address->ListenSockMap[i].Sock);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
RPC_STATUS GrowMap(PADDRESS Address, BOOL bIsListenMap)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine grow socket map in necessary.
|
|
|
|
Arguments:
|
|
|
|
Address - A pointer to the loadable transport interface address.
|
|
|
|
bIsListenMap - boolean value to select which map to grow,
|
|
1 means ListenSockMap, 0 means DataMap.
|
|
|
|
ReturnValue:
|
|
|
|
RPC_S_OUT_OF_MEMORY - out of memory while rellocating memory for a bigger
|
|
map.
|
|
|
|
RPC_S_OK - OK.
|
|
|
|
--*/
|
|
{
|
|
PSOCKMAP *pMap ;
|
|
MAPINFO *pMapInfo ;
|
|
PSOCKMAP TempMapPtr;
|
|
int i, j ;
|
|
|
|
|
|
if(bIsListenMap)
|
|
{
|
|
pMap = &(Address->ListenSockMap) ;
|
|
pMapInfo = &(Address->ListenMapInfo) ;
|
|
}
|
|
else
|
|
{
|
|
pMap = &(Address->DataMap);
|
|
pMapInfo = &(Address->DataMapInfo);
|
|
}
|
|
|
|
i = 0;
|
|
for(;;)
|
|
{
|
|
if ((*pMap)[i].Sock == 0)
|
|
break; // found room
|
|
|
|
if (i == pMapInfo->MaxEntries - 1)
|
|
{
|
|
// No room in current Map, grow it
|
|
TempMapPtr = *pMap;
|
|
*pMap = I_RpcAllocate(2 * pMapInfo->MaxEntries * sizeof(SOCKMAP));
|
|
|
|
if (Address->DataMap == 0)
|
|
{
|
|
*pMap = TempMapPtr;
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Copy old table to first half of new...
|
|
//
|
|
memcpy (*pMap, TempMapPtr,
|
|
pMapInfo->MaxEntries * sizeof(SOCKMAP));
|
|
|
|
//
|
|
// Initialize all new entries...
|
|
//
|
|
for (j=pMapInfo->MaxEntries; j < (2*pMapInfo->MaxEntries); j++ )
|
|
{
|
|
(*pMap)[j].Sock = 0;
|
|
}
|
|
|
|
// Grow table size
|
|
pMapInfo->MaxEntries *= 2;
|
|
|
|
// Free old table
|
|
I_RpcFree ( TempMapPtr );
|
|
|
|
break; // made room
|
|
}
|
|
|
|
i++; // try next entry
|
|
}
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
RPC_STATUS GrowMask(PADDRESS Address)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine grow socket Mask in necessary.
|
|
|
|
Arguments:
|
|
|
|
Address - A pointer to the loadable transport interface address.
|
|
|
|
ReturnValue:
|
|
|
|
RPC_S_OUT_OF_MEMORY - out of memory while rellocating memory for a bigger
|
|
mask.
|
|
|
|
RPC_S_OK - OK.
|
|
|
|
--*/
|
|
{
|
|
fd_big_set *TempMaskPtr;
|
|
|
|
if (Address->MasterMask->fd_count == Address->MaskSize)
|
|
{
|
|
// grow Address->MasterMask
|
|
|
|
TempMaskPtr = Address->MasterMask;
|
|
Address->MasterMask = I_RpcAllocate(sizeof(fd_big_set) +
|
|
2 * sizeof(SOCKET) *
|
|
Address->MaskSize);
|
|
|
|
if (Address->MasterMask == 0)
|
|
{
|
|
Address->MasterMask = TempMaskPtr;
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// copy old mask entries
|
|
memcpy(Address->MasterMask, TempMaskPtr,
|
|
sizeof(fd_big_set) + sizeof(SOCKET) * Address->MaskSize);
|
|
|
|
// free old MasterMask
|
|
I_RpcFree(TempMaskPtr);
|
|
|
|
// grow Address->Mask
|
|
TempMaskPtr = Address->Mask;
|
|
Address->Mask = I_RpcAllocate(sizeof(fd_big_set) +
|
|
2 * sizeof(SOCKET) * Address->MaskSize);
|
|
if (Address->Mask == 0)
|
|
{
|
|
Address->Mask = TempMaskPtr;
|
|
// We didn't update Address->MaskSize, so the size
|
|
// difference between MasterMask and Mask will be okay.
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// copy old mask entries
|
|
memcpy(Address->Mask, TempMaskPtr,
|
|
sizeof(fd_big_set) + sizeof(SOCKET) * Address->MaskSize);
|
|
|
|
// Free old Mask
|
|
I_RpcFree(TempMaskPtr);
|
|
|
|
|
|
// Really grow mask size
|
|
Address->MaskSize *= 2;
|
|
}
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS AddSocket(PADDRESS Address, SOCKET socket)
|
|
|
|
/*++
|
|
Routine Description:
|
|
Adds a socket to the master mask and grows the masks if neccassary
|
|
This routine is used to add listen socket
|
|
|
|
Arguments:
|
|
socket - the socket to be added
|
|
|
|
ReturnValue:
|
|
|
|
RPC_S_OUT_OF_MEMORY - out of memory while rellocating memory for a bigger
|
|
mask.
|
|
|
|
RPC_S_OK - OK.
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS status ;
|
|
int i ;
|
|
|
|
//
|
|
// Grow mask if neccassary
|
|
//
|
|
if((status = GrowMask(Address)) != RPC_S_OK)
|
|
return status ;
|
|
|
|
|
|
if((status = GrowMap(Address, 1)) != RPC_S_OK)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// add socket to the map
|
|
for(i=0; i < Address->ListenMapInfo.MaxEntries; i++)
|
|
{
|
|
if (Address->ListenSockMap[i].Sock == 0)
|
|
{
|
|
Address->ListenSockMap[i].Sock = socket;
|
|
Address->ListenSockMap[i].Conn = 0 ;
|
|
|
|
if (i > Address->ListenMapInfo.LastEntry)
|
|
Address->ListenMapInfo.LastEntry = i;
|
|
|
|
FD_BIG_SET(socket, Address) ;
|
|
|
|
return (RPC_S_OK) ;
|
|
}
|
|
}
|
|
|
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|
}
|
|
|
|
|
|
OPTIONAL_STATIC int
|
|
FindSockWithDataReady ( PADDRESS Address, BOOL bList )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for socket that is ready to receive data.
|
|
It could be a Data socket or a listening socket.
|
|
if bList = 0, we are looking for Listen socket
|
|
if bList = 1, we are looking for Data socket ready
|
|
|
|
Arguments:
|
|
|
|
Address - A pointer to the loadable transport interface address.
|
|
|
|
bList - A flag to indicate what kind of socket we are interested.
|
|
|
|
ReturnValue:
|
|
|
|
The index of the ready socket.
|
|
|
|
--*/
|
|
{
|
|
|
|
int i;
|
|
PSOCKMAP Map;
|
|
MAPINFO *pMapInfo;
|
|
|
|
|
|
if(bList)
|
|
{
|
|
Map = Address->ListenSockMap;
|
|
pMapInfo = &(Address->ListenMapInfo);
|
|
}
|
|
else
|
|
{
|
|
Map = Address->DataMap;
|
|
pMapInfo = &(Address->DataMapInfo);
|
|
}
|
|
|
|
//
|
|
// We make two passes here, if necessary. This is because there is
|
|
// a bitfield in which 1's correspond to sockets on which there is
|
|
// data to be read. If we started from the same bit each time looking
|
|
// for the first 1, then that socket would get all of the attention,
|
|
// and those further down the line would increasingly suffer from
|
|
// the "I'll only look at you if noone else needs attention"
|
|
// syndrome. So we keep track of where we found data last time,
|
|
// and start looking just beyond it next time. At the last entry,
|
|
// we wrap around and go into pass 2.
|
|
//
|
|
//
|
|
// First Pass scan...
|
|
//
|
|
for (i = pMapInfo->StartEntry; i <= pMapInfo->LastEntry; i++)
|
|
{
|
|
|
|
if ( FD_ISSET (Map[i].Sock,Address->Mask))
|
|
{
|
|
FD_CLR ( Map[i].Sock, Address->Mask );
|
|
if (i == pMapInfo->LastEntry)
|
|
pMapInfo->StartEntry = 1;
|
|
else
|
|
pMapInfo->StartEntry = i + 1;
|
|
return (i);
|
|
}
|
|
}
|
|
//
|
|
// Second Pass Scan...
|
|
//
|
|
for (i = 1; i < pMapInfo->StartEntry ; i++)
|
|
{
|
|
|
|
if (FD_ISSET (Map[i].Sock, Address->Mask))
|
|
{
|
|
FD_CLR ( Map[i].Sock, Address->Mask);
|
|
|
|
if (i == pMapInfo->LastEntry)
|
|
pMapInfo->StartEntry = 1;
|
|
else
|
|
pMapInfo->StartEntry = i + 1;
|
|
|
|
return (i);
|
|
}
|
|
}
|
|
//
|
|
// No data ready
|
|
//
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
OPTIONAL_STATIC int ServerSetupCommon (
|
|
IN PADDRESS Address,
|
|
IN int Port,
|
|
OUT RPC_CHAR PAPI * NetworkAddress,
|
|
IN int PendingQueueSize,
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does common server address setup.
|
|
|
|
Arguments:
|
|
|
|
Address - A pointer to the loadable transport interface address.
|
|
|
|
ListenSock - The socket on which to listen.
|
|
|
|
Port - is the same as the endpoint range from 0-255. A hack for NB.
|
|
|
|
ReturnValue:
|
|
|
|
Four states: if a port was allocated and set up, we return
|
|
that port number (a positive integer in the range of 0 to MAX_END -1 ).
|
|
If we failed on binding endpoint, that means that the requested
|
|
endpoint is used the return value will be 0.
|
|
If we ran out of memory trying to allocate
|
|
memory for this endpoint, we return a -1.
|
|
|
|
--*/
|
|
{
|
|
|
|
SOCKADDR_NB Server; /* sockaddr for the local machine */
|
|
char HostName[MAX_HOSTNAME_LEN];
|
|
int length;
|
|
SOCKET isock;
|
|
int PortUsed;
|
|
UNICODE_STRING UnicodeHostName;
|
|
ANSI_STRING AsciiHostName;
|
|
PPROTOCOL_MAP ProtocolEntry;
|
|
int Status;
|
|
int i, j;
|
|
int AddressInitialized = 0;
|
|
|
|
/* loop here for numbers of cards */
|
|
|
|
Address->ListenSockReady = 0;
|
|
for(j = 0; j <= NumCards; j++)
|
|
{
|
|
/* Initialize variable to keep state */
|
|
|
|
if (Status = MapProtocol(RpcProtocolSequence, j, &ProtocolEntry))
|
|
{
|
|
//
|
|
// Some cards may not be bound to..
|
|
// Try the rest just in case ..
|
|
//
|
|
continue;
|
|
|
|
}
|
|
|
|
/* PROTOCOL is -1 * lana */
|
|
|
|
isock = socket ( ADDRESS_FAMILY, SOCK_SEQPACKET,
|
|
-1 * (ProtocolEntry->Lana) );
|
|
|
|
|
|
if ( isock == INVALID_SOCKET)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: bad socket call %d \n",
|
|
WSAGetLastError());
|
|
#endif
|
|
CloseAllListenSock ( Address, j);
|
|
return ( MAX_NUM_ENDPOINT );
|
|
}
|
|
/* set up server sockaddr for connection */
|
|
|
|
memset( &Server, 0, sizeof(Server) );
|
|
Server.snb_family = ADDRESS_FAMILY;
|
|
|
|
length = MAX_HOSTNAME_LEN;
|
|
|
|
if( GetComputerName(HostName, &length) == FALSE)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: Can't get computer name \n");
|
|
#endif
|
|
closesocket(isock);
|
|
CloseAllListenSock ( Address, j);
|
|
return( MAX_NUM_ENDPOINT ) ;
|
|
}
|
|
|
|
SET_NETBIOS_SOCKADDR((&Server), NETBIOS_UNIQUE_NAME, HostName, Port);
|
|
|
|
if (bind(isock,(struct sockaddr *) &Server, sizeof(Server)))
|
|
{
|
|
CloseAllListenSock ( Address, j);
|
|
closesocket(isock);
|
|
return( 0 );
|
|
}
|
|
|
|
if(listen ( isock, PendingQueueSize ) == SOCKET_ERROR)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: bad listen call %d \n",
|
|
WSAGetLastError());
|
|
#endif
|
|
closesocket(isock);
|
|
CloseAllListenSock ( Address, j);
|
|
return( MAX_NUM_ENDPOINT );
|
|
}
|
|
|
|
if(AddressInitialized == 0)
|
|
{
|
|
|
|
/* do it only on the first time */
|
|
Address->NumConnections = 0;
|
|
|
|
Address->MasterMask = I_RpcAllocate(sizeof(fd_big_set) +
|
|
INITIAL_MASK_SIZE *
|
|
sizeof(SOCKET));
|
|
|
|
Address->Mask = I_RpcAllocate(sizeof(fd_big_set) +
|
|
INITIAL_MASK_SIZE * sizeof(SOCKET));
|
|
|
|
Address->DataMap = I_RpcAllocate(INITIAL_MAPSIZE * sizeof(SOCKMAP));
|
|
|
|
Address->ListenSockMap = I_RpcAllocate(INITIAL_MAPSIZE *
|
|
sizeof(SOCKMAP));
|
|
|
|
|
|
if ( (Address->DataMap == (SOCKMAP *) 0)
|
|
|| (Address->MasterMask == (fd_big_set *) 0)
|
|
|| (Address->Mask == (fd_big_set *) 0 )
|
|
|| (Address->ListenSockMap == (SOCKMAP *) 0)
|
|
)
|
|
{
|
|
if (Address->DataMap) I_RpcFree(Address->DataMap);
|
|
if (Address->MasterMask) I_RpcFree(Address->MasterMask);
|
|
if (Address->Mask) I_RpcFree(Address->Mask);
|
|
if (Address->ListenSockMap) I_RpcFree(Address->ListenSockMap);
|
|
closesocket(isock);
|
|
CloseAllListenSock ( Address, j);
|
|
return( -1 );
|
|
}
|
|
|
|
Address->MaskSize = INITIAL_MASK_SIZE;
|
|
FD_ZERO(Address->MasterMask);
|
|
FD_ZERO(Address->Mask);
|
|
|
|
Address->DataMapInfo.StartEntry = 1;
|
|
Address->DataMapInfo.LastEntry = 0;
|
|
Address->DataMapInfo.MaxEntries = INITIAL_MAPSIZE;
|
|
memset ( Address->DataMap, 0,
|
|
(INITIAL_MAPSIZE * sizeof (SOCKMAP)));
|
|
|
|
Address->ListenMapInfo.StartEntry = 1 ;
|
|
Address->ListenMapInfo.LastEntry = 0 ;
|
|
Address->ListenMapInfo.MaxEntries = INITIAL_MAPSIZE;
|
|
memset ( Address->ListenSockMap, 0, (INITIAL_MAPSIZE *
|
|
sizeof (SOCKMAP)));
|
|
|
|
|
|
Address->DataMap[0].Sock = (unsigned int) -1;
|
|
Address->ListenSockMap[0].Sock = (unsigned int) -1;
|
|
|
|
AddressInitialized = 1; /* marked as initalized */
|
|
|
|
Address->ListenSockReady = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(AddSocket(Address, isock) != RPC_S_OK)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: bad add socket sock: %x \n", isock);
|
|
#endif
|
|
closesocket(isock);
|
|
I_RpcFree(Address->MasterMask);
|
|
I_RpcFree(Address->Mask);
|
|
I_RpcFree(Address->DataMap);
|
|
I_RpcFree(Address->ListenSockMap);
|
|
CloseAllListenSock ( Address, j);
|
|
return (-1);
|
|
}
|
|
|
|
// No need to check if the masks need to grow here.
|
|
FD_BIG_SET(isock, Address);
|
|
|
|
} /* end for loop */
|
|
|
|
/* return back network address */
|
|
|
|
if(AddressInitialized)
|
|
{
|
|
length = MAX_HOSTNAME_LEN + 1;
|
|
|
|
/* ascii to unicode */
|
|
|
|
RtlInitAnsiString ( &AsciiHostName, HostName);
|
|
RtlAnsiStringToUnicodeString( &UnicodeHostName, &AsciiHostName, TRUE );
|
|
|
|
memcpy ( NetworkAddress, UnicodeHostName.Buffer,
|
|
UnicodeHostName.Length + sizeof(UNICODE_NULL) );
|
|
|
|
RtlFreeUnicodeString ( &UnicodeHostName );
|
|
|
|
return(Port);
|
|
}
|
|
else
|
|
{
|
|
return(MAX_NUM_ENDPOINT);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
ServerSetupWithEndpoint (
|
|
IN PADDRESS Address,
|
|
IN RPC_CHAR PAPI * Endpoint,
|
|
OUT RPC_CHAR PAPI * NetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN void PAPI * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to setup a SPX/IP connection with the
|
|
specified endpoint. We also need to determine the network address
|
|
of this server.
|
|
|
|
Arguments:
|
|
|
|
Address - Supplies this loadable transport interface address.
|
|
|
|
Endpoint - Supplies the endpoint for this address.
|
|
|
|
NetworkAddress - Returns the network address for this machine. This
|
|
buffer will have been allocated by the caller.
|
|
|
|
NetworkAddressLength - Supplies the length of the network address
|
|
argument.
|
|
|
|
SecurityDescriptor - Supplies the security descriptor to be passed
|
|
on this address.
|
|
|
|
PendingQueueSize - Supplies the size of the queue of pending
|
|
requests which should be created by the transport. Some transports
|
|
will not be able to make use of this value, while others will.
|
|
|
|
RpcProtocolSequence - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully setup this address.
|
|
|
|
RPC_P_NETWORK_ADDRESS_TOO_SMALL - The supplied network address buffer
|
|
is too small to contain the network address of this node. The
|
|
caller should call this routine again with a larger buffer.
|
|
|
|
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
|
|
invalid.
|
|
|
|
RPC_S_CANT_CREATE_ENDPOINT - The endpoint format is correct, but
|
|
the endpoint can not be created.
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint is not a valid
|
|
endpoint for SPX/IPX.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|
setup the address.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to setup the
|
|
address.
|
|
|
|
--*/
|
|
{
|
|
int PortIn,PortOut;
|
|
unsigned char port[ENDPOINT_LEN+1];
|
|
UNICODE_STRING UnicodePortNum;
|
|
ANSI_STRING AsciiPortNum;
|
|
|
|
UNUSED(RpcProtocolSequence);
|
|
UNUSED(SecurityDescriptor);
|
|
|
|
unicode_to_ascii (Endpoint, port);
|
|
|
|
|
|
if(strlen(port) != strspn(port, "0123456789"))
|
|
{
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
|
|
|
|
PortIn = atoi(port);
|
|
|
|
/* Verify the NetworkAddress and Endpoint. */
|
|
if((PortIn <= 0) ||( PortIn >= MAX_NUM_ENDPOINT) )
|
|
{
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
|
|
|
|
//
|
|
// Call common server setup code...
|
|
//
|
|
|
|
PortOut = ServerSetupCommon ( Address, PortIn,
|
|
NetworkAddress, PendingQueueSize,
|
|
RpcProtocolSequence);
|
|
|
|
// If the return value of ServerSetup isn't equal to
|
|
// the port number we sent it, there's been an error.
|
|
//
|
|
// Either it is returned as 0 (which means that for some
|
|
// reason we couldn't set up an endpoint) or as -1 (which
|
|
// means we ran out of memory).
|
|
//
|
|
if ( PortOut != PortIn )
|
|
{
|
|
if ( ( PortOut == 0 ) || PortOut >= MAX_NUM_ENDPOINT )
|
|
return ( RPC_S_CANT_CREATE_ENDPOINT );
|
|
else
|
|
return ( RPC_S_OUT_OF_MEMORY );
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ServerSetupUnknownEndpoint (
|
|
IN PADDRESS Address,
|
|
OUT RPC_CHAR PAPI * Endpoint,
|
|
IN unsigned int EndpointLength,
|
|
OUT RPC_CHAR PAPI * NetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN void PAPI * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to generate an endpoint and setup a server
|
|
address with that endpoint. We also need to determine the network
|
|
address of this server.
|
|
|
|
Arguments:
|
|
|
|
Address - Supplies this loadable transport interface address.
|
|
|
|
Endpoint - Returns the endpoint generated for this address. This
|
|
buffer will have been allocated by the caller.
|
|
|
|
EndpointLength - Supplies the length of the endpoint argument.
|
|
|
|
NetworkAddress - Returns the network address for this machine. This
|
|
buffer will have been allocated by the caller.
|
|
|
|
NetworkAddressLength - Supplies the length of the network address
|
|
argument.
|
|
|
|
SecurityDescriptor - Supplies the security descriptor to be passed
|
|
on this address.
|
|
|
|
PendingQueueSize - Supplies the size of the queue of pending
|
|
requests which should be created by the transport. Some transports
|
|
will not be able to make use of this value, while others will.
|
|
|
|
RpcProtocolSequence - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully setup this address.
|
|
|
|
RPC_P_NETWORK_ADDRESS_TOO_SMALL - The supplied network address buffer
|
|
is too small to contain the network address of this node. The
|
|
caller should call this routine again with a larger buffer.
|
|
|
|
RPC_P_ENDPOINT_TOO_SMALL - The supplied endpoint buffer is too small
|
|
to contain the endpoint we generated. The caller should call
|
|
this routine again with a larger buffer.
|
|
|
|
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
|
|
invalid.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|
setup the address.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to setup the
|
|
address.
|
|
|
|
--*/
|
|
{
|
|
int PortIn, PortOut;
|
|
char PortAscii[10];
|
|
UNICODE_STRING UnicodePortNum;
|
|
ANSI_STRING AsciiPortNum;
|
|
int i;
|
|
static init = 0;
|
|
/* keep track of which endpoint used */
|
|
static BOOL UsedEndpoint[MAX_NUM_ENDPOINT];
|
|
|
|
|
|
|
|
UNUSED(RpcProtocolSequence);
|
|
UNUSED(SecurityDescriptor);
|
|
|
|
|
|
if ( EndpointLength < (2 * (ENDPOINT_LEN + 1)) )
|
|
return( RPC_P_ENDPOINT_TOO_SMALL );
|
|
|
|
if ( NetworkAddressLength < (2 * (NETADDR_LEN + 1)) )
|
|
return( RPC_P_NETWORK_ADDRESS_TOO_SMALL );
|
|
|
|
//
|
|
// Call common server setup code...
|
|
//
|
|
/* give it a port to start */
|
|
PortIn = LAN_MAN_PORT + 1;
|
|
|
|
/* notice only 1 thread can enter this
|
|
routine at anytime because of the
|
|
static variable
|
|
*/
|
|
|
|
EnterCriticalSection(&TransCritSec);
|
|
if(!init)
|
|
{
|
|
memset(UsedEndpoint, 0, sizeof(BOOL) * MAX_NUM_ENDPOINT);
|
|
|
|
/* 0 to 32 ports used by LANMAN */
|
|
for(i = 0; i <= LAN_MAN_PORT; i++)
|
|
UsedEndpoint[i] = TRUE;
|
|
init = 1;
|
|
}
|
|
|
|
/* find the next avaliable port */
|
|
while((PortIn < MAX_NUM_ENDPOINT) && UsedEndpoint[PortIn] )
|
|
PortIn++;
|
|
|
|
if(PortIn > MAX_NUM_ENDPOINT)
|
|
{
|
|
|
|
LeaveCriticalSection(&TransCritSec);
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: endpoint out of range \n");
|
|
#endif
|
|
return(RPC_S_CANT_CREATE_ENDPOINT);
|
|
}
|
|
|
|
UsedEndpoint[PortIn] = TRUE;
|
|
LeaveCriticalSection(&TransCritSec);
|
|
|
|
|
|
while (1)
|
|
{
|
|
PortOut = ServerSetupCommon ( Address, PortIn, NetworkAddress,
|
|
PendingQueueSize, RpcProtocolSequence);
|
|
|
|
if ( PortOut == PortIn )
|
|
{
|
|
break;
|
|
}
|
|
if ( ( PortIn >= MAX_NUM_ENDPOINT ) || (PortOut >= MAX_NUM_ENDPOINT ))
|
|
{
|
|
return(RPC_S_CANT_CREATE_ENDPOINT);
|
|
}
|
|
if ( PortOut == -1 )
|
|
{
|
|
return ( RPC_S_OUT_OF_MEMORY );
|
|
}
|
|
|
|
PortIn++;
|
|
EnterCriticalSection(&TransCritSec);
|
|
UsedEndpoint[PortIn] = TRUE;
|
|
LeaveCriticalSection(&TransCritSec);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Return Endpoint
|
|
//
|
|
_itoa ( PortOut, PortAscii, 10 );
|
|
|
|
RtlInitAnsiString ( &AsciiPortNum, PortAscii);
|
|
RtlAnsiStringToUnicodeString( &UnicodePortNum, &AsciiPortNum, TRUE );
|
|
|
|
memcpy ( Endpoint, UnicodePortNum.Buffer,
|
|
UnicodePortNum.Length + sizeof(UNICODE_NULL) );
|
|
|
|
RtlFreeUnicodeString ( &UnicodePortNum );
|
|
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
void RPC_ENTRY
|
|
ServerAbortSetupAddress (
|
|
IN PADDRESS Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be called if an error occurs in setting up the
|
|
address between the time that SetupWithEndpoint or SetupUnknownEndpoint
|
|
successfully completed and before the next call into this loadable
|
|
transport module. We need to do any cleanup from Setup*.
|
|
|
|
Arguments:
|
|
|
|
Address - Supplies the address which is being aborted.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
if (Address->ListenSockReady != 0)
|
|
{
|
|
|
|
CloseAllListenSock ( Address, NumCards);
|
|
Address->ListenSockReady = 0;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ServerClose (
|
|
IN PSCONNECTION SConnection
|
|
)
|
|
//
|
|
// Close the connection.
|
|
//
|
|
{
|
|
int i;
|
|
PADDRESS Address;
|
|
PSOCKMAP Map;
|
|
|
|
// In certain cases, ServerClose can be called twice, so we must try and handle
|
|
// that case as normal.
|
|
|
|
if (InterlockedIncrement(&SConnection->ConnSockClosed) != 0)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5:Attempt To Close A Conn Twice: Sock[%d]\n",
|
|
SConnection->ConnSock);
|
|
#endif
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
Address = SConnection->Address;
|
|
Map = Address->DataMap;
|
|
|
|
EnterCriticalSection(&TransCritSec);
|
|
|
|
//
|
|
// Close the connection.
|
|
//
|
|
if (closesocket ( SConnection->ConnSock ) == SOCKET_ERROR)
|
|
{
|
|
|
|
LeaveCriticalSection(&TransCritSec);
|
|
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: warning closesocket %d failed %d\n",
|
|
SConnection->ConnSock, WSAGetLastError());
|
|
#endif
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
//
|
|
// Decrement the number of active connections
|
|
//
|
|
Address->NumConnections--;
|
|
|
|
//
|
|
// Clear the entry in the SOCKMAP structure
|
|
// ..but only if it was marked as NOT ReceiveDirect
|
|
if (SConnection->ReceiveDirectFlag != 0)
|
|
{
|
|
LeaveCriticalSection(&TransCritSec);
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
for (i=0; i <= Address->DataMapInfo.LastEntry; i++)
|
|
{
|
|
if (SConnection->ConnSock == Map[i].Sock)
|
|
{
|
|
Map[i].Sock = 0;
|
|
ASSERT(SConnection == Map[i].Conn);
|
|
Map[i].Conn = 0;
|
|
if (i == Address->DataMapInfo.LastEntry)
|
|
Address->DataMapInfo.LastEntry--;
|
|
FD_CLR(SConnection->ConnSock,Address->MasterMask);
|
|
LeaveCriticalSection(&TransCritSec);
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&TransCritSec);
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: Socket not found in address socket map\n");
|
|
#endif
|
|
|
|
ASSERT(!"We'd better not ever get here...");
|
|
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ServerSend (
|
|
IN PSCONNECTION SConnection,
|
|
IN void PAPI * Buffer,
|
|
IN unsigned int BufferLength
|
|
)
|
|
// Write a message to a connection.
|
|
{
|
|
int bytes;
|
|
|
|
/*
|
|
Send a message on the socket
|
|
*/
|
|
/* server doesn't need to send seq_num */
|
|
|
|
ASSERT(BufferLength <= MAXIMUM_SEND) ;
|
|
bytes = send (SConnection->ConnSock, (char *) Buffer,
|
|
(int) BufferLength , 0);
|
|
if (bytes != (int) BufferLength)
|
|
{
|
|
ServerClose ( SConnection );
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ServerReceive (
|
|
IN PSCONNECTION SConnection,
|
|
IN void * * Buffer,
|
|
IN unsigned int * BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ServerReceive will use this routine to read a message from a
|
|
connection. The correct size buffer has already been allocated for
|
|
us; all we have got to do is to read the message.
|
|
|
|
Arguments:
|
|
|
|
SConnection - Supplies the connection from which we are supposed to
|
|
read the message.
|
|
|
|
Buffer - Supplies a buffer to read the message into.
|
|
|
|
BufferLength - Supplies the length of the buffer.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
int bytes = 0;
|
|
unsigned short total_bytes = 0;
|
|
int err;
|
|
int flags ; /* flag for winsock */
|
|
int retry ; /* state var to keep try of the # retry */
|
|
DWORD *firstword;
|
|
/* allocate 1k for small messages */
|
|
if(*Buffer == 0)
|
|
{
|
|
*BufferLength = 1024;
|
|
RpcStatus = I_RpcTransServerReallocBuffer(SConnection,
|
|
Buffer,
|
|
0,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
ServerClose(SConnection);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
retry = 1; /* set no retry to start */
|
|
|
|
while(1)
|
|
{
|
|
flags = 0;
|
|
|
|
#ifdef TONY
|
|
PrintToDebugger("rpclts5: Buffer is %x, total_bytes: %d,
|
|
buflen: %d \n",
|
|
*Buffer, total_bytes, *BufferLength);
|
|
#endif
|
|
bytes = WSARecvEx( SConnection->ConnSock, (char *) * Buffer +
|
|
total_bytes, *BufferLength - total_bytes , &flags);
|
|
if(bytes == 0)
|
|
{
|
|
retry = 1;
|
|
continue;
|
|
}
|
|
if(bytes == SOCKET_ERROR)
|
|
{
|
|
err = WSAGetLastError();
|
|
if(err != WSAECONNRESET)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLS5: bad rec on Server receive lasterr(%d)\n"
|
|
, err);
|
|
#endif
|
|
}
|
|
ServerClose ( SConnection );
|
|
return(RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
/* add DWORD for the seq_number */
|
|
/* check to see if the server is
|
|
receiving from an old client.
|
|
for the first time old_client = -1
|
|
*/
|
|
|
|
if(SConnection->old_client == -1)
|
|
{
|
|
firstword = *Buffer;
|
|
if(*firstword == 0)
|
|
{
|
|
SConnection->old_client = 1;
|
|
SConnection->seq_num = 0;
|
|
}
|
|
else
|
|
{
|
|
SConnection->old_client = 0;
|
|
}
|
|
}
|
|
|
|
if(flags & MSG_PARTIAL)
|
|
{
|
|
if(retry == 0)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLS5: Partial receive second time");
|
|
#endif
|
|
ServerClose ( SConnection );
|
|
return(RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
total_bytes += bytes;
|
|
*BufferLength = I_RpcTransServerMaxFrag(SConnection);
|
|
|
|
|
|
|
|
if(SConnection->old_client)
|
|
{
|
|
*BufferLength += sizeof(DWORD);
|
|
}
|
|
|
|
RpcStatus = I_RpcTransServerReallocBuffer(SConnection,
|
|
Buffer,
|
|
total_bytes,
|
|
*BufferLength );
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLS5: can't rellocate in sever recv");
|
|
#endif
|
|
ServerClose ( SConnection );
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
retry = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
total_bytes += bytes;
|
|
*BufferLength = total_bytes;
|
|
|
|
if(SConnection->old_client == 1 )
|
|
{ /* take off seq_number */
|
|
*BufferLength -= sizeof(DWORD);
|
|
memcpy(*Buffer, (char *) *Buffer + sizeof(DWORD),
|
|
*BufferLength);
|
|
|
|
}
|
|
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUGPRC
|
|
PrintToDebugger("rpclts5: server receie 2 times \n");
|
|
#endif
|
|
|
|
ASSERT(0);
|
|
return(RPC_S_INTERNAL_ERROR);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OPTIONAL_STATIC RPC_STATUS AcceptNewConnection ( PADDRESS Address , int Index)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine accept new connection
|
|
|
|
Arguments:
|
|
|
|
Address - A pointer to the loadable transport interface address.
|
|
|
|
Index - Index of which Socket in the ListenSockMap that is ready for
|
|
accept call.
|
|
|
|
ReturnValue:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PSCONNECTION NewSConnection;
|
|
int i, j;
|
|
SOCKET isock;
|
|
unsigned int ReceiveDirectFlag;
|
|
int sockbufsize;
|
|
RPC_STATUS status;
|
|
|
|
static int SocketOptionsValue = 720000L;
|
|
|
|
|
|
if((status = GrowMap(Address, 0)) != RPC_S_OK)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if((status = GrowMask(Address)) != RPC_S_OK)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
ASSERT(Address->MasterMask->fd_count < Address->MaskSize);
|
|
|
|
//
|
|
//
|
|
// Accept the connection
|
|
//
|
|
|
|
isock = accept ( Address->ListenSockMap[Index].Sock, NULL, NULL );
|
|
if(isock == INVALID_SOCKET)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: bad accept");
|
|
#endif
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Allocate new connection structure
|
|
//
|
|
NewSConnection = I_RpcTransServerNewConnection ( Address, 0,
|
|
&ReceiveDirectFlag);
|
|
|
|
if ( NewSConnection == 0 )
|
|
{
|
|
// We're out of memory, abort the connection...
|
|
j = TRUE;
|
|
i = setsockopt( isock, SOL_SOCKET, SO_DONTLINGER, (const char *) &j,
|
|
sizeof(j));
|
|
|
|
ASSERT(i == 0);
|
|
|
|
i = closesocket( isock);
|
|
|
|
ASSERT(i == 0);
|
|
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
/* set old_client to -1 for later varification */
|
|
NewSConnection->old_client = -1;
|
|
|
|
// Initialize new connection structure...
|
|
//
|
|
// ...point to owning address structure...
|
|
//
|
|
NewSConnection->Address = Address;
|
|
//
|
|
// ...flag it !Closed...
|
|
//
|
|
NewSConnection->ConnSockClosed = -1;
|
|
//
|
|
// ...store the socket number...
|
|
//
|
|
NewSConnection->ConnSock = isock;
|
|
//
|
|
// ...save the receive direct flag
|
|
//
|
|
NewSConnection->ReceiveDirectFlag = ReceiveDirectFlag;
|
|
//
|
|
// ...increment the number of connections...
|
|
//
|
|
Address->NumConnections++;
|
|
//
|
|
// ...last but not least, make an entry in
|
|
// the SOCKMAP table. But only if it is not marked ReceiveDirect.
|
|
//
|
|
if (ReceiveDirectFlag)
|
|
{
|
|
I_RpcTransServerReceiveDirectReady(NewSConnection);
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
setsockopt( isock, SOL_SOCKET, SO_RCVTIMEO,
|
|
(char *) &SocketOptionsValue, sizeof(SocketOptionsValue) );
|
|
|
|
for (i=0; i < Address->DataMapInfo.MaxEntries; i++)
|
|
{
|
|
if (Address->DataMap[i].Sock == 0)
|
|
{
|
|
Address->DataMap[i].Sock = isock;
|
|
Address->DataMap[i].Conn = NewSConnection;
|
|
if (i > Address->DataMapInfo.LastEntry)
|
|
Address->DataMapInfo.LastEntry = i;
|
|
FD_BIG_SET(isock, Address);
|
|
return (RPC_S_OK);
|
|
}
|
|
}
|
|
|
|
ASSERT(!"This can never be reached");
|
|
|
|
return (RPC_S_INTERNAL_ERROR);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ServerReceiveAny (
|
|
IN PADDRESS Address,
|
|
OUT PSCONNECTION * pSConnection,
|
|
OUT void PAPI * PAPI * Buffer,
|
|
OUT unsigned int PAPI * BufferLength,
|
|
IN long Timeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine wait for any sockets (both listen and data) and call
|
|
|
|
if there is data to receive, it will call ServerReceive.
|
|
|
|
If there is a new connection, it will call AcceptNewConnection.
|
|
|
|
Arguments:
|
|
|
|
Address - A pointer to the loadable transport interface address.
|
|
|
|
pSConnection - A pointer to the connection structure.
|
|
|
|
Buffer - pointer to the receive data.
|
|
|
|
BufferLength - size of the receive message.
|
|
|
|
Timeout - Notuse.
|
|
|
|
ReturnValue:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
PSCONNECTION SConnection;
|
|
int Index;
|
|
int NumActive;
|
|
|
|
UNUSED (Timeout);
|
|
|
|
while (1)
|
|
{
|
|
//
|
|
// Find a connection with data ready to be recv-ed...
|
|
//
|
|
/* first look for data sockets */
|
|
if (Index = FindSockWithDataReady ( Address, 0 ))
|
|
{
|
|
//
|
|
// Found one. Find its Connection structure...
|
|
//
|
|
*pSConnection = SConnection = Address->DataMap[Index].Conn;
|
|
//
|
|
// Call ServerReceive to read the data, then return to the
|
|
// runtime with it
|
|
//
|
|
|
|
if (SConnection == 0)
|
|
{
|
|
//Got deleted ?
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPCLTS5: Connection Deleted[?]\n");
|
|
#endif
|
|
|
|
continue;
|
|
}
|
|
RpcStatus = ServerReceive ( SConnection, Buffer, BufferLength );
|
|
|
|
return (RpcStatus);
|
|
}
|
|
|
|
//
|
|
// All connections caught up for now...select() for more
|
|
// data ready...
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Fill in the select() mask
|
|
//
|
|
EnterCriticalSection(&TransCritSec);
|
|
memcpy (Address->Mask, Address->MasterMask,
|
|
sizeof(fd_big_set) + Address->MaskSize *sizeof(SOCKET));
|
|
LeaveCriticalSection(&TransCritSec);
|
|
|
|
//
|
|
// Wait for data...
|
|
//
|
|
|
|
NumActive = select ( 0,
|
|
(fd_set *) Address->Mask,
|
|
(fd_set *) 0,
|
|
(fd_set *) 0,
|
|
NULL ); /* infinite wait */
|
|
#ifdef DEBUGRPC
|
|
if (NumActive < 0)
|
|
{
|
|
PrintToDebugger("RPCLTS5: select ret (%d): LastErr (%d)\n",
|
|
NumActive, WSAGetLastError());
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
#endif
|
|
|
|
} while (NumActive <= 0);
|
|
|
|
//
|
|
// If there is no connect request on the listen socket, then
|
|
// break immediately...
|
|
//
|
|
|
|
/* now look for listenMapSock */
|
|
|
|
if(Index = FindSockWithDataReady(Address, 1))
|
|
{
|
|
|
|
EnterCriticalSection(&TransCritSec);
|
|
RpcStatus = AcceptNewConnection ( Address, Index );
|
|
LeaveCriticalSection(&TransCritSec);
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return RpcStatus;
|
|
}
|
|
FD_CLR(Address->ListenSockMap[Index].Sock, Address->Mask);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ServerReceiveDirect (
|
|
IN PSCONNECTION SConnection,
|
|
IN void * * Buffer,
|
|
IN unsigned int * BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ServerReceiveDirect will use this routine to read a message from a
|
|
connection. The correct size buffer has already been allocated for
|
|
us; all we have got to do is to read the message.
|
|
|
|
Arguments:
|
|
|
|
SConnection - Supplies the connection from which we are supposed to
|
|
read the message.
|
|
|
|
Buffer - Supplies a buffer to read the message into.
|
|
|
|
BufferLength - Supplies the length of the buffer.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
int bytes;
|
|
int total_bytes;
|
|
unsigned short native_length;
|
|
unsigned int maximum_receive;
|
|
int err;
|
|
|
|
// ReceiveDirect doesnt have a Buffer supplied
|
|
// Hence we ask runtime to get us the biggest one possible
|
|
|
|
ASSERT(SConnection->ReceiveDirectFlag != 0);
|
|
|
|
if(*Buffer != 0) {
|
|
maximum_receive = I_RpcTransServerMaxFrag( SConnection );
|
|
RpcStatus = I_RpcTransServerReallocBuffer(
|
|
SConnection,
|
|
Buffer,
|
|
0,
|
|
maximum_receive
|
|
);
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
ASSERT(RpcStatus == RPC_S_OUT_OF_MEMORY);
|
|
return(RpcStatus);
|
|
}
|
|
|
|
*BufferLength = maximum_receive;
|
|
}
|
|
|
|
return ServerReceive(SConnection, Buffer, BufferLength);
|
|
}
|
|
|
|
|
|
|
|
// This describes the transport to the runtime. A pointer to this
|
|
// data structure will be returned by TransportLoad.
|
|
|
|
static RPC_SERVER_TRANSPORT_INFO TransportInformation =
|
|
{
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
MAXIMUM_SEND,
|
|
sizeof(ADDRESS),
|
|
sizeof(SCONNECTION),
|
|
(TRANS_SERVER_SETUPWITHENDPOINT)ServerSetupWithEndpoint,
|
|
ServerSetupUnknownEndpoint,
|
|
ServerAbortSetupAddress,
|
|
ServerClose,
|
|
ServerSend,
|
|
(TRANS_SERVER_RECEIVEANY) ServerReceiveAny,
|
|
0,
|
|
0,
|
|
0,
|
|
(TRANS_SERVER_RECEIVEDIRECT) ServerReceiveDirect,
|
|
0
|
|
};
|
|
|
|
RPC_SERVER_TRANSPORT_INFO *
|
|
TransportLoad (
|
|
IN RPC_CHAR * RpcProtocolSequence
|
|
)
|
|
{
|
|
|
|
int err;
|
|
WSADATA WsaData;
|
|
UNUSED(RpcProtocolSequence);
|
|
|
|
err = WSAStartup( 0x0101, &WsaData );
|
|
if ( err != NO_ERROR ) {
|
|
return NULL;
|
|
}
|
|
|
|
InitializeCriticalSection(&TransCritSec);
|
|
|
|
InitialNtRegistry(); /* get the lana info */
|
|
/* Added for netbios */
|
|
/* not sure we need that */
|
|
|
|
return( &TransportInformation);
|
|
}
|
|
|
|
|