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.
 
 
 
 
 
 

1206 lines
27 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
ipxclnt.c
Abstract:
This is the IPX datagram client dll.
Author:
18 Jan 94 AlexMit
--*/
#define ENABLE_SOCKET_HACK
#include "sysinc.h"
#include <stdlib.h>
#include "rpc.h"
#include "rpcdcep.h"
#include "rpctran.h"
#include "rpcerrp.h"
#include "novell.h"
#include "gethost.h"
#if defined(__RPC_WIN16__)
#include "callback.h"
#else
#include "dos.h"
#endif
/********************************************************************/
/* Defines. */
#ifdef DBG
#define OPTIONAL_STATIC
#else
#define OPTIONAL_STATIC static
#endif
#define MAX_ENDPOINTS 10
#define NUM_IPX_BUF 4
#define ENDIAN_MASK 16
//
// Sockets are up to five decimal digits plus a NULL.
//
#define MAX_ENDPOINT_SIZE (6)
//
// Length of a hex network address.
//
#define NETADDR_LEN 21
#define HOSTNAME_LEN 21
//
// Endpoint to which the endpoint mapper listens.
//
#define ENDPOINT_MAPPER_EP "34280"
#define PROTSEQ "ncadg_ipx"
#define NT_PACKET_SIZE 1024
#if defined(__RPC_WIN16__)
#define TASKID_C taskid,
#define TASKID taskid
#define HACK WORD
#else
#define TASKID_C
#define TASKID
#define HACK BYTE
#endif
#define GUARD 0xcbadbedc
unsigned Sequence = 0;
/********************************************************************/
/* Structures. */
typedef struct CONTROL_BLOCK
{
#ifdef WIN
struct DG_IPX_ENDPOINT __far * endpoint;
#endif
unsigned Sequence;
ECB ecb;
IPX_HEADER ipx;
} CONTROL_BLOCK;
typedef struct DG_IPX_ENDPOINT
{
struct DG_IPX_ENDPOINT * prev;
struct DG_IPX_ENDPOINT * next;
WORD socket;
CONTROL_BLOCK PAPI * buf;
#ifdef WIN
HANDLE YieldHandle;
#endif
} DG_IPX_ENDPOINT;
typedef DG_IPX_ENDPOINT * PDG_IPX_ENDPOINT;
typedef BYTE NODE_NUM[6];
typedef struct {
IPX_ADDRESS ipx;
NODE_NUM local_target;
BOOL got_target;
} DG_IPX_ADDRESS;
typedef DG_IPX_ADDRESS * PDG_IPX_ADDRESS;
typedef long GUARD_TYPE;
#pragma pack(1)
#define TRANSPORTID 0x0e
#define TRANSPORTHOSTID 0x0d
#define TOWERFLOORS 5
/*Endpoint = 2 bytes, HostId = 10 bytes*/
#define TOWEREPSIZE 10
#define TOWERSIZE (TOWEREPSIZE+2)
#define PROTSEQ "ncadg_ipx"
#define ENDPOINT_MAPPER_EP "34280"
typedef struct _FLOOR_234 {
unsigned short ProtocolIdByteCount;
unsigned char FloorId;
unsigned short AddressByteCount;
unsigned char Data[2];
} FLOOR_234;
typedef 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()
/********************************************************************/
/* Globals. */
/* The maximum buffer size to transmit and receive from IPX. */
int packet_size;
/* The number of pieces to break a RPC packet into before giving it
to IPX. */
int max_num_send;
// Number of endpoints in use.
int num_endpoints;
#if defined(__RPC_WIN16__)
// Global to be filled in with a termination cleanup routine.
extern void (_far pascal _far *DllTermination)(void);
#endif
// Clean up end points when the application exits.
DG_IPX_ENDPOINT ep_list;
int consecutive_timeout_count = 0;
/********************************************************************/
/* Prototypes. */
OPTIONAL_STATIC void my_itoa ( int, char * );
RPC_STATUS RPC_ENTRY FreeLocalEndpoint( IN void * Endpoint );
/********************************************************************/
// This routine converts a two byte integer to an ascii string.
OPTIONAL_STATIC void my_itoa( int i, char * s )
{
int j = 0;
int k;
int d = 10000;
// Is the number zero?
if (i == 0)
s[j++] = '0';
else
{
// If the number negative?
if (i < 0)
{
s[j++] = '-';
i = -i;
}
// Skip leading zeros.
while (i < d)
d = d / 10;
// Insert digits.
while (d > 0)
{
k = i / d;
s[j++] = k + '0';
i = i - k*d;
d = d / 10;
}
}
s[j] = '\0';
return;
}
/********************************************************************/
int __loadds
ClientCleanup(void)
// Destructor function.
{
// Free all endpoints.
while (ep_list.next != &ep_list)
FreeLocalEndpoint( ep_list.next );
return 0;
}
#define STRUCTURE_FROM_MEMBER(base, STRUC, MEMBER) (STRUC *) (((char *) base) - (unsigned) (&(((STRUC *) 0)->MEMBER)))
void __loadds
post_ecb();
#pragma alloc_text(RPC16DG6_FIXED, post_ecb)
void __loadds
post_ecb()
/*++
Routine Description:
Called with interrupts off when one of our receive ECBs gets a packet.
It calls I_RpcWinAsyncCallComplete.
Arguments:
ES:SI holds the address of the ECB that was triggered.
Return Value:
none
--*/
{
char __far * trigger_ecb;
CONTROL_BLOCK __far * Block;
__asm
{
mov word ptr trigger_ecb, si
mov word ptr trigger_ecb+2, es
}
Block = STRUCTURE_FROM_MEMBER(trigger_ecb, CONTROL_BLOCK, ecb);
Block->Sequence = Sequence++;
#ifdef WIN
I_RpcWinAsyncCallComplete(Block->endpoint);
#endif
}
RPC_STATUS RPC_ENTRY
BeginCall(
void __RPC_FAR * OpaqueEndpoint,
void __RPC_FAR * Connection
)
/*++
Description:
Signals the beginning of a new RPC to the transport.
The transport will allocate yielding information now.
Arguments:
Connection - the DG_CCALL making the call
Endpoint - the transport endpoint structure
Returns:
RPC_S_OK if successful
RPC_S_OUT_OF_MEMORY if no yield handle is available
--*/
{
unsigned i;
DG_IPX_ENDPOINT * Endpoint = (DG_IPX_ENDPOINT *) OpaqueEndpoint;
#ifdef WIN
Endpoint->YieldHandle = I_RpcWinAsyncCallBegin(Endpoint);
if (!Endpoint->YieldHandle)
{
return RPC_S_OUT_OF_MEMORY;
}
#endif
for (i=0; i < NUM_IPX_BUF; ++i)
{
IPXListenForPacket( TASKID_C &Endpoint->buf[i].ecb );
}
return RPC_S_OK;
}
void RPC_ENTRY
EndCall(
void __RPC_FAR * OpaqueEndpoint
)
/*++
Description:
Signals the end of the RPC to the transport.
The transport will free its yielding information.
Arguments:
Endpoint - the transport endpoint structure
Returns:
none
--*/
{
unsigned i;
DG_IPX_ENDPOINT * Endpoint = (DG_IPX_ENDPOINT *) OpaqueEndpoint;
for (i=0; i < NUM_IPX_BUF; ++i)
{
if (Endpoint->buf[i].ecb.inUseFlag)
{
IPXCancelEvent( TASKID_C &Endpoint->buf[i].ecb );
while (Endpoint->buf[i].ecb.inUseFlag)
IPXRelinquishControl();
}
}
#ifdef WIN
I_RpcWinAsyncCallEnd(Endpoint->YieldHandle);
#endif
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
AssignLocalEndpoint(
IN void * Endpoint
)
/*++
Routine Description:
Ask transport for a new endpoint.
Arguments:
Return Value:
RPC_S_OK
--*/
{
DG_IPX_ENDPOINT *my_endpoint = (DG_IPX_ENDPOINT *) Endpoint;
CONTROL_BLOCK PAPI * buf;
char PAPI * data;
int i;
num_endpoints += 1;
/* Create a socket. Let IPX pick a dynamic socket number. */
my_endpoint->socket = 0;
if (IPXOpenSocket( TASKID_C &my_endpoint->socket, 0 ) != 0)
return RPC_S_OUT_OF_RESOURCES;
/* Allocate some ECBs and data.
** The structure is an array of CONTROL_BLOCKs
** followed by an array of buffers.
*/
buf = (CONTROL_BLOCK PAPI *) I_RpcAllocate( NUM_IPX_BUF *
(sizeof(CONTROL_BLOCK) + packet_size + 2*sizeof(GUARD_TYPE)) );
if (!buf)
{
IPXCloseSocket( TASKID_C my_endpoint->socket );
return RPC_S_OUT_OF_MEMORY;
}
data = (char PAPI *) (buf + NUM_IPX_BUF);
my_endpoint->buf = buf;
my_endpoint->next = ep_list.next;
my_endpoint->prev = &ep_list;
ep_list.next->prev = my_endpoint;
ep_list.next = my_endpoint;
/* Initialize and post some ECBs for IPX to play with. */
for (i = 0; i < NUM_IPX_BUF; i++)
{
/* Zero the control block. */
_fmemset( buf, 0, sizeof(CONTROL_BLOCK) );
/* Initialize some fields. */
*((GUARD_TYPE PAPI *) data) = GUARD;
data += sizeof(GUARD_TYPE);
#ifdef WIN
buf->endpoint = my_endpoint;
#endif
buf->ecb.ESRAddress = post_ecb;
buf->ecb.socketNumber = my_endpoint->socket;
buf->ecb.fragmentCount = 2;
buf->ecb.fragmentDescriptor[0].size = sizeof( buf->ipx );
buf->ecb.fragmentDescriptor[0].address = &buf->ipx;
buf->ecb.fragmentDescriptor[1].size = packet_size;
buf->ecb.fragmentDescriptor[1].address = data;
_fmemset(buf->ecb.immediateAddress, 0xff, 6);
buf += 1;
data += packet_size;
*((GUARD_TYPE PAPI *) data) = GUARD;
data += sizeof(GUARD_TYPE);
}
return RPC_S_OK;
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
FreeLocalEndpoint(
IN void * Endpoint
)
/*++
Routine Description:
Frees an endpoint
Arguments:
Return Value:
RPC_S_OK
--*/
{
DG_IPX_ENDPOINT *my_endpoint = (DG_IPX_ENDPOINT *) Endpoint;
// Decrement endpoint count.
num_endpoints -= 1;
my_endpoint->next->prev = my_endpoint->prev;
my_endpoint->prev->next = my_endpoint->next;
//
// This will synchronously cancel any pending ECBs on the socket.
//
IPXCloseSocket( TASKID_C my_endpoint->socket );
I_RpcFree(my_endpoint->buf);
return RPC_S_OK;
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
RegisterServerAddress(
IN void * pClientCall,
IN RPC_CHAR * pServer,
IN RPC_CHAR * pEndpoint,
OUT void PAPI * PAPI * ppTransAddress
)
/*++
Routine Description:
Registers a new call with the transport. This informs the transport that
data is about to be sent and received on this address to and from
the server/endpoint. This routine returns a 'transport address' through
which the sending and receiving will be accomplished.
Arguments:
pClientCall - A pointer to the protocol's DG_CCALL object for this call.
This is not used.
pServer - Name of the server we are talking with.
pEndpoint - Endpoint on that server.
ppTransAddress - Where to place a pointer to a new transport address
which the protocol will use to identify the socket
we are using.
Return Value:
RPC_S_OK
RPC_S_OUT_OF_MEMORY
--*/
{
RPC_STATUS status;
int portnum;
DG_IPX_ADDRESS PAPI * address = (DG_IPX_ADDRESS PAPI *) *ppTransAddress ;
if (*ppTransAddress == NULL)
return RPC_S_OUT_OF_MEMORY;
// Convert the server name to an IPX Address.
status = IpxGetHostByName(pServer, &address->ipx, pEndpoint, RPC_C_BINDING_DEFAULT_TIMEOUT
#ifdef __RPC_WIN16__
, RpcRuntimeInfo
#endif
);
if (status != RPC_S_OK)
return status;
address->ipx.Socket = ByteSwapShort(atoi(pEndpoint));
address->got_target = FALSE;
return RPC_S_OK;
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
DeregisterServerAddress(
IN void * pTransAddress
)
/*++
Routine Description:
This routine cleans up resources allocated in RegisterServerAddress.
As a courtesy, notify IPX that the address will no longer be used.
Arguments:
pTransAddress - Address to deregister.
Return Value:
RPC_S_OK
--*/
{
IPXDisconnectFromTarget( TASKID_C (BYTE *) &((DG_IPX_ADDRESS *) pTransAddress)->ipx );
return RPC_S_OK;
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
SendToServer(
IN void * TransportEndpoint,
IN void * Buffer,
IN unsigned long BufferLength,
IN BOOL Broadcast,
IN void * TransportAddress
)
/*++
Routine Description:
Sends a packet on the network through the transport address associated
with the passed packet.
Arguments:
pPack - Packet to send.
Broadcast - Whether to broadcast or not.
Return Value:
RPC_S_OK
<return value from MapStatusCode>
--*/
{
DG_IPX_ADDRESS *address = (PDG_IPX_ADDRESS)TransportAddress;
int socket = ((PDG_IPX_ENDPOINT)TransportEndpoint)->socket;
CONTROL_BLOCK cb;
int i;
int trip_time;
// Initialize the IPX header.
cb.ipx.PacketType = 4;
RpcpMemoryCopy( (char *) &cb.ipx.Destination,
(char *) &address->ipx,
sizeof( cb.ipx.Destination ) );
if (Broadcast)
for (i = 0; i < 6; i++)
cb.ipx.Destination.Node[i] = 0xff;
// If the local target is not known, look it up.
if (!address->got_target)
{
if (IPXGetLocalTarget( TASKID_C
(BYTE far *) &cb.ipx.Destination,
(BYTE far *) &address->local_target,
&trip_time ) != 0)
{
return RPC_P_SEND_FAILED;
}
address->got_target = TRUE;
}
// Initialize the control block.
//
cb.ecb.socketNumber = socket;
cb.ecb.ESRAddress = NULL;
cb.ecb.fragmentCount = 2;
cb.ecb.fragmentDescriptor[0].size = sizeof( cb.ipx );
cb.ecb.fragmentDescriptor[0].address = &cb.ipx;
cb.ecb.fragmentDescriptor[1].size = (unsigned) BufferLength;
cb.ecb.fragmentDescriptor[1].address = Buffer;
RpcpMemoryCopy( (char *) cb.ecb.immediateAddress,
(char *) &address->local_target,
sizeof(NODE_NUM) );
IPXSendPacket( TASKID_C &cb.ecb );
// Wait for the send to complete.
while ( cb.ecb.inUseFlag )
{
IPXRelinquishControl();
}
if (cb.ecb.completionCode != 0)
{
return RPC_P_SEND_FAILED;
}
return RPC_S_OK;
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
ReceivePacket(
IN void * TransportEndpoint,
IN void * Buffer,
IN unsigned long * BufferLength,
IN unsigned long Timeout,
OUT void * SenderAddress
)
/*++
Routine Description:
Receives a packet from the network.
Arguments:
pPack - Packet to receive into.
Timeout - Timeout in seconds.
Return Value:
RPC_S_OK
RPC_P_TIMEOUT
<return from WaitForSingleObject or MapStatusCode>
--*/
{
DG_IPX_ADDRESS * address = (PDG_IPX_ADDRESS)SenderAddress;
DG_IPX_ENDPOINT * endpoint = (PDG_IPX_ENDPOINT)TransportEndpoint;
WORD start;
int i;
CONTROL_BLOCK PAPI * buf;
unsigned LowestSequence;
unsigned LowestIndex;
RPC_STATUS Status = RPC_S_OK;
#ifdef WIN
i = I_RpcWinAsyncCallWait(endpoint->YieldHandle, 0, Timeout*1000UL);
if (RPC_WIN_WAIT_ABORTED == i)
{
return RPC_P_RECEIVE_FAILED;
}
if (RPC_WIN_WAIT_TIMEOUT == i)
{
Status = RPC_P_TIMEOUT;
}
#else
//
// Wait for a packet to arrive.
//
{
BOOL fArrival = FALSE;
unsigned StartTime = IPXGetIntervalMarker();
// Convert the second count to 1/18 of a second clock ticks.
if (Timeout > 17292)
Timeout = 65536;
else
Timeout *= 18;
do
{
for (i = 0; i < NUM_IPX_BUF; i++)
{
if (0 == endpoint->buf[i].ecb.inUseFlag)
{
break;
}
}
IPXRelinquishControl();
}
while ( i == NUM_IPX_BUF && IPXGetIntervalMarker() - StartTime < Timeout );
if (NUM_IPX_BUF == i)
{
Status = RPC_P_TIMEOUT;
}
}
#endif
if (RPC_P_TIMEOUT == Status)
{
//
// BUGBUG: if IPX isn't receiving, try canceling and relistening all ECBs.
//
if (++consecutive_timeout_count >= 3)
{
consecutive_timeout_count = 0;
#if defined(__RPC_WIN16__) && defined(DEBUGRPC)
OutputDebugString("IPX socket hack was used\n");
#endif
IPXCloseSocket(TASKID_C endpoint->socket);
if (0 != IPXOpenSocket( TASKID_C &endpoint->socket, 0))
{
#if defined(__RPC_WIN16__) && defined(DEBUGRPC)
OutputDebugString("IPX socket hack: can't reopen socket\n");
_asm int 3
#endif
}
for (i = 0; i < NUM_IPX_BUF; i++)
{
IPXListenForPacket( TASKID_C &endpoint->buf[i].ecb );
}
}
return RPC_P_TIMEOUT;
}
//
// Search for a packet to return. post_ecb() numbers packets in order of
// delivery, and we should return the first one.
//
LowestSequence = 0xffff;
LowestIndex = NUM_IPX_BUF;
for (i = 0; i < NUM_IPX_BUF; i++)
{
if (0 == endpoint->buf[i].ecb.inUseFlag)
{
if (endpoint->buf[i].Sequence <= LowestSequence)
{
LowestSequence = endpoint->buf[i].Sequence;
LowestIndex = i;
}
}
}
#if defined(DEBUGRPC)
if (LowestIndex >= NUM_IPX_BUF)
{
_asm int 3
}
#endif
if (LowestIndex < NUM_IPX_BUF)
{
consecutive_timeout_count = 0;
buf = endpoint->buf + LowestIndex;
#if defined(DEBUGRPC)
{
GUARD_TYPE PAPI * g = (GUARD_TYPE PAPI *) buf->ecb.fragmentDescriptor[1].address;
if (*(g-1) != GUARD ||
*((GUARD_TYPE *) (((char *) g) + packet_size)) != GUARD)
__asm int 3;
}
#endif
if (buf->ecb.completionCode == 0x00)
{
// Copy the data to the buffer.
//
buf->ipx.Length = ByteSwapShort( buf->ipx.Length );
#ifdef DEBUGRPC
if (buf->ipx.Length < sizeof(IPX_HEADER))
__asm int 3;
#endif
*BufferLength = buf->ipx.Length - sizeof(IPX_HEADER);
RpcpMemoryCopy( (char PAPI *) Buffer,
(char PAPI *) buf->ecb.fragmentDescriptor[1].address,
(unsigned) *BufferLength
);
// Set up the sender's address.
//
RpcpMemoryCopy( (char PAPI *) &address->ipx,
(char PAPI *) &buf->ipx.Source,
sizeof(IPX_ADDRESS) );
RpcpMemoryCopy( (char PAPI *) &address->local_target,
(char PAPI *) buf->ecb.immediateAddress,
sizeof(NODE_NUM) );
address->got_target = TRUE;
_fmemset(buf->ecb.immediateAddress, 0xff, 6);
// Give the ECB back to IPX.
IPXListenForPacket( TASKID_C &buf->ecb );
return RPC_S_OK;
}
else if (buf->ecb.completionCode == ECB_PACKET_OVERFLOW)
{
// The packet was too large, but the runtime will still
// want to examine the header. Let's copy whatever we
// can get.
//
buf->ipx.Length = ByteSwapShort( buf->ipx.Length );
if (buf->ipx.Length > NT_PACKET_SIZE)
{
buf->ipx.Length = NT_PACKET_SIZE;
}
*BufferLength = buf->ipx.Length - sizeof(IPX_HEADER);
RpcpMemoryCopy( (char PAPI *) Buffer,
(char PAPI *) buf->ecb.fragmentDescriptor[1].address,
(unsigned) *BufferLength
);
// Set up the sender's address.
//
RpcpMemoryCopy( (char PAPI *) &address->ipx,
(char PAPI *) &buf->ipx.Source,
sizeof(IPX_ADDRESS) );
RpcpMemoryCopy( (char PAPI *) &address->local_target,
(char PAPI *) buf->ecb.immediateAddress,
sizeof(NODE_NUM) );
address->got_target = TRUE;
_fmemset(buf->ecb.immediateAddress, 0xff, 6);
// Give the ECB back to IPX.
IPXListenForPacket( TASKID_C &buf->ecb );
return RPC_P_OVERSIZE_PACKET;
}
else
{
#if defined(DEBUGRPC)
_asm int 3
#endif
}
// Give the ECB back to IPX.
IPXListenForPacket( TASKID_C &buf->ecb );
}
return RPC_P_TIMEOUT;
}
/********************************************************************/
RPC_STATUS RPC_ENTRY TransportUnload()
{
#if defined(__RPC_WIN16__)
ClientCleanup();
if (nwipxspx && 0 != GetModuleHandle("NWIPXSPX"))
{
IPXSPXDeinit(taskid);
FreeLibrary(nwipxspx);
}
#else
// Shouldn't be called on dos
#ifdef DEBUGRPC
__asm int 3;
#endif
#endif
return RPC_S_OK;
}
/********************************************************************/
#pragma pack(1)
RPC_STATUS RPC_ENTRY
ClientTowerConstruct(
IN char PAPI * Endpoint,
IN char PAPI * NetworkAddress,
OUT short PAPI * Floors,
OUT unsigned long PAPI * ByteCount,
OUT unsigned char PAPI * PAPI * Tower,
IN char PAPI * Protseq
)
{
unsigned TowerSize;
unsigned short portnum;
PFLOOR_234 Floor;
IPX_ADDRESS netaddr;
/* Compute the memory size of the tower. */
*Floors = TOWERFLOORS;
TowerSize = TOWERSIZE;
TowerSize += 2*sizeof(FLOOR_234) - 4;
/* Allocate memory for the tower. */
*ByteCount = TowerSize;
if (0 == (*Tower = (unsigned char PAPI *) I_RpcAllocate(TowerSize)))
{
return (RPC_S_OUT_OF_MEMORY);
}
/* Put the endpoint address and transport protocol id in the first floor. */
Floor = (PFLOOR_234) *Tower;
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(TRANSPORTID & 0xFF);
Floor->AddressByteCount = 2;
if (Endpoint == NULL || *Endpoint == '\0')
{
Endpoint = ENDPOINT_MAPPER_EP;
}
portnum = ByteSwapShort(atoi(Endpoint));
memcpy((char PAPI *)&Floor->Data[0], &portnum, sizeof(portnum));
/* Put the network address and the transport host protocol id in the
second floor. */
Floor = NEXTFLOOR(PFLOOR_234, Floor);
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(TRANSPORTHOSTID & 0xFF);
Floor->AddressByteCount = TOWEREPSIZE;
Floor->Data[0] = '\0';
Floor->Data[1] = '\0';
memset(Floor->Data, 0, 10);
return(RPC_S_OK);
}
/********************************************************************/
RPC_STATUS RPC_ENTRY
ClientTowerExplode(
IN unsigned char PAPI * Tower,
OUT char PAPI * PAPI * Protseq,
OUT char PAPI * PAPI * Endpoint,
OUT char PAPI * PAPI * NetworkAddress
)
{
PFLOOR_234 Floor = (PFLOOR_234) Tower;
RPC_STATUS Status = RPC_S_OK;
unsigned short *Port;
if (Protseq)
{
*Protseq = (char PAPI *) I_RpcAllocate(strlen(PROTSEQ) + 1);
if (0 == *Protseq)
{
Status = RPC_S_OUT_OF_MEMORY;
}
else
{
memcpy(*Protseq, PROTSEQ, strlen(PROTSEQ) + 1);
}
}
if ((0 == Endpoint) || (Status != RPC_S_OK))
{
return (Status);
}
*Endpoint = (char PAPI *) I_RpcAllocate(MAX_ENDPOINT_SIZE);
if (0 == *Endpoint)
{
Status = RPC_S_OUT_OF_MEMORY;
if (0 != Protseq)
{
I_RpcFree(*Protseq);
}
}
else
{
Port = (unsigned short *)&Floor->Data[0];
my_itoa(ByteSwapShort(*Port), *Endpoint);
}
return(Status);
}
RPC_STATUS RPC_ENTRY
QueryClientEndpoint
(
IN void PAPI * pOriginalEndpoint,
OUT RPC_CHAR PAPI * pClientEndpoint
)
{
DG_IPX_ENDPOINT *my_endpoint = (DG_IPX_ENDPOINT *) pOriginalEndpoint;
//
// Convert endpoint to an ASCII string.
//
_ultoa(my_endpoint->socket, pClientEndpoint, 10);
return RPC_S_OK;
}
#pragma pack()
/********************************************************************/
DG_RPC_CLIENT_TRANSPORT_INFO TransInfo =
{
RPC_TRANSPORT_INTERFACE_VERSION,
TRANSPORTID,
ClientTowerConstruct,
ClientTowerExplode,
sizeof(DG_IPX_ADDRESS),
sizeof(DG_IPX_ENDPOINT),
MAX_ENDPOINT_SIZE,
0,
TransportUnload,
ReceivePacket,
SendToServer,
RegisterServerAddress,
DeregisterServerAddress,
AssignLocalEndpoint,
FreeLocalEndpoint,
QueryClientEndpoint,
0,
0,
BeginCall,
EndCall,
1024,
0,
0,
0,
0
};
/*********
***********************************************************/
DG_RPC_CLIENT_TRANSPORT_INFO * RPC_ENTRY
TransPortLoad(
RPC_CHAR * pProtocolSequence
#if defined(__RPC_WIN16__)
, RPC_CLIENT_RUNTIME_INFO PAPI * RpcClientRuntimeInfo
#endif
)
/*++
Routine Description:
This routine is the "psuedo constructor" for the client transport object.
This is the exported entry point into this dll.
Arguments:
pProtocolSequence - The protocol sequence we're running on.
Return Value:
Pointer to transport info if successful, otherwise NULL.
--*/
{
//
// Returns the IPX error code, or zero for success.
//
#if defined(__RPC_WIN16__)
int retcode;
retcode = IPXInitialize( &taskid, MAX_ENDPOINTS * NUM_IPX_BUF, NT_PACKET_SIZE );
if (retcode)
{
return 0;
}
AsyncCallComplete = RpcClientRuntimeInfo->AsyncCallComplete;
RpcRuntimeInfo = RpcClientRuntimeInfo;
DllTermination = TransportUnload;
#else
if (IPXInitialize())
{
return 0;
}
I_DosAtExit(ClientCleanup);
#endif
/* Initialize the global variables. */
consecutive_timeout_count = 0;
num_endpoints = 0;
ep_list.next = &ep_list;
ep_list.prev = &ep_list;
packet_size = IPXGetMaxPacketSize();
if (packet_size < 1024)
return NULL;
TransInfo.PreferredPduSize = packet_size;
TransInfo.MaxPduSize = packet_size;
TransInfo.MaxPacketSize = packet_size;
TransInfo.DefaultBufferLength = NUM_IPX_BUF * packet_size;
return (&TransInfo);
}