1568 lines
38 KiB
C++
1568 lines
38 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1996 - 1999
|
||
|
||
Module Name:
|
||
|
||
nbtrans.cxx
|
||
|
||
Abstract:
|
||
|
||
Netbios connection transport interface. Parts are similar
|
||
to wstran.cxx but there are major differences due to
|
||
addresses supporting multiple listen sockets.
|
||
|
||
Author:
|
||
|
||
Mario Goertzel [MarioGo]
|
||
|
||
|
||
Revision History:
|
||
|
||
MarioGo 3/28/1996 Based and depends on wstrans.cxx
|
||
MarioGo 2/04/1997 Updated for async and client
|
||
|
||
--*/
|
||
|
||
#include <precomp.hxx>
|
||
#include <CharConv.hxx>
|
||
|
||
// Globals
|
||
|
||
BOOL fNetbiosLoaded = FALSE;
|
||
|
||
const DWORD MAX_LANA = 256;
|
||
const DWORD MAX_RESERVED_EPT = 32; // LanMan uses ports < 32.
|
||
|
||
typedef struct
|
||
{
|
||
RPC_CHAR *Protseq;
|
||
UINT ProtseqLength;
|
||
PROTOCOL_ID id;
|
||
BYTE MinEndpoint;
|
||
BYTE MaxEndpoint;
|
||
} NB_PROTSEQ_CONFIG;
|
||
|
||
const NB_PROTSEQ_CONFIG NbProtseqConfig[] =
|
||
{
|
||
{
|
||
RPC_STRING_LITERAL("ncacn_nb_nb"),
|
||
11,
|
||
NBF,
|
||
33,
|
||
105
|
||
},
|
||
|
||
{
|
||
RPC_STRING_LITERAL("ncacn_nb_tcp"),
|
||
12,
|
||
NBT,
|
||
106,
|
||
180
|
||
},
|
||
|
||
{
|
||
RPC_STRING_LITERAL("ncacn_nb_ipx"),
|
||
12,
|
||
NBI,
|
||
181,
|
||
255
|
||
}
|
||
};
|
||
|
||
const DWORD cNetbiosProtseqs = sizeof(NbProtseqConfig)/sizeof(NB_PROTSEQ_CONFIG);
|
||
|
||
typedef struct
|
||
{
|
||
UCHAR ProtocolId;
|
||
UCHAR Lana;
|
||
} NB_PROTOCOL_MAP;
|
||
|
||
DWORD cLanas;
|
||
NB_PROTOCOL_MAP *pNetbiosLanaMap = 0;
|
||
|
||
BOOL *afUsedEndpoints = 0;
|
||
|
||
const RPC_CHAR *NetbiosRegistryKey =
|
||
RPC_CONST_STRING("Software\\Microsoft\\Rpc\\NetBios");
|
||
|
||
// enough to contain ncacn_nb_tcp#\0
|
||
const size_t MaxNbProtseqLength = 16;
|
||
|
||
|
||
RPC_STATUS
|
||
LoadNetbios()
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads RPC netbios configuration data from the registry.
|
||
|
||
Note:
|
||
|
||
Unlike wsock32.dll, advapi32.dll (required for registry APIs)
|
||
is already loaded by rpcrt4.dll. So it is okay to link
|
||
directly to advapi32.dll.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
|
||
--*/
|
||
{
|
||
HKEY hKey;
|
||
RPC_STATUS status;
|
||
int i;
|
||
PROTOCOL_ID id;
|
||
|
||
RPC_CHAR protseq[MaxNbProtseqLength];
|
||
DWORD cProtseq;
|
||
DWORD datatype;
|
||
DWORD lana;
|
||
DWORD cLana;
|
||
|
||
ASSERT(fNetbiosLoaded == FALSE);
|
||
|
||
if (!pNetbiosLanaMap)
|
||
{
|
||
// Alloc space for the lana to RPC protocol mapping
|
||
cLanas = 0;
|
||
pNetbiosLanaMap = new NB_PROTOCOL_MAP[MAX_LANA];
|
||
if (!pNetbiosLanaMap)
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
}
|
||
|
||
if (!afUsedEndpoints)
|
||
{
|
||
// Alloc space to keep track of which endpoints are in use.
|
||
afUsedEndpoints = new BOOL[256];
|
||
if (!afUsedEndpoints)
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
for (int i = 0; i <= MAX_RESERVED_EPT; i++)
|
||
{
|
||
afUsedEndpoints[i] = TRUE;
|
||
}
|
||
|
||
for (i = MAX_RESERVED_EPT + 1; i < 256; i++)
|
||
{
|
||
afUsedEndpoints[i] = FALSE;
|
||
}
|
||
}
|
||
|
||
status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||
NetbiosRegistryKey,
|
||
0,
|
||
KEY_READ,
|
||
&hKey);
|
||
|
||
if (status)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "Unable to open netbios key: %d\n",
|
||
GetLastError()));
|
||
|
||
return(RPC_S_OUT_OF_RESOURCES);
|
||
}
|
||
|
||
ASSERT(hKey);
|
||
|
||
for(i = 0, cLanas = 0; cLanas < MAX_LANA; i++)
|
||
{
|
||
cProtseq = MaxNbProtseqLength;
|
||
cLana = sizeof(lana);
|
||
|
||
status = RegEnumValueW(hKey,
|
||
i,
|
||
protseq,
|
||
&cProtseq,
|
||
0,
|
||
&datatype,
|
||
(PBYTE)&lana,
|
||
&cLana);
|
||
|
||
if (status == ERROR_NO_MORE_ITEMS)
|
||
{
|
||
// This is the normal exit path.
|
||
break;
|
||
}
|
||
|
||
if (status)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "Unable to read netbios key %d, %d\n",
|
||
i,
|
||
GetLastError()));
|
||
|
||
return(RPC_S_OUT_OF_RESOURCES);
|
||
}
|
||
|
||
if (datatype != REG_DWORD || lana >= MAX_LANA)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "Invalid config for netbios entry %d\n",
|
||
i));
|
||
|
||
ASSERT(0);
|
||
continue;
|
||
}
|
||
|
||
for (int j = 0; j < cNetbiosProtseqs; j++)
|
||
{
|
||
if (wcsncmp(protseq,
|
||
NbProtseqConfig[j].Protseq,
|
||
NbProtseqConfig[j].ProtseqLength) == 0)
|
||
{
|
||
id = NbProtseqConfig[j].id;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (j == cNetbiosProtseqs)
|
||
{
|
||
// Unknown protsrq.
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "Invalid config for netbios entry %S %d\n",
|
||
protseq,
|
||
i));
|
||
|
||
ASSERT(0);
|
||
continue;
|
||
}
|
||
|
||
pNetbiosLanaMap[cLanas].ProtocolId = (UCHAR)id;
|
||
pNetbiosLanaMap[cLanas].Lana = (UCHAR)lana;
|
||
cLanas++;
|
||
}
|
||
|
||
ASSERT(cLanas < MAX_LANA); // If this gets hit we may want to
|
||
// grow the table size or fix setup.
|
||
|
||
if (cLanas == 0)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "Invalid NETBIOS configuration\n"));
|
||
|
||
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
void RPC_ENTRY WS_ServerAbortListen(RPC_TRANSPORT_ADDRESS);
|
||
|
||
RPC_STATUS
|
||
NB_ServerListenHelper(
|
||
IN PWS_ADDRESS pAddress,
|
||
IN USHORT port,
|
||
IN const NB_PROTSEQ_CONFIG *pConfig,
|
||
IN unsigned int PendingQueueSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine does the work of actually creating a server address.
|
||
|
||
Arguments:
|
||
|
||
pAddress - A pointer to the loadable transport interface address.
|
||
Will contain the newly allocated listen socket when finished.
|
||
|
||
port - The port number to use, never zero here.
|
||
|
||
pConfig - Config data for the protseq we're using.
|
||
|
||
PendingQueueSize - Supplies the size of the queue of pending
|
||
requests which should be created by the transport.
|
||
In this case it is simply passed to listen().
|
||
|
||
ReturnValue:
|
||
|
||
RPC_S_OK
|
||
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_CANT_CREATE_ENDPOINT
|
||
|
||
--*/
|
||
{
|
||
int retval, length;
|
||
RPC_STATUS status;
|
||
WS_SOCKADDR sockaddr;
|
||
PWS_ADDRESS pList, pOld;
|
||
SOCKET sock;
|
||
PROTOCOL_ID index = pConfig->id;
|
||
BOOL found = FALSE;
|
||
DWORD dwLastError;
|
||
|
||
pList = pAddress;
|
||
|
||
status = RPC_S_CANT_CREATE_ENDPOINT;
|
||
|
||
ASSERT(cLanas > 0 && cLanas < MAX_LANA);
|
||
|
||
for (unsigned i = 0; i < cLanas; i++)
|
||
{
|
||
if (pNetbiosLanaMap[i].ProtocolId == (UCHAR)index)
|
||
{
|
||
//
|
||
// Open a socket.
|
||
//
|
||
sock = WSASocketT(WsTransportTable[index].AddressFamily,
|
||
WsTransportTable[index].SocketType,
|
||
WsTransportTable[index].Protocol * pNetbiosLanaMap[i].Lana,
|
||
0,
|
||
0,
|
||
WSA_FLAG_OVERLAPPED);
|
||
|
||
if (sock == INVALID_SOCKET)
|
||
{
|
||
switch(GetLastError())
|
||
{
|
||
case WSAEAFNOSUPPORT:
|
||
case WSAEPROTONOSUPPORT:
|
||
case WSAENETDOWN:
|
||
case WSAESOCKTNOSUPPORT:
|
||
case WSAEINVAL: // when registry is not yet setup.
|
||
status = RPC_S_PROTSEQ_NOT_SUPPORTED;
|
||
break;
|
||
|
||
case WSAENOBUFS:
|
||
case WSAEMFILE:
|
||
status = RPC_S_OUT_OF_MEMORY;
|
||
break;
|
||
|
||
default:
|
||
ASSERT(0);
|
||
status = RPC_S_OUT_OF_RESOURCES;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Try to bind to the lana.
|
||
//
|
||
{
|
||
DWORD Size = 1+MAX_COMPUTERNAME_LENGTH;
|
||
char AsciiComputerName[1+MAX_COMPUTERNAME_LENGTH];
|
||
|
||
if (!GetComputerNameA( AsciiComputerName, &Size) )
|
||
{
|
||
status = RPC_S_CANT_CREATE_ENDPOINT;
|
||
closesocket(sock);
|
||
break;
|
||
}
|
||
|
||
SET_NETBIOS_SOCKADDR(&sockaddr.nbaddr,
|
||
NETBIOS_UNIQUE_NAME,
|
||
AsciiComputerName,
|
||
(char) port);
|
||
}
|
||
|
||
if ( bind(sock,&sockaddr.generic,sizeof(WS_SOCKADDR)) )
|
||
{
|
||
dwLastError = GetLastError();
|
||
if (dwLastError == WSAEADDRINUSE)
|
||
{
|
||
//
|
||
// If the caller is trying use a dynamic endpoint
|
||
// then we may want to retry with another port.
|
||
//
|
||
status = ERROR_RETRY;
|
||
}
|
||
else if(dwLastError == WSAENETDOWN)
|
||
{
|
||
closesocket(sock);
|
||
continue;
|
||
}
|
||
else
|
||
status = RPC_S_CANT_CREATE_ENDPOINT;
|
||
closesocket(sock);
|
||
break;
|
||
}
|
||
|
||
if(listen(sock, PendingQueueSize) == SOCKET_ERROR)
|
||
{
|
||
status = RPC_S_OUT_OF_MEMORY;
|
||
closesocket(sock);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Allocate a new address object, if needed.
|
||
//
|
||
found = TRUE;
|
||
|
||
if (0 == pList)
|
||
{
|
||
// >1 lana, need to allocate another address.
|
||
pList = new WS_ADDRESS;
|
||
if (pList == 0)
|
||
{
|
||
status = RPC_S_OUT_OF_MEMORY;
|
||
break;
|
||
}
|
||
|
||
// Insert new address into list of nb addresses.
|
||
pOld->pNextAddress = pList;
|
||
}
|
||
|
||
pList->type = ADDRESS;
|
||
pList->id = index;
|
||
pList->ConnectionSocket = 0;
|
||
SetProtocolMultiplier(pList, pNetbiosLanaMap[i].Lana);
|
||
pList->NewConnection = WS_NewConnection;
|
||
pList->SubmitListen = WS_SubmitAccept;
|
||
pList->InAddressList = NotInList;
|
||
pList->pFirstAddress = pAddress;
|
||
pList->ListenSocket = 0;
|
||
pList->ConnectionSocket = 0;
|
||
pList->pNextAddress = 0;
|
||
pList->Endpoint = 0;
|
||
pList->pAddressVector = 0;
|
||
pList->pNext = 0;
|
||
memset(&pList->Listen, 0, sizeof(BASE_OVERLAPPED));
|
||
pList->Listen.pAsyncObject = pList;
|
||
pList->ListenSocket = sock;
|
||
RpcpInitializeListHead(&pList->ObjectList);
|
||
|
||
retval = pList->GetExtensionFunctionPointers(sock);
|
||
|
||
if (!retval)
|
||
{
|
||
switch (GetLastError())
|
||
{
|
||
case WSAEFAULT:
|
||
case WSAEINVAL:
|
||
status = RPC_S_INTERNAL_ERROR;
|
||
break;
|
||
|
||
case WSAEOPNOTSUPP:
|
||
status = RPC_S_PROTSEQ_NOT_SUPPORTED;
|
||
break;
|
||
|
||
default:
|
||
status = RPC_S_OUT_OF_RESOURCES;
|
||
}
|
||
closesocket(sock);
|
||
break;
|
||
}
|
||
|
||
status = COMMON_PrepareNewHandle((HANDLE)sock);
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
closesocket(sock);
|
||
break;
|
||
}
|
||
|
||
ASSERT(status == RPC_S_OK);
|
||
|
||
pOld = pList;
|
||
pList = 0;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Cleanup only if we find something
|
||
//
|
||
if ((TRUE == found) && (status != RPC_S_OK))
|
||
{
|
||
WS_ServerAbortListen(pAddress);
|
||
}
|
||
|
||
return(status);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NB_ServerListen(
|
||
IN PROTOCOL_ID index,
|
||
IN RPC_TRANSPORT_ADDRESS ThisAddress,
|
||
IN OUT PWSTR *pEndpoint,
|
||
IN UINT PendingQueueSize,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates a netbios server address receive new client
|
||
connections. If successful a call to NB_CompleteListen() will actually
|
||
allow new connection callbacks to the RPC runtime to occur. If the
|
||
runtime is unable to complete then it must abort the address by calling
|
||
WS_ServerAbortListen().
|
||
|
||
Arguments:
|
||
|
||
pAddress - A pointer to the loadable transport interface address.
|
||
pEndpoint - Optionally, the endpoint (0-255) to listen on. Set to
|
||
to listened port for dynamically allocated endpoints.
|
||
PendingQueueSize - Count to call listen() with.
|
||
ppAddressVector - Network address of this machine.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_CANT_CREATE_ENDPOINT
|
||
RPC_S_DUPLICATE_ENDPOINT
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS status;
|
||
NTSTATUS NtStatus;
|
||
USHORT port, maxport;
|
||
const NB_PROTSEQ_CONFIG *pConfig;
|
||
PWS_ADDRESS pAddress = (PWS_ADDRESS)ThisAddress;
|
||
|
||
// Figure out which flavor of Netbios we're going to use.
|
||
|
||
pConfig = 0;
|
||
|
||
for (int i = 0; i < cNetbiosProtseqs; i++)
|
||
{
|
||
if (index == NbProtseqConfig[i].id)
|
||
{
|
||
pConfig = &NbProtseqConfig[i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (0 == pConfig)
|
||
{
|
||
ASSERT(0);
|
||
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
|
||
}
|
||
|
||
// Figure out what ports to try to listen on.
|
||
|
||
if (*pEndpoint)
|
||
{
|
||
status = EndpointToPortNumber(*pEndpoint, port);
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
return(status);
|
||
}
|
||
|
||
if (port > 255)
|
||
{
|
||
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
||
}
|
||
|
||
// Static endpoint, only try the one endpoint.
|
||
|
||
status = NB_ServerListenHelper(pAddress,
|
||
port,
|
||
pConfig,
|
||
PendingQueueSize);
|
||
|
||
afUsedEndpoints[port] = TRUE;
|
||
}
|
||
else
|
||
{
|
||
port = pConfig->MinEndpoint;
|
||
maxport = pConfig->MaxEndpoint;
|
||
|
||
// Try to listen to a port. This is iterative for dynamic endpoints.
|
||
|
||
for(; port <= maxport; port++)
|
||
{
|
||
|
||
if (InterlockedExchange((PLONG)&afUsedEndpoints[port], TRUE) == FALSE)
|
||
{
|
||
|
||
status = NB_ServerListenHelper(pAddress,
|
||
port,
|
||
pConfig,
|
||
PendingQueueSize);
|
||
|
||
if (status == RPC_S_OK)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (status != ERROR_RETRY)
|
||
{
|
||
return(status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = ERROR_RETRY;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
if (status == ERROR_RETRY)
|
||
{
|
||
if (*pEndpoint)
|
||
{
|
||
return(RPC_S_DUPLICATE_ENDPOINT);
|
||
}
|
||
return(RPC_S_CANT_CREATE_ENDPOINT);
|
||
}
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Build address vector
|
||
//
|
||
|
||
ASSERT(pAddress->pAddressVector == 0);
|
||
|
||
NETWORK_ADDRESS_VECTOR *pVector;
|
||
|
||
pVector = new( sizeof(RPC_CHAR *)
|
||
+ gdwComputerNameLength * sizeof(RPC_CHAR))
|
||
NETWORK_ADDRESS_VECTOR;
|
||
|
||
if (pVector)
|
||
{
|
||
pVector->Count = 1;
|
||
pVector->NetworkAddresses[0] = (RPC_CHAR *)&pVector->NetworkAddresses[1];
|
||
|
||
wcscpy(pVector->NetworkAddresses[0], gpstrComputerName);
|
||
|
||
pAddress->pAddressVector = pVector;
|
||
*ppAddressVector = pVector;
|
||
}
|
||
else
|
||
{
|
||
WS_ServerAbortListen(ThisAddress);
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
//
|
||
// If needed, return the dynamic endpoint as a string.
|
||
//
|
||
if (!*pEndpoint)
|
||
{
|
||
*pEndpoint = new RPC_CHAR[NB_MAXIMUM_ENDPOINT];
|
||
if (!*pEndpoint)
|
||
{
|
||
WS_ServerAbortListen(ThisAddress);
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
PortNumberToEndpoint(port, *pEndpoint);
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
C_ASSERT(FIELD_OFFSET(NB_CONNECTION, fReceivePending) == FIELD_OFFSET(WS_CLIENT_CONNECTION, fReceivePending));
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NB_ClientOpen(
|
||
IN RPC_TRANSPORT_CONNECTION ThisConnection,
|
||
IN RPC_CHAR * ProtocolSequence,
|
||
IN RPC_CHAR * NetworkAddress,
|
||
IN RPC_CHAR * Endpoint,
|
||
IN RPC_CHAR * NetworkOptions,
|
||
IN UINT Timeout,
|
||
IN UINT SendBufferSize,
|
||
IN UINT RecvBufferSize,
|
||
IN void *ResolverHint,
|
||
IN BOOL fHintInitialized
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens a connection to a server.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - A place to store the connection
|
||
ProtocolSeqeunce - "ncacn_nb_*"
|
||
NetworkAddress - The name of the server, a 1-15 character netbios name
|
||
NetworkOptions - Ignored
|
||
Timeout - See RpcMgmtSetComTimeout
|
||
0 - Min
|
||
5 - Default
|
||
9 - Max
|
||
10 - Infinite
|
||
SendBufferSize -
|
||
RecvBufferSize - (Both optional) Specifies the size of the send/recv
|
||
transport buffers.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_SERVER_UNAVAILABLE
|
||
RPC_S_INVALID_ENDPOINT_FORMAT
|
||
RPC_S_INVALID_NET_ADDR
|
||
|
||
--*/
|
||
{
|
||
PNB_CONNECTION p = (PNB_CONNECTION)ThisConnection;
|
||
unsigned i;
|
||
PROTOCOL_ID id = 0;
|
||
USHORT port;
|
||
RPC_STATUS status;
|
||
UCHAR nbname[NB_MAXIMUM_NAME];
|
||
SOCKET sock;
|
||
WS_SOCKADDR addr;
|
||
BOOL fIsUserModeConnection;
|
||
|
||
// Figure out which specific Netbios protocol we're using
|
||
for (i = 0; i < cNetbiosProtseqs; i++)
|
||
{
|
||
if (wcscmp(NbProtseqConfig[i].Protseq, ProtocolSequence) == 0)
|
||
{
|
||
id = NbProtseqConfig[i].id;
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT(id);
|
||
|
||
// Initialize common part of the connection object
|
||
|
||
// use explicit placement to initialize vtable
|
||
p = new (p) NB_CONNECTION;
|
||
|
||
p->id = id;
|
||
p->type = CLIENT | CONNECTION;
|
||
p->Conn.Socket = 0;
|
||
p->fAborted = 0;
|
||
p->pReadBuffer = 0;
|
||
p->maxReadBuffer = 0;
|
||
p->iPostSize = CO_MIN_RECV;
|
||
p->iLastRead = 0;
|
||
memset(&p->Read.ol, 0, sizeof(p->Read.ol));
|
||
p->Read.pAsyncObject = p;
|
||
p->Read.thread = 0;
|
||
p->SequenceNumber = 0;
|
||
p->InitIoCounter();
|
||
p->fReceivePending = 0;
|
||
RpcpInitializeListHead(&p->ObjectList);
|
||
|
||
// The netbios endpoint is really just the 16th character in the
|
||
// netbios name registered by the server. The value is 1-255.
|
||
|
||
status = EndpointToPortNumber(Endpoint, port);
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
return status;
|
||
}
|
||
|
||
if (port > 255)
|
||
{
|
||
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
||
}
|
||
|
||
// Build the uppercase netbios name we're looking for.
|
||
|
||
if (NetworkAddress && *NetworkAddress)
|
||
{
|
||
if (wcslen(NetworkAddress) >= NB_MAXIMUM_NAME)
|
||
{
|
||
return(RPC_S_INVALID_NET_ADDR);
|
||
}
|
||
PlatformToAnsi(NetworkAddress, (PCHAR)nbname);
|
||
}
|
||
else
|
||
{
|
||
PlatformToAnsi(gpstrComputerName, (PCHAR)nbname);
|
||
}
|
||
|
||
_strupr((PCHAR)nbname);
|
||
|
||
// Loop over every lana until we run out or succeed.
|
||
unsigned ErrorCount = 0;
|
||
|
||
for (i = 0; i < cLanas; i++)
|
||
{
|
||
|
||
if (pNetbiosLanaMap[i].ProtocolId != id)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
UCHAR lana = pNetbiosLanaMap[i].Lana;
|
||
|
||
//
|
||
// Open socket
|
||
//
|
||
|
||
sock = WSASocketT(AF_NETBIOS,
|
||
SOCK_SEQPACKET,
|
||
-1 * lana,
|
||
0,
|
||
0,
|
||
WSA_FLAG_OVERLAPPED);
|
||
|
||
if (sock == INVALID_SOCKET)
|
||
{
|
||
switch(GetLastError())
|
||
{
|
||
case WSAEAFNOSUPPORT:
|
||
case WSAEPROTONOSUPPORT:
|
||
case WSAESOCKTNOSUPPORT:
|
||
case WSAEINVAL: // when registry is not yet setup.
|
||
ErrorCount++;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
// Keep trying until we run out of lana's.
|
||
|
||
// This was a 4.0 hot fix for exchange, they had an invalid lana
|
||
// in the configuration and it caused us to abort too early.
|
||
|
||
continue;
|
||
}
|
||
|
||
DWORD option = TRUE;
|
||
int retval;
|
||
|
||
retval = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR,
|
||
(PCHAR)&option, sizeof(option) );
|
||
|
||
ASSERT(0 == retval);
|
||
|
||
|
||
SET_NETBIOS_SOCKADDR( (&addr.nbaddr),
|
||
NETBIOS_UNIQUE_NAME,
|
||
nbname,
|
||
(CHAR)port );
|
||
|
||
//
|
||
// Connect the socket to the server. This is where we expect to block
|
||
// and/or fail.
|
||
//
|
||
|
||
if (connect(sock, &addr.generic, sizeof(addr)) == SOCKET_ERROR)
|
||
{
|
||
closesocket(sock);
|
||
// Keep trying until we run out of lana's.
|
||
continue;
|
||
}
|
||
|
||
status = COMMON_PrepareNewHandle((HANDLE)sock);
|
||
if (status != RPC_S_OK)
|
||
{
|
||
closesocket(sock);
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
// Connected, life is good.
|
||
p->Conn.Socket = sock;
|
||
|
||
fIsUserModeConnection = IsUserModeSocket(sock, &status);
|
||
if (status)
|
||
{
|
||
closesocket(sock);
|
||
ErrorCount ++;
|
||
continue;
|
||
}
|
||
// if this is a user mode connection, use Winsock functions ...
|
||
if (fIsUserModeConnection)
|
||
p = new (p) NB_SAN_CONNECTION;
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
// Either no lana's configured or none of them worked.
|
||
if (ErrorCount == cLanas)
|
||
{
|
||
return (RPC_S_PROTSEQ_NOT_SUPPORTED);
|
||
}
|
||
|
||
return(RPC_S_SERVER_UNAVAILABLE);
|
||
}
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NB_Send(
|
||
RPC_TRANSPORT_CONNECTION ThisConnection,
|
||
UINT Length,
|
||
BUFFER Buffer,
|
||
PVOID SendContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Submits a send of the buffer on the connection. Will complete with
|
||
ConnectionServerSend or ConnectionClientSend event either when
|
||
the data has been sent on the network or when the send fails.
|
||
|
||
This routine is specific to netbios since it supports sending
|
||
sequence numbers.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - The connection to send the data on.
|
||
Length - The length of the data to send.
|
||
Buffer - The data to send.
|
||
SendContext - A buffer to use as the CO_SEND_CONTEXT for
|
||
this operation.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
RPC_P_SEND_FAILED - Connection aborted
|
||
|
||
--*/
|
||
{
|
||
PNB_CONNECTION pConnection = (PNB_CONNECTION)ThisConnection;
|
||
CO_SEND_CONTEXT *pSend = (CO_SEND_CONTEXT *)SendContext;
|
||
BOOL b;
|
||
DWORD ignored;
|
||
RPC_STATUS status;
|
||
|
||
pConnection->StartingWriteIO();
|
||
|
||
if (pConnection->fAborted)
|
||
{
|
||
pConnection->WriteIOFinished();
|
||
return(RPC_P_SEND_FAILED);
|
||
}
|
||
|
||
pSend->maxWriteBuffer = Length;
|
||
pSend->pWriteBuffer = Buffer;
|
||
pSend->Write.pAsyncObject = pConnection;
|
||
pSend->Write.ol.hEvent = 0;
|
||
pSend->Write.ol.Offset = 0;
|
||
pSend->Write.ol.OffsetHigh = 0;
|
||
pSend->Write.thread = I_RpcTransProtectThread();
|
||
|
||
if ((pConnection->type & TYPE_MASK) == CLIENT)
|
||
{
|
||
// Client sends need to be prefixed with the sequence number.
|
||
|
||
// Note: this depends on having only a single client side
|
||
// send pending on a connection at a time. If this changes
|
||
// we can move the sequence number into the SEND_CONTEXT.
|
||
|
||
WSABUF bufs[2];
|
||
|
||
bufs[0].buf = (PCHAR)&pConnection->SequenceNumber;
|
||
bufs[0].len = sizeof(ULONG);
|
||
bufs[1].buf = (PCHAR)Buffer;
|
||
bufs[1].len = Length;
|
||
|
||
status = RPC_S_OK;
|
||
|
||
if (WSASend(pConnection->Conn.Socket,
|
||
bufs,
|
||
2,
|
||
&ignored,
|
||
0,
|
||
&pSend->Write.ol,
|
||
0))
|
||
{
|
||
status = GetLastError();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = pConnection->Send(pConnection->Conn.Handle,
|
||
Buffer,
|
||
Length,
|
||
&ignored,
|
||
&pSend->Write.ol
|
||
);
|
||
}
|
||
|
||
ASSERT(WSA_IO_PENDING == ERROR_IO_PENDING);
|
||
|
||
pConnection->WriteIOFinished();
|
||
|
||
if ( status != RPC_S_OK
|
||
&& status != ERROR_IO_PENDING)
|
||
{
|
||
|
||
if ( status != ERROR_NETNAME_DELETED
|
||
&& status != ERROR_GRACEFUL_DISCONNECT
|
||
&& status != WSAESHUTDOWN
|
||
&& status != WSAECONNRESET
|
||
&& status != WSAECONNABORTED
|
||
&& status != WSAENETRESET
|
||
)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "NB Send failed %d on %p\n",
|
||
status,
|
||
pConnection));
|
||
}
|
||
|
||
I_RpcTransUnprotectThread(pSend->Write.thread);
|
||
|
||
pConnection->WS_CONNECTION::Abort();
|
||
return(RPC_P_SEND_FAILED);
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NB_Recv(
|
||
RPC_TRANSPORT_CONNECTION ThisConnection
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called be the runtime on a connection without a currently
|
||
pending recv. This will submit the first recv on the
|
||
connection. Later recv's maybe posted by CO_Recv. This is
|
||
required to strip the sequence number off of fragments.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - A connection without a read pending on it.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
RPC_P_RECEIVE_FAILED
|
||
|
||
--*/
|
||
{
|
||
PNB_CONNECTION pConnection = (PNB_CONNECTION)ThisConnection;
|
||
|
||
// Reply fragments don't have a sequence number, so we'll
|
||
// just let the standard code deal with them.
|
||
if ((pConnection->type & TYPE_MASK) == CLIENT)
|
||
{
|
||
pConnection->SequenceNumber = 0;
|
||
return(CO_Recv(ThisConnection));
|
||
}
|
||
|
||
ASSERT(pConnection->iLastRead == 0);
|
||
|
||
static ULONG NetbiosSequenceNumber;
|
||
BOOL b;
|
||
DWORD ignored;
|
||
DWORD bytes;
|
||
RPC_STATUS status;
|
||
WSABUF bufs[2];
|
||
int retval;
|
||
|
||
if (pConnection->pReadBuffer == 0)
|
||
{
|
||
pConnection->pReadBuffer = TransConnectionAllocatePacket(pConnection,
|
||
pConnection->iPostSize);
|
||
|
||
if (NULL == pConnection->pReadBuffer)
|
||
{
|
||
pConnection->WS_CONNECTION::Abort();
|
||
return(RPC_P_RECEIVE_FAILED);
|
||
}
|
||
|
||
pConnection->maxReadBuffer = pConnection->iPostSize;
|
||
}
|
||
|
||
pConnection->StartingReadIO();
|
||
if (pConnection->fAborted)
|
||
{
|
||
pConnection->ReadIOFinished();
|
||
return(RPC_P_RECEIVE_FAILED);
|
||
}
|
||
|
||
pConnection->Read.thread = I_RpcTransProtectThread();
|
||
pConnection->Read.ol.hEvent = 0;
|
||
|
||
bufs[0].buf = (PCHAR)&NetbiosSequenceNumber;
|
||
bufs[0].len = sizeof(ULONG);
|
||
bufs[1].buf = (PCHAR)pConnection->pReadBuffer;
|
||
bufs[1].len = pConnection->maxReadBuffer;
|
||
|
||
ignored = 0;
|
||
|
||
retval = WSARecv(pConnection->Conn.Socket,
|
||
bufs,
|
||
2,
|
||
&bytes,
|
||
&ignored,
|
||
&pConnection->Read.ol,
|
||
0);
|
||
|
||
pConnection->ReadIOFinished();
|
||
|
||
if ( (0 != retval)
|
||
&& ((status = GetLastError()) != ERROR_IO_PENDING)
|
||
&& (status != WSAEMSGSIZE) )
|
||
{
|
||
|
||
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_INFO_LEVEL,
|
||
RPCTRANS "NB WSARecv failed %d on %p\n",
|
||
status,
|
||
pConnection));
|
||
|
||
I_RpcTransUnprotectThread(pConnection->Read.thread);
|
||
|
||
pConnection->WS_CONNECTION::Abort();
|
||
return(RPC_P_RECEIVE_FAILED);
|
||
}
|
||
|
||
// Even if the read completed here, it will also be posted to the
|
||
// completion port. This means we don't need to handle the read here.
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
RPC_STATUS NB_CONNECTION::ProcessRead(IN DWORD bytes, OUT BUFFER *pBuffer,
|
||
OUT PUINT pBufferLength)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wrapper for BASE_CONNECTION::ProcessRead. This removes alls signs of the sequence
|
||
number and return the results of BASE_CONNECTION::ProcessRead.
|
||
|
||
Arguments:
|
||
Return Value:
|
||
|
||
See BASE_CONNECTION::ProcessRead
|
||
|
||
--*/
|
||
{
|
||
// If this is the first read on the server then we need to substract
|
||
// four from the bytes read since reading the sequence number doesn't count.
|
||
|
||
if (type & SERVER)
|
||
{
|
||
// Server
|
||
if (iLastRead == 0)
|
||
{
|
||
// First read
|
||
|
||
if (bytes <= 4)
|
||
{
|
||
ASSERT(0);
|
||
WS_CONNECTION::Abort();
|
||
return(RPC_P_RECEIVE_FAILED);
|
||
}
|
||
|
||
bytes -= sizeof(ULONG);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SequenceNumber = 0;
|
||
}
|
||
|
||
return(WS_CONNECTION::ProcessRead(bytes,
|
||
pBuffer,
|
||
pBufferLength));
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NB_SyncSend(
|
||
IN RPC_TRANSPORT_CONNECTION Connection,
|
||
IN UINT BufferLength,
|
||
IN BUFFER Buffer,
|
||
IN BOOL fDisableShutdownCheck,
|
||
IN BOOL fDisableCancelCheck,
|
||
ULONG Timeout
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends a message on the connection. This method must appear
|
||
to be synchronous from the callers perspective.
|
||
|
||
Arguments:
|
||
|
||
Connection - The connection of send to.
|
||
BufferLength - The size of the buffer.
|
||
Buffer - The data to sent.
|
||
fDisableShutdownCheck - N/A to netbios.
|
||
|
||
Return Value:
|
||
|
||
RPC_P_SEND_FAILED - Connection will be closed if this is returned.
|
||
|
||
RPC_S_OK - Data sent
|
||
|
||
--*/
|
||
|
||
{
|
||
PNB_CONNECTION p = (PNB_CONNECTION)Connection;
|
||
ULONG bytes;
|
||
INT retval;
|
||
RPC_STATUS status;
|
||
WSABUF bufs[2];
|
||
int count;
|
||
HANDLE hEvent = I_RpcTransGetThreadEvent();
|
||
BOOL fWaitAlertably;
|
||
|
||
p->StartingWriteIO();
|
||
|
||
if (p->fAborted)
|
||
{
|
||
p->WriteIOFinished();
|
||
return(RPC_P_SEND_FAILED);
|
||
}
|
||
|
||
// Setting the low bit of the event indicates that the write
|
||
// completion should NOT be sent to the i/o completion port.
|
||
OVERLAPPED olWrite;
|
||
olWrite.Internal = 0;
|
||
olWrite.InternalHigh = 0;
|
||
olWrite.Offset = 0;
|
||
olWrite.OffsetHigh = 0;
|
||
olWrite.hEvent = (HANDLE) ((ULONG_PTR)hEvent | 0x1);
|
||
|
||
if ((p->type & TYPE_MASK) == CLIENT)
|
||
{
|
||
bufs[0].buf = (PCHAR)&p->SequenceNumber;
|
||
bufs[0].len = sizeof(ULONG);
|
||
bufs[1].buf = (PCHAR)Buffer;
|
||
bufs[1].len = BufferLength;
|
||
|
||
count = 2;
|
||
BufferLength += sizeof(ULONG);
|
||
}
|
||
else
|
||
{
|
||
bufs[0].buf = (PCHAR)Buffer;
|
||
bufs[0].len = BufferLength;
|
||
count = 1;
|
||
}
|
||
|
||
retval = WSASend(p->Conn.Socket,
|
||
bufs,
|
||
count,
|
||
&bytes,
|
||
0,
|
||
&olWrite,
|
||
0);
|
||
|
||
p->WriteIOFinished();
|
||
|
||
if (retval == 0)
|
||
{
|
||
ASSERT(bytes == BufferLength);
|
||
p->SequenceNumber++;
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
status = GetLastError();
|
||
if (status == WSA_IO_PENDING)
|
||
{
|
||
fWaitAlertably = !fDisableCancelCheck;
|
||
status = UTIL_GetOverlappedResultEx(p,
|
||
&olWrite,
|
||
&bytes,
|
||
fWaitAlertably,
|
||
Timeout);
|
||
|
||
if (status == RPC_S_OK)
|
||
{
|
||
ASSERT(bytes == BufferLength);
|
||
p->SequenceNumber++;
|
||
return(RPC_S_OK);
|
||
}
|
||
}
|
||
|
||
p->WS_CONNECTION::Abort();
|
||
|
||
if (status == RPC_S_CALL_CANCELLED)
|
||
{
|
||
// Wait for the write to finish. Since we closed the
|
||
// connection this won't take very long.
|
||
UTIL_WaitForSyncIO(&olWrite,
|
||
FALSE,
|
||
INFINITE);
|
||
}
|
||
else
|
||
{
|
||
if (status != RPC_P_TIMEOUT)
|
||
status = RPC_P_SEND_FAILED;
|
||
}
|
||
|
||
return(status);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NBF_ServerListen(
|
||
IN RPC_TRANSPORT_ADDRESS ThisAddress,
|
||
IN RPC_CHAR *NetworkAddress,
|
||
IN OUT PWSTR *pEndpoint,
|
||
IN UINT PendingQueueSize,
|
||
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||
IN ULONG EndpointFlags,
|
||
IN ULONG NICFlags,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
|
||
)
|
||
// See NB_ServerListen
|
||
{
|
||
return( NB_ServerListen(NBF,
|
||
ThisAddress,
|
||
pEndpoint,
|
||
PendingQueueSize,
|
||
ppAddressVector) );
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NBT_ServerListen(
|
||
IN RPC_TRANSPORT_ADDRESS ThisAddress,
|
||
IN RPC_CHAR *NetworkAddress,
|
||
IN OUT PWSTR *pEndpoint,
|
||
IN UINT PendingQueueSize,
|
||
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||
IN ULONG EndpointFlags,
|
||
IN ULONG NICFlags,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
|
||
)
|
||
// See NB_ServerListen
|
||
{
|
||
return( NB_ServerListen(NBT,
|
||
ThisAddress,
|
||
pEndpoint,
|
||
PendingQueueSize,
|
||
ppAddressVector) );
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
NBI_ServerListen(
|
||
IN RPC_TRANSPORT_ADDRESS ThisAddress,
|
||
IN RPC_CHAR *NetworkAddress,
|
||
IN OUT PWSTR *pEndpoint,
|
||
IN UINT PendingQueueSize,
|
||
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||
IN ULONG EndpointFlags,
|
||
IN ULONG NICFlags,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
|
||
)
|
||
// See NB_ServerListen
|
||
{
|
||
return( NB_ServerListen(NBI,
|
||
ThisAddress,
|
||
pEndpoint,
|
||
PendingQueueSize,
|
||
ppAddressVector) );
|
||
}
|
||
|
||
|
||
//
|
||
// Transport interface definitions
|
||
//
|
||
|
||
const RPC_CONNECTION_TRANSPORT
|
||
NBF_TransportInterface =
|
||
{
|
||
RPC_TRANSPORT_INTERFACE_VERSION,
|
||
NB_TOWER_ID,
|
||
NBF_ADDRESS_ID,
|
||
RPC_STRING_LITERAL("ncacn_nb_nb"),
|
||
"135",
|
||
COMMON_ProcessCalls,
|
||
COMMON_StartPnpNotifications,
|
||
COMMON_ListenForPNPNotifications,
|
||
COMMON_TowerConstruct,
|
||
COMMON_TowerExplode,
|
||
COMMON_PostRuntimeEvent,
|
||
FALSE,
|
||
sizeof(WS_ADDRESS),
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(CO_SEND_CONTEXT),
|
||
0,
|
||
NBF_MAX_SEND,
|
||
0,
|
||
0,
|
||
NB_ClientOpen,
|
||
0, // No SendRecv on winsock
|
||
CO_SyncRecv,
|
||
WS_Abort,
|
||
WS_Close,
|
||
NB_Send,
|
||
NB_Recv,
|
||
NB_SyncSend,
|
||
0, // turn on/off keep alives
|
||
NBF_ServerListen,
|
||
WS_ServerAbortListen,
|
||
COMMON_ServerCompleteListen,
|
||
0, // query client address support.
|
||
0, // query local address
|
||
0, // query client id support.
|
||
0, // Impersonate
|
||
0 // Revert
|
||
};
|
||
|
||
const RPC_CONNECTION_TRANSPORT
|
||
NBT_TransportInterface =
|
||
{
|
||
RPC_TRANSPORT_INTERFACE_VERSION,
|
||
NB_TOWER_ID,
|
||
IP_ADDRESS_ID,
|
||
RPC_STRING_LITERAL("ncacn_nb_tcp"),
|
||
"135",
|
||
COMMON_ProcessCalls,
|
||
COMMON_StartPnpNotifications,
|
||
COMMON_ListenForPNPNotifications,
|
||
COMMON_TowerConstruct,
|
||
COMMON_TowerExplode,
|
||
COMMON_PostRuntimeEvent,
|
||
FALSE,
|
||
sizeof(WS_ADDRESS),
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(CO_SEND_CONTEXT),
|
||
0,
|
||
NBT_MAX_SEND,
|
||
0,
|
||
0,
|
||
NB_ClientOpen,
|
||
0, // No SendRecv on winsock
|
||
CO_SyncRecv,
|
||
WS_Abort,
|
||
WS_Close,
|
||
NB_Send,
|
||
NB_Recv,
|
||
NB_SyncSend,
|
||
0, // turn on/off keep alives
|
||
NBT_ServerListen,
|
||
WS_ServerAbortListen,
|
||
COMMON_ServerCompleteListen,
|
||
0, // query client address support.
|
||
0, // query local address
|
||
0, // query client id support.
|
||
0, // Impersonate
|
||
0 // Revert
|
||
};
|
||
|
||
const RPC_CONNECTION_TRANSPORT
|
||
NBI_TransportInterface =
|
||
{
|
||
RPC_TRANSPORT_INTERFACE_VERSION,
|
||
NB_TOWER_ID,
|
||
IPX_ADDRESS_ID,
|
||
RPC_STRING_LITERAL("ncacn_nb_ipx"),
|
||
"135",
|
||
COMMON_ProcessCalls,
|
||
COMMON_StartPnpNotifications,
|
||
COMMON_ListenForPNPNotifications,
|
||
COMMON_TowerConstruct,
|
||
COMMON_TowerExplode,
|
||
COMMON_PostRuntimeEvent,
|
||
FALSE,
|
||
sizeof(WS_ADDRESS),
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(CO_SEND_CONTEXT),
|
||
0,
|
||
NBI_MAX_SEND,
|
||
0,
|
||
0,
|
||
NB_ClientOpen,
|
||
0, // No SendRecv on winsock
|
||
CO_SyncRecv,
|
||
WS_Abort,
|
||
WS_Close,
|
||
NB_Send,
|
||
NB_Recv,
|
||
NB_SyncSend,
|
||
0, // turn on/off keep alives
|
||
NBI_ServerListen,
|
||
WS_ServerAbortListen,
|
||
COMMON_ServerCompleteListen,
|
||
0, // query client address support.
|
||
0, // query local address
|
||
0, // query client id support.
|
||
0, // Impersonate
|
||
0 // Revert
|
||
};
|
||
|
||
|
||
|
||
const RPC_CONNECTION_TRANSPORT *
|
||
NB_TransportLoad (
|
||
IN PROTOCOL_ID index
|
||
)
|
||
{
|
||
RPC_STATUS status;
|
||
|
||
if (fWinsockLoaded == FALSE)
|
||
{
|
||
if (RPC_WSAStartup() == FALSE)
|
||
{
|
||
return 0;
|
||
}
|
||
fWinsockLoaded = TRUE;
|
||
}
|
||
|
||
if (fNetbiosLoaded == FALSE)
|
||
{
|
||
status = LoadNetbios();
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
fNetbiosLoaded = TRUE;
|
||
}
|
||
|
||
switch(index)
|
||
{
|
||
case NBF:
|
||
return(&NBF_TransportInterface);
|
||
break;
|
||
case NBT:
|
||
return(&NBT_TransportInterface);
|
||
break;
|
||
case NBI:
|
||
return(&NBI_TransportInterface);
|
||
break;
|
||
default:
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "NB_TransportLoad called with index: %d\n",
|
||
index));
|
||
|
||
ASSERT(0);
|
||
}
|
||
return(0);
|
||
}
|
||
|