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.
1444 lines
34 KiB
1444 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
winsock.c
|
|
|
|
Abstract:
|
|
|
|
Common code for winsock-based datagram transports.
|
|
|
|
Author:
|
|
|
|
Dave Steckler (davidst) 15-Mar-1993
|
|
|
|
Revision History:
|
|
|
|
Jeff Roberts (jroberts) 02-Dec-1994
|
|
|
|
Separated the protocol-independent parts from the UDP- and
|
|
IPX-specific parts.
|
|
|
|
--*/
|
|
#include <stdlib.h>
|
|
|
|
#include <sysinc.h>
|
|
|
|
#ifdef NTENV
|
|
#include <winsock2.h>
|
|
#else
|
|
#include <winsock.h>
|
|
#endif
|
|
|
|
#ifdef NTENV
|
|
#include <tdi.h>
|
|
#include <afd.h>
|
|
#endif
|
|
|
|
#include <rpc.h>
|
|
#include <rpcdcep.h>
|
|
#include <rpcerrp.h>
|
|
|
|
#include <rpctran.h>
|
|
|
|
#include "common.h"
|
|
#include <winbase.h>
|
|
|
|
#define ONE_MINUTE_IN_MSEC (1000 * 60)
|
|
|
|
struct ENDPOINT_INFO
|
|
{
|
|
SOCKET Socket;
|
|
int SocketType ;
|
|
unsigned Timeout;
|
|
};
|
|
|
|
#ifdef IPX
|
|
|
|
#define RegisterEndpoint IPX_RegisterEndpoint
|
|
#define RegisterAnyEndpoint IPX_RegisterAnyEndpoint
|
|
#define DeregisterEndpoint IPX_DeregisterEndpoint
|
|
#define CreateServerEndpoint IPX_CreateServerEndpoint
|
|
#define QueryClientEndpoint IPX_QueryClientEndpoint
|
|
#define QueryClientAddress IPX_QueryClientAddress
|
|
|
|
#define ForwardPacket IPX_ForwardPacket
|
|
|
|
#define TransportInformation IPX_TransportInformation
|
|
#define CreateTransAddress IPX_CreateTransAddress
|
|
|
|
#define SendPacketViaTdi IPX_SendPacketViaTdi
|
|
#define SendPacketViaWinsock IPX_SendPacketViaWinsock
|
|
#define ReceivePacketViaTdi IPX_ReceivePacketViaTdi
|
|
#define ReceivePacketViaWinsock IPX_ReceivePacketViaWinsock
|
|
|
|
#define SetTransportSpecificSocketOptions IPX_SetTransportSpecificSocketOptions
|
|
|
|
#else
|
|
|
|
#define RegisterEndpoint UDP_RegisterEndpoint
|
|
#define RegisterAnyEndpoint UDP_RegisterAnyEndpoint
|
|
#define DeregisterEndpoint UDP_DeregisterEndpoint
|
|
#define CreateServerEndpoint UDP_CreateServerEndpoint
|
|
#define QueryClientEndpoint UDP_QueryClientEndpoint
|
|
#define QueryClientAddress UDP_QueryClientAddress
|
|
|
|
#define ForwardPacket UDP_ForwardPacket
|
|
|
|
#define TransportInformation UDP_TransportInformation
|
|
#define CreateTransAddress UDP_CreateTransAddress
|
|
|
|
#define SendPacketViaTdi UDP_SendPacketViaTdi
|
|
#define SendPacketViaWinsock UDP_SendPacketViaWinsock
|
|
#define ReceivePacketViaTdi UDP_ReceivePacketViaTdi
|
|
#define ReceivePacketViaWinsock UDP_ReceivePacketViaWinsock
|
|
|
|
#define SetTransportSpecificSocketOptions UDP_SetTransportSpecificSocketOptions
|
|
|
|
#endif
|
|
|
|
//
|
|
// The protocol-specific file should define these fns.
|
|
//
|
|
RPC_STATUS RPC_ENTRY
|
|
RegisterEndpoint(
|
|
IN void * pServerAddress,
|
|
IN RPC_CHAR * pEndpoint,
|
|
OUT PDG_SERVER_TRANS_ADDRESS * ppTransAddress,
|
|
OUT RPC_CHAR PAPI * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN unsigned long EndpointFlags,
|
|
IN unsigned long NICFlags
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
DeregisterEndpoint(
|
|
IN OUT PDG_SERVER_TRANS_ADDRESS * pServerTransAddress
|
|
);
|
|
|
|
int
|
|
SetTransportSpecificSocketOptions(
|
|
SOCKET Socket
|
|
);
|
|
|
|
RPC_STATUS
|
|
QueryClientEndpoint(
|
|
IN void * pClientEndpoint,
|
|
OUT RPC_CHAR * pClientAddress
|
|
);
|
|
|
|
RPC_STATUS
|
|
CreateServerEndpoint(
|
|
IN char * pEndpoint,
|
|
IN void * pServerAddr
|
|
);
|
|
|
|
//
|
|
// The protocol-specific file can use these fns.
|
|
//
|
|
RPC_STATUS
|
|
MapStatusCode(
|
|
int SocketError,
|
|
RPC_STATUS Default
|
|
);
|
|
|
|
PDG_SERVER_TRANS_ADDRESS
|
|
CreateTransAddress(
|
|
void * pServerAddress,
|
|
RPC_CHAR * pEndpoint,
|
|
RPC_STATUS * pStatus
|
|
);
|
|
|
|
void DeleteTransAddress(
|
|
PDG_SERVER_TRANS_ADDRESS * ppTransAddress
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
SendPacketViaWinsock(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned DataLength,
|
|
void * pClientEndpoint
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
SendPacketViaTdi(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned DataLength,
|
|
void * pClientEndpoint
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ReceivePacketViaWinsock(
|
|
IN void __RPC_FAR * pAddress,
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN unsigned long LargestPacketSize,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned * pDataLength,
|
|
unsigned long Timeout,
|
|
void * pClientEndpoint
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ReceivePacketViaTdi(
|
|
IN void __RPC_FAR * pAddress,
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN unsigned long LargestPacketSize,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned * pDataLength,
|
|
unsigned long Timeout,
|
|
void * pClientEndpoint
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
RegisterAnyEndpoint(
|
|
IN void * pServerAddress,
|
|
OUT RPC_CHAR * pEndpointName,
|
|
OUT PDG_SERVER_TRANS_ADDRESS * ppServerTransAddress,
|
|
OUT RPC_CHAR PAPI * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN unsigned int EndpointLength,
|
|
IN unsigned long EndpointFlags,
|
|
IN unsigned long NICFlags
|
|
);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
TransportUnload(void);
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ForwardPacket(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned long DataLength,
|
|
void * pEndpoint
|
|
);
|
|
|
|
#if defined(IPX)
|
|
|
|
#include <wsipx.h>
|
|
#include <wsnwlink.h>
|
|
#include <nspapi.h>
|
|
|
|
#include "dgipxs.h"
|
|
#include "dgipxs.c"
|
|
|
|
#elif defined(UDP)
|
|
|
|
#include "dgudps.h"
|
|
#include "dgudps.c"
|
|
|
|
#else
|
|
#error "unknown winsock protocol"
|
|
#endif
|
|
|
|
void RPC_ENTRY
|
|
CloseClientEndpoint(
|
|
IN OUT ADDRESS_TYPE * pHandle
|
|
);
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ReceivePacketViaWinsock(
|
|
IN void __RPC_FAR * pAddress,
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN unsigned long LargestPacketSize,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned * pDataLength,
|
|
unsigned long Timeout,
|
|
void * pClientEndpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Receives a packet from the transport address the passed packet is
|
|
associated with.
|
|
|
|
Arguments:
|
|
|
|
pTransAddress - Server's transport address information.
|
|
|
|
LargestPacketSize - Size of largest packet we can accept.
|
|
|
|
pNcaPacketHeader - Pointer to buffer to place incoming pkt into.
|
|
|
|
pDataLength - Number of bytes read in.
|
|
|
|
Timeout - Receive timeout in milliseconds.
|
|
|
|
ppClientEndpoint - Pointer to the client address structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
result of recv
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
{
|
|
static HANDLE AsyncReadEvent = 0;
|
|
|
|
RPC_STATUS Status;
|
|
unsigned SocketError;
|
|
int BytesReceived;
|
|
int FromLen = sizeof(struct sockaddr);
|
|
|
|
struct ENDPOINT_INFO * pInfo = (struct ENDPOINT_INFO *) pTransAddress->pTsap;
|
|
|
|
ADDRESS_TYPE * pSockaddr = (ADDRESS_TYPE *) pClientEndpoint;
|
|
|
|
unsigned StartTick;
|
|
unsigned EndTick;
|
|
|
|
//
|
|
// The runtime will send us an infinite timeout when a single thread is
|
|
// left. Until that point we needn't worry about the ReceiveAny stuff.
|
|
//
|
|
if (0 != Timeout)
|
|
{
|
|
if (Timeout != pInfo->Timeout)
|
|
{
|
|
pInfo->Timeout = Timeout;
|
|
|
|
setsockopt(pInfo->Socket,
|
|
SOL_SOCKET,
|
|
SO_RCVTIMEO,
|
|
(char *) &Timeout,
|
|
sizeof(Timeout)
|
|
);
|
|
//
|
|
// If we can't set the timeout, too bad. We will carry on anyway.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Do the obvious thing - just wait for data.
|
|
//
|
|
BytesReceived = recvfrom(
|
|
pInfo->Socket, // socket
|
|
(char *)pNcaPacketHeader, // buffer
|
|
(int)LargestPacketSize, // buflen
|
|
0, // flags
|
|
(struct sockaddr *) pSockaddr, // where received from
|
|
&FromLen // received from length
|
|
);
|
|
|
|
//
|
|
// Did we get something?
|
|
//
|
|
if ((BytesReceived == SOCKET_ERROR) || (BytesReceived == 0))
|
|
{
|
|
return MapStatusCode(WSAGetLastError(), RPC_P_RECEIVE_FAILED);
|
|
}
|
|
else
|
|
{
|
|
*pDataLength = BytesReceived;
|
|
return RPC_S_OK;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the c/o ReceiveAny thread isn't running yet, wait for its arrival
|
|
// as well as for data on my socket.
|
|
//
|
|
if (0 == PrimaryAddress.ThreadListening)
|
|
{
|
|
insert_failed:
|
|
|
|
Timeout = ONE_MINUTE_IN_MSEC;
|
|
pInfo->Timeout = Timeout;
|
|
|
|
setsockopt(pInfo->Socket,
|
|
SOL_SOCKET,
|
|
SO_RCVTIMEO,
|
|
(char *) &Timeout,
|
|
sizeof(Timeout)
|
|
);
|
|
|
|
do
|
|
{
|
|
BytesReceived = recvfrom(
|
|
pInfo->Socket, // socket
|
|
(char *)pNcaPacketHeader, // buffer
|
|
(int)LargestPacketSize, // buflen
|
|
0, // flags
|
|
(struct sockaddr *) pSockaddr, // where received from
|
|
&FromLen // received from length
|
|
);
|
|
|
|
//
|
|
// Did we get something?
|
|
//
|
|
if ((BytesReceived == SOCKET_ERROR) || (BytesReceived == 0))
|
|
{
|
|
if (WSAGetLastError() != WSAETIMEDOUT)
|
|
{
|
|
return MapStatusCode(WSAGetLastError(), RPC_P_RECEIVE_FAILED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pDataLength = BytesReceived;
|
|
return RPC_S_OK;
|
|
}
|
|
}
|
|
while ( 0 == PrimaryAddress.ThreadListening );
|
|
}
|
|
|
|
//
|
|
// The c/o ReceiveAny thread is alive; add our socket to the global
|
|
// mask and let the other thread wait for it.
|
|
//
|
|
EnterCriticalSection(&PrimaryAddress.TransCritSec);
|
|
|
|
//
|
|
// Add a slot in the data (receive) map for my socket.
|
|
//
|
|
#if defined(IPX)
|
|
Status = InsertDataSocket(NULL, FALSE, pInfo->Socket, pAddress, NCADG_IPX);
|
|
#else
|
|
Status = InsertDataSocket(NULL, FALSE, pInfo->Socket, pAddress, NCADG_IP_UDP);
|
|
#endif
|
|
|
|
if (Status)
|
|
{
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
goto insert_failed;
|
|
}
|
|
|
|
Status = PokeSyncSocket();
|
|
|
|
if (Status)
|
|
{
|
|
DeleteDataSocket(pInfo->Socket);
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
goto insert_failed;
|
|
}
|
|
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
|
|
return RPC_P_TIMEOUT;
|
|
}
|
|
|
|
#ifdef NTENV
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ReceivePacketViaTdi(
|
|
IN void __RPC_FAR * pAddress,
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN unsigned long LargestPacketSize,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned * pDataLength,
|
|
unsigned long Timeout,
|
|
void * pClientEndpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Receives a packet from the transport address the passed packet is
|
|
associated with.
|
|
|
|
Arguments:
|
|
|
|
pTransAddress - Server's transport address information.
|
|
|
|
LargestPacketSize - Size of largest packet we can accept.
|
|
|
|
pNcaPacketHeader - Pointer to buffer to place incoming pkt into.
|
|
|
|
pDataLength - Number of bytes read in.
|
|
|
|
Timeout - Receive timeout in milliseconds.
|
|
|
|
ppClientEndpoint - Pointer to the client address structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
result of recv
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS Status;
|
|
unsigned SocketError;
|
|
int BytesReceived;
|
|
int FromLen = sizeof(struct sockaddr);
|
|
struct ENDPOINT_INFO * pInfo = (struct ENDPOINT_INFO *) pTransAddress->pTsap;
|
|
ADDRESS_TYPE * pSockAddr = (ADDRESS_TYPE *) pClientEndpoint;
|
|
DWORD cAddr;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
AFD_RECV_DATAGRAM_INFO recvInfo;
|
|
DWORD status;
|
|
NTSTATUS NtStatus;
|
|
WSABUF buffer;
|
|
HANDLE hIoEvent;
|
|
|
|
hIoEvent = I_RpcGetThreadEvent();
|
|
|
|
if (0 == hIoEvent)
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
buffer.len = LargestPacketSize;
|
|
buffer.buf = pNcaPacketHeader;
|
|
|
|
cAddr = ADDRESS_SIZE;
|
|
|
|
recvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
|
|
recvInfo.AfdFlags = 0;
|
|
recvInfo.BufferArray = &buffer;
|
|
recvInfo.BufferCount = 1;
|
|
recvInfo.Address = pSockAddr;
|
|
recvInfo.AddressLength = &cAddr;
|
|
|
|
|
|
while (Timeout || PrimaryAddress.ThreadListening == 0)
|
|
{
|
|
|
|
insert_failed:
|
|
|
|
ioStatus.Status = 0;
|
|
ioStatus.Information = 0;
|
|
|
|
ASSERT(*(PDWORD)pNcaPacketHeader = 0xDEADF00D);
|
|
|
|
NtStatus = NtDeviceIoControlFile((HANDLE)pInfo->Socket,
|
|
hIoEvent,
|
|
0,
|
|
0,
|
|
&ioStatus,
|
|
IOCTL_AFD_RECEIVE_DATAGRAM,
|
|
&recvInfo,
|
|
sizeof(recvInfo),
|
|
NULL,
|
|
0);
|
|
|
|
if (NtStatus == STATUS_PENDING)
|
|
{
|
|
status = WaitForSingleObject(hIoEvent,
|
|
Timeout ? Timeout : 60*1000);
|
|
|
|
if (status != STATUS_WAIT_0)
|
|
{
|
|
IO_STATUS_BLOCK ioStatus2;
|
|
ASSERT(status == STATUS_TIMEOUT);
|
|
|
|
// Cancel the IO
|
|
|
|
ioStatus2.Status = STATUS_PENDING;
|
|
|
|
NtStatus = NtCancelIoFile((HANDLE)pInfo->Socket,
|
|
&ioStatus2);
|
|
|
|
ASSERT(NtStatus != STATUS_PENDING);
|
|
ASSERT(NT_SUCCESS(NtStatus));
|
|
ASSERT(NT_SUCCESS(ioStatus2.Status));
|
|
|
|
if (Timeout)
|
|
{
|
|
return(RPC_P_TIMEOUT);
|
|
}
|
|
//
|
|
// The runtime wants the thread to either add the socket
|
|
// to the connection oriented listen or remain in the
|
|
// transport interface.
|
|
// We will either loop back into the receive or
|
|
// add ourselves to the listen socket now.
|
|
//
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
if ( NtStatus == STATUS_BUFFER_OVERFLOW
|
|
|| NtStatus == STATUS_RECEIVE_PARTIAL )
|
|
{
|
|
ASSERT(ioStatus.Information == LargestPacketSize);
|
|
return(RPC_P_OVERSIZE_PACKET);
|
|
}
|
|
#if DBG
|
|
DbgPrint("RPC DG: Receive failed %p\n", NtStatus);
|
|
#endif
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
#if DBG
|
|
if (NtStatus != 0)
|
|
{
|
|
DbgPrint("RPC DG: Receive completed and returned 0x%p\n", NtStatus);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( ioStatus.Status == STATUS_BUFFER_OVERFLOW
|
|
|| ioStatus.Status == STATUS_RECEIVE_PARTIAL )
|
|
{
|
|
ASSERT(ioStatus.Information == LargestPacketSize);
|
|
return(RPC_P_OVERSIZE_PACKET);
|
|
}
|
|
|
|
if (ioStatus.Status != 0)
|
|
{
|
|
#if DBG
|
|
DbgPrint("RPC DG: Recieve completed with 0x%p\n", ioStatus.Status);
|
|
#endif
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
ASSERT( ioStatus.Information != 0
|
|
&& ioStatus.Information <= LargestPacketSize);
|
|
|
|
ASSERT(cAddr <= ADDRESS_SIZE);
|
|
|
|
*pDataLength = ioStatus.Information;
|
|
|
|
|
|
ASSERT(*(PDWORD)pNcaPacketHeader != 0xDEADF00D);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
//
|
|
// The c/o ReceiveAny thread is alive; add our socket to the global
|
|
// mask and let the other thread wait for it.
|
|
//
|
|
EnterCriticalSection(&PrimaryAddress.TransCritSec);
|
|
|
|
//
|
|
// Add a slot in the data (receive) map for my socket.
|
|
//
|
|
#if defined(IPX)
|
|
Status = InsertDataSocket(NULL, FALSE, pInfo->Socket, pAddress, NCADG_IPX);
|
|
#else
|
|
Status = InsertDataSocket(NULL, FALSE, pInfo->Socket, pAddress, NCADG_IP_UDP);
|
|
#endif
|
|
|
|
if (Status)
|
|
{
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
goto insert_failed;
|
|
}
|
|
|
|
Status = PokeSyncSocket();
|
|
|
|
if (Status)
|
|
{
|
|
DeleteDataSocket(pInfo->Socket);
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
goto insert_failed;
|
|
}
|
|
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
|
|
return RPC_P_TIMEOUT;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
RegisterAnyEndpoint(
|
|
IN void * pServerAddress,
|
|
OUT RPC_CHAR * pEndpointName,
|
|
OUT PDG_SERVER_TRANS_ADDRESS * ppServerTransAddress,
|
|
OUT RPC_CHAR PAPI * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN unsigned int EndpointLength,
|
|
IN unsigned long EndpointFlags,
|
|
IN unsigned long NICFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Figures out a unique endpoint and creates it.
|
|
|
|
Arguments:
|
|
|
|
pServerAddress - pointer to the DG_ADDRESS object we are associated with.
|
|
(see comments in RegisterEndpoint about why this is 'void *')
|
|
|
|
pEndpointName - Memory of at least MAX_ANY_ENDPOINT_NAME RPC_CHARS
|
|
in length. This will be filled in with the endpoint.
|
|
|
|
ppServerAddress - Where to place the newly created address.
|
|
|
|
NetworkAddress - Network address in string format - ie "11.2.39.56"
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
<any error from RegisterEndpoint>
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
RPC_STATUS Status;
|
|
int i = 0;
|
|
|
|
#if defined(IPX) || !defined(NTENV)
|
|
pEndpointName[0] = (RPC_CHAR)(i+'0');
|
|
pEndpointName[1] = '\0';
|
|
#else
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING portString;
|
|
portString.Buffer = pEndpointName;
|
|
|
|
portString.MaximumLength = 16;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
unsigned short port;
|
|
Status = I_RpcServerAllocatePort(EndpointFlags, &port);
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
// Convert port to string.
|
|
NtStatus = RtlIntegerToUnicodeString(port, 10, &portString);
|
|
ASSERT(NT_SUCCESS(NtStatus));
|
|
#endif
|
|
|
|
Status = RegisterEndpoint(pServerAddress,
|
|
pEndpointName,
|
|
ppServerTransAddress,
|
|
lNetworkAddress,
|
|
NumNetworkAddress,
|
|
NetworkAddressLength,
|
|
EndpointFlags,
|
|
NICFlags
|
|
);
|
|
|
|
#if !defined(IPX) && defined(NTENV)
|
|
if (port == 0 || Status != RPC_S_DUPLICATE_ENDPOINT)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return Status;
|
|
|
|
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
SendPacketViaWinsock(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned DataLength,
|
|
void * pClientEndpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends a packet back to the client it was received from.
|
|
|
|
Arguments:
|
|
|
|
|
|
pTransAddress - Server's transport address information.
|
|
|
|
pNcaPacketHeader - Pointer to buffer to place incoming pkt into.
|
|
|
|
pDataLength - Number of bytes read in.
|
|
|
|
pClientEndpoint - Pointer to the client address structure in
|
|
sockaddr format.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
result of send
|
|
|
|
--*/
|
|
|
|
{
|
|
PDG_SERVER_TRANS_ADDRESS pTransportAddress =
|
|
(PDG_SERVER_TRANS_ADDRESS) pTransAddress;
|
|
|
|
unsigned BytesSent;
|
|
struct ENDPOINT_INFO *pInfo = (struct ENDPOINT_INFO *) pTransAddress->pTsap;
|
|
ADDRESS_TYPE * pSockaddr = (ADDRESS_TYPE *) pClientEndpoint;
|
|
|
|
BytesSent = sendto(
|
|
pInfo->Socket, // socket
|
|
pNcaPacketHeader, // buffer
|
|
DataLength, // buflen
|
|
0, // flags
|
|
(struct sockaddr *) pSockaddr, // address
|
|
sizeof(ADDRESS_TYPE) // svr addr size
|
|
);
|
|
|
|
if (BytesSent == DataLength)
|
|
{
|
|
return RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
return MapStatusCode(WSAGetLastError(), RPC_P_SEND_FAILED);
|
|
}
|
|
}
|
|
|
|
#ifdef NTENV
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
SendPacketViaTdi(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned DataLength,
|
|
void * pClientEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends a packet back to the client it was received from.
|
|
|
|
Arguments:
|
|
|
|
|
|
pTransAddress - Server's transport address information.
|
|
|
|
pNcaPacketHeader - Pointer to buffer to place incoming pkt into.
|
|
|
|
pDataLength - Number of bytes read in.
|
|
|
|
pClientEndpoint - Pointer to the client address structure in
|
|
sockaddr format.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
result of send
|
|
|
|
--*/
|
|
|
|
{
|
|
PDG_SERVER_TRANS_ADDRESS pTransportAddress =
|
|
(PDG_SERVER_TRANS_ADDRESS) pTransAddress;
|
|
|
|
struct ENDPOINT_INFO *pInfo = (struct ENDPOINT_INFO *) pTransAddress->pTsap;
|
|
ADDRESS_TYPE * pSockAddr = (ADDRESS_TYPE *) pClientEndpoint;
|
|
RAW_ADDRESS_TYPE rawAddress;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
AFD_SEND_DATAGRAM_INFO sendInfo;
|
|
WSABUF buffer;
|
|
DWORD status;
|
|
NTSTATUS NtStatus;
|
|
HANDLE hIoEvent = I_RpcGetThreadEvent();
|
|
|
|
if (0 == hIoEvent)
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
buffer.len = DataLength;
|
|
buffer.buf = pNcaPacketHeader;
|
|
|
|
InitRawAddress(rawAddress, pSockAddr);
|
|
|
|
sendInfo.AfdFlags = 0;
|
|
sendInfo.BufferArray = &buffer;
|
|
sendInfo.BufferCount = 1;
|
|
sendInfo.TdiRequest.SendDatagramInformation = &sendInfo.TdiConnInfo;
|
|
sendInfo.TdiConnInfo.UserDataLength = 0;
|
|
sendInfo.TdiConnInfo.UserData = 0;
|
|
sendInfo.TdiConnInfo.OptionsLength = 0;
|
|
sendInfo.TdiConnInfo.Options = 0;
|
|
sendInfo.TdiConnInfo.RemoteAddressLength = RAW_ADDRESS_SIZE;
|
|
sendInfo.TdiConnInfo.RemoteAddress = &rawAddress;
|
|
|
|
ioStatus.Status = STATUS_PENDING;
|
|
ioStatus.Information = 0;
|
|
|
|
NtStatus = NtDeviceIoControlFile((HANDLE)pInfo->Socket,
|
|
hIoEvent,
|
|
0,
|
|
0,
|
|
&ioStatus,
|
|
IOCTL_AFD_SEND_DATAGRAM,
|
|
&sendInfo,
|
|
sizeof(sendInfo),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (NtStatus == STATUS_PENDING)
|
|
{
|
|
status = WaitForSingleObject(hIoEvent,
|
|
INFINITE);
|
|
|
|
ASSERT(status == STATUS_WAIT_0);
|
|
}
|
|
else
|
|
{
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
#if DBG
|
|
DbgPrint("RPC DG: Send failed %p\n", NtStatus);
|
|
ASSERT(0);
|
|
#endif
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
}
|
|
|
|
if (ioStatus.Information != DataLength)
|
|
{
|
|
#if DBG
|
|
DbgPrint("RPC DG: Send wait failed %p\n", ioStatus.Status);
|
|
ASSERT(0);
|
|
#endif
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
#endif // ! NTENV
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ForwardPacket(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress,
|
|
IN char * pNcaPacketHeader,
|
|
IN unsigned long DataLength,
|
|
void * pEndpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends a packet to the server it was originally destined for (that
|
|
is, the client had a dynamic endpoint it wished the enpoint mapper
|
|
to resolve and forward the packet to).
|
|
|
|
Arguments:
|
|
|
|
|
|
pTransAddress - Server's transport address information.
|
|
|
|
pNcaPacketHeader - Pointer to buffer to place incoming pkt into.
|
|
|
|
pDataLength - Number of bytes read in.
|
|
|
|
pEndpoint - Pointer to the server port num to forward to.
|
|
This is in string format.
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
result of send
|
|
|
|
--*/
|
|
|
|
{
|
|
// If a transport had specific needs placed into the
|
|
// transport address, it would cast pTransAddress into
|
|
// its own trans address datastructure. UDP has
|
|
// no additional info.
|
|
|
|
struct ENDPOINT_INFO * pInfo = (struct ENDPOINT_INFO *) pTransAddress->pTsap;
|
|
ADDRESS_TYPE SockAddr;
|
|
|
|
|
|
if ((CreateServerEndpoint(((char*) pEndpoint), &SockAddr)) != RPC_S_OK)
|
|
{
|
|
return RPC_S_CANT_CREATE_ENDPOINT;
|
|
}
|
|
|
|
return ( TransportInformation.SendPacketBack(pTransAddress,
|
|
pNcaPacketHeader,
|
|
DataLength,
|
|
(PVOID)&SockAddr) );
|
|
}
|
|
|
|
|
|
PDG_SERVER_TRANS_ADDRESS
|
|
CreateTransAddress(
|
|
void * pServerAddress,
|
|
RPC_CHAR * pEndpoint,
|
|
RPC_STATUS * pStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new endpoint on this server.
|
|
|
|
Arguments:
|
|
|
|
pServerAddress - DG_ADDRESS object this endpoint is associated with. This
|
|
is a 'void *' instead of a PDG_ADDRESS because we don't want to include
|
|
or link in all the garbage associated with PDG_ADDRESS.
|
|
|
|
pEndpoint - Name of the endpoint to create.
|
|
|
|
pStatus - Where to place the output status.
|
|
RPC_S_OK
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
|
|
Return Value:
|
|
|
|
<none>
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
long Endpoint;
|
|
int EndpointLength;
|
|
int i;
|
|
int SockStatus;
|
|
int Socket;
|
|
int PacketType;
|
|
PDG_SERVER_TRANS_ADDRESS pTransAddress;
|
|
|
|
int length;
|
|
SOCKET PortUsed;
|
|
char PortAscii[10];
|
|
#ifdef NTENV
|
|
UNICODE_STRING UnicodePortNum;
|
|
ANSI_STRING AsciiPortNum;
|
|
NTSTATUS NtStatus ;
|
|
#endif
|
|
ADDRESS_TYPE ReceiveAddr;
|
|
struct ENDPOINT_INFO * pInfo;
|
|
int NewSize = 0x40000;
|
|
|
|
//
|
|
// 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';
|
|
|
|
// Watch out for overflow.
|
|
if (Endpoint > 0x10000)
|
|
{
|
|
*pStatus = RPC_S_INVALID_ENDPOINT_FORMAT;
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pStatus = RPC_S_INVALID_ENDPOINT_FORMAT;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a socket.
|
|
//
|
|
Socket = socket(ADDRESS_FAMILY, SOCK_DGRAM, PROTOCOL);
|
|
if (Socket == INVALID_SOCKET)
|
|
{
|
|
*pStatus = RPC_S_CANT_CREATE_ENDPOINT;
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Set transport-variable options.
|
|
//
|
|
SockStatus = SetTransportSpecificSocketOptions(Socket);
|
|
if (NO_ERROR != SockStatus)
|
|
{
|
|
closesocket(Socket);
|
|
*pStatus = MapStatusCode(SockStatus, RPC_S_INTERNAL_ERROR);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// set socket recv buffer size..
|
|
//
|
|
|
|
SockStatus = setsockopt(Socket,
|
|
SOL_SOCKET,
|
|
SO_RCVBUF,
|
|
(char *) &NewSize,
|
|
sizeof(NewSize)
|
|
);
|
|
|
|
//
|
|
// Create a binding to that socket.
|
|
//
|
|
InitLocalAddress(ReceiveAddr, (unsigned short) Endpoint);
|
|
|
|
//Bind the socket to the port number.
|
|
SockStatus = bind(
|
|
Socket,
|
|
(struct sockaddr *)&ReceiveAddr,
|
|
sizeof(ReceiveAddr)
|
|
);
|
|
|
|
if (SockStatus == SOCKET_ERROR)
|
|
{
|
|
SockStatus = WSAGetLastError();
|
|
|
|
switch (SockStatus)
|
|
{
|
|
case WSAEADDRINUSE:
|
|
{
|
|
*pStatus= RPC_S_DUPLICATE_ENDPOINT;
|
|
break;
|
|
}
|
|
|
|
case WSAENOBUFS:
|
|
{
|
|
*pStatus= RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
#ifdef DEBUGRPC
|
|
DbgPrint("RPC DG: surprising error 0x%lx (%lu) from bind()\n",
|
|
SockStatus, SockStatus);
|
|
#endif
|
|
*pStatus= RPC_S_CANT_CREATE_ENDPOINT;
|
|
}
|
|
}
|
|
closesocket(Socket);
|
|
return NULL;
|
|
}
|
|
|
|
length = sizeof ( ReceiveAddr );
|
|
|
|
//Puts the string name of the endpoint used into ReceiveAddr.sin_port
|
|
|
|
if (getsockname ( Socket, (struct sockaddr *) &ReceiveAddr, &length ))
|
|
{
|
|
*pStatus = RPC_S_CANT_CREATE_ENDPOINT;
|
|
closesocket(Socket);
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// If we asked for a specific port(endpoint != 0), return it
|
|
// Otherwise, fetch the assigned port number (asssigned during the bind)
|
|
// and stuff it into the given endpoint structure in appropriate format.
|
|
if (Endpoint == 0)
|
|
{
|
|
PortUsed = GetSocket(ReceiveAddr);
|
|
|
|
RpcItoa ( PortUsed, PortAscii, 10 );
|
|
|
|
#ifdef NTENV
|
|
RtlInitAnsiString ( &AsciiPortNum, PortAscii);
|
|
NtStatus = RtlAnsiStringToUnicodeString( &UnicodePortNum, &AsciiPortNum, TRUE );
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
closesocket(Socket) ;
|
|
return (NULL) ;
|
|
}
|
|
|
|
memcpy ( pEndpoint,
|
|
UnicodePortNum.Buffer,
|
|
UnicodePortNum.Length + sizeof(UNICODE_NULL) );
|
|
|
|
RtlFreeUnicodeString ( &UnicodePortNum );
|
|
#else
|
|
strcpy (pEndpoint, PortAscii);
|
|
#endif // NTENV
|
|
}
|
|
|
|
|
|
// Allocate mem for the TransAddress
|
|
pTransAddress = I_RpcAllocate(sizeof(DG_SERVER_TRANS_ADDRESS) +
|
|
sizeof(struct ENDPOINT_INFO));
|
|
if (pTransAddress == 0)
|
|
{
|
|
*pStatus = RPC_S_OUT_OF_MEMORY;
|
|
closesocket(Socket);
|
|
return NULL;
|
|
}
|
|
|
|
pTransAddress->pServerAddress = pServerAddress;
|
|
|
|
pInfo = (struct ENDPOINT_INFO *) &pTransAddress[1];
|
|
|
|
pInfo->Socket = Socket;
|
|
pInfo->Timeout = 0;
|
|
#ifdef IPX
|
|
pInfo->SocketType = NCADG_IPX ;
|
|
#else
|
|
pInfo->SocketType = NCADG_IP_UDP ;
|
|
#endif
|
|
|
|
pTransAddress->pTsap = pInfo;
|
|
|
|
*pStatus = RPC_S_OK;
|
|
|
|
return pTransAddress;
|
|
}
|
|
|
|
//
|
|
// The following fns are used by UDP, to, but need to be defined only once.
|
|
//
|
|
#ifdef IPX
|
|
|
|
|
|
void
|
|
DeleteTransAddress(
|
|
PDG_SERVER_TRANS_ADDRESS * ppTransAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroys an endpoint.
|
|
|
|
Arguments:
|
|
|
|
<none>
|
|
|
|
Return Value:
|
|
|
|
<none> RRR
|
|
|
|
--*/
|
|
|
|
{
|
|
struct ENDPOINT_INFO * pInfo = (struct ENDPOINT_INFO *) (*ppTransAddress)->pTsap;
|
|
|
|
if (pInfo->Socket != INVALID_SOCKET)
|
|
{
|
|
closesocket(pInfo->Socket);
|
|
pInfo->Socket = INVALID_SOCKET;
|
|
pInfo->Timeout = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void RPC_ENTRY
|
|
CloseClientEndpoint(
|
|
IN OUT ADDRESS_TYPE * pHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a "client handle"
|
|
|
|
Arguments:
|
|
|
|
The handle.
|
|
|
|
Return Value:
|
|
|
|
<none>
|
|
|
|
--*/
|
|
|
|
{
|
|
// nothing to do here on IPX or UDP.
|
|
}
|
|
|
|
|
|
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
|
|
DG_ServerReceive(
|
|
IN void __RPC_FAR * pAddress,
|
|
IN OUT void PAPI * PAPI * Buffer,
|
|
IN OUT unsigned int PAPI * BufferLength
|
|
)
|
|
{
|
|
return I_RpcLaunchDatagramReceiveThread(pAddress);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
TransportUnload()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor for the server transport.
|
|
|
|
Arguments:
|
|
|
|
<none>
|
|
|
|
Return Value:
|
|
|
|
<none>
|
|
|
|
--*/
|
|
|
|
{
|
|
WSACleanup();
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
DG_StartListening(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress
|
|
)
|
|
{
|
|
RPC_STATUS Status ;
|
|
struct ENDPOINT_INFO * pInfo = (struct ENDPOINT_INFO *) (pTransAddress)->pTsap;
|
|
|
|
EnterCriticalSection(&PrimaryAddress.TransCritSec) ;
|
|
|
|
// Add a slot in the data (receive) map for my socket.
|
|
//
|
|
Status = InsertDataSocket(NULL, FALSE,
|
|
pInfo->Socket, pTransAddress->pServerAddress,
|
|
pInfo->SocketType);
|
|
if (Status)
|
|
{
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
return Status;
|
|
}
|
|
|
|
LeaveCriticalSection(&PrimaryAddress.TransCritSec);
|
|
return MaybePokeSyncSocket() ;
|
|
}
|
|
#else
|
|
extern RPC_STATUS RPC_ENTRY
|
|
DG_StartListening(
|
|
IN PDG_SERVER_TRANS_ADDRESS pTransAddress
|
|
) ;
|
|
#endif
|
|
|
|
|
|
DG_RPC_SERVER_TRANSPORT_INFO
|
|
TransportInformation =
|
|
{
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
sizeof(ADDRESS_TYPE),
|
|
sizeof(SOCKET),
|
|
ADDRESS_STRING_SIZE,
|
|
ENDPOINT_STRING_SIZE,
|
|
|
|
TransportUnload,
|
|
#if defined(NTENV)
|
|
0,
|
|
#else
|
|
ReceivePacketViaWinsock,
|
|
#endif
|
|
RegisterEndpoint,
|
|
DeregisterEndpoint,
|
|
RegisterAnyEndpoint,
|
|
#if defined(NTENV)
|
|
0,
|
|
#else
|
|
SendPacketViaWinsock,
|
|
#endif
|
|
ForwardPacket,
|
|
CloseClientEndpoint,
|
|
QueryClientAddress,
|
|
QueryClientEndpoint,
|
|
DG_StartListening,
|
|
0,
|
|
|
|
1024,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
#ifdef IPX
|
|
unsigned int IPX_NumNetworkCard()
|
|
{
|
|
return(1);
|
|
}
|
|
#endif
|
|
|