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.
957 lines
23 KiB
957 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nbltclnt.c
|
|
|
|
Abstract:
|
|
|
|
Loadable transport for NT - client side.
|
|
This file is packaged as a dynamic link library, that is loaded on
|
|
demand by the RPC runtime. It provides basic connection-oriented,
|
|
message-based operations. A connection is created with Open and
|
|
destroyed with Close. You read and write messages with Receive and
|
|
and Send.
|
|
|
|
Author:
|
|
|
|
Steven Zeck (stevez) 2/12/92
|
|
|
|
Danny Glasser (dannygl) 3/1/93
|
|
|
|
--*/
|
|
|
|
#include "NetBCom.h"
|
|
#include <osfpcket.hxx>
|
|
#include <stdlib.h>
|
|
|
|
// The following maps lana_num to self indexes and keeps track of
|
|
// the initialization state of each logical adapter.
|
|
//
|
|
// NOTE: This variable should *not* be accessed directly by name.
|
|
// It should be accessed via the ProtocolTable manifest defined
|
|
// in NETBCOM.H.
|
|
//
|
|
// NOTE: This variable is exported from the client DLL for use by the
|
|
// server DLL.
|
|
|
|
|
|
|
|
// This is the critical section object used by both the client and server
|
|
// transports to serialize access to ProtoToLana[] and other global
|
|
// objects.
|
|
//
|
|
// NOTE: On NT, this variable is exported from the client DLL for use by
|
|
// the server DLL.
|
|
|
|
#ifdef WIN32RPC
|
|
CRITICAL_SECTION NetBiosMutex;
|
|
#endif
|
|
|
|
|
|
// This table maps system error codes into RPC generic ones.
|
|
|
|
ERROR_TABLE NetBiosErrors[] =
|
|
{
|
|
NRC_BFULL, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_CMDTMO, RPC_S_SERVER_UNAVAILABLE,
|
|
NRC_NORES, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_NAMTFUL, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_ACTSES, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_LOCTFUL, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_REMTFUL, RPC_S_SERVER_TOO_BUSY,
|
|
NRC_TOOMANY, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_MAXAPPS, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_NORESOURCES, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_NOCALL, RPC_S_SERVER_UNAVAILABLE,
|
|
NRC_SCLOSED, RPC_P_SEND_FAILED,
|
|
NRC_SABORT, RPC_P_SEND_FAILED,
|
|
0
|
|
};
|
|
|
|
#if !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_PPC_)
|
|
#define UNALIGNED
|
|
#endif
|
|
|
|
|
|
/*
|
|
Following Macros and structs are needed for Tower Stuff
|
|
*/
|
|
|
|
#pragma pack(1)
|
|
#define NB_TRANSPORTID 0x12
|
|
#define NB_NBID 0x13
|
|
#define NB_XNSID 0x15
|
|
#define NB_IPID 0x09
|
|
#define NB_IPXID 0x0d
|
|
#define NB_TOWERFLOORS 5
|
|
|
|
#define NB_PROTSEQ "ncacn_nb_nb"
|
|
#define XNS_PROTSEQ "ncacn_nb_xns"
|
|
#define IP_PROTSEQ "ncacn_nb_tcp"
|
|
#define IPX_PROTSEQ "ncacn_nb_ipx"
|
|
|
|
typedef struct _FLOOR_234 {
|
|
unsigned short ProtocolIdByteCount;
|
|
unsigned char FloorId;
|
|
unsigned short AddressByteCount;
|
|
unsigned char Data[2];
|
|
} FLOOR_234, __RPC_FAR * PFLOOR_234;
|
|
|
|
|
|
#define NEXTFLOOR(t,x) (t)((unsigned char __RPC_FAR *)x +((t)x)->ProtocolIdByteCount\
|
|
+ ((t)x)->AddressByteCount\
|
|
+ sizeof(((t)x)->ProtocolIdByteCount)\
|
|
+ sizeof(((t)x)->AddressByteCount))
|
|
|
|
/*
|
|
End of Tower Stuff!
|
|
*/
|
|
|
|
#pragma pack()
|
|
|
|
|
|
// The following is the structure that's allocated to contain the Send
|
|
// NCB and buffer.
|
|
|
|
typedef struct {
|
|
|
|
NCB theNCB;
|
|
CLIENT_BUFFER theBuffer;
|
|
|
|
} SEND_INFO, *PSEND_INFO;
|
|
|
|
|
|
// The following is the structure that's allocated to contain the Receive
|
|
// NCB and buffer.
|
|
|
|
typedef struct {
|
|
|
|
NCB theNCB;
|
|
BYTE theBuffer[NETB_MAXIMUM_DATA];
|
|
|
|
} RECEIVE_INFO, *PRECEIVE_INFO;
|
|
|
|
|
|
// Following is the per session (connection) state with the server.
|
|
|
|
typedef struct _CONNECTION {
|
|
unsigned char lsn; // netbios Local Session Number
|
|
unsigned char lana_num; // LAN Adapter Number
|
|
|
|
PSEND_INFO pSend; // The NCB and buffer for the send command
|
|
// (and others)
|
|
|
|
PRECEIVE_INFO pRcv; // The NCB and buffer for the receive command
|
|
|
|
} CONNECTION, *PCONNECTION;
|
|
|
|
|
|
extern RPC_CLIENT_TRANSPORT_INFO TransInfo;
|
|
|
|
// Forward function prototypes
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Close (
|
|
PCONNECTION pConn
|
|
);
|
|
|
|
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO __RPC_FAR * RPC_ENTRY
|
|
TransportLoad (
|
|
IN RPC_CHAR __RPC_FAR * RpcProtocolSequence
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loadable transport initialization function.
|
|
|
|
Arguments:
|
|
|
|
RpcProtocolSequence - the protocol string that mapped to this library.
|
|
|
|
RpcClientRuntimeInfo - Supplies the pointers to the support functions
|
|
in the runtime to be used by the transport support providers.
|
|
(Win16 only)
|
|
|
|
Returns:
|
|
|
|
A pointer to a RPC_CLIENT_TRANSPORT_INFO describing this transport.
|
|
|
|
--*/
|
|
|
|
{
|
|
InitNBMutex();
|
|
|
|
return(SetupNetBios(RpcProtocolSequence)? &TransInfo: 0);
|
|
}
|
|
|
|
|
|
INTERNAL_FUNCTION RPC_STATUS
|
|
GetSelfName (
|
|
OUT NCB *pNCB,
|
|
IN int DriverNumber,
|
|
IN RPC_CHAR * ProtoSeq
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function fills in the ncb_name field for a given adapter number.
|
|
This selfName is needed when making a CALL (connection) with a server.
|
|
It identifies which lsn will get messages sent from the server to
|
|
this machine. There must be a different selfName for each logical
|
|
adapter number. All the selfNames are the same for the first 15
|
|
characters. The last byte is the "index" which is allocated by this
|
|
function.
|
|
|
|
Arguments:
|
|
|
|
pNCB - NCB to put the name
|
|
|
|
DriverNumber - the logical driver number for the protocol.
|
|
|
|
ProtoSeq - Protocol sequence to map to lan_num.
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK, RPC_S_OUT_OF_RESOURCES, Status code mapping.
|
|
|
|
--*/
|
|
|
|
{
|
|
// The following is a list of endpoints that we won't try to use
|
|
// in constructing a selfname.
|
|
|
|
static unsigned char WellKnownEndpoints[] =
|
|
{
|
|
0x00, // redirector
|
|
0x03, // redirector - messenger
|
|
0x05, // redirector - forwarded names
|
|
0x20, // server
|
|
0x1f // winball & NetDDE
|
|
};
|
|
|
|
#define KNOWN_EP_TABLE_SIZE \
|
|
(sizeof(WellKnownEndpoints) / sizeof(*WellKnownEndpoints))
|
|
|
|
RPC_STATUS status;
|
|
PPROTOCOL_MAP ProtocolEntry;
|
|
int i;
|
|
#if defined(NTENV) || defined(DOSWIN32RPC)
|
|
UCHAR ncb_status;
|
|
#endif
|
|
|
|
// Reset all fields of NCB and stuff the lana_num field.
|
|
|
|
memset(pNCB, 0 , sizeof(NCB));
|
|
|
|
EnterCriticalSection(&NetBiosMutex);
|
|
|
|
// Look up the protocol sequence in the protocol table
|
|
if (status = MapProtocol(ProtoSeq, DriverNumber, &ProtocolEntry))
|
|
{
|
|
LeaveCriticalSection(&NetBiosMutex);
|
|
return(status);
|
|
}
|
|
|
|
pNCB->ncb_lana_num = ProtocolEntry->Lana;
|
|
|
|
// If a NetBIOS has already been added on this protocol, then we're done.
|
|
if (ProtocolEntry->SelfName)
|
|
{
|
|
memcpy(pNCB->ncb_name, MachineName, sizeof(MachineName));
|
|
pNCB->ncb_name[NAME_LAST_BYTE] = ProtocolEntry->SelfName;
|
|
|
|
LeaveCriticalSection(&NetBiosMutex);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
#if defined(NTENV)
|
|
|
|
// Allocate resources for the adapter #
|
|
|
|
if (ncb_status = AdapterReset(ProtocolEntry))
|
|
{
|
|
LeaveCriticalSection(&NetBiosMutex);
|
|
|
|
return(MapStatusCode(NetBiosErrors,
|
|
ncb_status, RPC_S_OUT_OF_RESOURCES));
|
|
}
|
|
#endif
|
|
// Copy the machine name into the NCB. The last byte is zero.
|
|
memcpy(pNCB->ncb_name, MachineName, sizeof(MachineName));
|
|
|
|
// Manufacture a unique name on the client side by modifying
|
|
// the last byte in the machine name.
|
|
pNCB->ncb_retcode = NRC_DUPNAME;
|
|
|
|
do {
|
|
pNCB->ncb_name[NAME_LAST_BYTE]++;
|
|
|
|
// Scan for well-known endpoints and skip them when found.
|
|
|
|
for (i = 0; i < KNOWN_EP_TABLE_SIZE; i++)
|
|
{
|
|
if (WellKnownEndpoints[i]
|
|
== (unsigned char) pNCB->ncb_name[NAME_LAST_BYTE])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we matched an endpoint in the table, we try the next endpoint.
|
|
if (i < KNOWN_EP_TABLE_SIZE)
|
|
{
|
|
continue;
|
|
}
|
|
// Attempt to add the name
|
|
execNCB(NCBADDNAME, pNCB);
|
|
|
|
}
|
|
while (pNCB->ncb_retcode == NRC_DUPNAME
|
|
&& pNCB->ncb_name[NAME_LAST_BYTE] < UCHAR_MAX);
|
|
|
|
|
|
if (pNCB->ncb_retcode)
|
|
{
|
|
|
|
I_RpcFree(ProtocolTable[i].ProtoSeq);
|
|
ProtocolTable[i].ProtoSeq = 0;
|
|
|
|
LeaveCriticalSection(&NetBiosMutex);
|
|
|
|
return(MapStatusCode(NetBiosErrors, pNCB->ncb_retcode,
|
|
RPC_S_OUT_OF_RESOURCES));
|
|
}
|
|
|
|
|
|
|
|
// Place the last byte in the saved array of names.
|
|
|
|
ProtocolEntry->SelfName = pNCB->ncb_name[NAME_LAST_BYTE];
|
|
|
|
LeaveCriticalSection(&NetBiosMutex);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
toUpper(
|
|
IN RPC_CHAR ch
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a RPC_CHAR character to upper case 8 bit ASCII.
|
|
|
|
Arguments:
|
|
|
|
ch - character to convert.
|
|
|
|
Returns:
|
|
|
|
Converted character.
|
|
|
|
--*/
|
|
|
|
{
|
|
return ((unsigned char) ((ch >= 'a' && ch <= 'z')? ch & ~0x20: ch));
|
|
}
|
|
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Open (
|
|
PCONNECTION pConn,
|
|
IN RPC_CHAR __RPC_FAR * NetworkAddress,
|
|
IN RPC_CHAR __RPC_FAR * Endpoint,
|
|
IN RPC_CHAR __RPC_FAR * NetworkOptions,
|
|
IN RPC_CHAR __RPC_FAR * TransportAddress,
|
|
IN RPC_CHAR __RPC_FAR * RpcProtocolSequence,
|
|
IN unsigned int Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open a connection from a client to a server. Fill in a CALL NCB with
|
|
the requested server name and submit it to NetBios.
|
|
|
|
Arguments:
|
|
|
|
pConn - Pointer to a connection to initialize.
|
|
|
|
NetworkAddress - The name of the server. Format: ServerName.
|
|
|
|
Endpoint - The NetBios "socket number". It must be an string of digits
|
|
which has a converted range from 0..255.
|
|
|
|
NetworkOptions - unused
|
|
TransportAddress - unused
|
|
|
|
RpcProtocolSequence - this string is used to map to a NetBios apdater
|
|
number. Format of the string is "ncacn_nb_<protocol>. This
|
|
<protocol> (<> are not in the string) is used to do the mapping.
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK, RPC_S_INVALID_ENDPOINT_FORMAT, RPC_S_SERVER_UNAVAILABLE
|
|
|
|
--*/
|
|
|
|
{
|
|
int result;
|
|
NCB theNCB;
|
|
unsigned char *pName;
|
|
unsigned int EndpointNumber;
|
|
int DriverNumber = 0;
|
|
RPC_STATUS status = 0;
|
|
unsigned short CalledOnce = 0;
|
|
|
|
PUNUSED(NetworkOptions); PUNUSED(TransportAddress);
|
|
PUNUSED(RpcProtocolSequence); UNUSED(Timeout);
|
|
|
|
EndpointNumber = atoi(Endpoint);
|
|
|
|
if (EndpointNumber > 0xff || EndpointNumber == 0)
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
|
|
// Zero the connection structure, so that we don't have to worry later
|
|
// about uninitialized fields.
|
|
memset(pConn, 0, sizeof(*pConn));
|
|
|
|
|
|
// We allocate objects dynamically here. From this point on in the
|
|
// function we set status and jump to Open_FatalError if we want to
|
|
// abort the Open operation.
|
|
|
|
// Note: We allocate the buffers here (rather than having them
|
|
// allocated as part of the PCONNECTION) because the Win16 PCONNECTION
|
|
// is allocated from the RPC run-time's near heap, so having a large
|
|
// PCONNECTION would sharply limit the number of connections from a
|
|
// Win16 client. By using I_RpcAllocate(), we get the memory from
|
|
// the far heap.
|
|
|
|
if (! (pConn->pSend = (PSEND_INFO) I_RpcAllocate(sizeof(*pConn->pSend))))
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
|
|
goto Open_FatalError;
|
|
}
|
|
|
|
if (! (pConn->pRcv = (PRECEIVE_INFO) I_RpcAllocate(sizeof(*pConn->pRcv))))
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
|
|
goto Open_FatalError;
|
|
}
|
|
|
|
// Initialize the sequence number for the send buffer, zero the NCB
|
|
// structures for both buffers, and on Win16 set the connection ptr
|
|
// for both buffers.
|
|
|
|
pConn->pSend->theBuffer.seq_num = 0;
|
|
memset(&pConn->pSend->theNCB, 0, sizeof(pConn->pSend->theNCB));
|
|
memset(&pConn->pRcv->theNCB, 0, sizeof(pConn->pRcv->theNCB));
|
|
|
|
// This loop will enumerate and attempt to make a connection with
|
|
// all the logical drivers assoicated with this protocol.
|
|
|
|
do
|
|
{
|
|
// Get the name of this machine into the NCB.
|
|
pName = theNCB.ncb_callname;
|
|
|
|
if (status = GetSelfName(&theNCB, DriverNumber++, RpcProtocolSequence))
|
|
{
|
|
if ((status == RPC_S_PROTSEQ_NOT_FOUND) && (CalledOnce))
|
|
status = RPC_S_SERVER_UNAVAILABLE;
|
|
|
|
goto Open_FatalError;
|
|
}
|
|
|
|
if (NetworkAddress[0])
|
|
{
|
|
RPC_CHAR * SavedHostName = NetworkAddress;
|
|
|
|
// Copy the upper case server name to the NCB.
|
|
|
|
while (*NetworkAddress)
|
|
*pName++ = toUpper(*NetworkAddress++);
|
|
|
|
NetworkAddress = SavedHostName;
|
|
|
|
// Pad the name appropriately
|
|
memset(pName, NETBIOS_NAME_PAD_BYTE,
|
|
theNCB.ncb_callname + sizeof(theNCB.ncb_callname) - pName);
|
|
}
|
|
else
|
|
{
|
|
// No server name, use the name of this machine.
|
|
|
|
memcpy(pName, MachineName, sizeof(MachineName));
|
|
}
|
|
|
|
|
|
theNCB.ncb_callname[NAME_LAST_BYTE] = (unsigned char) EndpointNumber;
|
|
|
|
// BUGBUG - Should we use SubmitMaybeAsyncNCB() here?
|
|
|
|
theNCB.ncb_command = NCBCALL;
|
|
if (result = Netbios(&theNCB))
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("NCBCALL failed retcode %x\n", theNCB.ncb_retcode);
|
|
#endif
|
|
status = RPC_S_SERVER_UNAVAILABLE;
|
|
goto Open_FatalError;
|
|
}
|
|
|
|
if (theNCB.ncb_retcode == NRC_NOCALL)
|
|
{
|
|
CalledOnce = TRUE;
|
|
}
|
|
}
|
|
while (theNCB.ncb_retcode == NRC_NOCALL);
|
|
|
|
// Connection complete, initialize the connection.
|
|
|
|
status = MapStatusCode(NetBiosErrors, theNCB.ncb_retcode,
|
|
RPC_S_SERVER_UNAVAILABLE);
|
|
|
|
if (! status)
|
|
{
|
|
|
|
pConn->lsn = theNCB.ncb_lsn;
|
|
pConn->lana_num = theNCB.ncb_lana_num;
|
|
}
|
|
|
|
Open_FatalError:
|
|
|
|
// If any of the above operations failed, we call Close() to free the
|
|
// resources that we allocated.
|
|
if (status)
|
|
{
|
|
Close(pConn);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Close (
|
|
PCONNECTION pConn
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close a client connection.
|
|
|
|
Arguments:
|
|
|
|
pConn - Connection to close
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
{
|
|
|
|
// If there's an active connection, we hang it up.
|
|
|
|
if (pConn->lsn)
|
|
{
|
|
NCB theNCB;
|
|
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
|
|
theNCB.ncb_lsn = pConn->lsn;
|
|
theNCB.ncb_lana_num = pConn->lana_num;
|
|
|
|
theNCB.ncb_command = NCBHANGUP;
|
|
|
|
Netbios(&theNCB);
|
|
|
|
pConn->lsn = 0;
|
|
}
|
|
|
|
// Free the send and receive buffers
|
|
if (pConn->pSend)
|
|
{
|
|
I_RpcFree(pConn->pSend);
|
|
|
|
pConn->pSend = 0;
|
|
}
|
|
|
|
if (pConn->pRcv)
|
|
{
|
|
I_RpcFree(pConn->pRcv);
|
|
|
|
pConn->pRcv = 0;
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Send (
|
|
PCONNECTION pConn,
|
|
void * Buffer,
|
|
unsigned int Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a message to a connection. Construct an NCB to send the
|
|
requested buffer and submit it to NetBios.
|
|
|
|
Send NCBs are submitted asynchronously. This is done to improve
|
|
performance, as the sending thread can now go back and get the next
|
|
chunk of data while the NetBIOS provider is transmitting the data
|
|
to the server.
|
|
|
|
Before we submit the Send NCB, we must verify that the previously
|
|
submitted one (if any) has completed. If it has completed with an
|
|
error, we return the error without submitting a new send. Since a
|
|
given Send() command is always followed by either another Send() or
|
|
by a SendReceive(), it is SendReceive() that waits for the last
|
|
SendNCB to complete.
|
|
|
|
Arguments:
|
|
|
|
pConn - connection to act on.
|
|
|
|
Buffer - pointer to buffer to write.
|
|
|
|
Length - length of buffer to write.
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK, RPC_P_SEND_FAILED
|
|
|
|
--*/
|
|
{
|
|
int result;
|
|
NCB *pNCB = &pConn->pSend->theNCB;
|
|
rpcconn_common * PacketHeader = (rpcconn_common *) Buffer;
|
|
|
|
// Copy the data info the connection's buffer
|
|
memcpy(pConn->pSend->theBuffer.data, Buffer, (unsigned short) Length);
|
|
|
|
pNCB->ncb_buffer = (unsigned char *) &pConn->pSend->theBuffer;
|
|
pNCB->ncb_length = (unsigned short) (Length + NETB_OVERHEAD);
|
|
pNCB->ncb_lsn = pConn->lsn;
|
|
pNCB->ncb_lana_num = pConn->lana_num;
|
|
pNCB->ncb_command = NCBSEND;
|
|
|
|
if ((result = Netbios(pNCB)))
|
|
{
|
|
Close(pConn);
|
|
return (RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
if (pNCB->ncb_cmd_cplt)
|
|
{
|
|
Close(pConn);
|
|
return (RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
if (PacketHeader->PTYPE != rpc_fault)
|
|
{
|
|
pConn->pSend->theBuffer.seq_num++;
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Receive (
|
|
PCONNECTION pConn,
|
|
void * * Buffer,
|
|
unsigned int * BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read a message from a connection into the supplied buffer.
|
|
|
|
Receive NCBs are submitted both synchronously and asynchronously.
|
|
Both SendReceive() and Receive() submit an async receive NCB if
|
|
the one which returns data to them filled the NCB buffer. If
|
|
the buffer was not filled, we assume that this is the end of the
|
|
data that the server is returning for this RPC call, so we don't
|
|
submit a new NCB.
|
|
|
|
Arguments:
|
|
|
|
pConn - connection to receive a message on.
|
|
|
|
Buffer - pointer to a buffer to return the message in. This buffer
|
|
may be enlarged if it is too small to hold the returned buffer.
|
|
|
|
BufferLength - pointer to where the size of the buffer is supplied
|
|
on entry and the size of the returned data is stored on return.
|
|
|
|
Returns:
|
|
|
|
The new message in the copied to the buffer and length updated.
|
|
|
|
RPC_S_OK, RPC_S_OUT_OF_MEMORY, RPC_P_RECEIVE_FAILED
|
|
|
|
--*/
|
|
{
|
|
NCB *pNCB = &pConn->pRcv->theNCB;
|
|
unsigned char ncberr;
|
|
int result;
|
|
RPC_TRANS_STATUS status = 0;
|
|
DWORD NtStatus;
|
|
|
|
pNCB->ncb_buffer = pConn->pRcv->theBuffer;
|
|
pNCB->ncb_length = (unsigned short) sizeof(pConn->pRcv->theBuffer);
|
|
pNCB->ncb_lsn = pConn->lsn;
|
|
pNCB->ncb_lana_num = pConn->lana_num;
|
|
pNCB->ncb_command = NCBRECV;
|
|
|
|
if (result = Netbios(pNCB))
|
|
{
|
|
Close(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
if (pNCB->ncb_cmd_cplt)
|
|
{
|
|
Close(pConn);
|
|
return RPC_P_RECEIVE_FAILED;
|
|
}
|
|
|
|
// If the caller-supplied buffer is too small, we enlarge it.
|
|
if (pNCB->ncb_length > *BufferLength)
|
|
{
|
|
if (I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
*BufferLength,
|
|
pNCB->ncb_length))
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// We don't set the buffer length and copy the data if the realloc
|
|
// failed.
|
|
|
|
if (! status)
|
|
{
|
|
// Set the buffer length to the length of the returned buffer
|
|
*BufferLength = pNCB->ncb_length;
|
|
|
|
// Copy the data into the buffer
|
|
memcpy(*Buffer, pNCB->ncb_buffer, *BufferLength);
|
|
}
|
|
|
|
pConn->pSend->theBuffer.seq_num = 0;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
#pragma pack(1)
|
|
RPC_STATUS RPC_ENTRY
|
|
TowerConstruct(
|
|
IN char __RPC_FAR * Endpoint,
|
|
IN char __RPC_FAR * NetworkAddress,
|
|
OUT unsigned short UNALIGNED __RPC_FAR * Floors,
|
|
OUT unsigned long UNALIGNED __RPC_FAR * ByteCount,
|
|
OUT unsigned char __RPC_FAR * UNALIGNED __RPC_FAR * Tower,
|
|
IN char __RPC_FAR * Protseq
|
|
)
|
|
{
|
|
|
|
unsigned long TowerSize;
|
|
UNALIGNED PFLOOR_234 Floor;
|
|
unsigned long HostId;
|
|
|
|
//BUGBUG: Need appropriate error code for unsupported Protseqs
|
|
|
|
if (strcmp(Protseq,NB_PROTSEQ) == 0)
|
|
HostId = NB_NBID;
|
|
else if (strcmp(Protseq, IP_PROTSEQ) == 0)
|
|
HostId = NB_IPID;
|
|
else if (strcmp(Protseq, XNS_PROTSEQ) == 0)
|
|
HostId = NB_XNSID;
|
|
else if (strcmp(Protseq, IPX_PROTSEQ) == 0)
|
|
HostId = NB_IPXID;
|
|
else return (RPC_S_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
*Floors = NB_TOWERFLOORS;
|
|
TowerSize = ((Endpoint == NULL) || (*Endpoint == '\0')) ?
|
|
2 : strlen(Endpoint) + 1;
|
|
TowerSize += ((NetworkAddress== NULL) || (*NetworkAddress== '\0')) ?
|
|
2 : strlen(NetworkAddress) + 1;
|
|
TowerSize += 2*sizeof(FLOOR_234) - 4;
|
|
|
|
if ((*Tower = (unsigned char __RPC_FAR*)I_RpcAllocate((unsigned int)
|
|
(*ByteCount = TowerSize)))
|
|
== NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Floor = (PFLOOR_234) *Tower;
|
|
|
|
Floor->ProtocolIdByteCount = 1;
|
|
Floor->FloorId = (unsigned char)(NB_TRANSPORTID & 0xFF);
|
|
if ((Endpoint) && (*Endpoint))
|
|
{
|
|
memcpy((char __RPC_FAR *)&Floor->Data[0], Endpoint,
|
|
(Floor->AddressByteCount = strlen(Endpoint)+1));
|
|
}
|
|
else
|
|
{
|
|
Floor->AddressByteCount = 2;
|
|
Floor->Data[0] = 0;
|
|
}
|
|
//Onto the next floor
|
|
Floor = NEXTFLOOR(PFLOOR_234, Floor);
|
|
Floor->ProtocolIdByteCount = 1;
|
|
Floor->FloorId = (unsigned char)(HostId & 0xFF);
|
|
if ((NetworkAddress) && (*NetworkAddress))
|
|
{
|
|
memcpy((char __RPC_FAR *)&Floor->Data[0], NetworkAddress,
|
|
(Floor->AddressByteCount = strlen(NetworkAddress) + 1));
|
|
}
|
|
else
|
|
{
|
|
Floor->AddressByteCount = 2;
|
|
Floor->Data[0] = 0;
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
TowerExplode(
|
|
IN unsigned char __RPC_FAR * Tower,
|
|
OUT char __RPC_FAR * UNALIGNED __RPC_FAR * Protseq,
|
|
OUT char __RPC_FAR * UNALIGNED __RPC_FAR * Endpoint,
|
|
OUT char __RPC_FAR * UNALIGNED __RPC_FAR * NetworkAddress
|
|
)
|
|
{
|
|
UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
char __RPC_FAR * Pseq;
|
|
|
|
UNUSED(NetworkAddress);
|
|
|
|
if (Endpoint != NULL)
|
|
{
|
|
|
|
*Endpoint = I_RpcAllocate(Floor->AddressByteCount);
|
|
if (*Endpoint == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(*Endpoint, (char __RPC_FAR *)&Floor->Data[0],
|
|
Floor->AddressByteCount);
|
|
}
|
|
}
|
|
|
|
Floor = NEXTFLOOR(PFLOOR_234, Floor);
|
|
|
|
switch (Floor->FloorId)
|
|
{
|
|
|
|
case NB_NBID:
|
|
Pseq = NB_PROTSEQ;
|
|
break;
|
|
|
|
case NB_IPID:
|
|
Pseq = IP_PROTSEQ;
|
|
break;
|
|
|
|
case NB_XNSID:
|
|
Pseq = XNS_PROTSEQ;
|
|
break;
|
|
|
|
case NB_IPXID:
|
|
Pseq = IPX_PROTSEQ;
|
|
break;
|
|
|
|
default:
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
if ((Protseq != NULL) && (Status == RPC_S_OK))
|
|
{
|
|
*Protseq = I_RpcAllocate(strlen(Pseq) + 1);
|
|
if (*Protseq == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
if (Endpoint != NULL)
|
|
I_RpcFree(*Endpoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
memcpy(*Protseq, Pseq, strlen(Pseq) + 1);
|
|
}
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
#pragma pack()
|
|
|
|
|
|
// This structure is returned to the RPC runtime when the DLL is loaded.
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO TransInfo = {
|
|
|
|
RPC_TRANSPORT_INTERFACE_VERSION, // version # of loadable trans interface
|
|
NB_TRANSPORTID,
|
|
|
|
TowerConstruct,
|
|
TowerExplode,
|
|
|
|
NETB_MAXIMUM_DATA, // maximum # bytes for send or receive
|
|
sizeof(CONNECTION), // # of bytes to allocate for connections
|
|
|
|
// List of function pointers to export.
|
|
|
|
Open, Close, Send, Receive, 0,
|
|
0,
|
|
0,
|
|
0
|
|
|
|
};
|