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.
602 lines
12 KiB
602 lines
12 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"
|
|
#include "rpc.h"
|
|
#include "rpcdcep.h"
|
|
#include "dgtrans.h"
|
|
#include "rpctran.h"
|
|
#include "rpcerrp.h"
|
|
|
|
#ifdef WIN
|
|
#define WSOCKETS_DLL
|
|
#endif
|
|
|
|
#include "socket.h"
|
|
#include "in.h"
|
|
#include "netdb.h"
|
|
|
|
#include "windows.h"
|
|
|
|
#define errno _FakeErrno
|
|
int _FakeErrno;
|
|
|
|
|
|
#define ERROR_SEM_TIMEOUT RPC_P_TIMEOUT
|
|
|
|
unsigned long LargestPacketSize = 1024;
|
|
/*
|
|
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;
|
|
|
|
|
|
typedef DG_UDP_ENDPOINT * PDG_UDP_ENDPOINT;
|
|
|
|
typedef struct {
|
|
struct sockaddr_in ServerAddress;
|
|
BOOL ServerLookupFailed;
|
|
} DG_UDP_ADDRESS;
|
|
|
|
typedef DG_UDP_ADDRESS * PDG_UDP_ADDRESS;
|
|
|
|
RPC_CLIENT_RUNTIME_INFO * RpcRuntimeInfo;
|
|
|
|
#define DG_UDP_TRANSPORT_VERSION 1
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
AssignLocalEndpoint(
|
|
IN void * Endpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask transport for a new endpoint.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#ifdef NTENV
|
|
BOOL SetSocketOptions;
|
|
#endif
|
|
struct sockaddr_in Client;
|
|
|
|
//
|
|
// Create a socket.
|
|
//
|
|
|
|
PDG_UDP_ENDPOINT TransportEndpoint = (PDG_UDP_ENDPOINT) Endpoint;
|
|
|
|
TransportEndpoint->Socket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (TransportEndpoint->Socket < 0)
|
|
{
|
|
return (RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
//Enable broadcasts by default .. on this socket
|
|
//We may change this later - to do broadcasts by demand
|
|
|
|
#ifdef NTENV
|
|
|
|
SetSocketOptions = TRUE;
|
|
if (setsockopt(
|
|
TransportEndpoint->Socket,
|
|
SOL_SOCKET,
|
|
SO_BROADCAST,
|
|
(char *)&SetSocketOptions,
|
|
sizeof(SetSocketOptions)) != 0)
|
|
{
|
|
close_socket(TransportEndpoint->Socket);
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
Dos sockets bug ? - Must bind the socket
|
|
*/
|
|
memset((char *)&Client, 0, sizeof(Client));
|
|
Client.sin_family = AF_INET;
|
|
Client.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
if (bind(TransportEndpoint->Socket, (struct sockaddr_in *)&Client,
|
|
sizeof(Client)))
|
|
{
|
|
close_socket(TransportEndpoint->Socket);
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
FD_ZERO(&(TransportEndpoint->Set));
|
|
FD_SET(TransportEndpoint->Socket, &(TransportEndpoint->Set));
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
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;
|
|
|
|
close_socket(TransportEndpoint->Socket);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
RegisterServerAddress(
|
|
IN void __RPC_FAR * pClientCall,
|
|
IN RPC_CHAR __RPC_FAR * pServer,
|
|
IN RPC_CHAR __RPC_FAR * pEndpoint,
|
|
OUT void __RPC_FAR * __RPC_FAR * 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 ;
|
|
|
|
if (*ppTransAddress == NULL)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
//
|
|
// convert the endpoint to a number.
|
|
//
|
|
|
|
pdgAddress->ServerLookupFailed = FALSE;
|
|
|
|
EndpointLength = RpcpStringLength(pEndpoint);
|
|
for (i=0, Endpoint=0 ; i< EndpointLength ; i++)
|
|
{
|
|
if ( ((char)pEndpoint[i] >= '0') && ((char)pEndpoint[i] <= '9'))
|
|
{
|
|
Endpoint *= 10;
|
|
Endpoint += (char)pEndpoint[i]-'0';
|
|
}
|
|
}
|
|
|
|
//
|
|
// Put our server name in a character array (instead of wchar)
|
|
//
|
|
|
|
if ((pServer == NULL) || (*pServer == '\0'))
|
|
{
|
|
pCharServerName = "localhost";
|
|
}
|
|
else
|
|
{
|
|
ServerLength = RpcpStringLength((char *)pServer);
|
|
if ( (pCharServerName =
|
|
(char *)(* (RpcRuntimeInfo->Allocate))(ServerLength+1)) == 0 )
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
|
|
for (i=0 ; i<ServerLength+1 ; i++)
|
|
{
|
|
pCharServerName[i] = (char)pServer[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get a "pointer" to our server.
|
|
//
|
|
|
|
pHostEntry = w_gethostbyname(pCharServerName, host_buff);
|
|
|
|
if ((pServer != NULL) && (*pServer != '\0'))
|
|
{
|
|
(*(RpcRuntimeInfo->Free))(pCharServerName);
|
|
}
|
|
|
|
if (pHostEntry == NULL )
|
|
{
|
|
/*
|
|
|
|
An app can give us a bogus servername and it should still work
|
|
for broadcasts
|
|
|
|
*pStatus = RPC_S_SERVER_UNAVAILABLE;
|
|
return;
|
|
*/
|
|
|
|
pdgAddress->ServerLookupFailed = TRUE;
|
|
}
|
|
|
|
pdgAddress->ServerAddress.sin_family = AF_INET;
|
|
pdgAddress->ServerAddress.sin_port = htons(Endpoint);
|
|
|
|
if (pdgAddress->ServerLookupFailed == FALSE)
|
|
{
|
|
RpcpMemoryCopy((char *) &(pdgAddress->ServerAddress.sin_addr.s_addr),
|
|
(char *) pHostEntry->h_addr,
|
|
pHostEntry->h_length);
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
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 RPC_ENTRY
|
|
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;
|
|
int Socket = ((PDG_UDP_ENDPOINT)TransportEndpoint)->Socket;
|
|
|
|
//
|
|
// Send the data on the net.
|
|
//
|
|
|
|
if ((Broadcast == FALSE) && (pTransAddress->ServerLookupFailed == TRUE))
|
|
{
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
if (Broadcast)
|
|
{
|
|
struct sockaddr_in ServerAddress;
|
|
unsigned long Tmp = INADDR_BROADCAST;
|
|
|
|
ServerAddress.sin_family = AF_INET;
|
|
ServerAddress.sin_port = pTransAddress->ServerAddress.sin_port;
|
|
RpcpMemoryCopy((char *) &ServerAddress.sin_addr.s_addr,
|
|
(char *) &Tmp,
|
|
sizeof(Tmp));
|
|
|
|
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 == BufferLength)
|
|
{
|
|
return RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
_asm { int 3 };
|
|
return RPC_S_INTERNAL_ERROR;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
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 milliseconds.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
ERROR_SEM_TIMEOUT
|
|
<return from WaitForSingleObject or MapStatusCode>
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PDG_UDP_ADDRESS pTransAddress = (PDG_UDP_ADDRESS)SenderAddress;
|
|
PDG_UDP_ENDPOINT Endpoint = (PDG_UDP_ENDPOINT)TransportEndpoint;
|
|
|
|
int SockStatus;
|
|
int BytesReceived;
|
|
struct sockaddr DummySockAddr;
|
|
int DummyLen=sizeof(DummySockAddr);
|
|
struct timeval TimeoutVal;
|
|
|
|
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 ERROR_SEM_TIMEOUT;
|
|
}
|
|
|
|
//
|
|
// Receive something on our socket.
|
|
//
|
|
|
|
BytesReceived = recvfrom(
|
|
Endpoint->Socket,
|
|
(char *)Buffer,
|
|
(int)LargestPacketSize,
|
|
0,
|
|
&DummySockAddr,
|
|
&DummyLen
|
|
);
|
|
|
|
//
|
|
// Did we get something?
|
|
//
|
|
|
|
if ((BytesReceived < 0 ) || (BytesReceived == 0))
|
|
{
|
|
return RPC_S_INTERNAL_ERROR;
|
|
_asm { int 3 };
|
|
}
|
|
else
|
|
{
|
|
*BufferLength = BytesReceived;
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DG_RPC_CLIENT_TRANSPORT_INFO TransInfo = {
|
|
2,
|
|
1024,
|
|
sizeof(DG_UDP_ADDRESS),
|
|
sizeof(DG_UDP_ENDPOINT),
|
|
0,
|
|
0,
|
|
ReceivePacket,
|
|
SendToServer,
|
|
RegisterServerAddress,
|
|
DeregisterServerAddress,
|
|
AssignLocalEndpoint,
|
|
FreeLocalEndpoint
|
|
};
|
|
|
|
|
|
|
|
DG_RPC_CLIENT_TRANSPORT_INFO * RPC_ENTRY
|
|
TransPortLoad(
|
|
RPC_CHAR * pProtocolSequence,
|
|
RPC_CLIENT_RUNTIME_INFO * ClientRuntimeInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
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;
|
|
#ifdef NTENV
|
|
WSADATA Data;
|
|
|
|
//
|
|
// Initialize our network.
|
|
//
|
|
|
|
Status = WSAStartup(
|
|
0x0101, // version required
|
|
&Data
|
|
);
|
|
|
|
if (Status != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
RpcRuntimeInfo = ClientRuntimeInfo;
|
|
|
|
return (&TransInfo);
|
|
|
|
}
|
|
|