Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

948 lines
27 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"
#ifdef WIN32RPC
#include <windows.h>
#endif // WIN32RPC
#include "rpc.h"
#include "rpcdcep.h"
#include "rpctran.h"
#include "rpcerrp.h"
#include "rpcqos.h"
#include "osfpcket.hxx"
// 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, PAPI * PFLOOR_234;
#define NEXTFLOOR(t,x) (t)((unsigned char PAPI *)x +((t)x)->ProtocolIdByteCount\
+ ((t)x)->AddressByteCount\
+ sizeof(((t)x)->ProtocolIdByteCount)\
+ sizeof(((t)x)->AddressByteCount))
/*
End of Tower Stuff!
*/
#pragma pack()
#define WAITDELAY 1000L
void
WaitForPipe (
IN RPC_CHAR * TransportAddress
)
// Wait for a pipe instance to be available for the pipe specified by
// transport info.
{
WaitNamedPipeW(TransportAddress, WAITDELAY);
}
// We need space for the computer name so that we can use local pipes rather
// than remote pipes when connecting with ourselves.
RPC_CHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 3] = { 0 };
int ComputerNameObtained = 0;
RPC_STATUS RPC_ENTRY
ClientOpen (
IN PNP_CCONNECTION CConnection,
IN RPC_CHAR * NetworkAddress,
IN RPC_CHAR * Endpoint,
IN RPC_CHAR * NetworkOptions,
IN RPC_CHAR * TransportAddress,
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.
--*/
{
volatile unsigned long TickCount ;
UNICODE_STRING unicodestring;
OBJECT_ATTRIBUTES objectattributes;
IO_STATUS_BLOCK iostatus;
NTSTATUS status, closestatus;
FILE_PIPE_INFORMATION pipeinformation;
int retrycount;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
BOOLEAN SecuritySpecified = FALSE;
RPC_STATUS RpcStatus;
unsigned HostLength;
unsigned EndpointLength;
unsigned FullLength;
#ifdef WIN32RPC
BOOLEAN BooleanStatus;
DWORD ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
unsigned int NetworkAddressIsMeFlag = 0;
#endif // WIN32RPC
#ifndef WIN32RPC
UNUSED(NetworkAddress);
UNUSED(Endpoint);
#endif
UNUSED(RpcProtocolSequence);
UNUSED(Timeout);
// We need to check to see if the network options contain security
// information for us to use.
ASSERT(NetworkOptions != 0);
if (NetworkOptions[0] != 0)
{
RpcStatus = I_RpcParseSecurity(NetworkOptions,
&SecurityQualityOfService);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_INVALID_NETWORK_OPTIONS );
return(RpcStatus);
}
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecuritySpecified = TRUE;
}
//
// Verify NetworkAddress is of the form "", "host", or "\\host".
// If "\\host", skip over the backslashes.
//
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;
}
}
#ifdef WIN32RPC
// If the network address is actually this machine, we want to use a
// local pipe rather than a remote pipe.
ASSERT(NetworkAddress != 0);
RtlAcquirePebLock();
if ( ComputerNameObtained == 0 )
{
BooleanStatus = GetComputerNameW(ComputerName, &ComputerNameLength);
if (BooleanStatus == TRUE)
{
ComputerNameObtained = 1;
}
#if DBG
else
{
DbgPrint("RPCLTC1 GetComputerName returned %lx\n", GetLastError());
}
#endif // DBG
}
RtlReleasePebLock();
if (NetworkAddress[0] == '\0')
{
NetworkAddressIsMeFlag = 1;
}
else if ( (ComputerNameObtained == 1)
&& (_wcsicmp(NetworkAddress, ComputerName) == 0) )
{
NetworkAddressIsMeFlag = 1;
}
if (NetworkAddressIsMeFlag)
{
static RPC_CHAR DotString[2] = { '.', '\0' };
NetworkAddress = DotString;
}
//
// Create the actual transport address: "\\" + NetAddress + Endpoint + '\0'
//
HostLength = lstrlenW(NetworkAddress);
EndpointLength = lstrlenW(Endpoint);
FullLength = 2 + HostLength + EndpointLength + 1;
TransportAddress = (RPC_CHAR *) I_RpcAllocate(FullLength * sizeof(RPC_CHAR));
if (TransportAddress == 0)
return(RPC_S_OUT_OF_MEMORY);
TransportAddress[0] = '\\';
TransportAddress[1] = '\\';
memcpy(TransportAddress + 2,
NetworkAddress,
HostLength * sizeof(RPC_CHAR)
);
memcpy(TransportAddress + 2 + HostLength,
Endpoint,
(EndpointLength + 1) * sizeof(RPC_CHAR)
);
// The Win32 APIs, CreateFileW and OpenFileW do not allow us to set
// the security quality of service field of the object attributes, so
// we will do all of the stuff that CreateFileW does, and call
// NtOpenFile ourselves.
BooleanStatus = RtlDosPathNameToNtPathName_U(TransportAddress,
&unicodestring, 0, 0);
if ( !BooleanStatus )
{
I_RpcFree(TransportAddress);
return(RPC_S_INVALID_ENDPOINT_FORMAT);
}
#else // WIN32RPC
//
// Create the actual transport address: "\\" + NetAddress + Endpoint + '\0'
//
unsigned HostLength = lstrlenW(NetworkAddress);
unsigned EndpointLength = lstrlenW(Endpoint);
unsigned FullLength = 2 + HostLength + EndpointLength + 1;
TransportAddress = (RPC_CHAR *) I_RpcAllocate(FullLength * sizeof(RPC_CHAR));
if (TransportAddress == 0)
return(RPC_S_OUT_OF_MEMORY);
TransportAddress[0] = '\\';
TransportAddress[1] = '\\';
memcpy(TransportAddress+2*sizeof(RPC_CHAR),
NetworkAddress,
HostLength * sizeof(RPC_CHAR)
);
memcpy(TransportAddress + 2*sizeof(RPC_CHAR) + HostLength*sizeof(RPC_CHAR),
Endpoint,
EndpointLength + 1
);
// We need to initialize the unicode string, and then initialize the
// object attributes.
RtlInitUnicodeString(&unicodestring,TransportAddress);
#endif // WIN32RPC
InitializeObjectAttributes(&objectattributes,&unicodestring,
OBJ_CASE_INSENSITIVE,0,0);
if (SecuritySpecified != FALSE)
objectattributes.SecurityQualityOfService = &SecurityQualityOfService;
// Open the named pipe instance. We want to retry the operation,
// after waiting for a named pipe instance to be in the listening
// state, hence, we need to loop. The choice of retrying three
// times is fairly arbitrary.
for (retrycount = 20; retrycount != 0; retrycount--)
{
TickCount = GetTickCount() ;
status = NtOpenFile(&CConnection->Pipe,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&objectattributes,&iostatus,
// FILE_SHARE_READ | FILE_SHARE_WRITE,0);
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
ASSERT( status != STATUS_PENDING );
// If no error occured, then go ahead and finish opening the named
// pipe.
if (NT_SUCCESS(status))
{
// The named pipe instance we just opened is in byte mode; we
// need it to be in message mode and queued operation. Queued
// operation means that when an io operation is requested, it
// is queued up and the thread returns from the API (with
// STATUS_PENDING). To wait for the io operation to complete,
// NtWaitForSingleObject must be used to wait on the pipe handle.
pipeinformation.ReadMode = FILE_PIPE_MESSAGE_MODE;
pipeinformation.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
// Set this information for the pipe instance
// (NtSetInformationFile is used, because NT treats named
// pipes as just another file system). Also deal with the
// fact that we may need to wait for the operation to complete.
status = NtSetInformationFile(CConnection->Pipe,&iostatus,
&pipeinformation,sizeof(FILE_PIPE_INFORMATION),
FilePipeInformation);
ASSERT( status != STATUS_PENDING );
#ifdef WIN32RPC
RtlFreeHeap(RtlProcessHeap(), 0, unicodestring.Buffer);
#endif // WIN32RPC
I_RpcFree(TransportAddress);
// Something went wrong; before returning an error code to the
// caller, we need to close the named pipe instance just in case
// it is still open.
if (!NT_SUCCESS(status))
{
// Ignore any errors from NtClose, because we are trying to
// recover from an error.
closestatus = NtClose(CConnection->Pipe);
#if DBG
if ( !NT_SUCCESS(closestatus) )
{
DbgPrint("NtClose : %lx\n", closestatus);
}
#endif // DBG
ASSERT(NT_SUCCESS(closestatus));
if ( status == STATUS_ACCESS_DENIED )
{
return(RPC_S_ACCESS_DENIED);
}
if ( status == STATUS_BAD_IMPERSONATION_LEVEL )
{
return(RPC_S_ACCESS_DENIED);
}
return(RPC_S_SERVER_UNAVAILABLE);
}
return(RPC_S_OK);
}
// If an error occured in the open operation, other than that no
// pipe instance is available in the listening state, reflect it
// back to the caller.
if (status != STATUS_PIPE_NOT_AVAILABLE)
{
#ifdef WIN32RPC
RtlFreeHeap(RtlProcessHeap(), 0, unicodestring.Buffer);
#endif // WIN32RPC
I_RpcFree(TransportAddress);
if (status == STATUS_OBJECT_NAME_INVALID)
return(RPC_S_INVALID_ENDPOINT_FORMAT);
if (status == STATUS_NO_MEMORY)
return(RPC_S_OUT_OF_MEMORY);
if ( ( status == STATUS_ACCESS_DENIED )
|| ( status == STATUS_LOGON_FAILURE )
|| ( status == STATUS_LOGON_TYPE_NOT_GRANTED )
|| ( status == STATUS_PASSWORD_EXPIRED )
|| ( status == STATUS_PASSWORD_MUST_CHANGE )
|| ( status == STATUS_BAD_IMPERSONATION_LEVEL ) )
{
return(RPC_S_ACCESS_DENIED);
}
return(RPC_S_SERVER_UNAVAILABLE);
}
// If we reach here, we want to wait for a named pipe instance to
// become available in the listening state.
WaitForPipe(TransportAddress);
}
#ifdef WIN32RPC
RtlFreeHeap(RtlProcessHeap(), 0, unicodestring.Buffer);
#endif // WIN32RPC
I_RpcFree(TransportAddress);
// We fall through to here if we retry opening the pipe too many
// times and fail.
return(RPC_S_SERVER_TOO_BUSY);
}
RPC_STATUS RPC_ENTRY
ClientClose (
IN PNP_CCONNECTION CConnection
)
// Close the client connection.
{
NTSTATUS status;
status = NtClose(CConnection->Pipe);
#if DBG
if ( !NT_SUCCESS(status) )
{
DbgPrint("NtClose : %lx\n", status);
}
#endif // DBG
ASSERT(NT_SUCCESS(status));
// We need to return something, though whoever calls this routine does
// not check the return value.
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientSend (
IN PNP_CCONNECTION CConnection,
IN void PAPI * Buffer,
IN unsigned int BufferLength
)
// Write a message to a connection.
{
NTSTATUS status;
RPC_STATUS RpcStatus;
IO_STATUS_BLOCK iostatus;
// We use NtWriteFile to actually do the write, and then wait if
// necessary for the io operation to complete.
status = NtWriteFile(CConnection->Pipe,0,0,0,&iostatus,
Buffer, BufferLength,0,0);
ASSERT( status != STATUS_PENDING );
if ( !NT_SUCCESS(status) )
{
RpcStatus = ClientClose(CConnection);
ASSERT( RpcStatus == RPC_S_OK );
return(RPC_P_SEND_FAILED);
}
return(RPC_S_OK);
}
static RPC_STATUS
ReadRestOfMessage (
IN PNP_CCONNECTION CConnection,
IN PIO_STATUS_BLOCK IoStatus,
IN OUT void PAPI * PAPI * Buffer,
IN OUT unsigned int PAPI * 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.
IoStatus - Supplies an io status buffer containing information about
the receive of the first part of the packet.
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 FirstLength, TotalLength;
NTSTATUS NtStatus;
RPC_STATUS RpcStatus;
// We need to remember the length of the first part of the message
// which we have already read.
FirstLength = (unsigned int) IoStatus->Information;
// 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.
NtStatus = NtReadFile(CConnection->Pipe, 0, 0, 0, IoStatus,
((unsigned char *) *Buffer) + FirstLength,
TotalLength - FirstLength, 0, 0);
ASSERT( NtStatus != STATUS_PENDING );
// The amount of data actually read from the pipe is specified in
// the io status block. The length is include to account for the
// amount we read with the first read on the pipe.
*BufferLength = (unsigned int) IoStatus->Information + FirstLength;
// If there was no data actually read from the pipe, that indicates
// that the pipe has closed.
if ( ( IoStatus->Information == 0 )
|| ( !NT_SUCCESS(NtStatus) ) )
{
RpcStatus = ClientClose(CConnection);
ASSERT( RpcStatus == RPC_S_OK );
return(RPC_P_RECEIVE_FAILED);
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientReceive (
IN PNP_CCONNECTION CConnection,
IN OUT void PAPI * PAPI * Buffer,
IN OUT unsigned int PAPI * 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.
{
NTSTATUS status;
RPC_STATUS RpcStatus;
IO_STATUS_BLOCK iostatus;
// Go ahead and read from the pipe.
status = NtReadFile(CConnection->Pipe, 0, 0, 0, &iostatus,
*Buffer, *BufferLength, 0, 0);
ASSERT( status != STATUS_PENDING );
// Not all of the message would fit into the buffer we specified, so
// we need to get a larger buffer and read the rest of the message
// into it.
if (status == STATUS_BUFFER_OVERFLOW)
{
// This helper routine will take care of peeking the pipe, growing
// the buffer, and then reading the rest of the message into the
// buffer.
return(ReadRestOfMessage(CConnection, &iostatus, Buffer, BufferLength));
}
// The amount of data actually read from the pipe is specified in
// the io status block.
*BufferLength = (unsigned int) iostatus.Information;
// If there was no data actually read from the pipe, that indicates
// that the pipe has closed.
if ( (iostatus.Information == 0)
|| (!NT_SUCCESS(status)))
{
RpcStatus = ClientClose(CConnection);
ASSERT( RpcStatus == RPC_S_OK );
return(RPC_P_RECEIVE_FAILED);
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientSendReceive (
IN PNP_CCONNECTION CConnection,
IN void PAPI * SendBuffer,
IN unsigned int SendBufferLength,
IN OUT void PAPI * PAPI * ReceiveBuffer,
IN OUT unsigned int PAPI * ReceiveBufferLength
)
// Write and then read a message from the connection. This is done using
// the pipe transceive fsctl. Like with cRead, we need to deal with things
// when only part of the message will fit into the buffer which the runtime
// allocated for us. We call a helper routine to take care of peeking the
// pipe, allocating a larger buffer, and then reading the rest of the
// message.
{
NTSTATUS status;
RPC_STATUS RpcStatus;
IO_STATUS_BLOCK iostatus;
// The transceive (write followed by a read) is performed using a
// file system fsctl.
status = NtFsControlFile(CConnection->Pipe,0,0,0,&iostatus,
FSCTL_PIPE_TRANSCEIVE,SendBuffer,SendBufferLength,
*ReceiveBuffer, *ReceiveBufferLength);
ASSERT( status != STATUS_PENDING );
// Not all of the message would fit into the buffer we specified, so
// we need to get a larger buffer and read the rest of the message
// into it.
if (status == STATUS_BUFFER_OVERFLOW)
{
// This helper routine will take care of peeking the pipe, growing
// the buffer, and then reading the rest of the message into the
// buffer.
return(ReadRestOfMessage(CConnection, &iostatus, ReceiveBuffer,
ReceiveBufferLength));
}
// The amount of data actually read from the pipe is specified in
// the io status block.
*ReceiveBufferLength = (unsigned int) iostatus.Information;
// If there was no data actually read from the pipe, that indicates
// that the pipe has closed.
if ( (iostatus.Information == 0)
|| (!NT_SUCCESS(status)))
{
RpcStatus = ClientClose(CConnection);
ASSERT( RpcStatus == RPC_S_OK );
if ( ( status == STATUS_PIPE_DISCONNECTED )
|| ( status == STATUS_INVALID_PIPE_STATE ) )
{
return(RPC_P_SEND_FAILED);
}
return(RPC_P_RECEIVE_FAILED);
}
return(RPC_S_OK);
}
#pragma pack(1)
RPC_STATUS RPC_ENTRY
ClientTowerConstruct(
IN char PAPI * Endpoint,
IN char PAPI * NetworkAddress,
OUT UNALIGNED unsigned short PAPI * Floors,
OUT UNALIGNED unsigned long PAPI * ByteCount,
OUT unsigned char PAPI * UNALIGNED PAPI * Tower,
IN char PAPI * 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 PAPI*)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 PAPI *)&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 PAPI *)&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 PAPI * Tower,
OUT char PAPI * UNALIGNED PAPI * Protseq,
OUT char PAPI * UNALIGNED PAPI * Endpoint,
OUT char PAPI * UNALIGNED PAPI * 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 PAPI *)&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,
(TRANS_CLIENT_TOWERCONSTRUCT)ClientTowerConstruct,
(TRANS_CLIENT_TOWEREXPLODE)ClientTowerExplode,
NP_MAXIMUM_SEND,
sizeof(NP_CCONNECTION),
ClientOpen,
ClientClose,
ClientSend,
ClientReceive,
ClientSendReceive,
NULL,
NULL,
NULL
};
RPC_CLIENT_TRANSPORT_INFO *
TransportLoad (
IN RPC_CHAR * RpcProtocolSequence
)
// This routine will get called first thing after the runtime has loaded
// the DLL. We need to return a pointer to the RPC_CLIENT_INFO for this
// transport module if everything is ok, and (0) otherwise.
{
#if DBG
// DbgUserBreakPoint();
#endif
UNUSED(RpcProtocolSequence);
return(&TransportInfo);
}