/*++ Copyright (c) 1995 Microsoft Corporation Module Name: common.c Abstract: Revision History: Mazhar Mohammed Consolidated winsock transports Comments: This file contains common code for RPC transport dlls using Winsock. --*/ #include "sysinc.h" #include #include #include "rpc.h" #include "rpcdcep.h" #include "rpctran.h" #include "rpcerrp.h" #include "common.h" #include "reg.h" #define ADDRESS_FAMILY AF_NS #define ENDPOINT_LEN 5 /* for registry lookup */ PROTOCOL_MAP ProtoToLana[MAX_LANA] = { 0}; /* number of Network cards */ int NumCards; unsigned char chtob( unsigned char c1, unsigned char c2 ) /* Convert two hex digits (stored as ascii) into one byte. */ { unsigned char out; if (c1 >= '0' && c1 <= '9') out = (c1 - '0') << 4; else { if (c1 >= 'a' && c1 <= 'f') out = (c1 - 'a' + 10) << 4; else if (c1 >= 'A' && c1 <= 'F') out = (c1 - 'A' + 10) << 4; else out = 0; } if (c2 >= '0' && c2 <= '9') out |= c2 -'0'; else { if (c2 >= 'a' && c2 <= 'f') out |= c2 - 'a' + 10; else if (c2 >= 'A' && c2 <= 'F') out |= c2 - 'A' + 10; else out = 0; } return out; } int tcp_get_host_by_name( SOCKET socket, void *netaddr, char *host) { UNALIGNED struct sockaddr_in *server = netaddr; UNALIGNED struct hostent *phostentry; unsigned long host_addr; if (*host == '\0') { // An empty hostname means to RPC to the local machine host_addr = LOOPBACK; } else { // Assume a numeric address host_addr = inet_addr(host); if (host_addr == -1) { // Try a friendly name phostentry = gethostbyname(host); if (phostentry == (struct hostent *)NULL) { return (RPC_S_SERVER_UNAVAILABLE); } else { host_addr = *(unsigned long *)phostentry->h_addr; } } } memcpy((char *) &server->sin_addr, (unsigned char *) &host_addr, sizeof(unsigned long)); return 0; } RPC_STATUS MapStatusCode( int SocketError, RPC_STATUS Default ) /*++ Routine Description: Maps a winsock return value into a RPC_STATUS. Right now, any winsock error is an internal error. Arguments: ErrorCode - Input error code. Return Value: mapped status code --*/ { RPC_STATUS Status; switch (SocketError) { case 0: { Status = RPC_S_OK; break; } case WSAETIMEDOUT: { Status = RPC_P_TIMEOUT; break; } case WSAENOBUFS: { Status = RPC_S_OUT_OF_MEMORY; break; } case WSAEMSGSIZE: { Status = RPC_P_OVERSIZE_PACKET; break; } default: { #ifdef DEBUGRPC PrintToDebugger("RPC DG: Winsock error %d\n", SocketError); #endif Status = Default; } } return Status; } // we need to have a common transport load module (no protocol specific ifdefs in here) BOOL SpxCacheInitialized = FALSE; RPC_CLIENT_TRANSPORT_INFO PAPI * RPC_ENTRY TransportLoad ( IN RPC_CHAR PAPI * RpcProtocolSequence ) // Loadable transport initialization function { WSADATA WsaData; SOCKET Socket; static int initialized = 0 ; int Status ; UNUSED (RpcProtocolSequence); if(!initialized) { RpcTryExcept { Status = WSAStartup( 0x0101, &WsaData ) ; } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { Status = ERROR_OUTOFMEMORY ; } RpcEndExcept if ( Status != NO_ERROR ) { return NULL; } #ifdef NTENV InitialNtRegistry(); #endif initialized = 1 ; } // check if the string is in UNICODE if (RpcpStringCompare(RpcProtocolSequence, RPC_CONST_STRING("ncacn_spx")) == 0) { //For SPX we do this to avoid a bizzare deadlock Socket = socket(ADDRESS_FAMILY, SOCK_STREAM, NSPROTO_SPXII); if (Socket == INVALID_SOCKET) { return (NULL); } closesocket(Socket); if (FALSE == SpxCacheInitialized) { RPC_STATUS Status = InitializeSpxCache(); if (Status) { return 0; } SpxCacheInitialized = TRUE; } return (&SPX_TransInfo) ; } if (RpcpStringCompare(RpcProtocolSequence, RPC_CONST_STRING("ncacn_ip_tcp")) == 0) { return (&TCP_TransInfo) ; } #ifdef NTENV if (RpcpStringCompare(RpcProtocolSequence, RPC_CONST_STRING("ncacn_at_dsp")) == 0) { return(&ADSP_TransInfo) ; } #endif #if 0 if (RpcpStringCompare(RpcProtocolSequence, RPC_CONST_STRING("ncacn_np")) == 0) { return (&NP_TransInfo) ; } #endif #if defined(NTENV) || defined(WIN96) if (RpcpStringCompare(RpcProtocolSequence, RPC_CONST_STRING("ncadg_ipx")) == 0) { return IpxTransportLoad(); } if (RpcpStringCompare(RpcProtocolSequence, RPC_CONST_STRING("ncadg_ip_udp")) == 0) { return UdpTransportLoad(); } #ifndef WIN96 if (RpcpStringNCompare(RpcProtocolSequence, RPC_CONST_STRING("ncacn_nb"), 8) == 0) { return ((RPC_CLIENT_TRANSPORT_INFO PAPI *) &NB_TransInfo) ; } #endif // !WIN96 #endif // NTENV || WIN96 ASSERT(0) ; return NULL ; } void unicode_to_ascii ( RPC_CHAR * in, unsigned char * out ) { unsigned char *ascii_ptr; RPC_CHAR *unicode_ptr; ascii_ptr = out; unicode_ptr = in; *ascii_ptr = (unsigned char) *unicode_ptr ; while (1) { if (*ascii_ptr == 0) return; ascii_ptr++; unicode_ptr++; *ascii_ptr = (unsigned char) *unicode_ptr; } } void InitialNtRegistry( ) /*++ Routine Description: This information is automatically generated by NT setup and the Networks Control Panel applet. Because it can change dynamically, we load it all at once to achieve consistent data. Arguments: None ReturnValue: None --*/ { HKEY RegHandle; LONG status; int i; char protseq[64]; DWORD protseq_len; DWORD lana; DWORD lana_len; DWORD data_type; char * LanaString ; int LanaNum; // Return immediately if the table is already initialized. if (ProtocolTable[0].ProtoSeq) { return; } NumCards = 0; // Open the registry key for RPC NetBIOS information status = RegOpenKeyExA(RPC_REG_ROOT, REG_NETBIOS, 0, KEY_READ, &RegHandle); ASSERT(!status); if (status) { return; } for (i = 0; !status && i < MAX_LANA; i++) { protseq_len = sizeof(protseq); lana_len = sizeof(lana); status = RegEnumValueA(RegHandle, i, protseq, &protseq_len, NULL, &data_type, (LPBYTE) &lana, &lana_len); if (!status && data_type == REG_DWORD && lana <= MAX_LANA) { ProtocolTable[i].ProtoSeq = I_RpcAllocate(protseq_len + 1); ASSERT(ProtocolTable[i].ProtoSeq); if (! ProtocolTable[i].ProtoSeq) { status = RPC_S_OUT_OF_RESOURCES; } else { strcpy(ProtocolTable[i].ProtoSeq, protseq); ProtocolTable[i].Lana = (unsigned char) lana; LanaString = protseq + strlen(protseq) -1; LanaNum = atoi(LanaString); #ifdef TONY PrintToDebugger("RPCLTSCM: the current lana examinging is %d \n" , LanaNum); #endif /* find out how many cards we have */ if(NumCards < LanaNum) { NumCards = LanaNum; } } } else { ASSERT(status == ERROR_NO_MORE_ITEMS); } } RegCloseKey(RegHandle); return; } RPC_STATUS MapProtocol( IN RPC_CHAR *ProtoSeq, IN int DriverNumber, OUT PPROTOCOL_MAP *ProtocolEntry ) /*++ Routine Description: This function maps a protocol string into a protocol map entry. Arguments: ProtoSeq - the protocol sequence that we want to map DriverNumber - the logical driver number for the protocol. ProtocolEntry - pointer to place to return the results. Return Value: RPC_S_OK, RPC_S_OUT_OF_RESOURCES, RPC_S_INVALID_ENDPOINT_FORMAT The output pointer is set to the corresponding entry when found. --*/ { long status; char Protocol[40]; char LanaString[10]; long BufferLength = sizeof(LanaString); int i; // Copy the possible unicode protocol string to ascii. for (i = 0; (Protocol[i] = (char) ProtoSeq[i]) && i < sizeof(Protocol); i++) ; // Add the logical driver number to the protocol string. This // allows multiple drivers (net cards) to be attached to the same // logical protocol. Protocol[i] = (char) ('0' + DriverNumber); Protocol[i+1] = 0; // First look in the proto sequences that we have already mapped. for (i = 0; ProtocolTable[i].ProtoSeq && i < MAX_LANA; i++) { // If found, set the output pointer. if (strcmp(ProtocolTable[i].ProtoSeq, Protocol) == 0) { *ProtocolEntry = &ProtocolTable[i]; return(RPC_S_OK); } } return(RPC_S_PROTSEQ_NOT_FOUND); }