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.
818 lines
18 KiB
818 lines
18 KiB
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <sysinc.h>
|
|
#include <rpc.h>
|
|
#include <rpcdcep.h>
|
|
#include <rpctran.h>
|
|
#include <rpcerrp.h>
|
|
#include <novell.h>
|
|
#include <gethost.h>
|
|
#include "callback.h"
|
|
|
|
#define MAX_CONNECTIONS 10
|
|
|
|
// NULL Pointer macros
|
|
|
|
#define NULL_HGLOBAL (HGLOBAL)NULL
|
|
#define NULL_ECB 0
|
|
#define NULL_SPX 0
|
|
#define NULL_CHAR 0
|
|
|
|
// SPX ConnectionControl BIT masks
|
|
|
|
#define SPX_CC_EOM 0x10
|
|
|
|
// venerable byte swaping macro
|
|
|
|
#define SwapWord(i) ((( (unsigned short) (i) & 0xff) << 8) | \
|
|
(( (unsigned short) (i) & 0xff00) >> 8))
|
|
|
|
// Macros for critical section protection
|
|
|
|
#define Begin_Critical_Section() _asm cli
|
|
#define End_Critical_Section() _asm sti
|
|
|
|
// Tower Stuff
|
|
|
|
#define TRANSPORTID 0x0c
|
|
#define TRANSPORTHOSTID 0x0d
|
|
|
|
#define TOWERFLOORS 5
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct _FLLOR_234 {
|
|
unsigned short ProtocolIdByteCount;
|
|
unsigned char FloorId;
|
|
unsigned short AddressByteCount;
|
|
unsigned char Data[2];
|
|
} FLOOR_234, * PFLOOR_234;
|
|
|
|
#pragma pack()
|
|
|
|
#define NEXTFLOOR(t,x) (t)((unsigned char *)x +((t)x)->ProtocolIdByteCount\
|
|
+ ((t)x)->AddressByteCount \
|
|
+ sizeof(((t)x)->ProtocolIdByteCount) \
|
|
+ sizeof(((t)x)->AddressByteCount))
|
|
|
|
#define ENDPOINT_MAPPER_EP "34280"
|
|
|
|
|
|
// Structure definitions
|
|
|
|
typedef struct {
|
|
DWORD taskid;
|
|
WORD ConnID;
|
|
WORD local_socket;
|
|
HGLOBAL yield;
|
|
int yielding;
|
|
#define MAX_ECBS 5
|
|
struct XECB_st * ecbs[MAX_ECBS];
|
|
struct XECB_st * q_head;
|
|
struct XECB_st * q_tail;
|
|
} CONNECTION, * PCONNECTION;
|
|
|
|
|
|
typedef struct XECB_st {
|
|
void * linkAddress;
|
|
void (*ESRAddress)();
|
|
BYTE inUseFlag;
|
|
BYTE completionCode;
|
|
WORD socketNumber; /* high-low */
|
|
BYTE IPXWorkspace[4]; /* N/A */
|
|
BYTE driverWorkspace[12]; /* N/A */
|
|
BYTE immediateAddress[6]; /* high-low */
|
|
WORD fragmentCount; /* low-high */
|
|
ECBFragment fragmentDescriptor[2];
|
|
PCONNECTION pConn;
|
|
} XECB;
|
|
|
|
typedef struct {
|
|
unsigned char rpc_vers;
|
|
unsigned char rpc_vers_minor;
|
|
unsigned char PTYPE;
|
|
unsigned char pfc_flags;
|
|
unsigned char drep[4];
|
|
#define BIG_ENDIAN 16 // drep[0] & BIG_ENDIAN indicate byte ordering
|
|
unsigned short frag_length;
|
|
unsigned short auth_length;
|
|
unsigned long call_id;
|
|
} ncacn_header;
|
|
|
|
// DLL global variables
|
|
|
|
unsigned int spx_max_userdata_size; // max userdata size per SPX packet
|
|
|
|
extern void (_far pascal _far *DllTermination)(void);
|
|
|
|
void __cdecl __export __loadds post_ecb(void);
|
|
|
|
#pragma alloc_text(RPC16C6_FIXED, post_ecb)
|
|
|
|
|
|
#ifdef DEBUGRPC
|
|
|
|
void
|
|
do_popup(char * format, ...)
|
|
{
|
|
char errmsg[256];
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
wvsprintf(errmsg, format, args);
|
|
|
|
va_end(args);
|
|
|
|
MessageBox((HWND)0, errmsg, "RPC/SPX", MB_SYSTEMMODAL|MB_ICONSTOP);
|
|
}
|
|
#else
|
|
|
|
#define do_popup(x)
|
|
|
|
#endif
|
|
|
|
|
|
void
|
|
free_ecb(XECB * ecb)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
|
|
if (!ecb)
|
|
{
|
|
_asm int 3
|
|
}
|
|
|
|
if (ecb->inUseFlag)
|
|
{
|
|
_asm int 3
|
|
}
|
|
#endif
|
|
|
|
|
|
if (ecb->fragmentCount > 1) {
|
|
GlobalFreePtr(ecb->fragmentDescriptor[1].address);
|
|
}
|
|
GlobalFreePtr(ecb->fragmentDescriptor[0].address);
|
|
GlobalFreePtr(ecb);
|
|
}
|
|
|
|
XECB *
|
|
allocate_send_ecb(PCONNECTION pConn)
|
|
{
|
|
XECB * ecb;
|
|
SPX_HEADER * spx;
|
|
|
|
if ((ecb = (XECB *)GlobalAllocPtr(GPTR, sizeof(XECB))) == NULL_ECB) {
|
|
return (NULL_ECB);
|
|
}
|
|
|
|
if ((spx = (SPX_HEADER *)GlobalAllocPtr(GPTR, sizeof(SPX_HEADER))) == NULL_SPX) {
|
|
GlobalFreePtr(ecb);
|
|
return (NULL_ECB);
|
|
}
|
|
|
|
// Initialize SPX Header...
|
|
|
|
spx->ipx.PacketType = 5; // SPX packet
|
|
|
|
// Initialize ECB...
|
|
|
|
ecb->ESRAddress = 0;
|
|
|
|
ecb->fragmentCount = 1;
|
|
|
|
ecb->fragmentDescriptor[0].address = spx;
|
|
ecb->fragmentDescriptor[0].size = sizeof(SPX_HEADER);
|
|
|
|
ecb->socketNumber = pConn->local_socket;
|
|
|
|
ecb->pConn = pConn;
|
|
|
|
return (ecb);
|
|
}
|
|
|
|
XECB *
|
|
allocate_receive_ecb(PCONNECTION pConn)
|
|
{
|
|
XECB * ecb;
|
|
char * buf;
|
|
|
|
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB) {
|
|
return (NULL_ECB);
|
|
}
|
|
|
|
//
|
|
// Win95 servers are willing to send 0x5d9 bytes on an 802.2 network.
|
|
// Novell clients report 802.2 max as 0x5d8, wasting one byte of potential,
|
|
// and if a full packet arrives they copy the whole thing. So we must
|
|
// allocate space for that extra byte.
|
|
//
|
|
//
|
|
if ((buf = (char *)GlobalAllocPtr(GPTR, 2+spx_max_userdata_size)) == NULL_CHAR) {
|
|
free_ecb(ecb);
|
|
return (NULL_ECB);
|
|
}
|
|
|
|
ecb->fragmentDescriptor[1].address = buf;
|
|
ecb->fragmentDescriptor[1].size = 2+spx_max_userdata_size;
|
|
|
|
ecb->ESRAddress = post_ecb;
|
|
|
|
ecb->fragmentCount = 2;
|
|
|
|
return (ecb);
|
|
}
|
|
|
|
void __loadds
|
|
post_ecb()
|
|
{
|
|
XECB * ecb;
|
|
PCONNECTION pConn;
|
|
|
|
__asm
|
|
{
|
|
mov word ptr ecb+2, es
|
|
mov word ptr ecb, si
|
|
}
|
|
|
|
#ifdef DEBUGRPC
|
|
|
|
if (!ecb)
|
|
{
|
|
_asm int 3
|
|
}
|
|
#endif
|
|
|
|
pConn = ecb->pConn;
|
|
|
|
ecb->linkAddress = NULL_ECB;
|
|
if (pConn->q_tail == NULL_ECB) {
|
|
pConn->q_head = ecb;
|
|
} else {
|
|
pConn->q_tail->linkAddress = ecb;
|
|
}
|
|
pConn->q_tail = ecb;
|
|
|
|
if (pConn->yielding) {
|
|
I_RpcWinAsyncCallComplete(pConn);
|
|
}
|
|
}
|
|
|
|
XECB *
|
|
wait_for_ecb(PCONNECTION pConn)
|
|
{
|
|
XECB * ecb;
|
|
|
|
Begin_Critical_Section();
|
|
|
|
if (pConn->q_head == NULL_ECB) {
|
|
pConn->yield = I_RpcWinAsyncCallBegin(pConn);
|
|
pConn->yielding = 1;
|
|
End_Critical_Section();
|
|
IPXRelinquishControl();
|
|
if (I_RpcWinAsyncCallWait(pConn->yield, (HWND)NULL, RPC_WIN_INFINITE_TIMEOUT) == 0) {
|
|
pConn->yielding = 0;
|
|
I_RpcWinAsyncCallEnd(pConn->yield);
|
|
return (NULL_ECB);
|
|
}
|
|
Begin_Critical_Section();
|
|
I_RpcWinAsyncCallEnd(pConn->yield);
|
|
pConn->yielding = 0;
|
|
}
|
|
|
|
ecb = pConn->q_head;
|
|
if ((pConn->q_head = ecb->linkAddress) == NULL_ECB) {
|
|
pConn->q_tail = NULL_ECB;
|
|
}
|
|
|
|
End_Critical_Section();
|
|
|
|
return (ecb);
|
|
}
|
|
|
|
void
|
|
spx_abort(PCONNECTION pConn)
|
|
{
|
|
int i;
|
|
|
|
if (pConn->local_socket) {
|
|
if (pConn->ConnID) {
|
|
SPXAbortConnection(pConn->ConnID);
|
|
pConn->ConnID = 0;
|
|
}
|
|
IPXCloseSocket(taskid, pConn->local_socket);
|
|
pConn->local_socket = 0;
|
|
}
|
|
|
|
for (i = 0; i < MAX_ECBS; i++) {
|
|
if (pConn->ecbs[i] != NULL) {
|
|
free_ecb(pConn->ecbs[i]);
|
|
pConn->ecbs[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY _loadds
|
|
spx_close(PCONNECTION pConn)
|
|
{
|
|
int i;
|
|
XECB * ecb;
|
|
|
|
if (pConn->ConnID)
|
|
{
|
|
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
SPXTerminateConnection(taskid, pConn->ConnID, (ECB *) ecb);
|
|
|
|
while (ecb->inUseFlag)
|
|
{
|
|
IPXRelinquishControl();
|
|
}
|
|
|
|
free_ecb(ecb);
|
|
|
|
pConn->ConnID = 0;
|
|
}
|
|
|
|
if (pConn->local_socket)
|
|
{
|
|
IPXCloseSocket(taskid, pConn->local_socket);
|
|
|
|
pConn->local_socket = 0;
|
|
}
|
|
|
|
|
|
for (i = 0; i < MAX_ECBS; i++)
|
|
{
|
|
if (pConn->ecbs[i] != NULL)
|
|
{
|
|
free_ecb(pConn->ecbs[i]);
|
|
pConn->ecbs[i] = 0;
|
|
}
|
|
}
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY _loadds
|
|
spx_open (PCONNECTION pConn,
|
|
IN RPC_CHAR * NetworkAddress,
|
|
IN RPC_CHAR * Endpoint,
|
|
IN RPC_CHAR * NetworkOptions,
|
|
IN RPC_CHAR * TransportAddress,
|
|
IN RPC_CHAR * RpcProtocolSequence,
|
|
IN unsigned int Timeout
|
|
)
|
|
{
|
|
int i;
|
|
int ret;
|
|
int status;
|
|
XECB * ecb;
|
|
SPX_HEADER * spx;
|
|
|
|
retry:
|
|
|
|
pConn->q_head = pConn->q_tail = NULL_ECB;
|
|
pConn->yielding = 0;
|
|
|
|
// Allocate socket ...
|
|
|
|
pConn->ConnID = 0;
|
|
|
|
pConn->local_socket = 0;
|
|
|
|
for (i = 0; i < MAX_ECBS; i++) {
|
|
pConn->ecbs[i] = NULL;
|
|
}
|
|
|
|
status = IPXOpenSocket(taskid, &pConn->local_socket, 0xff);
|
|
|
|
if (status != SUCCESSFUL) {
|
|
do_popup("IPXOpenSocket %x", status);
|
|
return (RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
|
|
for (i = 0; i < MAX_ECBS; i++) {
|
|
if ((pConn->ecbs[i] = allocate_receive_ecb(pConn)) == NULL_ECB) {
|
|
spx_close(pConn);
|
|
return (RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
SPXListenForSequencedPacket(taskid, (ECB *) pConn->ecbs[i]);
|
|
}
|
|
|
|
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB) {
|
|
spx_abort(pConn);
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Map Address into IPX address...
|
|
|
|
spx = ecb->fragmentDescriptor[0].address;
|
|
|
|
status = IpxGetHostByName(NetworkAddress, &spx->ipx.Destination, Endpoint, Timeout,
|
|
RpcRuntimeInfo );
|
|
if (status != RPC_S_OK) {
|
|
free_ecb(ecb);
|
|
spx_close(pConn);
|
|
return(status);
|
|
}
|
|
|
|
ret = SPXEstablishConnection(taskid, 0, 0xff,(LPWORD)&pConn->ConnID,
|
|
(ECB *) ecb);
|
|
|
|
if (ret != SUCCESSFUL)
|
|
{
|
|
free_ecb(ecb);
|
|
spx_close(pConn);
|
|
return RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
while (ecb->inUseFlag) {
|
|
IPXRelinquishControl();
|
|
}
|
|
|
|
if (ecb->completionCode != SUCCESSFUL) {
|
|
free_ecb(ecb);
|
|
spx_close(pConn);
|
|
|
|
if (TRUE == CachedServerNotContacted(NetworkAddress))
|
|
{
|
|
goto retry;
|
|
}
|
|
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
free_ecb(ecb);
|
|
|
|
CachedServerContacted(NetworkAddress);
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
int
|
|
put_packets(PCONNECTION pConn,
|
|
XECB * ecb,
|
|
char * buf,
|
|
unsigned int bufsiz)
|
|
{
|
|
SPX_HEADER * spx;
|
|
unsigned int packet_size;
|
|
|
|
spx = ecb->fragmentDescriptor[0].address;
|
|
|
|
while (bufsiz > 0) {
|
|
|
|
packet_size = min(bufsiz, spx_max_userdata_size);
|
|
|
|
spx->ConnControl = packet_size == bufsiz ? SPX_CC_EOM : 0;
|
|
|
|
spx->DataType = 0;
|
|
|
|
ecb->fragmentDescriptor[1].address = buf;
|
|
ecb->fragmentDescriptor[1].size = packet_size;
|
|
|
|
SPXSendSequencedPacket(taskid, pConn->ConnID, (ECB *) ecb);
|
|
|
|
while (ecb->inUseFlag) {
|
|
IPXRelinquishControl();
|
|
}
|
|
|
|
if (ecb->completionCode != SUCCESSFUL) {
|
|
return (-1);
|
|
}
|
|
buf += packet_size;
|
|
bufsiz -= packet_size;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY _loadds
|
|
spx_send(PCONNECTION pConn,
|
|
void * Buffer,
|
|
unsigned int Length
|
|
)
|
|
{
|
|
XECB * ecb;
|
|
|
|
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB) {
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
ecb->fragmentCount = 2;
|
|
|
|
if (put_packets(pConn, ecb, Buffer, Length) == -1) {
|
|
ecb->fragmentCount = 1;
|
|
free_ecb(ecb);
|
|
spx_close(pConn);
|
|
return (RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
ecb->fragmentCount = 1;
|
|
|
|
free_ecb(ecb);
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
get_remaining_packets(PCONNECTION pConn, char * buf, unsigned int bufsiz)
|
|
{
|
|
unsigned int length;
|
|
XECB * ecb;
|
|
SPX_HEADER * spx;
|
|
|
|
while (bufsiz > 0) {
|
|
ecb = wait_for_ecb(pConn);
|
|
if (ecb == NULL_ECB || ecb->completionCode != SUCCESSFUL) {
|
|
spx_abort(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
spx = ecb->fragmentDescriptor[0].address;
|
|
length = SwapWord(spx->ipx.Length) - sizeof(SPX_HEADER);
|
|
memcpy(buf, ecb->fragmentDescriptor[1].address, length);
|
|
SPXListenForSequencedPacket(taskid, (ECB *) ecb);
|
|
bufsiz -= length;
|
|
buf += length;
|
|
}
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY _loadds
|
|
spx_receive(PCONNECTION pConn,
|
|
void * * Buffer,
|
|
unsigned int * BufferLength
|
|
)
|
|
{
|
|
unsigned int first_packet_length, fragment_length;
|
|
SPX_HEADER * spx;
|
|
XECB * ecb;
|
|
ncacn_header *ncacn;
|
|
|
|
ecb = wait_for_ecb(pConn);
|
|
if (ecb == NULL_ECB || ecb->completionCode != SUCCESSFUL) {
|
|
spx_close(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
spx = ecb->fragmentDescriptor[0].address;
|
|
|
|
if (spx->DataType == 0xFE) {
|
|
spx_close(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
|
|
first_packet_length = SwapWord(spx->ipx.Length) - sizeof(SPX_HEADER);
|
|
|
|
ncacn = (ncacn_header *)ecb->fragmentDescriptor[1].address;
|
|
|
|
if ( (ncacn->drep[0] & BIG_ENDIAN) == 0) {
|
|
fragment_length = SwapWord(ncacn->frag_length);
|
|
} else {
|
|
fragment_length = ncacn->frag_length; // it's little-endian
|
|
}
|
|
|
|
//
|
|
// If the runtime supplied buffer isn't big enough to hold all SPX packets
|
|
// which form the RPC fragment, then go back to the runtime to reallocate it.
|
|
//
|
|
if (fragment_length > *BufferLength) {
|
|
if (I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
0,
|
|
fragment_length)) {
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
*BufferLength = fragment_length;
|
|
|
|
memcpy(*Buffer, ncacn, first_packet_length);
|
|
|
|
SPXListenForSequencedPacket(taskid, (ECB *) ecb);
|
|
|
|
if (fragment_length > first_packet_length) {
|
|
return get_remaining_packets(pConn,
|
|
(char *)*Buffer + first_packet_length,
|
|
fragment_length - first_packet_length);
|
|
}
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
spx_tower_construct(
|
|
IN char * Endpoint,
|
|
IN char * NetworkAddress,
|
|
OUT unsigned short * Floors,
|
|
OUT unsigned long * ByteCount,
|
|
OUT unsigned char * * Tower,
|
|
IN char * Protseq
|
|
)
|
|
{
|
|
unsigned int TowerSize;
|
|
PFLOOR_234 Floor;
|
|
IPX_ADDRESS ipx;
|
|
RPC_STATUS status;
|
|
unsigned portnum;
|
|
|
|
/* Compute the memory size of the tower. */
|
|
*Floors = TOWERFLOORS;
|
|
TowerSize = 12;
|
|
TowerSize += 2*sizeof(FLOOR_234) - 4;
|
|
|
|
/* Allocate memory for the tower. */
|
|
*ByteCount = TowerSize;
|
|
if ((*Tower = (unsigned char *)I_RpcAllocate(TowerSize)) == NULL)
|
|
{
|
|
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 = atoi(Endpoint);
|
|
Floor->Data[0] = portnum / 0x100;
|
|
Floor->Data[1] = portnum % 0x100;
|
|
|
|
/* 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 = 4 + 6;
|
|
|
|
memset(Floor->Data, '\0', 10);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
spx_tower_explode(
|
|
IN unsigned char * Tower,
|
|
OUT char * * Protseq,
|
|
OUT char * * Endpoint,
|
|
OUT char * * NetworkAddress
|
|
)
|
|
{
|
|
PFLOOR_234 Floor = (PFLOOR_234) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
unsigned short portnum;
|
|
char * spx_protseq = "ncacn_spx";
|
|
|
|
if (Protseq != NULL) {
|
|
*Protseq = (char *)I_RpcAllocate(strlen(spx_protseq) + 1);
|
|
if (*Protseq == NULL)
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
else
|
|
memcpy(*Protseq, spx_protseq, strlen(spx_protseq) + 1);
|
|
}
|
|
|
|
if ((Endpoint == NULL) || (Status != RPC_S_OK)) {
|
|
return (Status);
|
|
}
|
|
|
|
*Endpoint = (char *)I_RpcAllocate(6); //Ports are all <64K [5 decimal dig +1]
|
|
if (*Endpoint == NULL) {
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
if (Protseq != NULL) {
|
|
I_RpcFree(*Protseq);
|
|
}
|
|
} else {
|
|
portnum = SwapWord(*(short *)Floor->Data);
|
|
_itoa(portnum, *Endpoint, 10);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
void PASCAL __loadds
|
|
spx_wrapup(void)
|
|
{
|
|
if (nwipxspx && 0 != GetModuleHandle("NWIPXSPX"))
|
|
{
|
|
IPXSPXDeinit(taskid);
|
|
FreeLibrary(nwipxspx);
|
|
}
|
|
}
|
|
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO TransInfo =
|
|
{
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
TRANSPORTID,
|
|
|
|
(TRANS_CLIENT_TOWERCONSTRUCT) spx_tower_construct,
|
|
(TRANS_CLIENT_TOWEREXPLODE) spx_tower_explode,
|
|
|
|
0,
|
|
sizeof(CONNECTION),
|
|
|
|
(TRANS_CLIENT_OPEN) spx_open,
|
|
(TRANS_CLIENT_CLOSE) spx_close,
|
|
(TRANS_CLIENT_SEND) spx_send,
|
|
(TRANS_CLIENT_RECEIVE) spx_receive,
|
|
0,
|
|
0,
|
|
|
|
0,
|
|
0
|
|
};
|
|
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO * RPC_ENTRY
|
|
TransPortLoad (
|
|
IN RPC_CHAR * RpcProtocolSequence,
|
|
IN RPC_CLIENT_RUNTIME_INFO PAPI * RpcClientRuntimeInfo
|
|
)
|
|
{
|
|
int retcode;
|
|
BYTE major_revision, minor_revision;
|
|
unsigned int max_connections, available_connections;
|
|
|
|
if (IPXInitialize(&taskid, MAX_CONNECTIONS * MAX_ECBS, 0) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
AsyncCallComplete = RpcClientRuntimeInfo->AsyncCallComplete;
|
|
|
|
RpcRuntimeInfo = RpcClientRuntimeInfo;
|
|
|
|
taskid = 0xffffffff;
|
|
|
|
retcode = SPXInitialize(&taskid,
|
|
MAX_CONNECTIONS * MAX_ECBS, // maxECBs
|
|
0,
|
|
&major_revision,
|
|
&minor_revision,
|
|
&max_connections,
|
|
&available_connections);
|
|
|
|
switch (retcode) {
|
|
case 0:
|
|
do_popup("Not installed");
|
|
return (NULL);
|
|
|
|
case 0xf0:
|
|
if (GetWinFlags() & WF_ENHANCED) {
|
|
do_popup("not supported");
|
|
return (NULL);
|
|
}
|
|
do_popup("Failed increasing local memory");
|
|
return (NULL);
|
|
case 0xf1:
|
|
do_popup("not initialized");
|
|
return (NULL);
|
|
case 0xf2:
|
|
do_popup("no DOS memory");
|
|
return(NULL);
|
|
case 0xf3:
|
|
do_popup("no free ECB");
|
|
return(NULL);
|
|
case 0xf4:
|
|
do_popup("Lock failed");
|
|
return(NULL);
|
|
case 0xf5:
|
|
do_popup("Over the maximum limit");
|
|
return(NULL);
|
|
|
|
case 0xf6:
|
|
do_popup("previously initialized");
|
|
//Intentional Fall Through
|
|
case SPX_INSTALLED:
|
|
break;
|
|
|
|
default:
|
|
do_popup("Unknown SPX Failure");
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
spx_max_userdata_size = IPXGetMaxPacketSize() - sizeof(SPX_HEADER);
|
|
|
|
TransInfo.MaximumPacketSize = (spx_max_userdata_size * MAX_ECBS)
|
|
& 0xFFF8;
|
|
|
|
DllTermination = spx_wrapup;
|
|
|
|
return(&TransInfo);
|
|
}
|
|
|