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.
1202 lines
26 KiB
1202 lines
26 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:
|
|
|
|
Tony Chan (tonychan) 21-Oct-1995 Added Async Support
|
|
|
|
--*/
|
|
|
|
|
|
#include "sysinc.h"
|
|
#include "rpc.h"
|
|
#include "rpcdcep.h"
|
|
#include "rpctran.h"
|
|
#include "rpcerrp.h"
|
|
#include "winsock.h"
|
|
#include "windows.h"
|
|
#include "callback.h"
|
|
|
|
#define errno _FakeErrno
|
|
int _FakeErrno;
|
|
|
|
#define WNDCLASSNAME "DGUDPC"
|
|
#define WNDTEXT "RPC UDP/IP"
|
|
|
|
|
|
#define WM_ASYNC_EVENT WM_USER + 10
|
|
|
|
|
|
extern void (_far pascal _far *DllTermination)(void);
|
|
extern HANDLE hInstanceDLL;
|
|
extern atoi(char *);
|
|
|
|
#define MAX_PDU 1024
|
|
#define MAXENDPOINT_SIZE 6
|
|
|
|
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;
|
|
HWND hWnd;
|
|
BOOL fLocalYield;
|
|
HANDLE hYield;
|
|
BOOL fCallComplete;
|
|
} 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;
|
|
|
|
#define DG_UDP_TRANSPORT_VERSION 1
|
|
|
|
|
|
#define ByteSwapLong(Value) \
|
|
Value = ( (((Value) & 0xFF000000) >> 24) \
|
|
| (((Value) & 0x00FF0000) >> 8) \
|
|
| (((Value) & 0x0000FF00) << 8) \
|
|
| (((Value) & 0x000000FF) << 24))
|
|
|
|
#define ByteSwapShort(Value) \
|
|
Value = ( (((Value) & 0x00FF) << 8) \
|
|
| (((Value) & 0xFF00) >> 8))
|
|
|
|
|
|
|
|
/*
|
|
Following Macros and structs are needed for Tower Stuff
|
|
*/
|
|
|
|
#pragma pack(1)
|
|
#define UDP_TRANSPORTID 0x08
|
|
#define UDP_TRANSPORTHOSTID 0x09
|
|
#define UDP_TOWERFLOORS 5
|
|
#define UDP_IP_EP "135"
|
|
|
|
#define UDP_PROTSEQ "ncadg_ip_udp"
|
|
|
|
typedef struct _FLOOR_234 {
|
|
unsigned short ProtocolIdByteCount;
|
|
unsigned char FloorId;
|
|
unsigned short AddressByteCount;
|
|
unsigned char Data[2];
|
|
} FLOOR_234, PAPI * 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))
|
|
|
|
/*
|
|
End of Tower Stuff!
|
|
*/
|
|
|
|
|
|
#pragma pack()
|
|
|
|
RPC_STATUS
|
|
MapStatus(
|
|
int SocketError,
|
|
RPC_STATUS Default
|
|
);
|
|
|
|
|
|
LONG FAR PASCAL _loadds
|
|
AsyncEventProc(HWND hWnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PDG_UDP_ENDPOINT Endpoint ;
|
|
|
|
switch (msg) {
|
|
case WM_ASYNC_EVENT:
|
|
Endpoint = (PDG_UDP_ENDPOINT) GetWindowLong(hWnd, 0);
|
|
if (Endpoint->fLocalYield)
|
|
{
|
|
Endpoint->fCallComplete = TRUE ;
|
|
}
|
|
else
|
|
{
|
|
I_RpcWinAsyncCallComplete(Endpoint);
|
|
}
|
|
return (TRUE);
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
int BlockForRecv(PDG_UDP_ENDPOINT Endpoint)
|
|
{
|
|
|
|
Endpoint->fLocalYield = FALSE ;
|
|
|
|
if (WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd,
|
|
WM_ASYNC_EVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
|
|
{
|
|
return (SOCKET_ERROR) ;
|
|
}
|
|
|
|
if (I_RpcWinAsyncCallWait(Endpoint->hYield, Endpoint->hWnd) == FALSE)
|
|
{
|
|
WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd, 0, 0) ;
|
|
return(SOCKET_ERROR);
|
|
}
|
|
|
|
if (WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd, 0, 0) == SOCKET_ERROR)
|
|
{
|
|
return (SOCKET_ERROR) ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
void LocalBlockingFunc(PDG_UDP_ENDPOINT Endpoint)
|
|
{
|
|
MSG wMsg;
|
|
DWORD dwYieldTime ;
|
|
|
|
dwYieldTime = GetCurrentTime() + 2000 ;
|
|
|
|
while (!Endpoint->fCallComplete && GetCurrentTime() < dwYieldTime)
|
|
{
|
|
if (PeekMessage(&wMsg, Endpoint->hWnd, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&wMsg);
|
|
DispatchMessage(&wMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int LocalBlockForRecv(PDG_UDP_ENDPOINT Endpoint)
|
|
{
|
|
|
|
Endpoint->fLocalYield = TRUE ;
|
|
Endpoint->fCallComplete = FALSE ;
|
|
|
|
if (WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd,
|
|
WM_ASYNC_EVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
|
|
{
|
|
return (SOCKET_ERROR) ;
|
|
}
|
|
|
|
LocalBlockingFunc(Endpoint) ;
|
|
|
|
if (WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd, 0, 0) == SOCKET_ERROR)
|
|
{
|
|
return (SOCKET_ERROR) ;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int LocalBlockForSend(PDG_UDP_ENDPOINT Endpoint)
|
|
{
|
|
|
|
Endpoint->fLocalYield = TRUE ;
|
|
Endpoint->fCallComplete = FALSE ;
|
|
|
|
if (WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd,
|
|
WM_ASYNC_EVENT, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
|
|
{
|
|
return (SOCKET_ERROR) ;
|
|
}
|
|
|
|
LocalBlockingFunc(Endpoint) ;
|
|
|
|
if (WSAAsyncSelect(Endpoint->Socket, Endpoint->hWnd, 0, 0) == SOCKET_ERROR)
|
|
{
|
|
return (SOCKET_ERROR) ;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
AssignLocalEndpoint(
|
|
IN void * Endpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask transport for a new endpoint.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOL SetSocketOptions;
|
|
struct sockaddr_in Client;
|
|
int Error;
|
|
WSADATA Data;
|
|
int Status;
|
|
unsigned long nobio = 1;
|
|
|
|
PDG_UDP_ENDPOINT TransportEndpoint = (PDG_UDP_ENDPOINT) Endpoint;
|
|
|
|
Status = WSAStartup(
|
|
0x0101, // version required
|
|
&Data
|
|
);
|
|
|
|
if (Status != 0)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
//
|
|
// Create a socket.
|
|
//
|
|
TransportEndpoint->Socket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (TransportEndpoint->Socket < 0)
|
|
{
|
|
Error = WSAGetLastError();
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
//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);
|
|
}
|
|
|
|
/*
|
|
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 FAR *)&Client,
|
|
sizeof(Client)))
|
|
{
|
|
closesocket(TransportEndpoint->Socket);
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
FD_ZERO(&(TransportEndpoint->Set));
|
|
FD_SET(TransportEndpoint->Socket, &(TransportEndpoint->Set));
|
|
|
|
// Create hidden window to receive Async messages
|
|
|
|
TransportEndpoint->hWnd = CreateWindow(WNDCLASSNAME,
|
|
WNDTEXT,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
(HWND)NULL,
|
|
(HMENU)NULL,
|
|
hInstanceDLL,
|
|
(LPVOID)0);
|
|
if (!TransportEndpoint->hWnd)
|
|
{
|
|
closesocket(TransportEndpoint->Socket);
|
|
WSACleanup();
|
|
return (RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
UpdateWindow(TransportEndpoint->hWnd);
|
|
|
|
ShowWindow(TransportEndpoint->hWnd, SW_HIDE);
|
|
|
|
SetWindowLong(TransportEndpoint->hWnd, 0, (LONG)TransportEndpoint);
|
|
|
|
TransportEndpoint->hYield = (HANDLE)NULL;
|
|
|
|
ioctlsocket(TransportEndpoint->Socket, FIONBIO, &nobio);
|
|
|
|
|
|
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;
|
|
|
|
closesocket(TransportEndpoint->Socket);
|
|
|
|
if (FALSE == RpcRuntimeInfo->TaskExiting)
|
|
{
|
|
DestroyWindow(TransportEndpoint->hWnd);
|
|
}
|
|
|
|
WSACleanup();
|
|
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 i;
|
|
struct hostent *pHostEntry;
|
|
unsigned long HostAddr;
|
|
int Endpoint;
|
|
PDG_UDP_ADDRESS pdgAddress = (PDG_UDP_ADDRESS) *ppTransAddress ;
|
|
WSADATA Data;
|
|
|
|
if (*ppTransAddress == NULL)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
Status = WSAStartup(
|
|
0x0101, // version required
|
|
&Data
|
|
);
|
|
|
|
if (Status != 0)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
pdgAddress->ServerLookupFailed = FALSE;
|
|
|
|
//
|
|
// convert the endpoint to a number.
|
|
//
|
|
|
|
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';
|
|
}
|
|
}
|
|
|
|
if ((pServer == NULL) || (*pServer == '\0'))
|
|
{
|
|
pdgAddress->ServerLookupFailed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
HostAddr = inet_addr(pServer);
|
|
if (HostAddr == -1)
|
|
{
|
|
pHostEntry = gethostbyname(pServer);
|
|
if (pHostEntry == 0)
|
|
{
|
|
pdgAddress->ServerLookupFailed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
HostAddr = *(unsigned long *)pHostEntry->h_addr;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
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 *) &HostAddr,
|
|
sizeof (unsigned long)
|
|
);
|
|
}
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
WSACleanup();
|
|
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);
|
|
}
|
|
|
|
#ifdef DEBUGRPC
|
|
if ( BufferLength > MAX_PDU)
|
|
{
|
|
_asm { int 3 } ;
|
|
}
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
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,
|
|
(int)BufferLength,
|
|
0,
|
|
(struct sockaddr *)&ServerAddress,
|
|
sizeof(ServerAddress)
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
SockStatus = sendto(
|
|
Socket,
|
|
(char *)Buffer,
|
|
(int)BufferLength,
|
|
0,
|
|
(struct sockaddr *)&(pTransAddress->ServerAddress),
|
|
sizeof(pTransAddress->ServerAddress)
|
|
);
|
|
|
|
}
|
|
|
|
if (SockStatus == BufferLength)
|
|
{
|
|
return RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
SockStatus = WSAGetLastError();
|
|
|
|
// UDP Problem ? May be - just hack around it for the timebeing
|
|
//
|
|
if (SockStatus == WSAEWOULDBLOCK)
|
|
{
|
|
if(LocalBlockForSend(TransportEndpoint) == SOCKET_ERROR)
|
|
{
|
|
return (RPC_P_SEND_FAILED);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
#ifdef DEBUGRPC
|
|
_asm { int 3 };
|
|
#endif
|
|
|
|
return MapStatus(SockStatus, RPC_P_SEND_FAILED);
|
|
}
|
|
} // while
|
|
}
|
|
|
|
|
|
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;
|
|
int DummyLen=sizeof(struct sockaddr_in);
|
|
int status;
|
|
|
|
|
|
//
|
|
// Wait for our socket to be receivable.
|
|
//
|
|
|
|
Endpoint->hYield = I_RpcWinAsyncCallBegin(Endpoint);
|
|
#if 0
|
|
SockStatus = select(
|
|
1,
|
|
&(Endpoint->Set),
|
|
0,
|
|
0,
|
|
&TimeoutVal
|
|
);
|
|
|
|
if (SockStatus == 0)
|
|
{
|
|
FD_SET(Endpoint->Socket, &(Endpoint->Set));
|
|
return ERROR_SEM_TIMEOUT;
|
|
}
|
|
|
|
if (SockStatus == -1)
|
|
{
|
|
SockStatus = WSAGetLastError();
|
|
|
|
#ifdef DEBUGRPC
|
|
_asm int 3
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Receive something on our socket.
|
|
//
|
|
while(1)
|
|
{
|
|
BytesReceived = recvfrom(
|
|
Endpoint->Socket,
|
|
(char *)Buffer,
|
|
(int)LargestPacketSize,
|
|
0,
|
|
SenderAddress,
|
|
&DummyLen
|
|
);
|
|
|
|
//
|
|
// Did we get something?
|
|
//
|
|
|
|
if ((BytesReceived < 0 ) || (BytesReceived == 0))
|
|
{
|
|
SockStatus = WSAGetLastError();
|
|
|
|
// UDP Problem ? May be - just hack around it for the timebeing
|
|
//
|
|
if ( (SockStatus == WSAEWOULDBLOCK)
|
|
|| (SockStatus == 0 )
|
|
)
|
|
{
|
|
status = BlockForRecv(Endpoint) ;
|
|
if (status != 0)
|
|
{
|
|
I_RpcWinAsyncCallEnd(Endpoint->hYield);
|
|
return RPC_P_RECEIVE_FAILED ; /* is this correct ?? */
|
|
}
|
|
continue; // we have a window message, try to receiveagain
|
|
}
|
|
#ifdef DEBUGRPC
|
|
_asm { int 3 };
|
|
#endif
|
|
|
|
I_RpcWinAsyncCallEnd(Endpoint->hYield);
|
|
return MapStatus(SockStatus, RPC_P_TIMEOUT);
|
|
}
|
|
|
|
*BufferLength = BytesReceived;
|
|
I_RpcWinAsyncCallEnd(Endpoint->hYield);
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
Cleanup(
|
|
void
|
|
)
|
|
{
|
|
/*
|
|
WSACleanup();
|
|
*/
|
|
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, * HostId;
|
|
unsigned short * Port;
|
|
PFLOOR_234 Floor;
|
|
|
|
if (Protseq);
|
|
|
|
*Floors = UDP_TOWERFLOORS;
|
|
TowerSize = 6; /*Endpoint = 2 bytes, HostId = 4 bytes*/
|
|
|
|
TowerSize += 2*sizeof(FLOOR_234) - 4;
|
|
|
|
if ((*Tower = (unsigned char PAPI*) I_RpcAllocate((unsigned int)
|
|
(*ByteCount = TowerSize)))
|
|
== NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Floor = (PFLOOR_234) *Tower;
|
|
Floor->ProtocolIdByteCount = 1;
|
|
Floor->FloorId = (unsigned char)(UDP_TRANSPORTID & 0xFF);
|
|
Floor->AddressByteCount = 2;
|
|
Port = (unsigned short *) &Floor->Data[0];
|
|
if (Endpoint == NULL || *Endpoint == '\0')
|
|
{
|
|
Endpoint = UDP_IP_EP;
|
|
}
|
|
|
|
*Port = htons ( atoi (Endpoint));
|
|
|
|
//Onto the next floor
|
|
Floor = NEXTFLOOR(PFLOOR_234, Floor);
|
|
Floor->ProtocolIdByteCount = 1;
|
|
Floor->FloorId = (unsigned char)(UDP_TRANSPORTHOSTID & 0xFF);
|
|
Floor->AddressByteCount = 4;
|
|
|
|
HostId = (unsigned long *)&Floor->Data[0];
|
|
|
|
if ((NetworkAddress) && (*NetworkAddress))
|
|
{
|
|
*HostId = inet_addr((char *) NetworkAddress);
|
|
}
|
|
else
|
|
{
|
|
*HostId = 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_234 Floor = (PFLOOR_234) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
unsigned short portnum, *Port;
|
|
|
|
if (Protseq != NULL)
|
|
{
|
|
*Protseq = (char PAPI *) I_RpcAllocate(strlen(UDP_PROTSEQ) + 1);
|
|
if (*Protseq == NULL)
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
else
|
|
memcpy(*Protseq, UDP_PROTSEQ, strlen(UDP_PROTSEQ) + 1);
|
|
}
|
|
|
|
if ((Endpoint == NULL) || (Status != RPC_S_OK))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
*Endpoint = (char PAPI *) I_RpcAllocate(6); //Ports are all <64K [5 decimal dig +1]
|
|
if (*Endpoint == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
Port = (unsigned short *)&Floor->Data[0];
|
|
portnum = *Port;
|
|
_itoa(ByteSwapShort(portnum), *Endpoint, 10);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
#pragma pack()
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
QueryClientEndpoint
|
|
(
|
|
IN void PAPI * pOriginalEndpoint,
|
|
OUT RPC_CHAR PAPI * pClientEndpoint
|
|
)
|
|
{
|
|
struct sockaddr_in PAPI * pSockAddr =
|
|
(struct sockaddr_in PAPI *) pOriginalEndpoint;
|
|
unsigned long NativeSocket = ntohs(pSockAddr->sin_port);
|
|
|
|
_ultoa(NativeSocket, pClientEndpoint, 10);
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
SetBufferLength(
|
|
IN void PAPI * Endpoint,
|
|
IN unsigned Length
|
|
)
|
|
{
|
|
DG_UDP_ENDPOINT __RPC_FAR * pInfo = (DG_UDP_ENDPOINT __RPC_FAR *) 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;
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
InqBufferLength(
|
|
IN void __RPC_FAR * Endpoint,
|
|
IN unsigned __RPC_FAR * Length
|
|
)
|
|
{
|
|
DG_UDP_ENDPOINT __RPC_FAR * pInfo = (DG_UDP_ENDPOINT __RPC_FAR *) Endpoint;
|
|
int SockStatus;
|
|
int Lengthsize;
|
|
|
|
SockStatus = getsockopt(pInfo->Socket,
|
|
SOL_SOCKET,
|
|
SO_RCVBUF,
|
|
(char __RPC_FAR *) Length,
|
|
&Lengthsize
|
|
);
|
|
|
|
// Lenghtsize must == 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,
|
|
Cleanup,
|
|
ReceivePacket,
|
|
SendToServer,
|
|
MAXENDPOINT_SIZE,
|
|
ClientTowerConstruct,
|
|
ClientTowerExplode,
|
|
UDP_TRANSPORTID,
|
|
RegisterServerAddress,
|
|
DeregisterServerAddress,
|
|
AssignLocalEndpoint,
|
|
FreeLocalEndpoint,
|
|
QueryClientEndpoint,
|
|
SetBufferLength
|
|
};
|
|
|
|
void __far __pascal MyWep();
|
|
|
|
|
|
|
|
DG_RPC_CLIENT_TRANSPORT_INFO * RPC_ENTRY
|
|
TransportLoad(
|
|
RPC_CHAR * pProtocolSequence,
|
|
RPC_CLIENT_RUNTIME_INFO PAPI * 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;
|
|
WSADATA Data;
|
|
WNDCLASS wc;
|
|
|
|
//
|
|
// Initialize our network.
|
|
//
|
|
|
|
Status = WSAStartup(
|
|
0x0101, // version required
|
|
&Data
|
|
);
|
|
|
|
if (Status != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
RpcRuntimeInfo = ClientRuntimeInfo;
|
|
AsyncCallComplete = RpcRuntimeInfo->AsyncCallComplete;
|
|
|
|
wc.style = WS_OVERLAPPED;
|
|
wc.lpfnWndProc = (WNDPROC) AsyncEventProc;
|
|
wc.cbWndExtra = sizeof(PDG_UDP_ENDPOINT);
|
|
wc.cbClsExtra = 0;
|
|
wc.hInstance = hInstanceDLL;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
|
|
wc.hbrBackground = GetStockObject (WHITE_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = WNDCLASSNAME;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
DllTermination = MyWep;
|
|
|
|
return (&TransInfo);
|
|
}
|
|
|
|
|
|
|
|
void __far __pascal
|
|
MyWep(
|
|
)
|
|
{
|
|
if (0 != GetModuleHandle("WINSOCK"))
|
|
{
|
|
WSACleanup();
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
MapStatus(
|
|
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:
|
|
{
|
|
Status = Default;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|