Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1258 lines
28 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
dgudpc.cxx
Abstract:
This is the UDP datagram client dll.
Author:
Dave Steckler (davidst) 15-Mar-1993
Revision History:
--*/
#include <sysinc.h>
#define FD_SETSIZE 1
#include <rpc.h>
#include <rpcdcep.h>
#include <winsock.h>
#ifdef IPX
#include <wsipx.h>
#include <wsnwlink.h>
#include <nspapi.h>
#endif
#include <rpcerrp.h>
#include <rpctran.h>
#include <stdlib.h>
#ifdef ENABLE_FACK_BODIES
#define MAX_PDU (1514)
#else
#define MAX_PDU 1024
#endif
#define ENDPOINT_LEN 6
#ifdef IPX
#define NETADDR_LEN 22
#define MAX_HOSTNAME_LEN 22
#define ADDRESS_FAMILY AF_IPX
#define PROTOCOL NSPROTO_IPX
#else
#define ADDRESS_FAMILY AF_INET
#define PROTOCOL 0
#define MAX_HOSTNAME_LEN 32
//
// Host name won't be bigger than 15, i.e.,
// nnn.nnn.nnn.nnn
//
#define NETADDR_LEN 15
#endif
#ifdef IPX
/* For some reason, getsockname wants to return more then sizeof(SOCKADDR_IPX)
bytes. bugbug. */
typedef union SOCKADDR_FIX
{
SOCKADDR_IPX s;
struct sockaddr unused;
} SOCKADDR_FIX;
typedef struct
{
CSADDR_INFO info;
SOCKADDR_FIX addr1;
SOCKADDR_FIX addr2;
} CSADDR_BUFFER;
#endif
/*
These are Transport Specific ENDPOINTS and ADDRESS
Runtime has allocated a chuck of memory and as far as runtime is
concerned this is opaque data that transport uses in transport
specific way!
*/
typedef struct {
int Socket;
fd_set Set;
} DG_UDP_ENDPOINT;
unsigned long LargestPacketSize = MAX_PDU;
typedef DG_UDP_ENDPOINT * PDG_UDP_ENDPOINT;
typedef struct {
#ifdef IPX
SOCKADDR_FIX ServerAddress;
#else
struct sockaddr_in ServerAddress;
#endif
BOOL ServerLookupFailed;
} DG_UDP_ADDRESS;
typedef DG_UDP_ADDRESS * PDG_UDP_ADDRESS;
#define DG_UDP_TRANSPORT_VERSION 1
#pragma pack(1)
#ifdef IPX
#define TRANSPORTID 0x0e
#define TRANSPORTHOSTID 0x0d
#define TOWERFLOORS 5
/*Endpoint = 2 bytes, HostId = 10 bytes*/
#define TOWEREPSIZE 10
#define TOWERSIZE (TOWEREPSIZE+2)
#define PROTSEQ "ncadg_ipx"
#define ENDPOINT_MAPPER_EP "34280"
#define MAX_ENDPOINT_SIZE 8
#else
#define TRANSPORTID 0x08
#define TRANSPORTHOSTID 0x09
#define TOWERFLOORS 5
/*Endpoint = 2 bytes, HostId = 4 bytes*/
#define TOWEREPSIZE 4
#define TOWERSIZE (TOWEREPSIZE+2)
#define PROTSEQ "ncadg_ip_udp"
#define ENDPOINT_MAPPER_EP "135"
#define MAX_ENDPOINT_SIZE 6
#endif
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))
#define ByteSwapLong(Value) \
Value = ( (((unsigned long) (Value) & 0xFF000000) >> 24) \
| (((unsigned long) (Value) & 0x00FF0000) >> 8) \
| (((unsigned long) (Value) & 0x0000FF00) << 8) \
| (((unsigned long) (Value) & 0x000000FF) << 24))
#define ByteSwapShort(Value) \
Value = ( (((unsigned short) (Value) & 0x00FF) << 8) \
| (((unsigned short) (Value) & 0xFF00) >> 8))
/*
End of Tower Stuff!
*/
#pragma pack()
#define LOOPBACK (htonl(INADDR_LOOPBACK))
#ifdef IPX
GUID SERVICE_TYPE = { 0x000b0640, 0, 0, { 0xC0,0,0,0,0,0,0,0x46 } };
#endif
#ifdef IPX
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;
}
// This routine takes a host name or address as a string and returns it
// as a SOCKADDR_IPX structure. It accepts a NULL string for the local
// host address. This routine works for IPX addresses.
int my_get_host_by_name(
SOCKET socket,
void *netaddr,
char *host
)
{
// Allocate extra some extra space.
CSADDR_BUFFER csaddr[2];
int num;
int length;
DWORD protocol_list[2];
DWORD csaddr_size = sizeof(csaddr);
SOCKADDR_FIX *ipx = netaddr;
int i;
// Verify the length of the host name.
length = strlen(host);
// If no address was specified, look up the local address.
if (length == 0)
{
length = sizeof ( SOCKADDR_FIX );
if (getsockname ( socket, (struct sockaddr *) netaddr, &length ))
return ( RPC_S_SERVER_UNAVAILABLE );
}
// If the name starts with ~, convert it directly to a network address.
else if (host[0] == '~')
{
if (length != 21)
return RPC_S_SERVER_UNAVAILABLE;
for (i = 0; i < 4; i++)
ipx->s.sa_netnum[i] = chtob( host[2*i + 1], host[2*i + 2] );
for (i = 0; i < 6; i++)
ipx->s.sa_nodenum[i] = chtob( host[2*i + 9], host[2*i + 10] );
}
// Quit if the name is too long.
else if (length > MAX_HOSTNAME_LEN)
return RPC_S_SERVER_UNAVAILABLE;
// If a name was passed, look it up in the SAP service.
else
{
// Get address.
protocol_list[0] = PROTOCOL;
protocol_list[1] = 0;
num = GetAddressByName( NS_SAP, &SERVICE_TYPE, host, protocol_list,
0, FALSE, &csaddr, &csaddr_size,
NULL, 0 );
if (num <= 0)
{
// PrintToDebugger( "GetAddressByName failed 0x%x\n", WSAGetLastError() );
return RPC_S_SERVER_UNAVAILABLE;
}
// Copy the address.
memcpy( netaddr, csaddr[0].info.RemoteAddr.lpSockaddr, sizeof(SOCKADDR_FIX) );
}
return RPC_S_OK;
}
#endif
RPC_STATUS
MapStatusCode(
int SocketError,
RPC_STATUS Default
)
/*++
Routine Description:
Maps a winsock return value into a RPC_STATUS.
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;
}
RPC_STATUS
AssignLocalEndpoint(
IN void * Endpoint
)
/*++
Routine Description:
Ask transport for a new endpoint.
Arguments:
Return Value:
RPC_S_OK
--*/
{
BOOL SetSocketOptions;
int PacketType;
//
// Create a socket.
//
PDG_UDP_ENDPOINT TransportEndpoint = (PDG_UDP_ENDPOINT) Endpoint;
TransportEndpoint->Socket = socket(ADDRESS_FAMILY, SOCK_DGRAM, PROTOCOL);
if (TransportEndpoint->Socket == INVALID_SOCKET)
{
return (MapStatusCode(WSAGetLastError(), RPC_S_CALL_FAILED_DNE) );
}
#ifdef IPX
// Use packet type 4.
PacketType = 4;
if (setsockopt(
TransportEndpoint->Socket,
NSPROTO_IPX,
IPX_PTYPE,
(char *) &PacketType,
sizeof(PacketType)) != 0)
{
closesocket(TransportEndpoint->Socket);
return(RPC_S_CALL_FAILED_DNE);
}
#endif
//Enable broadcasts by default .. on this socket
//We may change this later - to do broadcasts by demand
SetSocketOptions = TRUE;
if (setsockopt(
TransportEndpoint->Socket,
SOL_SOCKET,
SO_BROADCAST,
(char *)&SetSocketOptions,
sizeof(SetSocketOptions)) != 0)
{
closesocket(TransportEndpoint->Socket);
return(RPC_S_CALL_FAILED_DNE);
}
SetSocketOptions = 1000L; //1 sec
if (setsockopt(
TransportEndpoint->Socket,
SOL_SOCKET,
SO_RCVTIMEO,
(char *)&SetSocketOptions,
sizeof(SetSocketOptions)) != 0)
{
closesocket(TransportEndpoint->Socket);
return(RPC_S_CALL_FAILED_DNE);
}
FD_ZERO(&(TransportEndpoint->Set));
FD_SET(TransportEndpoint->Socket, &(TransportEndpoint->Set));
return(RPC_S_OK);
}
RPC_STATUS
FreeLocalEndpoint(
IN void * Endpoint
)
/*++
Routine Description:
Frees an endpoint
Arguments:
Return Value:
RPC_S_OK
--*/
{
//We wont free the memory as the runtime will do that
//We just do the transport related stuff
PDG_UDP_ENDPOINT TransportEndpoint = (PDG_UDP_ENDPOINT)Endpoint;
closesocket(TransportEndpoint->Socket);
return(RPC_S_OK);
}
RPC_STATUS
ReceivePacket(
IN void * TransportEndpoint,
IN void * Buffer,
IN unsigned long * BufferLength,
IN unsigned long Timeout,
IN void * SenderAddress
)
/*++
Routine Description:
Receives a packet from the network.
Arguments:
pPack - Packet to receive into.
Timeout - Timeout in seconds.
Return Value:
RPC_S_OK
RPC_P_TIMEOUT
<return from WaitForSingleObject or MapStatusCode>
--*/
{
PDG_UDP_ENDPOINT Endpoint = (PDG_UDP_ENDPOINT)TransportEndpoint;
int SockStatus;
int BytesReceived;
struct timeval TimeoutVal;
int DummyLen = sizeof(struct sockaddr);
//
// Receive something on our socket.
//
//
// By default the socket we have setup will wait
// for 1 sec [default timeout] for a packet.
// If timeout is greater than 1 sec we need to force a select
// In the common case we just go and do a recvfrom and avoid the
// hit of doing a select followed by a recv
if (Timeout > 1)
{
TimeoutVal.tv_sec = Timeout;
TimeoutVal.tv_usec = 0;
//
// Wait for our socket to be receivable.
//
SockStatus = select(
1,
&(Endpoint->Set),
0,
0,
&TimeoutVal
);
if (SockStatus == 0)
{
FD_SET(Endpoint->Socket, &(Endpoint->Set));
return RPC_P_TIMEOUT;
}
#if DBG
if (SockStatus < 0)
{
PrintToDebugger("select returned %d \n", SockStatus);
}
#endif
ASSERT(FD_ISSET(Endpoint->Socket, &(Endpoint->Set)));
}
BytesReceived = recvfrom(
Endpoint->Socket,
(char *)Buffer,
(int)LargestPacketSize,
0,
SenderAddress,
&DummyLen
);
//
// Did we get something?
//
if ((BytesReceived == SOCKET_ERROR) || (BytesReceived == 0))
{
return MapStatusCode(WSAGetLastError(), RPC_P_RECEIVE_FAILED);
}
*BufferLength = BytesReceived;
return RPC_S_OK;
}
RPC_CHAR MaxEndpoint[] = { '6', '5', '5', '3', '5', '\0' };
#ifdef IPX
RPC_STATUS
RegisterServerAddress(
IN void * pClientCall,
IN RPC_CHAR * pServer,
IN RPC_CHAR * pEndpoint,
OUT void PAPI * PAPI * ppTransAddress
)
/*++
Routine Description:
Registers a new call with the transport. This informs the transport that
data is about to be sent and received on this address to and from
the server/endpoint. This routine returns a 'transport address' through
which the sending and receiving will be accomplished.
This routine serves mainly as a psuedo-constructor for a
DG_UDP_CLIENT_TRANSPORT object, where all the real work occurs.
Arguments:
pClientCall - A pointer to the protocol's DG_CCALL object for this call.
This is defined as a 'void *' instead of a PDG_CCALL because we don't
want to have to include (and link in) all the stuff associated
with DG_CCALL (including DCE_BINDING, BINDING_HANDLE, MESSAGE_OBJECT,
etc.)
pServer - Name of the server we are talking with.
pEndpoint - Endpoint on that server.
ppTransAddress - Where to place a pointer to a new transport address
which the protocol will use to identify the socket
we are using.
Return Value:
RPC_S_OK
RPC_S_OUT_OF_MEMORY
<return from construction of DG_UDP_CLIENT_TRANS_ADDRESS>
--*/
{
int Endpoint;
int EndpointLength;
int i;
int length;
SOCKET dummy;
SOCKADDR_FIX dummy_address;
PDG_UDP_ADDRESS pdgAddress = (PDG_UDP_ADDRESS) *ppTransAddress ;
RPC_STATUS status;
UNICODE_STRING UServer;
UNICODE_STRING UEndpoint;
ANSI_STRING AServer;
ANSI_STRING AEndpoint;
NTSTATUS NtStatus;
if (*ppTransAddress == NULL)
{
return RPC_S_OUT_OF_MEMORY;
}
pdgAddress->ServerLookupFailed = TRUE;
//
// convert the endpoint to a number.
//
EndpointLength = RpcpStringLength(pEndpoint);
if (EndpointLength > 5 ||
(EndpointLength == 5 && RpcpStringCompare(pEndpoint, MaxEndpoint) > 0))
{
return RPC_S_INVALID_ENDPOINT_FORMAT;
}
for (i=0, Endpoint=0 ; i< EndpointLength ; i++)
{
if ( ((char)pEndpoint[i] >= '0') && ((char)pEndpoint[i] <= '9'))
{
Endpoint *= 10;
Endpoint += (char)pEndpoint[i]-'0';
}
else
{
return RPC_S_INVALID_ENDPOINT_FORMAT;
}
}
// Get a socket in case my_get_address_by_name needs to look up the local
// address.
memset( &dummy_address, 0, sizeof(dummy_address) );
dummy_address.s.sa_family = ADDRESS_FAMILY;
dummy = socket( ADDRESS_FAMILY, SOCK_DGRAM, PROTOCOL );
if (dummy == INVALID_SOCKET)
return RPC_S_OK;
length = sizeof ( pdgAddress->ServerAddress );
if (bind( dummy, &dummy_address.unused, length ) != 0)
return RPC_S_OK;
// Find the address.
RtlInitUnicodeString(&UServer,pServer);
RtlInitUnicodeString(&UEndpoint,pEndpoint);
AServer.Buffer = NULL;
AEndpoint.Buffer = NULL;
NtStatus = RtlUnicodeStringToAnsiString(&AServer,&UServer,TRUE);
if (NT_SUCCESS(NtStatus))
{
NtStatus = RtlUnicodeStringToAnsiString(&AEndpoint,&UEndpoint,TRUE);
if (NT_SUCCESS(NtStatus))
{
status = my_get_host_by_name(dummy,
&pdgAddress->ServerAddress,
AServer.Buffer
);
if (status == RPC_S_OK)
pdgAddress->ServerLookupFailed = FALSE;
}
}
RtlFreeAnsiString(&AServer);
RtlFreeAnsiString(&AEndpoint);
closesocket( dummy );
pdgAddress->ServerAddress.s.sa_family = ADDRESS_FAMILY;
pdgAddress->ServerAddress.s.sa_socket = htons((unsigned short) Endpoint);
return RPC_S_OK;
}
#else
RPC_STATUS
RegisterServerAddress(
IN void * pClientCall,
IN RPC_CHAR * pServer,
IN RPC_CHAR * pEndpoint,
OUT void PAPI * PAPI * ppTransAddress
)
/*++
Routine Description:
Registers a new call with the transport. This informs the transport that
data is about to be sent and received on this address to and from
the server/endpoint. This routine returns a 'transport address' through
which the sending and receiving will be accomplished.
This routine serves mainly as a psuedo-constructor for a
DG_UDP_CLIENT_TRANSPORT object, where all the real work occurs.
Arguments:
pClientCall - A pointer to the protocol's DG_CCALL object for this call.
This is defined as a 'void *' instead of a PDG_CCALL because we don't
want to have to include (and link in) all the stuff associated
with DG_CCALL (including DCE_BINDING, BINDING_HANDLE, MESSAGE_OBJECT,
etc.)
pServer - Name of the server we are talking with.
pEndpoint - Endpoint on that server.
ppTransAddress - Where to place a pointer to a new transport address
which the protocol will use to identify the socket
we are using.
Return Value:
RPC_S_OK
RPC_S_OUT_OF_MEMORY
<return from construction of DG_UDP_CLIENT_TRANS_ADDRESS>
--*/
{
RPC_STATUS Status;
int EndpointLength;
int ServerLength;
int i;
char * pCharServerName;
struct hostent *pHostEntry;
int Endpoint;
PDG_UDP_ADDRESS pdgAddress = (PDG_UDP_ADDRESS) *ppTransAddress ;
unsigned long HostAddr;
if (*ppTransAddress == NULL)
{
return RPC_S_OUT_OF_MEMORY;
}
pdgAddress->ServerLookupFailed = FALSE;
//
// convert the endpoint to a number.
//
EndpointLength = RpcpStringLength(pEndpoint);
if (EndpointLength > 5 ||
(EndpointLength == 5 && RpcpStringCompare(pEndpoint, MaxEndpoint) > 0))
{
return RPC_S_INVALID_ENDPOINT_FORMAT;
}
for (i=0, Endpoint=0 ; i< EndpointLength ; i++)
{
if ( ((char)pEndpoint[i] >= '0') && ((char)pEndpoint[i] <= '9'))
{
Endpoint *= 10;
Endpoint += (char)pEndpoint[i]-'0';
}
else
{
return RPC_S_INVALID_ENDPOINT_FORMAT;
}
}
//
// Put our server name in a character array (instead of wchar)
//
if ((pServer == NULL) || (*pServer == '\0'))
{
HostAddr = LOOPBACK;
}
else
{
ServerLength = RpcpStringLength((char *)pServer);
if ( (pCharServerName = (char *) I_RpcAllocate(ServerLength+1)) == 0 )
return (RPC_S_OUT_OF_MEMORY);
for (i=0 ; i<ServerLength+1 ; i++)
{
pCharServerName[i] = (char)pServer[i];
}
HostAddr = inet_addr(pCharServerName);
if (HostAddr == -1)
{
pHostEntry = gethostbyname(pCharServerName);
if (pHostEntry == 0)
{
pdgAddress->ServerLookupFailed = TRUE;
}
else
{
HostAddr = *(unsigned long *)pHostEntry->h_addr;
}
}
I_RpcFree(pCharServerName);
}
pdgAddress->ServerAddress.sin_family = ADDRESS_FAMILY;
pdgAddress->ServerAddress.sin_port = htons((unsigned short) Endpoint);
if (pdgAddress->ServerLookupFailed == FALSE)
{
RpcpMemoryCopy((char *) &(pdgAddress->ServerAddress.sin_addr.s_addr),
(char *) &HostAddr,
sizeof(unsigned long));
}
return RPC_S_OK;
}
#endif
RPC_STATUS
DeregisterServerAddress(
IN void * pTransAddress
)
/*++
Routine Description:
This routine serves as a psuedo-destructor for a DG_UDP_CLIENT_TRANSPORT
object. It frees up a socket.
Arguments:
pTransAddress - Address to deregister.
Return Value:
RPC_S_OK
--*/
{
return RPC_S_OK;
}
RPC_STATUS
SendToServer(
IN void * TransportEndpoint,
IN void * Buffer,
IN unsigned long BufferLength,
IN BOOL Broadcast,
IN void * TransportAddress
)
/*++
Routine Description:
Sends a packet on the network through the transport address associated
with the passed packet.
Arguments:
pPack - Packet to send.
Broadcast - Whether to broadcast or not.
Return Value:
RPC_S_OK
<return value from MapStatusCode>
--*/
{
PDG_UDP_ADDRESS pTransAddress = (PDG_UDP_ADDRESS)TransportAddress;
int SockStatus;
SOCKET Socket = ((PDG_UDP_ENDPOINT)TransportEndpoint)->Socket;
//
// Send the data on the net.
//
if ((Broadcast == FALSE) && (pTransAddress->ServerLookupFailed == TRUE))
{
return(RPC_S_SERVER_UNAVAILABLE);
}
ASSERT(BufferLength <= MAX_PDU);
if (Broadcast)
{
#ifdef IPX
SOCKADDR_FIX ServerAddress;
int i;
RpcpMemoryCopy( (char *) &ServerAddress,
(char *) &pTransAddress->ServerAddress,
sizeof( ServerAddress ) );
for (i = 0; i < 6; i++)
ServerAddress.s.sa_nodenum[i] = (char) 0xff;
#else
struct sockaddr_in ServerAddress;
ServerAddress.sin_family = ADDRESS_FAMILY;
ServerAddress.sin_port = pTransAddress->ServerAddress.sin_port;
*((long *) &ServerAddress.sin_addr.s_addr) = INADDR_BROADCAST;
#endif
SockStatus = sendto(
Socket,
(char *)Buffer,
BufferLength,
0,
(struct sockaddr *)&ServerAddress,
sizeof(ServerAddress)
);
}
else
{
SockStatus = sendto(
Socket,
(char *)Buffer,
BufferLength,
0,
(struct sockaddr *)&(pTransAddress->ServerAddress),
sizeof(pTransAddress->ServerAddress)
);
}
if (SockStatus == (int) BufferLength)
{
return RPC_S_OK;
}
else
{
return MapStatusCode(WSAGetLastError(), RPC_P_SEND_FAILED);
}
}
#pragma pack(1)
RPC_STATUS RPC_ENTRY
ClientTowerConstruct(
IN char PAPI * Endpoint,
IN char PAPI * NetworkAddress,
OUT UNALIGNED unsigned short PAPI * Floors,
OUT UNALIGNED unsigned long PAPI * ByteCount,
OUT unsigned char PAPI * UNALIGNED PAPI * Tower,
IN char PAPI * Protseq
)
{
unsigned long TowerSize;
unsigned short portnum;
UNALIGNED PFLOOR_234 Floor;
#ifdef IPX
SOCKADDR_IPX netaddr;
#else
unsigned long hostval;
#endif
/* Compute the memory size of the tower. */
*Floors = TOWERFLOORS;
TowerSize = TOWERSIZE;
TowerSize += 2*sizeof(FLOOR_234) - 4;
/* Allocate memory for the tower. */
*ByteCount = TowerSize;
if ((*Tower = (unsigned char PAPI*)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 = (unsigned short) htons ( (unsigned short) atoi (Endpoint));
memcpy((char PAPI *)&Floor->Data[0], &portnum, sizeof(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))
{
#ifdef IPX
my_get_host_by_name( 0, &netaddr, NetworkAddress );
memcpy(&Floor->Data[0], netaddr.sa_netnum, sizeof(netaddr.sa_netnum));
memcpy(&Floor->Data[4], netaddr.sa_nodenum, sizeof(netaddr.sa_nodenum));
#else
hostval = inet_addr((char *) NetworkAddress);
memcpy((char PAPI *)&Floor->Data[0], &hostval, sizeof(hostval));
#endif
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientTowerExplode(
IN unsigned char PAPI * Tower,
OUT char PAPI * UNALIGNED PAPI * Protseq,
OUT char PAPI * UNALIGNED PAPI * Endpoint,
OUT char PAPI * UNALIGNED PAPI * NetworkAddress
)
{
UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
RPC_STATUS Status = RPC_S_OK;
unsigned short portnum;
UNALIGNED unsigned short *Port;
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(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
{
#if defined(MIPS) || defined(_ALPHA_)
memcpy(&portnum, (char PAPI *)&Floor->Data[0], sizeof(portnum));
#else
Port = (unsigned short *)&Floor->Data[0];
portnum = *Port;
#endif
_itoa(ByteSwapShort(portnum), *Endpoint, 10);
}
return(Status);
}
#pragma pack()
#ifdef IPX
RPC_STATUS
QueryClientEndpoint
(
IN void * pOriginalEndpoint,
OUT RPC_CHAR * pClientEndpoint
)
{
SOCKADDR_IPX * pSockAddr = (SOCKADDR_IPX *) pOriginalEndpoint;
unsigned NativeSocket = ntohs(pSockAddr->sa_socket);
char AnsiBuffer[6];
char * pAnsi = AnsiBuffer;
RPC_CHAR * pUni = pClientEndpoint;
//
// Convert endpoint to an ASCII string, and thence to Unicode.
//
_ultoa(NativeSocket, AnsiBuffer, 10);
do
{
*pUni++ = *pAnsi;
}
while ( *pAnsi++ );
return RPC_S_OK;
}
#else
RPC_STATUS RPC_ENTRY
QueryClientEndpoint
(
IN void * pOriginalEndpoint,
OUT RPC_CHAR * pClientEndpoint
)
{
struct sockaddr_in * pSockAddr = (struct sockaddr_in *) pOriginalEndpoint;
unsigned NativeSocket = ntohs(pSockAddr->sin_port);
char AnsiBuffer[6];
char * pAnsi = AnsiBuffer;
RPC_CHAR * pUni = pClientEndpoint;
//
// Convert endpoint to an ASCII string, and thence to Unicode.
//
_ultoa(NativeSocket, AnsiBuffer, 10);
do
{
*pUni++ = *pAnsi;
}
while ( *pAnsi++ );
return RPC_S_OK;
}
#endif
RPC_STATUS RPC_ENTRY
SetBufferLength(
IN void PAPI * Endpoint,
IN unsigned Length
)
{
DG_UDP_ENDPOINT * pInfo = (DG_UDP_ENDPOINT *) Endpoint;
int SockStatus;
SockStatus = setsockopt(pInfo->Socket,
SOL_SOCKET,
SO_RCVBUF,
(char *) &Length,
sizeof(Length)
);
if (SockStatus == SOCKET_ERROR)
{
return RPC_S_OUT_OF_MEMORY;
}
return RPC_S_OK;
}
DG_RPC_CLIENT_TRANSPORT_INFO TransInfo = {
2,
MAX_PDU,
sizeof(DG_UDP_ADDRESS),
sizeof(DG_UDP_ENDPOINT),
0,
0,
ReceivePacket,
SendToServer,
MAX_ENDPOINT_SIZE,
(TRANS_CLIENT_TOWERCONSTRUCT) ClientTowerConstruct,
(TRANS_CLIENT_TOWEREXPLODE) ClientTowerExplode,
TRANSPORTID,
RegisterServerAddress,
DeregisterServerAddress,
AssignLocalEndpoint,
FreeLocalEndpoint,
QueryClientEndpoint,
SetBufferLength
};
PDG_RPC_CLIENT_TRANSPORT_INFO
TransportLoad(
RPC_CHAR * pProtocolSequence
)
/*++
Routine Description:
This routine is the "psuedo constructor" for the client transport object.
This is the exported entry point into this dll.
Arguments:
pProtocolSequence - The protocol sequence we're running on.
Return Value:
Pointer to a DG_UDP_CLIENT_TRANSPORT if successful, otherwise NULL.
--*/
{
RPC_STATUS Status;
WSADATA Data;
#ifdef IPX
SOCKET Socket;
#endif
//
// Initialize our network.
//
Status = WSAStartup(
0x0101, // version required
&Data
);
if (Status != 0)
{
return 0;
}
#ifdef IPX
Socket = socket(ADDRESS_FAMILY, SOCK_DGRAM, PROTOCOL);
if (Socket == INVALID_SOCKET)
{
return (0);
}
closesocket(Socket);
#endif
return (&TransInfo);
}