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.
755 lines
20 KiB
755 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ltnpclnt.c
|
|
|
|
Abstract:
|
|
|
|
This is the implementation of the named pipe loadable transport
|
|
interface module for NT clients.
|
|
|
|
Author:
|
|
|
|
Michael Montague (mikemon) 06-Jun-1991
|
|
|
|
Revision History:
|
|
|
|
02-Mar-1992 mikemon
|
|
|
|
Made the changes necessary to get this code working with the new
|
|
loadable transport interface.
|
|
|
|
--*/
|
|
|
|
#include <sysinc.h>
|
|
#include <windows.h>
|
|
#include <rpc.h>
|
|
#include <rpcdcep.h>
|
|
#include <rpctran.h>
|
|
#include <rpcerrp.h>
|
|
#include <osfpcket.hxx>
|
|
|
|
#if !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_PPC_)
|
|
#define UNALIGNED
|
|
#endif
|
|
|
|
#define UNUSED(obj) ((void) (obj))
|
|
|
|
// This is the structure of the data at the end of every client connection
|
|
// object (see the runtime and OSF_CCONNECTION) for this transport module.
|
|
|
|
typedef struct
|
|
{
|
|
HANDLE Pipe;
|
|
} NP_CCONNECTION, *PNP_CCONNECTION;
|
|
|
|
// This is the maximum send which should be used for this transport module.
|
|
// We just need to be prepared to receive that amount. It is four times the
|
|
// maximum user data per frame on an ethernet, using named pipes.
|
|
|
|
#define NP_MAXIMUM_SEND 5680
|
|
|
|
/*
|
|
Following Macros and structs are needed for Tower Stuff
|
|
*/
|
|
|
|
#pragma pack(1)
|
|
#define NP_TRANSPORTID 0x0F
|
|
#define NP_TRANSPORTHOSTID 0x11
|
|
#define NP_TOWERFLOORS 5
|
|
|
|
typedef struct _FLOOR_234 {
|
|
unsigned short ProtocolIdByteCount;
|
|
unsigned char FloorId;
|
|
unsigned short AddressByteCount;
|
|
unsigned char Data[2];
|
|
} FLOOR_234, * PFLOOR_234;
|
|
|
|
|
|
#define NEXTFLOOR(t,x) (t)((unsigned char *)x +((t)x)->ProtocolIdByteCount\
|
|
+ ((t)x)->AddressByteCount\
|
|
+ sizeof(((t)x)->ProtocolIdByteCount)\
|
|
+ sizeof(((t)x)->AddressByteCount))
|
|
|
|
/*
|
|
End of Tower Stuff!
|
|
*/
|
|
|
|
#pragma pack()
|
|
|
|
// We need space for the computer name so that we can use local pipes rather
|
|
// than remote pipes when connecting with ourselves.
|
|
|
|
RPC_STATUS
|
|
ParseSecurity (
|
|
IN RPC_CHAR * NetworkOptions,
|
|
OUT PDWORD SecurityQualityOfService
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse a string of security options and build into the binary format
|
|
required by the operating system. The network options must follow
|
|
the following syntax. Case is not sensitive.
|
|
|
|
security=
|
|
[anonymous|identification|impersonation|delegation]
|
|
[dynamic|static]
|
|
[true|false]
|
|
|
|
All three fields must be present. To specify impersonation
|
|
with dynamic tracking and effective only, use the following
|
|
string for the network options.
|
|
|
|
"security=impersonation dynamic true"
|
|
|
|
Arguments:
|
|
|
|
NetworkOptions - Supplies the string containing the network options
|
|
to be parsed.
|
|
|
|
SecurityQualityOfService - Returns the binary format of the network
|
|
options.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Network Options parsed successfully.
|
|
|
|
FALSE - Parse failed.
|
|
|
|
--*/
|
|
{
|
|
DWORD Qos;
|
|
|
|
ASSERT( NetworkOptions[0] != 0 );
|
|
|
|
// We need to parse the security information from the network
|
|
// options, and then stuff it into the object attributes. To
|
|
// begin with, we check for "security=" at the beginning of
|
|
// the network options.
|
|
|
|
if (RpcpStringNCompare(NetworkOptions, "security=", sizeof("security=") - 1) != 0 )
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
Qos = SECURITY_SQOS_PRESENT;
|
|
|
|
NetworkOptions += sizeof("security=") - 1;
|
|
|
|
// Ok, now we need to determine if the next field is one of
|
|
// Anonymous, Identification, Impersonation, or Delegation.
|
|
|
|
if (RpcpStringNCompare(NetworkOptions, "anonymous", sizeof("anonymous") - 1) == 0 )
|
|
{
|
|
Qos |= SECURITY_ANONYMOUS;
|
|
NetworkOptions += sizeof("anonymous") - 1;
|
|
}
|
|
else if (RpcpStringNCompare(NetworkOptions, "identification", sizeof("identification") - 1) == 0 )
|
|
{
|
|
Qos |= SECURITY_IDENTIFICATION;
|
|
NetworkOptions += sizeof("identification") - 1;
|
|
}
|
|
else if (RpcpStringNCompare(NetworkOptions, "impersonation", sizeof("impersonation") - 1) == 0 )
|
|
{
|
|
Qos |= SECURITY_IMPERSONATION;
|
|
NetworkOptions += sizeof("impersonation") - 1;
|
|
}
|
|
else if (RpcpStringNCompare(NetworkOptions, "delegation", sizeof("delegation") - 1) == 0 )
|
|
{
|
|
Qos |= SECURITY_DELEGATION;
|
|
NetworkOptions += sizeof("delegation") - 1;
|
|
}
|
|
else
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
if ( *NetworkOptions != RPC_CONST_CHAR(' ') )
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
NetworkOptions++;
|
|
|
|
// Next comes the context tracking field; it must be one of
|
|
// dynamic or static.
|
|
|
|
if (RpcpStringNCompare(NetworkOptions, "dynamic", sizeof("dynamic") - 1) == 0 )
|
|
{
|
|
Qos |= SECURITY_CONTEXT_TRACKING;
|
|
NetworkOptions += sizeof("dynamic") - 1;
|
|
}
|
|
else if (RpcpStringNCompare(NetworkOptions, "static", sizeof("static") - 1) == 0 )
|
|
{
|
|
NetworkOptions += sizeof("static") - 1;
|
|
}
|
|
else
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
if ( *NetworkOptions != RPC_CONST_CHAR(' ') )
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
NetworkOptions++;
|
|
|
|
// Finally, comes the effective only flag. This must be one of
|
|
// true or false.
|
|
|
|
if (RpcpStringNCompare(NetworkOptions, "true", sizeof("true") - 1) == 0 )
|
|
{
|
|
Qos |= SECURITY_EFFECTIVE_ONLY;
|
|
NetworkOptions += sizeof("true") - 1;
|
|
}
|
|
else if (RpcpStringNCompare(NetworkOptions, "false", sizeof("false") - 1) == 0 )
|
|
{
|
|
NetworkOptions += sizeof("false") - 1;
|
|
}
|
|
else
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
if ( *NetworkOptions != 0 )
|
|
{
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
|
|
*SecurityQualityOfService = Qos;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientOpen (
|
|
IN PNP_CCONNECTION CConnection,
|
|
IN RPC_CHAR * NetworkAddress,
|
|
IN RPC_CHAR * Endpoint,
|
|
IN RPC_CHAR * NetworkOptions,
|
|
IN RPC_CHAR * Reserved1,
|
|
IN RPC_CHAR * RpcProtocolSequence,
|
|
IN unsigned int Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to open a client connection here. A return value of zero or one
|
|
indicates that the connection was successfully completed. In addition,
|
|
a return value of one indicates that the transport does security, so
|
|
the RPC protocol layer should not try and do security. A return value
|
|
of negative one indicates that the connection could not be completed,
|
|
but to go ahead and try again in a little while. Otherwise, any other
|
|
code will be returned from RpcBindToInterface, RpcGetBuffer, or
|
|
RpcSendReceive.
|
|
|
|
Arguments:
|
|
|
|
CConnection - Supplies the loadable transport interface named pipe
|
|
connection which we should try and open.
|
|
|
|
NetworkAddress - Supplies the network address. For named pipes,
|
|
the network address is the \\<server> part of the pipe name. For
|
|
local pipes, this will be the empty string.
|
|
|
|
Endpoint - Supplies the endpoint. A named pipe endpoint is the
|
|
\pipe\<pipename> part of the pipe name.
|
|
|
|
NetworkOptions - Supplies the network options to be used when we
|
|
attempt to open the named pipe instance. For named pipes, we
|
|
have one possible network option: security. The network options
|
|
must follow the following syntax. Case is not sensitive.
|
|
|
|
security=
|
|
[anonymous|identification|impersonation|delegation]
|
|
[dynamic|static]
|
|
[true|false]
|
|
|
|
All three fields must be present. To specify impersonation
|
|
with dynamic tracking and effective only, use the following
|
|
string for the network options.
|
|
|
|
"security=impersonation dynamic true"
|
|
|
|
TransportAddress - Supplies the network address and endpoint
|
|
concatenated together. We will use this rather than concatenating
|
|
the network address and endpoint ourselves.
|
|
|
|
RpcProtocolSequence - Unused.
|
|
|
|
Timeout - Unused.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully opened the connection as requested.
|
|
|
|
RPC_S_OUT_OF_MEMORY - We ran out of memory trying to open the
|
|
connection.
|
|
|
|
RPC_S_INVALID_NETWORK_OPTIONS - The supplied network options are
|
|
not in the format specified above.
|
|
|
|
RPC_S_SERVER_UNAVAILABLE - We are unable to make a connection to the
|
|
requested transport address, because it does not exist (as far
|
|
as we can determine).
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint specified is
|
|
syntactically invalid.
|
|
|
|
RPC_S_ACCESS_DENIED - The client is denied access to the server for
|
|
security reasons.
|
|
|
|
--*/
|
|
{
|
|
DWORD SecurityQualityOfService;
|
|
DWORD CreateStatus;
|
|
DWORD PipeMode;
|
|
RPC_CHAR * TransportAddress;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
UNUSED(RpcProtocolSequence);
|
|
UNUSED(Timeout);
|
|
|
|
// We need to check to see if the network options contain security
|
|
// information for us to use.
|
|
|
|
ASSERT(NetworkOptions != 0);
|
|
|
|
SecurityQualityOfService = 0;
|
|
|
|
if (NetworkOptions[0] != 0) {
|
|
if (ParseSecurity(NetworkOptions, &SecurityQualityOfService) != RPC_S_OK) {
|
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
}
|
|
}
|
|
|
|
if (NetworkAddress == NULL) {
|
|
return (RPC_S_INVALID_NET_ADDR);
|
|
}
|
|
|
|
if (NetworkAddress[0] == '\\') {
|
|
if (NetworkAddress[1] == '\\') {
|
|
if (NetworkAddress[2] != '\0' && NetworkAddress[2] != '\\') {
|
|
NetworkAddress += 2;
|
|
} else {
|
|
return (RPC_S_INVALID_NET_ADDR);
|
|
}
|
|
} else {
|
|
return (RPC_S_INVALID_NET_ADDR);
|
|
}
|
|
}
|
|
|
|
TransportAddress = (RPC_CHAR *) I_RpcAllocate(strlen(NetworkAddress) +
|
|
strlen(Endpoint) + 3);
|
|
|
|
if (TransportAddress == NULL) {
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
TransportAddress[0]='\\';
|
|
TransportAddress[1]='\\';
|
|
lstrcat(TransportAddress,NetworkAddress);
|
|
lstrcat(TransportAddress,Endpoint);
|
|
|
|
if (WaitNamedPipe(TransportAddress, NMPWAIT_USE_DEFAULT_WAIT) == FALSE) {
|
|
I_RpcFree(TransportAddress);
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
CConnection->Pipe = CreateFile(
|
|
TransportAddress,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, // Security Attribuates (object)
|
|
OPEN_EXISTING, // fdwCreate
|
|
SecurityQualityOfService, // fdwAttrAndFlags
|
|
NULL // Template File Handle
|
|
);
|
|
|
|
I_RpcFree(TransportAddress);
|
|
|
|
CreateStatus = GetLastError();
|
|
|
|
if (CConnection->Pipe == INVALID_HANDLE_VALUE) {
|
|
|
|
switch (CreateStatus) {
|
|
case ERROR_LOGON_FAILURE:
|
|
case ERROR_ACCESS_DENIED:
|
|
case ERROR_BAD_IMPERSONATION_LEVEL:
|
|
return (RPC_S_ACCESS_DENIED);
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
default:
|
|
return(RPC_S_SERVER_TOO_BUSY);
|
|
}
|
|
}
|
|
|
|
PipeMode = PIPE_READMODE_MESSAGE;
|
|
|
|
if (SetNamedPipeHandleState(CConnection->Pipe, &PipeMode, NULL, NULL) == FALSE) {
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientClose (
|
|
IN PNP_CCONNECTION CConnection
|
|
)
|
|
{
|
|
BOOL CloseStatus;
|
|
|
|
CloseStatus = CloseHandle(CConnection->Pipe);
|
|
|
|
ASSERT(CloseStatus);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientSend (
|
|
IN PNP_CCONNECTION CConnection,
|
|
IN void * Buffer,
|
|
IN unsigned int BufferLength
|
|
)
|
|
{
|
|
DWORD ActuallyWritten;
|
|
|
|
if (WriteFile(CConnection->Pipe, Buffer, BufferLength, &ActuallyWritten, NULL) == FALSE) {
|
|
ClientClose(CConnection);
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
static RPC_STATUS
|
|
ReadRestOfMessage (
|
|
IN PNP_CCONNECTION CConnection,
|
|
IN DWORD FirstLength,
|
|
IN OUT void * * Buffer,
|
|
IN OUT unsigned int * BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We will read the rest of the packet in this routine. First we look at
|
|
the beginning of the packet to figure out how much data there is to come,
|
|
we allocate a larger buffer, and then we read the rest of the message.
|
|
|
|
Arguments:
|
|
|
|
CConnection - Supplies the connection from which we want to receive
|
|
the rest of the packet.
|
|
|
|
FirstLength - How much data was receive during the first ReadFile().
|
|
|
|
Buffer - Supplies the part of the packet read, and returns the completed
|
|
packet.
|
|
|
|
BufferLength - Supplies the length of the original buffer, and returns
|
|
the length of the new buffer.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully received the rest of the packet.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to grow the
|
|
buffer.
|
|
|
|
RPC_P_RECEIVE_FAILED - The receive operation failed and the connection
|
|
was closed.
|
|
|
|
--*/
|
|
{
|
|
unsigned int TotalLength;
|
|
DWORD ActuallyRead;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
// Ok, now we need to look at the beginning of the packet to figure
|
|
// out how much more data we have yet to receive.
|
|
|
|
if ( DataConvertEndian(((rpcconn_common *) (*Buffer))->drep) != 0 )
|
|
{
|
|
TotalLength = ((rpcconn_common *) (*Buffer))->frag_length;
|
|
ByteSwapShort(TotalLength);
|
|
}
|
|
else
|
|
{
|
|
TotalLength = ((rpcconn_common*) (*Buffer))->frag_length;
|
|
}
|
|
|
|
// We got the amount of data available in the message from the
|
|
// header of the packet, so now we allocate a new buffer.
|
|
|
|
RpcStatus = I_RpcTransClientReallocBuffer(CConnection, Buffer,
|
|
*BufferLength, TotalLength);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
|
|
return(RpcStatus);
|
|
}
|
|
|
|
// As before, we read from the pipe, but this time, we read
|
|
// at an offset into the buffer so that the entire message
|
|
// will be contigous in memory.
|
|
|
|
if (ReadFile(CConnection->Pipe, ((unsigned char *)*Buffer) + FirstLength,
|
|
TotalLength - FirstLength, &ActuallyRead, NULL) == FALSE || ActuallyRead == 0) {
|
|
ClientClose(CConnection);
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
*BufferLength = ActuallyRead + FirstLength;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientReceive (
|
|
IN PNP_CCONNECTION CConnection,
|
|
IN OUT void * * Buffer,
|
|
IN OUT unsigned int * BufferLength
|
|
)
|
|
// Read a message from a connection. We are given a buffer that is a
|
|
// good guess (we hope) for the correct size, but it may be smaller than
|
|
// the whole message. We go ahead and try and read the message using
|
|
// the buffer which the runtime already allocated for us. If it is
|
|
// too small, we call a helper routine which peeks to see how much bigger
|
|
// the buffer needs to be, then allocates that size buffer, and reads the
|
|
// rest of the message.
|
|
{
|
|
DWORD ActuallyRead;
|
|
BOOL ReadStatus;
|
|
|
|
ReadStatus = ReadFile(CConnection->Pipe, *Buffer, *BufferLength, &ActuallyRead, NULL);
|
|
|
|
if (ReadStatus == FALSE) {
|
|
if (GetLastError() == ERROR_MORE_DATA) {
|
|
return(ReadRestOfMessage(CConnection, ActuallyRead, Buffer, BufferLength));
|
|
}
|
|
}
|
|
|
|
*BufferLength = ActuallyRead;
|
|
|
|
// If there was no data actually read from the pipe, that indicates
|
|
// that the pipe has closed.
|
|
|
|
if (ActuallyRead == 0 || ReadStatus == FALSE) {
|
|
ClientClose(CConnection);
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientSendReceive (
|
|
IN PNP_CCONNECTION CConnection,
|
|
IN void * SendBuffer,
|
|
IN unsigned int SendBufferLength,
|
|
IN OUT void * * ReceiveBuffer,
|
|
IN OUT unsigned int * ReceiveBufferLength
|
|
)
|
|
{
|
|
DWORD ActuallyRead;
|
|
BOOL TransactStatus;
|
|
DWORD TransactFailureReason;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
// The transceive (write followed by a read) is performed using a
|
|
// file system fsctl.
|
|
|
|
TransactStatus = TransactNamedPipe(CConnection->Pipe,
|
|
SendBuffer, SendBufferLength,
|
|
*ReceiveBuffer, *ReceiveBufferLength,
|
|
&ActuallyRead, NULL);
|
|
|
|
if (TransactStatus == FALSE) {
|
|
TransactFailureReason = GetLastError();
|
|
if (TransactFailureReason == ERROR_MORE_DATA) {
|
|
return(ReadRestOfMessage(CConnection, ActuallyRead, ReceiveBuffer,
|
|
ReceiveBufferLength));
|
|
}
|
|
}
|
|
|
|
// The amount of data actually read from the pipe is specified in
|
|
// the io status block.
|
|
|
|
*ReceiveBufferLength = ActuallyRead;
|
|
|
|
// If there was no data actually read from the pipe, that indicates
|
|
// that the pipe has closed.
|
|
|
|
if (ActuallyRead == 0 || TransactStatus == FALSE) {
|
|
ClientClose(CConnection);
|
|
if (TransactFailureReason == ERROR_VC_DISCONNECTED ||
|
|
// TransactFailureReason == ERROR_BROKEN_PIPE ||
|
|
TransactFailureReason == ERROR_BAD_PIPE)
|
|
{
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
#pragma pack(1)
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientTowerConstruct(
|
|
IN char * Endpoint,
|
|
IN char * NetworkAddress,
|
|
OUT UNALIGNED unsigned short * Floors,
|
|
OUT UNALIGNED unsigned long * ByteCount,
|
|
OUT unsigned char * UNALIGNED * Tower,
|
|
IN char * Protseq
|
|
)
|
|
{
|
|
|
|
unsigned long TowerSize;
|
|
UNALIGNED PFLOOR_234 Floor;
|
|
|
|
UNUSED(Protseq);
|
|
|
|
*Floors = NP_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 *)I_RpcAllocate(*ByteCount = TowerSize))
|
|
== NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Floor = (PFLOOR_234) *Tower;
|
|
|
|
Floor->ProtocolIdByteCount = 1;
|
|
Floor->FloorId = (unsigned char)(NP_TRANSPORTID & 0xFF);
|
|
if ((Endpoint) && (*Endpoint))
|
|
{
|
|
memcpy((char *)&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)(NP_TRANSPORTHOSTID & 0x0F);
|
|
if ((NetworkAddress) && (*NetworkAddress))
|
|
{
|
|
memcpy((char *)&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
|
|
ClientTowerExplode(
|
|
IN unsigned char * Tower,
|
|
OUT char * UNALIGNED * Protseq,
|
|
OUT char * UNALIGNED * Endpoint,
|
|
OUT char * UNALIGNED * NetworkAddress
|
|
)
|
|
{
|
|
UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
|
|
if (Protseq != NULL)
|
|
{
|
|
*Protseq = I_RpcAllocate(strlen("ncacn_np") + 1);
|
|
if (*Protseq == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(*Protseq, "ncacn_np", strlen("ncacn_np") + 1);
|
|
}
|
|
}
|
|
|
|
if ((Endpoint == NULL) || (Status != RPC_S_OK))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
*Endpoint = I_RpcAllocate(Floor->AddressByteCount);
|
|
if (*Endpoint == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
if (Protseq != NULL)
|
|
I_RpcFree(*Protseq);
|
|
}
|
|
else
|
|
{
|
|
memcpy(*Endpoint, (char *)&Floor->Data[0], Floor->AddressByteCount);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
#pragma pack()
|
|
|
|
// The following structure describes all of the characteristics (at least
|
|
// the ones that the runtime cares about) of this transport module. A
|
|
// pointer to this data structure will be returned by TransportLoad.
|
|
|
|
static RPC_CLIENT_TRANSPORT_INFO TransportInfo =
|
|
{
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
NP_TRANSPORTID,
|
|
|
|
ClientTowerConstruct,
|
|
ClientTowerExplode,
|
|
|
|
NP_MAXIMUM_SEND,
|
|
sizeof(NP_CCONNECTION),
|
|
|
|
ClientOpen,
|
|
ClientClose,
|
|
ClientSend,
|
|
ClientReceive,
|
|
ClientSendReceive,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO *
|
|
TransportLoad (
|
|
IN RPC_CHAR * RpcProtocolSequence
|
|
)
|
|
{
|
|
UNUSED(RpcProtocolSequence);
|
|
|
|
return(&TransportInfo);
|
|
}
|
|
|
|
|