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.
682 lines
15 KiB
682 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cltnvns.c
|
|
|
|
Abstract:
|
|
|
|
This is the client side loadable transport module for VINES
|
|
|
|
Author:
|
|
|
|
tony chan (tonychan) 5-May-1995 Creation
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
|
|
|
|
|
|
|
|
typedef int SOCKET;
|
|
|
|
#define SOCKADDR_VNS struct vns_sockaddr
|
|
#define FD_SETSIZE 1
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "sysinc.h"
|
|
#include "rpc.h"
|
|
#include "rpcdcep.h"
|
|
#include "rpctran.h"
|
|
#include "rpcerrp.h"
|
|
|
|
// Vines includes
|
|
#define INCL_SOCK
|
|
#define INCL_ST
|
|
#define INCL_WS
|
|
#include <vnsapi.h>
|
|
|
|
|
|
#define PFC_FIRST_FRAG 0x01
|
|
|
|
typedef struct
|
|
{
|
|
SOCKET Socket;
|
|
long Timeout;
|
|
unsigned long TickCount;
|
|
char PAPI * Buffer;
|
|
unsigned short State;
|
|
unsigned short PeekInfo;
|
|
/* bogus int for sockset */
|
|
int SockSet;
|
|
BOOL LocalRpc;
|
|
IPCPORT remoteport; /* address to keep around for VINES */
|
|
unsigned int cid;
|
|
IPCPORT localport;
|
|
} CONNECTION, *PCONNECTION;
|
|
|
|
typedef struct
|
|
{
|
|
short numofport;
|
|
char porttype;
|
|
IPCPORT ipcport;
|
|
} VNSRECORD;
|
|
|
|
#define ENDIAN_MASK 16
|
|
#define NO_MORE_SENDS_OR_RECVS 2
|
|
#define ENDPOINT_LEN 5
|
|
|
|
// The maximum send is the size of four user data frames on an ethernet.
|
|
|
|
#define MAXIMUM_SEND ((3 * 1450) & 0xFFF8)
|
|
#define HOSTNAME_LEN 32
|
|
#define DLL_NAME "rpcltc8.dll"
|
|
#define ENDPOINT_MAPPER_EP "385"
|
|
|
|
#define ADDRESS_FAMILY AF_BAN
|
|
#define SOCKET_TYPE SOCK_SEQPACKET
|
|
#define PROTOCOL -1
|
|
|
|
typedef unsigned char BYTE;
|
|
typedef unsigned short WORD;
|
|
#define LOBYTE(w) ((BYTE)(w))
|
|
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
|
|
#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
|
|
#define SET_PORT(p,wkp) \
|
|
((p[8] = (unsigned char)HIBYTE((unsigned short) wkp), \
|
|
p[9] = (unsigned char)LOBYTE((unsigned short) wkp)))
|
|
|
|
|
|
/* define to make compiler happy, llibban calls malloc, free */
|
|
|
|
|
|
void * __cdecl __loadds malloc(size_t x)
|
|
{
|
|
return(I_RpcAllocate(x));
|
|
}
|
|
|
|
void __cdecl __loadds free(void * t)
|
|
{
|
|
I_RpcFree(t);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Shutdown Detection Garbage
|
|
|
|
*/
|
|
/* BUG: do we need these? */
|
|
#define NOPENDINGRPC 0
|
|
#define RPCINITIATED 1
|
|
|
|
#define NOPEEKINFO 0
|
|
#define PEEKEDHEADER 1
|
|
#define PEEKEDBUFFER 2
|
|
|
|
#define rpc_shutdown 17
|
|
#define rpc_fault 3
|
|
|
|
|
|
/*
|
|
Following Macros and structs are needed for Tower Stuff
|
|
*/
|
|
|
|
#pragma pack(1)
|
|
|
|
#define TRANSPORTID 0x1A
|
|
#define TRANSPORTHOSTID 0x1C
|
|
#define TOWERFLOORS 5
|
|
#define TOWEREPSIZE 4
|
|
#define TOWERSIZE (TOWEREPSIZE+2)
|
|
#define PROTSEQ "ncacn_vns_spp"
|
|
|
|
|
|
typedef struct _FLOOR_234 {
|
|
unsigned short ProtocolIdByteCount;
|
|
unsigned char FloorId;
|
|
unsigned short AddressByteCount;
|
|
unsigned char Data[2];
|
|
} FLOOR_234;
|
|
typedef FLOOR_234 PAPI UNALIGNED * 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()
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientOpen (
|
|
IN 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
|
|
)
|
|
|
|
// Open a client connection
|
|
|
|
{
|
|
|
|
|
|
|
|
int err;
|
|
|
|
// Vines add on
|
|
VNS_ST_SESS StSess;
|
|
IPCPORT remoteport;
|
|
struct sockreq srdata; /* to send/receive data */
|
|
CallStatus cs;
|
|
VNSRECORD vnsrecord ;
|
|
short len = STNAMELEN;
|
|
char LocalNetworkAddress[63];
|
|
|
|
#if 0
|
|
_asm
|
|
{
|
|
int 3
|
|
}
|
|
#endif
|
|
|
|
/* copy to the stack */
|
|
_fstrcpy(LocalNetworkAddress, NetworkAddress);
|
|
|
|
if (NetworkAddress == NULL || NetworkAddress[0] == '\0')
|
|
{
|
|
/* local server is not supported right? */
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
memset(&remoteport,0,sizeof(IPCPORT));
|
|
memset(&StSess, 0, sizeof(VNS_ST_SESS));
|
|
memset(&srdata, 0, sizeof(struct sockreq));
|
|
|
|
cs = VnsStartStSession(NULL, TRUE, NULL, &StSess);
|
|
if(cs != 0)
|
|
{
|
|
#ifdef DEBUGPRC
|
|
_asm
|
|
{
|
|
int 3
|
|
}
|
|
#endif
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
memset(&vnsrecord, 0, sizeof(VNSRECORD));
|
|
vnsrecord.numofport = 1;
|
|
vnsrecord.porttype = 1;
|
|
|
|
/* find out which interrupt to call */
|
|
{
|
|
_asm
|
|
{
|
|
push ax
|
|
push bx
|
|
push dx
|
|
push ds
|
|
push di
|
|
|
|
mov ax, 0d701h
|
|
|
|
/* calling BANYAN to find out interrupt */
|
|
|
|
mov bx, 0
|
|
int 2fh
|
|
cmp bl, 60h
|
|
jb BAD
|
|
clc
|
|
mov ax, bx
|
|
jmp BANCALL
|
|
|
|
BAD:
|
|
int 3
|
|
|
|
|
|
}
|
|
}
|
|
|
|
{
|
|
_asm
|
|
{
|
|
|
|
BANCALL:
|
|
|
|
/* creating self-modifiing code
|
|
WARNING: don't put vnsrecord as global
|
|
DS of overlads != SS of Caller
|
|
|
|
*/
|
|
mov ah, al
|
|
mov al, 0CDh
|
|
lea bx, SELF
|
|
mov WORD PTR CS:[bx], ax
|
|
|
|
mov ax, ss
|
|
lea dx, LocalNetworkAddress
|
|
lea di, vnsrecord
|
|
mov ds, ax
|
|
mov bx, 2
|
|
mov ax, 7
|
|
jmp SELF /* instruction becomes CDint#
|
|
usually it's CD63 means int 63
|
|
the jmp is for flushing the i cache
|
|
*/
|
|
|
|
SELF:
|
|
|
|
nop /* leave space for the self modify code */
|
|
nop
|
|
/* need to check ax for error message */
|
|
|
|
pop di
|
|
pop ds
|
|
pop dx
|
|
pop bx
|
|
pop ax
|
|
}
|
|
}
|
|
|
|
VnsEndStSession( &StSess );
|
|
|
|
memcpy(&remoteport, &(vnsrecord.ipcport), sizeof(IPCPORT));
|
|
|
|
SET_PORT(remoteport, atoi(Endpoint) );
|
|
memcpy(&(pConn->remoteport), &(remoteport), sizeof(IPCPORT));
|
|
|
|
//
|
|
// Get a socket
|
|
//
|
|
|
|
err = VnsOpenSocket(&pConn->Socket, ADDRESS_FAMILY,
|
|
SOCKET_TYPE, PROTOCOL, pConn->localport , 0);
|
|
if (err != 0)
|
|
{
|
|
|
|
#if DEBUGRPC
|
|
_asm
|
|
{
|
|
int 3
|
|
}
|
|
#endif
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
err = 0;
|
|
srdata.type = SO_CONNECT;
|
|
srdata.msg = (char FAR *) NetworkAddress;
|
|
srdata.len = 0;
|
|
srdata.s = pConn->Socket;
|
|
srdata.flags = SO_EOM ;
|
|
srdata.timeout = (unsigned int)-1;
|
|
memcpy(srdata.addr, remoteport, sizeof(IPCPORT));
|
|
err = VnsSocketSend(&srdata);
|
|
if (!err) err = srdata.error;
|
|
|
|
if (err)
|
|
{
|
|
#if DEBUGRPC
|
|
_asm
|
|
{
|
|
int 3
|
|
}
|
|
return(err);
|
|
#endif
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
/* save the cid for next send */
|
|
pConn->cid = srdata.cid;
|
|
pConn->Timeout = RPC_C_CANCEL_INFINITE_TIMEOUT;
|
|
|
|
pConn->State = NOPENDINGRPC;
|
|
pConn->PeekInfo = NOPEEKINFO;
|
|
pConn->TickCount = 0;
|
|
|
|
|
|
// Create hidden window to receive Async messages
|
|
|
|
return (RPC_S_OK);
|
|
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientClose (
|
|
IN PCONNECTION pConn
|
|
)
|
|
|
|
// Close a client connection
|
|
|
|
{
|
|
struct sockreq srdata;
|
|
int err;
|
|
|
|
srdata.type = SO_DISCONNECT;
|
|
srdata.len = 0;
|
|
srdata.s = pConn->Socket;
|
|
srdata.flags = SO_EOM ;
|
|
srdata.timeout = (unsigned int)-1;
|
|
srdata.cid = pConn->cid;
|
|
memcpy(srdata.addr, pConn->remoteport, sizeof(IPCPORT));
|
|
err = VnsSocketSend(&srdata);
|
|
if (!err) err = srdata.error;
|
|
if (err)
|
|
{
|
|
return(RPC_S_INTERNAL_ERROR);
|
|
|
|
}
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientSend (
|
|
IN PCONNECTION pConn,
|
|
IN void PAPI * Buffer,
|
|
IN unsigned int BufferLength
|
|
)
|
|
|
|
// Write a message to a connection. This operation is retried in case
|
|
// the server is "busy".
|
|
|
|
{
|
|
struct sockreq srdata;
|
|
int err;
|
|
|
|
srdata.type = SO_DATA;
|
|
srdata.msg = Buffer;
|
|
srdata.len = BufferLength;
|
|
srdata.s = pConn->Socket;
|
|
srdata.flags = SO_EOM ;
|
|
srdata.timeout = (unsigned int)-1;
|
|
srdata.cid = pConn->cid;
|
|
memcpy(srdata.addr, pConn->remoteport, sizeof(IPCPORT));
|
|
err = VnsSocketSend(&srdata);
|
|
if (!err)
|
|
{
|
|
err = srdata.error;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
ClientRecv (
|
|
IN PCONNECTION pConn,
|
|
IN OUT void PAPI * PAPI * Buffer,
|
|
IN OUT unsigned int PAPI * BufferLength
|
|
)
|
|
|
|
// Read a message from a connection.
|
|
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
struct sockreq srdata;
|
|
int err;
|
|
int total_bytes = 0;
|
|
|
|
/* init */
|
|
memset(&srdata,0,sizeof(struct sockreq));
|
|
srdata.type = SO_DATA ;
|
|
srdata.s = pConn->Socket;
|
|
srdata.timeout = (unsigned int) -1 ;
|
|
srdata.cid = pConn->cid;
|
|
srdata.flags = SO_CREC;
|
|
memcpy(srdata.addr, pConn->localport, sizeof(IPCPORT));
|
|
|
|
|
|
/* allocate 1k for small messages */
|
|
|
|
*BufferLength = 1450; /* that's the default buffer size for VINES */
|
|
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
0,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
ClientClose(pConn);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
|
|
while(1)
|
|
{
|
|
|
|
|
|
srdata.msg =(char FAR *)*Buffer + total_bytes;
|
|
srdata.len = *BufferLength - total_bytes;
|
|
err = VnsSocketReceive(&srdata);
|
|
if (!err)
|
|
{
|
|
err = srdata.error;
|
|
}
|
|
|
|
if((err != 0) && (err != BYMSGSIZE))
|
|
{
|
|
ClientClose ( pConn );
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
|
|
|
|
/* if((srdata.flags && SO_EOM )== SO_EOM) */
|
|
if((srdata.flags != (SO_CREC + SO_EOM)))
|
|
{
|
|
total_bytes += srdata.cc;
|
|
*BufferLength = MAXIMUM_SEND;
|
|
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
total_bytes,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
ClientClose ( pConn );
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
total_bytes += srdata.cc;
|
|
*BufferLength = total_bytes;
|
|
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(RPC_S_INTERNAL_ERROR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#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 long TowerSize;
|
|
unsigned short portnum;
|
|
UNALIGNED PFLOOR_234 Floor;
|
|
unsigned short AddressSize = 0;
|
|
|
|
/* Compute the memory size of the tower. */
|
|
*Floors = TOWERFLOORS;
|
|
TowerSize = TOWERSIZE;
|
|
|
|
if (NetworkAddress == NULL || NetworkAddress[0] == '\0')
|
|
{
|
|
/* local server is not supported right? */
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
AddressSize = (unsigned short) strlen(NetworkAddress) + 1;
|
|
TowerSize += 2*sizeof(FLOOR_234) - 4 + AddressSize;
|
|
|
|
/* Allocate memory for the tower. */
|
|
*ByteCount = TowerSize;
|
|
if ((*Tower = (unsigned char PAPI*)I_RpcAllocate((unsigned int)
|
|
TowerSize)) == NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
memset(*Tower, 0, TowerSize);
|
|
|
|
/* 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 = (unsigned short) atoi (Endpoint) ;
|
|
Floor->Data[0] = HIBYTE(portnum) ;
|
|
Floor->Data[1] = LOBYTE(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';
|
|
|
|
|
|
if ((NetworkAddress) && (*NetworkAddress))
|
|
{
|
|
Floor->AddressByteCount = AddressSize ;
|
|
memcpy((char PAPI *)&Floor->Data[0], NetworkAddress, AddressSize);
|
|
}
|
|
else
|
|
return ( RPC_S_OUT_OF_MEMORY ) ;
|
|
|
|
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
|
|
)
|
|
{
|
|
UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
unsigned short portnum;
|
|
|
|
if (Protseq != NULL)
|
|
{
|
|
*Protseq = I_RpcAllocate(strlen(PROTSEQ) + 1);
|
|
if (*Protseq == NULL)
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
else
|
|
memcpy(*Protseq, PROTSEQ, strlen(PROTSEQ) + 1);
|
|
}
|
|
|
|
if ((Endpoint == NULL) || (Status != RPC_S_OK))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
*Endpoint = I_RpcAllocate(ENDPOINT_LEN+1); //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 = MAKEWORD(Floor->Data[1], Floor->Data[0]) ;
|
|
_itoa(portnum, *Endpoint, 10);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma pack()
|
|
RPC_CLIENT_TRANSPORT_INFO TransInfo =
|
|
{
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
TRANSPORTID,
|
|
|
|
ClientTowerConstruct,
|
|
ClientTowerExplode,
|
|
|
|
MAXIMUM_SEND,
|
|
sizeof (CONNECTION),
|
|
|
|
ClientOpen,
|
|
ClientClose,
|
|
ClientSend,
|
|
ClientRecv,
|
|
NULL,
|
|
0,
|
|
|
|
0,
|
|
0
|
|
};
|
|
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO PAPI * RPC_ENTRY TransportLoad (
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence
|
|
)
|
|
|
|
// Loadable transport initialization function
|
|
|
|
{
|
|
|
|
UNUSED (RpcProtocolSequence);
|
|
|
|
return(&TransInfo);
|
|
}
|
|
|
|
|