|
|
/* --------------------------------------------------------------------
File : nbltclnt.c
Title : client loadable transport for Windows NT NetBIOS - client side
Description :
History :
19-1-95 Tony Chan Use winsock to support NetBIOS
WITH SEQ_NUMBER
Compatibility issue In order to be compatible with the old NetBIOS server transport, If the first DWORD of the packet is 0, we know that it's a old NetBIOS client connection. Therefore, we will take away the seq # and return only the data to the runtime. If the first DWORD of the first message is not 0, it's actually is the runtime message_header RPC_version #, so we hand the whole buffer to the runtime. If we are dealing with old server, on all subsequence Send, we need to prepend seq_number, and we need to take away sequence # on all recv from old client
-------------------------------------------------------------------- */
/*
OLD_CLIENT: if define old client, this transport will behave as an old client otherwise it will behave as a new client without sending out sequence number.
*/
#define OLD_CLIENT 1
#include "sysinc.h"
#define FD_SETSIZE 1
#include <winsock.h>
#include <tdi.h>
// NetBIOS winsock header file
#include <wsnetbs.h>
#include <winbase.h>
#include <stdlib.h>
#include "rpc.h"
#include "rpcdcep.h"
#include "rpctran.h"
#include "rpcerrp.h"
#include "common.h"
#include "reg.h" /* registry lookup rountine */
/*
Following Macros and structs are needed for Tower Stuff */
#pragma pack(1)
#define NB_TRANSPORTID 0x12
#define NB_NBID 0x13
#define NB_XNSID 0x15
#define NB_IPID 0x09
#define NB_IPXID 0x0d
#define NB_TOWERFLOORS 5
#define NB_PROTSEQ "ncacn_nb_nb"
#define IP_PROTSEQ "ncacn_nb_tcp"
#define IPX_PROTSEQ "ncacn_nb_ipx"
typedef struct _FLOOR_234 { unsigned short ProtocolIdByteCount; unsigned char FloorId; unsigned short AddressByteCount; unsigned char Data[2]; } FLOOR_234, __RPC_FAR * PFLOOR_234;
#define NEXTFLOOR(t,x) (t)((unsigned char __RPC_FAR *)x +((t)x)->ProtocolIdByteCount\
+ ((t)x)->AddressByteCount\ + sizeof(((t)x)->ProtocolIdByteCount)\ + sizeof(((t)x)->AddressByteCount))
/*
End of Tower Stuff! */
#define ENDIAN_MASK 16
#define ENDPOINT_LEN 3
#define PFC_FIRST_FRAG 0x01
typedef struct { SOCKET Socket; char PAPI * Buffer; fd_set SockSet; BOOL LocalRpc; #ifdef OLD_CLIENT
int seq_num; /* for the old client case */ #endif
} CONNECTION, *PCONNECTION;
#define NB_OK 0
#define NB_CONTINUE 1
#define NB_FAIL 2
extern int NumCards; /* defined in reg.h */
int CreateAndSetupNBSocket ( IN PCONNECTION pConn, IN RPC_CHAR PAPI *RpcProtocolSequence, IN char PAPI *HostName, IN int PortIn, IN int CardIndex ) { PPROTOCOL_MAP ProtocolEntry; SOCKADDR_NB server ; int Status; BOOL reuse; /* for socket option */
if (Status = MapProtocol(RpcProtocolSequence, CardIndex, &ProtocolEntry)) { return NB_CONTINUE ; }
// Get a socket, the PROTOCOL
// is defined to be (-1 * LANA numbmer)
if ((pConn->Socket = socket(AF_NETBIOS, SOCK_SEQPACKET , -1 * (ProtocolEntry->Lana))) == INVALID_SOCKET) { #ifdef DEBUGRPC
PrintToDebugger( "%s: socket - %d\n", "rpcltccm - NB", WSAGetLastError() ); #endif
return(NB_FAIL); }
reuse = TRUE; setsockopt(pConn->Socket, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(BOOL));
// setup server sockaddr
server.snb_family = AF_NETBIOS; SET_NETBIOS_SOCKADDR((&server), NETBIOS_UNIQUE_NAME, HostName, (char ) PortIn);
// try to connect
if (connect(pConn->Socket, (struct sockaddr *) &server, sizeof (server)) == SOCKET_ERROR) { #ifdef DEBUGRPC
PrintToDebugger( "%s: Connect - %d to port %d\n", "rpcltccm - NB", WSAGetLastError(), PortIn ); #endif
closesocket(pConn->Socket); pConn->Socket = 0;
return(NB_CONTINUE); }
return NB_OK ; }
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
{ SOCKADDR_NB server; /* sock address for server */ size_t hostNameLen; /* length of the host name */
unsigned char remotehostname[NETBIOS_NAME_LENGTH+1];
unsigned char port[ENDPOINT_LEN+1]; /* port number in string format */ int status; int i; unsigned int PortIn; /* port in integer format */ PPROTOCOL_MAP ProtocolEntry;
UNUSED(NetworkAddress); UNUSED(NetworkOptions); UNUSED(TransportAddress); UNUSED(RpcProtocolSequence); UNUSED(Timeout);
if (RpcpStringLength(NetworkAddress) > NETBIOS_NAME_LENGTH) { return (RPC_S_INVALID_NET_ADDR) ; }
#ifdef NTENV
if(RpcpStringLength(Endpoint) != wcsspn(Endpoint, RPC_CONST_STRING("0123456789"))) #else
if(RpcpStringLength(Endpoint) != strspn(Endpoint, RPC_CONST_STRING("0123456789"))) #endif // #ifdef NTENV
{ return(RPC_S_INVALID_ENDPOINT_FORMAT); }
if(RpcpStringLength(Endpoint) > ENDPOINT_LEN) { return(RPC_S_INVALID_ENDPOINT_FORMAT); }
// Convert the endpoint string to a number and validate.
unicode_to_ascii (Endpoint, port); PortIn = atoi(port);
if((PortIn == 0) ||( PortIn >= 255) ) { return(RPC_S_INVALID_ENDPOINT_FORMAT); } /* setup hostname */
unicode_to_ascii (NetworkAddress, remotehostname); if ( remotehostname[0] == '\0') { pConn->LocalRpc = TRUE; hostNameLen = MAX_COMPUTERNAME_LENGTH + 1; GetComputerName(remotehostname, &hostNameLen); }
_strupr(remotehostname); /* conver to upper case for netbios */
for (i = 0; i <=NumCards; i++) { status = CreateAndSetupNBSocket( pConn, RpcProtocolSequence, remotehostname, PortIn, i) ; if (status == NB_CONTINUE) { continue; }
if (status != NB_OK) { return RPC_S_SERVER_UNAVAILABLE ; }
break; }
if (status != NB_OK) { return RPC_S_SERVER_UNAVAILABLE ; }
// got the connection
#ifdef OLD_CLIENT
pConn->seq_num = 0; /* init seq number */ #endif
return(RPC_S_OK); }
RPC_STATUS RPC_ENTRY ClientClose ( IN PCONNECTION pConn )
// Close a client connection
{ closesocket(pConn->Socket); pConn->Socket = 0; return (RPC_S_OK); }
RPC_STATUS RPC_ENTRY ClientSend ( IN PCONNECTION pConn, IN void PAPI * Buffer, IN unsigned int BufferLength ) {
int bytes; int total_bytes = 0; int Status; unsigned long PrevTicks;
#ifdef OLD_CLIENT
/* structure to support seq number */ typedef struct a_BufferWithSeq { DWORD seq_num; char Buffer[5280];
} t_BufferWithSeq;
t_BufferWithSeq BufferWithSeq ;
ASSERT(BufferLength <= 5280); BufferWithSeq.seq_num = pConn->seq_num; memcpy(&(BufferWithSeq.Buffer), Buffer, BufferLength); bytes = send(pConn->Socket, (char *) & BufferWithSeq, (int) sizeof(DWORD) + BufferLength, 0);
if (bytes != (int) (BufferLength + sizeof(DWORD))) { ClientClose ( pConn ); return(RPC_P_SEND_FAILED); } pConn->seq_num++; #else
ASSERT(BufferLength <= 5280); bytes = send(pConn->Socket, (char *) Buffer, (int) BufferLength, 0); if (bytes != (int) BufferLength ) { ClientClose ( pConn ); return(RPC_P_SEND_FAILED); }
#endif
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 = RPC_S_OK; int bytes; unsigned int totalBytes = 0; int err; /* for error message */ int flags; int retry ; /* reset seq number once receive */ pConn->seq_num = 0;
if (*Buffer == 0) { *BufferLength = 1024; RpcStatus = I_RpcTransClientReallocBuffer(pConn, Buffer, 0, *BufferLength); if (RpcStatus != RPC_S_OK) { return(RPC_S_OUT_OF_MEMORY); } }
retry = 1;
while(1) { flags = 0; bytes = WSARecvEx( pConn->Socket, (char *)*Buffer + totalBytes, *BufferLength - totalBytes, &flags);
if (bytes <= 0 ) // if connection close, bytes will = 0, we need to close connection
{ #ifdef DEBUGRPC
PrintToDebugger("rpcltccm - NB: bad client receive lasterr(%d) \n", WSAGetLastError()); #endif
ClientClose(pConn); return(RPC_P_RECEIVE_FAILED); }
totalBytes += bytes;
if(flags & MSG_PARTIAL) { if (retry == 0) { #ifdef DEBUGRPC
PrintToDebugger("rpcltccm - NB: twice client receive lasterr(%d) \n", WSAGetLastError()); #endif
ClientClose(pConn); return(RPC_P_RECEIVE_FAILED); }
*BufferLength = I_RpcTransClientMaxFrag(pConn); RpcStatus = I_RpcTransClientReallocBuffer(pConn, Buffer, totalBytes, *BufferLength); if (RpcStatus != RPC_S_OK) { #ifdef DEBUGRPC
PrintToDebugger("rpcltccm - NB: bad client receive \n"); #endif
return(RPC_S_OUT_OF_MEMORY); }
retry = 0;
} else {
*BufferLength = totalBytes; return(RPC_S_OK);
} } ASSERT(0); 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; UNALIGNED PFLOOR_234 Floor; unsigned long HostId;
//BUGBUG: Need appropriate error code for unsupported Protseqs
if (strcmp(Protseq,NB_PROTSEQ) == 0) HostId = NB_NBID; else if (strcmp(Protseq, IP_PROTSEQ) == 0) HostId = NB_IPID; else if (strcmp(Protseq, IPX_PROTSEQ) == 0) HostId = NB_IPXID; else return (RPC_S_OUT_OF_MEMORY);
*Floors = NB_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 __RPC_FAR*)I_RpcAllocate((unsigned int) (*ByteCount = TowerSize))) == NULL) { return (RPC_S_OUT_OF_MEMORY); }
Floor = (PFLOOR_234) *Tower;
Floor->ProtocolIdByteCount = 1; Floor->FloorId = (unsigned char)(NB_TRANSPORTID & 0xFF); if ((Endpoint) && (*Endpoint)) { memcpy((char __RPC_FAR *)&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)(HostId & 0xFF); if ((NetworkAddress) && (*NetworkAddress)) { memcpy((char __RPC_FAR *)&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 * 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; char __RPC_FAR * Pseq;
UNUSED(NetworkAddress);
if (Endpoint != NULL) {
*Endpoint = I_RpcAllocate(Floor->AddressByteCount); if (*Endpoint == NULL) { Status = RPC_S_OUT_OF_MEMORY; } else { memcpy(*Endpoint, (char __RPC_FAR *)&Floor->Data[0], Floor->AddressByteCount); } }
Floor = NEXTFLOOR(PFLOOR_234, Floor);
switch (Floor->FloorId) {
case NB_NBID: Pseq = NB_PROTSEQ; break;
case NB_IPID: Pseq = IP_PROTSEQ; break;
case NB_IPXID: Pseq = IPX_PROTSEQ; break;
default: return(RPC_S_OUT_OF_MEMORY);
}
if ((Protseq != NULL) && (Status == RPC_S_OK)) { *Protseq = I_RpcAllocate(strlen(Pseq) + 1); if (*Protseq == NULL) { Status = RPC_S_OUT_OF_MEMORY; if (Endpoint != NULL) I_RpcFree(*Endpoint);
} else { memcpy(*Protseq, Pseq, strlen(Pseq) + 1); } }
return(Status);
}
#pragma pack()
RPC_CLIENT_TRANSPORT_INFO NB_TransInfo = { RPC_TRANSPORT_INTERFACE_VERSION, NB_TRANSPORTID,
ClientTowerConstruct, ClientTowerExplode,
5280, sizeof (CONNECTION),
ClientOpen, ClientClose, ClientSend, ClientRecv, NULL, NULL,
NULL, NULL };
|