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.
507 lines
12 KiB
507 lines
12 KiB
/* --------------------------------------------------------------------
|
|
File : dnltclnt.c
|
|
|
|
Title : client loadable transport for DECnet DOS - client side
|
|
|
|
Description :
|
|
|
|
History :
|
|
|
|
6-26-91 Jim Teague Initial version.
|
|
|
|
-------------------------------------------------------------------- */
|
|
|
|
#include "dnltclnt.h"
|
|
|
|
#pragma pack(1)
|
|
#define DNA_SESSION_CONTROL 0x02
|
|
#define NSP_TRANSPORT 0x04
|
|
#define DNA_ROUTING 0x06
|
|
|
|
#define DNET_TOWERFLOORS 6
|
|
#define DNET_EP "#69"
|
|
#define DNET_PROTSEQ "ncacn_dnet_nsp"
|
|
#define DNET_FLOOR3_SIZE 8 /* LHSbc = 2, LHSd = 1, RHSbc = 2, RHSd = 3 */
|
|
#define DNET_FLOOR4_SIZE 5 /* LHSbc = 2, LHSd = 1, RHSbc = 2, RHSd = 0 */
|
|
#define DNET_FLOOR5_SIZE 9 /* LHSbc = 2, LHSd = 1, RHSbc = 2, RHSd = 4 */
|
|
|
|
|
|
typedef struct _FLOOR {
|
|
unsigned short LHSByteCount;
|
|
unsigned char LHSData;
|
|
unsigned short RHSByteCount;
|
|
unsigned char RHSData[2];
|
|
|
|
} FLOOR, PAPI * PFLOOR;
|
|
|
|
#define NEXTFLOOR(t,x) (t)((unsigned char PAPI *)x \
|
|
+ ((t)x)->LHSByteCount \
|
|
+ ((t)x)->RHSByteCount \
|
|
+ sizeof(((t)x)->LHSByteCount) \
|
|
+ sizeof(((t)x)->RHSByteCount))
|
|
|
|
#pragma pack()
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientOpen (
|
|
PCONNECTION pConn,
|
|
IN unsigned char * NetworkAddress,
|
|
IN unsigned char * Endpoint,
|
|
IN unsigned char * NetworkOptions,
|
|
IN unsigned char * TransportAddress,
|
|
IN unsigned char * RpcProtocolSequence,
|
|
IN unsigned int Timeout
|
|
)
|
|
|
|
// Open a client connection
|
|
|
|
{
|
|
|
|
struct sockaddr_dn server;
|
|
struct nodeent *hostentry;
|
|
struct dn_naddr *dotaddress;
|
|
int i;
|
|
//
|
|
// See if node address is in numeric format...
|
|
//
|
|
if ((i = strcspn(NetworkAddress,".0123456789")) == 0)
|
|
{
|
|
dotaddress = dnet_addr(NetworkAddress);
|
|
hostentry = getnodebyaddr (dotaddress->a_addr,
|
|
sizeof(short),AF_DECnet);
|
|
}
|
|
else
|
|
hostentry = getnodebyname (NetworkAddress);
|
|
|
|
if (hostentry == (struct nodeent *) 0)
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
|
|
server.sdn_family = AF_DECnet;
|
|
server.sdn_objnum = 0;
|
|
server.sdn_objnamel = 0;
|
|
server.sdn_objname[0] = 0;
|
|
//
|
|
// Look at the port string: if the first character is '#',
|
|
// then interpret it as an object number...
|
|
//
|
|
if (*Endpoint == '#')
|
|
server.sdn_objnum = atoi(Endpoint+1);
|
|
|
|
//
|
|
// ...otherwise, it is an object name...
|
|
//
|
|
else
|
|
{
|
|
server.sdn_objnamel = strlen(Endpoint);
|
|
strcpy (server.sdn_objname,Endpoint);
|
|
}
|
|
|
|
server.sdn_add.a_len = hostentry->n_length;
|
|
memcpy ((char *) &server.sdn_add.a_addr,
|
|
(char *) hostentry->n_addr,
|
|
hostentry->n_length);
|
|
|
|
//
|
|
// Get a socket
|
|
//
|
|
if ((pConn->Socket = socket(AF_DECnet, SOCK_STREAM, 0)) < 0)
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
|
|
//
|
|
// Try to connect...
|
|
//
|
|
if (connect(pConn->Socket, (struct sockaddr_dn *) &server,
|
|
sizeof (server)) < 0)
|
|
return (RPC_S_SERVER_UNAVAILABLE);
|
|
|
|
return (RPC_S_OK);
|
|
|
|
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientClose (
|
|
PCONNECTION pConn
|
|
)
|
|
|
|
// Close a client connection
|
|
|
|
{
|
|
// Don't close a connection that is already closed...
|
|
|
|
sclose(pConn->Socket);
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientWrite (
|
|
PCONNECTION pConn,
|
|
void * Buffer,
|
|
unsigned int BufferLength
|
|
)
|
|
|
|
// Write a message to a connection. This operation is retried in case
|
|
// the server is "busy".
|
|
|
|
{
|
|
int bytes;
|
|
|
|
//
|
|
// Send a message on the socket
|
|
//
|
|
bytes = send(pConn->Socket, (char *) Buffer, (int) BufferLength, 0);
|
|
|
|
if (bytes != (int) BufferLength)
|
|
{
|
|
ClientClose(pConn);
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientRead (
|
|
PCONNECTION pConn,
|
|
void ** Buffer,
|
|
unsigned int * BufferLength
|
|
)
|
|
|
|
// Read a message from a connection.
|
|
|
|
{
|
|
unsigned short bytes;
|
|
unsigned short total_bytes;
|
|
message_header header;
|
|
unsigned short native_length;
|
|
fd_set ClientConnMask;
|
|
unsigned short got_data;
|
|
RPC_STATUS status;
|
|
|
|
FD_ZERO(&ClientConnMask);
|
|
|
|
|
|
FD_SET(pConn->Socket, &ClientConnMask);
|
|
got_data = select(MAX_SOCKETS,&ClientConnMask,(fd_set *) 0,
|
|
(fd_set *) 0, NULL);
|
|
//
|
|
// If there's data, deal with it.
|
|
//
|
|
if (got_data <= 0)
|
|
{
|
|
ClientClose(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
//
|
|
// Read protocol header to see how big
|
|
// the record is...
|
|
//
|
|
bytes = recv ( pConn->Socket, (char *) &header, sizeof (header), 0);
|
|
|
|
if (bytes == 0)
|
|
{
|
|
ClientClose(pConn);
|
|
return(RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
|
|
if (bytes != sizeof(header))
|
|
{
|
|
ClientClose(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
//
|
|
// If this fragment header came from a reverse-endian machine
|
|
// we will have to byte swap the frag_length field...
|
|
//
|
|
if ( (header.drep[0] & ENDIAN_MASK) == 0)
|
|
{
|
|
// Big endian...swap bytes...
|
|
//
|
|
((unsigned char *) &native_length)[0] =
|
|
((unsigned char *) &header.frag_length)[1];
|
|
((unsigned char *) &native_length)[1] =
|
|
((unsigned char *) &header.frag_length)[0];
|
|
}
|
|
else
|
|
// Little endian, just like us
|
|
//
|
|
native_length = header.frag_length;
|
|
|
|
//
|
|
// Make sure buffer is big enough. If it isn't, then go back
|
|
// to the runtime to reallocate it.
|
|
//
|
|
if (native_length > *BufferLength)
|
|
{
|
|
status = I_RpcTransClientReallocBuffer (pConn,
|
|
Buffer,
|
|
0,
|
|
native_length);
|
|
if (status)
|
|
{
|
|
ClientClose(pConn);
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
*BufferLength = native_length;
|
|
//
|
|
// Read message segments until we get what we expect...
|
|
//
|
|
memcpy (*Buffer, &header, sizeof(message_header));
|
|
|
|
total_bytes = sizeof(message_header);
|
|
|
|
while (total_bytes < native_length)
|
|
{
|
|
if((bytes = recv( pConn->Socket,
|
|
(unsigned char *) *Buffer + total_bytes,
|
|
(int) (*BufferLength - total_bytes), 0)) == -1)
|
|
{
|
|
ClientClose(pConn);
|
|
return (RPC_P_RECEIVE_FAILED);
|
|
}
|
|
else
|
|
total_bytes += bytes;
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma pack(1)
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientTowerConstruct(
|
|
IN char PAPI * Endpoint,
|
|
IN char PAPI * NetworkAddress,
|
|
OUT unsigned short PAPI * Floors,
|
|
OUT unsigned long PAPI * ByteCount,
|
|
OUT unsigned char PAPI * PAPI * Tower,
|
|
IN char PAPI * Protseq
|
|
)
|
|
/*++
|
|
|
|
|
|
Routine Description:
|
|
|
|
This function constructs upper floors of DCE tower from
|
|
the supplied endpoint and network address. It returns #of floors
|
|
[lower+upper] for this protocol/transport, bytes in upper floors
|
|
and the tower [floors 4,5]
|
|
|
|
Arguments:
|
|
|
|
Endpoint- A pointer to string representation of Endpoint
|
|
|
|
NetworkAddress - A pointer to string representation of NW Address
|
|
|
|
Floors - A pointer to #of floors in the tower
|
|
|
|
ByteCount - Size of upper floors of tower.
|
|
|
|
Tower - The constructed tower returmed - The memory is allocated
|
|
by the routine and caller will have to free it.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
RPC_S_OUT_OF_MEMORY - There is no memory to return the constructed
|
|
Tower.
|
|
--*/
|
|
{
|
|
|
|
unsigned long TowerSize;
|
|
struct dn_naddr _far * dotaddress;
|
|
struct nodeent _far * hostentry;
|
|
PFLOOR Floor;
|
|
int i;
|
|
unsigned char * Port;
|
|
|
|
*Floors = DNET_TOWERFLOORS;
|
|
|
|
if (Protseq);
|
|
|
|
TowerSize = 0;
|
|
|
|
TowerSize = DNET_FLOOR3_SIZE + DNET_FLOOR4_SIZE + DNET_FLOOR5_SIZE;
|
|
|
|
if ((*Tower = (unsigned char PAPI*)I_RpcAllocate((unsigned int)
|
|
(*ByteCount = TowerSize)))
|
|
== NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Floor = (PFLOOR) *Tower;
|
|
Floor->LHSByteCount = 1;
|
|
Floor->LHSData = (unsigned char)(DNA_SESSION_CONTROL & 0xFF);
|
|
Floor->RHSByteCount = 3;
|
|
Port = (unsigned char *) &Floor->RHSData[0];
|
|
|
|
if (Endpoint == NULL || *Endpoint == '\0')
|
|
{
|
|
Endpoint = DNET_EP;
|
|
}
|
|
|
|
memcpy ( Port, Endpoint, strlen(Endpoint));
|
|
|
|
/*
|
|
* Onto the next floor...
|
|
*/
|
|
Floor = NEXTFLOOR(PFLOOR, Floor) ;
|
|
|
|
Floor->LHSByteCount = 1;
|
|
Floor->LHSData = (unsigned char)(NSP_TRANSPORT & 0xFF);
|
|
Floor->RHSByteCount = 0;
|
|
|
|
/*
|
|
* Next floor...
|
|
*/
|
|
Floor = NEXTFLOOR(PFLOOR, Floor);
|
|
|
|
Floor->LHSByteCount = 1;
|
|
Floor->LHSData = (unsigned char)(DNA_ROUTING & 0xFF);
|
|
Floor->RHSByteCount = 4;
|
|
|
|
//dotaddress = (struct dn_naddr *)&Floor->RHSData[0];
|
|
|
|
if ((NetworkAddress) && (*NetworkAddress))
|
|
{
|
|
// if (i = strcspn(NetworkAddress,".0123456789"))
|
|
// {
|
|
// dotaddress = dnet_addr((unsigned char *) NetworkAddress);
|
|
// hostentry = getnodebyaddr (dotaddress->a_addr,sizeof(short),
|
|
// AF_DECnet);
|
|
// }
|
|
// else
|
|
// hostentry = getnodebyname (NetworkAddress);
|
|
//
|
|
// memcpy (&Floor->RHSData[0],&hostentry->n_length,Floor->RHSByteCount);
|
|
Floor->RHSData[0] = 0;
|
|
Floor->RHSData[1] = 1;
|
|
Floor->RHSData[2] = 2;
|
|
Floor->RHSData[3] = 3;
|
|
}
|
|
else
|
|
{
|
|
dotaddress = 0;
|
|
}
|
|
|
|
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
|
|
)
|
|
{
|
|
/*++
|
|
|
|
|
|
Routine Description:
|
|
|
|
This function takes the protocol/transport specific floors
|
|
and returns Protseq, Endpoint and NwAddress
|
|
|
|
Note: Since ther is no need to return NW Address, currently
|
|
nothing is done for NW Address.
|
|
|
|
Arguments:
|
|
|
|
Tower - The DCE tower, upper floors
|
|
|
|
Protseq - Protocol Sequence returned- memory is allocated by the
|
|
routine and caller will have to free using I_RpcFree
|
|
|
|
Endpoitn- Endpoint returned- memory is allocated by the
|
|
routine and caller will have to free using I_RpcFree
|
|
|
|
NWAddress- Nothing is done here - just incase we need it later
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
RPC_S_OUT_OF_MEMORY - There is no memory to return the constructed
|
|
Tower.
|
|
--*/
|
|
PFLOOR Floor = (PFLOOR) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
|
|
if (Protseq != NULL)
|
|
{
|
|
*Protseq = I_RpcAllocate(strlen(DNET_PROTSEQ) + 1);
|
|
|
|
if (*Protseq == NULL)
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
else
|
|
memcpy(*Protseq, DNET_PROTSEQ, strlen(DNET_PROTSEQ) + 1);
|
|
}
|
|
|
|
if ((Endpoint == NULL) || (Status != RPC_S_OK))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
*Endpoint = I_RpcAllocate(Floor->RHSByteCount + 1);
|
|
|
|
if (*Endpoint == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
if (Protseq != NULL)
|
|
{
|
|
I_RpcFree (*Protseq);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy ( *Endpoint, &Floor->RHSData[3], Floor->RHSByteCount-3);
|
|
*(*Endpoint + (Floor->RHSByteCount-3)) = (unsigned char) 0;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO TransInfo = {
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
DNET_MAXIMUM_SEND,
|
|
sizeof (CONNECTION),
|
|
ClientOpen,
|
|
ClientClose,
|
|
ClientWrite,
|
|
ClientRead,
|
|
NULL,
|
|
ClientTowerConstruct,
|
|
ClientTowerExplode,
|
|
DNA_SESSION_CONTROL,
|
|
0
|
|
};
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO * RPC_ENTRY TransPortLoad (
|
|
IN RPC_CHAR * RpcProtocolSequence
|
|
)
|
|
|
|
// Loadable transport initialization function
|
|
|
|
{
|
|
return(&TransInfo);
|
|
}
|
|
|