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.
3061 lines
81 KiB
3061 lines
81 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
dgtrans.cxx
|
|
|
|
Abstract:
|
|
|
|
Common code for winsock-based datagram transports.
|
|
|
|
Author:
|
|
|
|
Dave Steckler (davidst) 15-Mar-1993
|
|
Jeff Roberts (jroberts) 02-Dec-1994
|
|
Mario Goertzel (mariogo) 10-Apr-1996
|
|
Michael Burton (t-mburt) 05-Sep-1997
|
|
Charlie Wickham (charlwi) 01-Oct-1997
|
|
|
|
Revision History:
|
|
|
|
Dave wrote a version.
|
|
Connie changed it but forgot to add her name.
|
|
Jeff made it work.
|
|
Mario rewrote most of it for NT and io completion ports.
|
|
|
|
MarioGo 12/10/1996 Changes for async support, added client
|
|
t-mburt 09/05/1997 Added prelim support for clusters
|
|
charlwi 10/01/1997 Finished cluster work
|
|
|
|
--*/
|
|
#include <precomp.hxx>
|
|
#include <trans.hxx>
|
|
#include <dgtrans.hxx>
|
|
#include <wswrap.hxx>
|
|
|
|
#ifdef NCADG_MQ_ON
|
|
#include "mqtrans.hxx"
|
|
#endif
|
|
|
|
//
|
|
// If a datagram send doesn't complete within 5 seconds, abort it.
|
|
//
|
|
#define DG_SEND_TIMEOUT (5000)
|
|
|
|
// Cluster SOCKADDR_CLUSTER initialization routine
|
|
inline void
|
|
CDP_InitLocalAddress(
|
|
SOCKADDR_CLUSTER *Address,
|
|
unsigned short Endpoint
|
|
)
|
|
{
|
|
Address->sac_family = AF_CLUSTER;
|
|
Address->sac_node = CLUSADDR_ANY;
|
|
Address->sac_port = Endpoint;
|
|
Address->sac_zero = 0;
|
|
}
|
|
|
|
extern RPC_STATUS CDP_InitializeSockAddr(char *Endpoint, WS_SOCKADDR *, DG_TRANSPORT_ENDPOINT ThisEndpoint = NULL);
|
|
extern RPC_STATUS UDP_InitializeSockAddr(char *Endpoint, WS_SOCKADDR *, DG_TRANSPORT_ENDPOINT ThisEndpoint = NULL);
|
|
|
|
#ifdef IPX_ON
|
|
extern RPC_STATUS IPX_InitializeSockAddr(char *Endpoint, WS_SOCKADDR *);
|
|
#endif
|
|
|
|
const DG_TRANS_INFO DgTransportTable[] =
|
|
{
|
|
// UDP
|
|
{
|
|
AF_INET,
|
|
SOCK_DGRAM,
|
|
IPPROTO_UDP,
|
|
0x40000,
|
|
0x10000,
|
|
UDP_InitializeSockAddr
|
|
},
|
|
|
|
#ifdef IPX_ON
|
|
// IPX
|
|
{
|
|
AF_IPX,
|
|
SOCK_DGRAM,
|
|
NSPROTO_IPX,
|
|
0x40000,
|
|
0x10000,
|
|
IPX_InitializeSockAddr
|
|
},
|
|
#else
|
|
// IPX
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
},
|
|
#endif
|
|
|
|
// CDP
|
|
{
|
|
AF_CLUSTER,
|
|
SOCK_DGRAM,
|
|
CLUSPROTO_CDP,
|
|
0x40000,
|
|
0x10000,
|
|
CDP_InitializeSockAddr
|
|
}
|
|
|
|
};
|
|
|
|
inline const DG_TRANS_INFO *GetDgTransportInfo(PROTOCOL_ID id)
|
|
{
|
|
#ifdef IPX_ON
|
|
ASSERT(id == UDP || id == IPX || id == CDP);
|
|
#else
|
|
ASSERT(id == UDP || id == CDP);
|
|
#endif
|
|
|
|
return &DgTransportTable[id - UDP];
|
|
}
|
|
|
|
typedef const DG_TRANS_INFO *PDG_TRANS_INFO;
|
|
|
|
// may be TRUE only for rpcss. For all others it's FALSE
|
|
BOOL fWSARecvMsgFnPtrInitialized = FALSE;
|
|
const UUID WSARecvMsgFnPtrUuid = WSAID_WSARECVMSG;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Generic datagram (winsock and NT based) routines.
|
|
//
|
|
|
|
RPC_STATUS
|
|
DG_SubmitReceive(IN PWS_DATAGRAM_ENDPOINT pEndpoint,
|
|
IN PWS_DATAGRAM pDatagram)
|
|
/*++
|
|
|
|
Arguments:
|
|
|
|
pEndpoint - The endpoint on which the receive should be posted.
|
|
pDatagram - The datagram object to manage the receive.
|
|
|
|
Return Value:
|
|
|
|
RPC_P_IO_PENDING - OK
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS status;
|
|
NTSTATUS NtStatus;
|
|
DWORD bytes, flags;
|
|
int err;
|
|
|
|
if (pDatagram->Packet.buf == 0)
|
|
{
|
|
status = I_RpcTransDatagramAllocate(pEndpoint,
|
|
(BUFFER *)&pDatagram->Packet.buf,
|
|
(PUINT) &pDatagram->Packet.len,
|
|
&pDatagram->AddressPair);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
pDatagram->AddressPair->LocalAddress
|
|
= WSA_CMSG_DATA(&pDatagram->MessageAncillaryData)
|
|
+ FIELD_OFFSET(in_pktinfo, ipi_addr);
|
|
|
|
ASSERT( pDatagram->Packet.buf );
|
|
}
|
|
|
|
ASSERT(*(PDWORD)pDatagram->Packet.buf = 0xDEADF00D);
|
|
bytes = flags = 0;
|
|
|
|
if (!fWSARecvMsgFnPtrInitialized)
|
|
{
|
|
pDatagram->cRecvAddr = sizeof(WS_SOCKADDR);
|
|
|
|
err = WSARecvFrom(((WS_DATAGRAM_ENDPOINT*)(pDatagram->pEndpoint))->Socket,
|
|
&pDatagram->Packet,
|
|
1,
|
|
&bytes,
|
|
&flags,
|
|
&((WS_SOCKADDR *)pDatagram->AddressPair->RemoteAddress)->generic,
|
|
&pDatagram->cRecvAddr,
|
|
&pDatagram->Read.ol,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
pDatagram->Msg.lpBuffers = &pDatagram->Packet;
|
|
pDatagram->Msg.name = &((WS_SOCKADDR *)pDatagram->AddressPair->RemoteAddress)->generic;
|
|
pDatagram->Msg.namelen = sizeof(WS_SOCKADDR);
|
|
pDatagram->Msg.dwBufferCount = 1;
|
|
pDatagram->Msg.Control.buf = (char *)pDatagram->MessageAncillaryData;
|
|
pDatagram->Msg.Control.len = sizeof(pDatagram->MessageAncillaryData);
|
|
pDatagram->Msg.dwFlags = 0;
|
|
err = WSARecvMsg(((WS_DATAGRAM_ENDPOINT*)(pDatagram->pEndpoint))->Socket,
|
|
&pDatagram->Msg,
|
|
&bytes,
|
|
&pDatagram->Read.ol,
|
|
0);
|
|
}
|
|
#if 0
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "ERROR: RecvFrom: %p buf %p (%d bytes) status %d\n",
|
|
pDatagram,
|
|
pDatagram->Packet.buf,
|
|
pDatagram->Packet.len,
|
|
err == 0 ? 0 : GetLastError()));
|
|
#endif
|
|
|
|
if (err == NO_ERROR)
|
|
{
|
|
return(RPC_P_IO_PENDING);
|
|
}
|
|
|
|
status = GetLastError();
|
|
if ( status == ERROR_IO_PENDING
|
|
|| status == WSAEMSGSIZE )
|
|
{
|
|
// WSAEMSGSIZE will be handled in complete.cxx. This is like "NO_ERROR"
|
|
return(RPC_P_IO_PENDING);
|
|
}
|
|
|
|
RpcpErrorAddRecord( EEInfoGCWinsock,
|
|
status,
|
|
EEInfoDLWinsockDatagramSubmitReceive10,
|
|
((WS_DATAGRAM_ENDPOINT*)(pDatagram->pEndpoint))->Socket
|
|
);
|
|
|
|
if (WSAECONNRESET == status)
|
|
{
|
|
return RPC_P_PORT_DOWN;
|
|
}
|
|
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "WSARecvFrom failed %p\n",
|
|
GetLastError()));
|
|
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
|
|
void
|
|
DG_SubmitReceives(
|
|
BASE_ADDRESS *ThisEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function called when the pending IO count
|
|
on an address is too low.
|
|
|
|
Arguments:
|
|
|
|
ThisEndpoint - The address to submit IOs on.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PWS_DATAGRAM pDg;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
|
|
if (pEndpoint->Socket == 0)
|
|
{
|
|
//
|
|
// The address is currently deactivated, don't submit more I/O
|
|
//
|
|
return;
|
|
}
|
|
|
|
do
|
|
{
|
|
BOOL fIoSubmitted;
|
|
|
|
fIoSubmitted = FALSE;
|
|
|
|
// Only one thread should be trying to submit IOs at a time.
|
|
// This saves locking each DATAGRAM object.
|
|
|
|
// Simple lock - but requires a loop. See the comment at the end
|
|
// of the loop.
|
|
|
|
if (pEndpoint->fSubmittingIos != 0)
|
|
break;
|
|
|
|
if (InterlockedIncrement(&pEndpoint->fSubmittingIos) != 1)
|
|
break;
|
|
|
|
// Submit new IOs on all the idle datagram objects
|
|
|
|
for (int i = 0; i < pEndpoint->cMaximumIos; i++)
|
|
{
|
|
pDg = &pEndpoint->aDatagrams[i];
|
|
|
|
if (pDg->Busy)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Must be all set for the IO to complete before trying
|
|
// to submit the IO.
|
|
InterlockedIncrement(&pEndpoint->cPendingIos);
|
|
pDg->Busy = TRUE;
|
|
|
|
if (DG_SubmitReceive(pEndpoint, pDg) == RPC_P_IO_PENDING)
|
|
{
|
|
fIoSubmitted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pDg->Busy = FALSE;
|
|
InterlockedDecrement(&pEndpoint->cPendingIos);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Release the "lock" on the endpoint object.
|
|
//
|
|
// Xeon processors have eratta G40:
|
|
// Potential Loss of Data Coherency Duaring MP Data Ownership Transfer.
|
|
// To work around it, it is necessary to use InterlockedExchange rather then an assignment
|
|
// to force cache coherency.
|
|
InterlockedExchange(&pEndpoint->fSubmittingIos, 0);
|
|
|
|
if (!fIoSubmitted && pEndpoint->cPendingIos == 0)
|
|
{
|
|
// It appears that no IO is pending on the endpoint.
|
|
COMMON_AddressManager(pEndpoint);
|
|
return;
|
|
}
|
|
|
|
// Even if we submitted new IOs, they may all have completed
|
|
// already. Which means we may need to loop and submit more
|
|
// IOs. This is needed since the thread which completed the
|
|
// last IO may have run into our lock and returned.
|
|
}
|
|
while (pEndpoint->cPendingIos == 0);
|
|
|
|
return;
|
|
}
|
|
|
|
NETWORK_ADDRESS_VECTOR *
|
|
DG_GetNetworkAddressVector(
|
|
IN RPC_TRANSPORT_ADDRESS pAddress
|
|
)
|
|
{
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT) pAddress;
|
|
ASSERT(pEndpoint->pAddressVector);
|
|
return pEndpoint->pAddressVector;
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
DG_SendPacket(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN DG_TRANSPORT_ADDRESS pAddress,
|
|
IN BUFFER pHeader,
|
|
IN unsigned cHeader,
|
|
IN BUFFER pBody,
|
|
IN unsigned cBody,
|
|
IN BUFFER pTrailer,
|
|
IN unsigned cTrailer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends a packet to an address.
|
|
|
|
The routine will send a packet built out of the three buffers supplied.
|
|
All the buffers are optional, the actual packet sent will be built from
|
|
all the buffers actually supplied. In each call at least buffer should
|
|
NOT be null.
|
|
|
|
Arguments:
|
|
|
|
ThisEndpoint - Endpoint to send from.
|
|
pAddress - Address to send to.
|
|
|
|
pHeader - First data buffer
|
|
cHeader - Size of the first data buffer or 0.
|
|
|
|
pBody - Second data buffer
|
|
cBody - Size of the second data buffer or 0.
|
|
|
|
pTrailer - Third data buffer.
|
|
cTrailer - Size of the first data buffer or 0.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_P_SEND_FAILED
|
|
|
|
--*/
|
|
{
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR* pSockAddr = (WS_SOCKADDR *)pAddress;
|
|
WSABUF buffers[3];
|
|
int cBuffers;
|
|
HANDLE hIoEvent;
|
|
|
|
DWORD Status = 0;
|
|
|
|
if (pHeader)
|
|
{
|
|
CallTestHook( TH_X_DG_SEND, pHeader, &Status );
|
|
}
|
|
else
|
|
{
|
|
CallTestHook( TH_X_DG_SEND, pBody, &Status );
|
|
}
|
|
|
|
if (Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
hIoEvent = I_RpcTransGetThreadEvent();
|
|
|
|
cBuffers = 0;
|
|
if (cHeader)
|
|
{
|
|
buffers[cBuffers].len = cHeader;
|
|
buffers[cBuffers].buf = (PCHAR) pHeader;
|
|
cBuffers++;
|
|
}
|
|
if (cBody)
|
|
{
|
|
buffers[cBuffers].len = cBody;
|
|
buffers[cBuffers].buf = (PCHAR) pBody;
|
|
cBuffers++;
|
|
}
|
|
if (cTrailer)
|
|
{
|
|
buffers[cBuffers].len = cTrailer;
|
|
buffers[cBuffers].buf = (PCHAR) pTrailer;
|
|
cBuffers++;
|
|
}
|
|
ASSERT(cBuffers);
|
|
|
|
// All RPC packets have version 4.
|
|
//
|
|
ASSERT( buffers[0].buf[0] == 4 );
|
|
|
|
|
|
OVERLAPPED ol;
|
|
ol.hEvent = (HANDLE)(ULONG_PTR(hIoEvent) | 1);
|
|
DWORD bytes;
|
|
|
|
if ( WSASendTo(pEndpoint->Socket,
|
|
buffers,
|
|
cBuffers,
|
|
&bytes,
|
|
0,
|
|
&pSockAddr->generic,
|
|
WsTransportTable[pEndpoint->id].SockAddrSize,
|
|
&ol,
|
|
0) != 0)
|
|
{
|
|
DWORD Status = GetLastError();
|
|
|
|
RpcpErrorAddRecord( EEInfoGCWinsock,
|
|
Status,
|
|
EEInfoDLWinsockDatagramSend10,
|
|
PULONG(&pSockAddr->generic)[0],
|
|
PULONG(&pSockAddr->generic)[1]
|
|
);
|
|
|
|
if (WSAENETUNREACH == Status)
|
|
{
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "WSASendTo failed with net unreachable\n",
|
|
GetLastError()));
|
|
|
|
return RPC_P_PORT_DOWN;
|
|
}
|
|
|
|
if (WSAEHOSTDOWN == Status)
|
|
{
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "WSASendTo failed with host down\n",
|
|
GetLastError()));
|
|
return RPC_P_HOST_DOWN;
|
|
}
|
|
|
|
if (Status != WSA_IO_PENDING)
|
|
{
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "WSASendTo failed %d\n",
|
|
GetLastError()));
|
|
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
if (WAIT_OBJECT_0 != WaitForSingleObject( hIoEvent, DG_SEND_TIMEOUT ))
|
|
{
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "Dg Send timed out\n"));
|
|
|
|
//
|
|
// Cancel the send and wait for it to complete.
|
|
//
|
|
CancelIo( (HANDLE)pEndpoint->Socket );
|
|
|
|
GetOverlappedResult((HANDLE)pEndpoint->Socket,
|
|
&ol,
|
|
&bytes,
|
|
TRUE);
|
|
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
BOOL b = GetOverlappedResult((HANDLE)pEndpoint->Socket,
|
|
&ol,
|
|
&bytes,
|
|
TRUE);
|
|
|
|
if (!b)
|
|
{
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "Dg Send wait failed %d\n",
|
|
GetLastError()));
|
|
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
}
|
|
|
|
ASSERT(bytes == cHeader + cBody + cTrailer);
|
|
|
|
if (pEndpoint->cMinimumIos &&
|
|
pEndpoint->cPendingIos <= pEndpoint->cMinimumIos)
|
|
{
|
|
// It's ok if this fails, this is just a performance optimization.
|
|
// Right after a send there often "idle" time waiting for the response
|
|
// so this is a good time to submit receives.
|
|
|
|
DG_SubmitReceives(pEndpoint);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
DG_ForwardPacket(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN BUFFER pHeader,
|
|
IN unsigned cHeader,
|
|
IN BUFFER pBody,
|
|
IN unsigned cBody,
|
|
IN BUFFER pTrailer,
|
|
IN unsigned cTrailer,
|
|
IN CHAR * pszPort
|
|
)
|
|
|
|
/*++
|
|
|
|
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:
|
|
|
|
ThisEndpoint - The endpoint to forward the packet from.
|
|
|
|
// Buffer like DG_SendPacket
|
|
|
|
pszPort - Pointer to the server port num to forward to.
|
|
This is in an Ansi string.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_CANT_CREATE_ENDPOINT - pEndpoint invalid.
|
|
|
|
results of SendPacket().
|
|
|
|
--*/
|
|
|
|
{
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR SockAddr;
|
|
PDG_TRANS_INFO pInfo = GetDgTransportInfo(pEndpoint->id);
|
|
DG_TRANSPORT_ENDPOINT EndpointWithAddressToForwardTo;
|
|
|
|
ASSERT(pEndpoint->type | SERVER);
|
|
|
|
// If selective bindings are enabled, forward the packet to the
|
|
// interface that the current endpoint is listening on
|
|
// rather then to the loopback address. Otherwise, forward to
|
|
// the loopback address by default.
|
|
if (pFirewallTable != NULL)
|
|
EndpointWithAddressToForwardTo = ThisEndpoint;
|
|
else
|
|
EndpointWithAddressToForwardTo = NULL;
|
|
|
|
if (pInfo->EndpointToAddr(pszPort, &SockAddr, EndpointWithAddressToForwardTo) != RPC_S_OK)
|
|
{
|
|
return RPC_S_CANT_CREATE_ENDPOINT;
|
|
}
|
|
|
|
return ( DG_SendPacket(ThisEndpoint,
|
|
(PVOID)&SockAddr,
|
|
pHeader,
|
|
cHeader,
|
|
pBody,
|
|
cBody,
|
|
pTrailer,
|
|
cTrailer) );
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
DG_ReceivePacket(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
OUT DG_TRANSPORT_ADDRESS *pReplyAddress,
|
|
OUT PUINT pBufferLength,
|
|
OUT BUFFER *pBuffer,
|
|
IN LONG Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to wait for a datagram from a server. Returns the data
|
|
returned and the address of the machine which replied.
|
|
|
|
This is a blocking API. It should only be called during sync
|
|
client RPC threads.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - The endpoint to receive from.
|
|
ReplyAddress - Contain the source address of the datagram if
|
|
successful.
|
|
BufferLength - The size of Buffer on input, the size of the
|
|
datagram received on output.
|
|
Timeout - Milliseconds to wait for a datagram.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
RPC_P_OVERSIZE_PACKET - Datagram > BufferLength arrived,
|
|
first BufferLength bytes of Buffer contain the partial datagram.
|
|
|
|
RPC_P_RECEIVE_FAILED
|
|
|
|
RPC_P_TIMEOUT
|
|
--*/
|
|
{
|
|
RPC_STATUS status;
|
|
BOOL b;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
PWS_DATAGRAM pDatagram = &pEndpoint->aDatagrams[0];
|
|
DWORD bytes;
|
|
DWORD flags;
|
|
int err;
|
|
|
|
ASSERT((pEndpoint->type & TYPE_MASK) == CLIENT);
|
|
ASSERT(pEndpoint->aDatagrams[0].Read.ol.hEvent);
|
|
|
|
DWORD Status = 0;
|
|
|
|
CallTestHook( TH_X_DG_SYNC_RECV, ThisEndpoint, &Status );
|
|
|
|
if (Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (pDatagram->Busy == 0)
|
|
{
|
|
if (pEndpoint->aDatagrams[0].Packet.buf == 0)
|
|
{
|
|
status = I_RpcTransDatagramAllocate(pEndpoint,
|
|
(BUFFER *)&pDatagram->Packet.buf,
|
|
(PUINT) &pDatagram->Packet.len,
|
|
&pDatagram->AddressPair);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
pDatagram->cRecvAddr = sizeof(WS_SOCKADDR);
|
|
pDatagram->AddressPair->LocalAddress
|
|
= WSA_CMSG_DATA(&pDatagram->MessageAncillaryData)
|
|
+ FIELD_OFFSET(in_pktinfo, ipi_addr);
|
|
|
|
ASSERT( pDatagram->Packet.buf );
|
|
}
|
|
|
|
bytes = flags = 0;
|
|
|
|
if (!fWSARecvMsgFnPtrInitialized)
|
|
{
|
|
err = WSARecvFrom(pEndpoint->Socket,
|
|
&pDatagram->Packet,
|
|
1,
|
|
&bytes,
|
|
&flags,
|
|
&((WS_SOCKADDR *)pDatagram->AddressPair->RemoteAddress)->generic,
|
|
&pDatagram->cRecvAddr,
|
|
&pDatagram->Read.ol,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
pDatagram->Msg.lpBuffers = &pDatagram->Packet;
|
|
pDatagram->Msg.name = &((WS_SOCKADDR *)pDatagram->AddressPair->RemoteAddress)->generic;
|
|
pDatagram->Msg.namelen = sizeof(WS_SOCKADDR);
|
|
pDatagram->Msg.dwBufferCount = 1;
|
|
pDatagram->Msg.Control.buf = (char *)&pDatagram->MessageAncillaryData;
|
|
pDatagram->Msg.Control.len = sizeof(pDatagram->MessageAncillaryData);
|
|
pDatagram->Msg.dwFlags = 0;
|
|
|
|
err = WSARecvMsg(((WS_DATAGRAM_ENDPOINT*)(pDatagram->pEndpoint))->Socket,
|
|
&pDatagram->Msg,
|
|
&bytes,
|
|
&pDatagram->Read.ol,
|
|
0);
|
|
}
|
|
|
|
if ( err != 0)
|
|
{
|
|
|
|
status = GetLastError();
|
|
|
|
if (status != WSA_IO_PENDING)
|
|
{
|
|
RpcpErrorAddRecord( EEInfoGCWinsock,
|
|
status,
|
|
EEInfoDLWinsockDatagramReceive10,
|
|
pEndpoint->Socket
|
|
);
|
|
|
|
if (status == WSAEMSGSIZE)
|
|
{
|
|
status = RPC_P_OVERSIZE_PACKET;
|
|
}
|
|
else if (status == WSAECONNRESET)
|
|
{
|
|
return RPC_P_PORT_DOWN;
|
|
}
|
|
else
|
|
{
|
|
// No need to free the packet now.
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "WSARecvFrom failed %d\n",
|
|
status));
|
|
|
|
ASSERT(pDatagram->Busy == 0);
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = RPC_P_IO_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = RPC_S_OK;
|
|
}
|
|
|
|
pDatagram->Busy = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pDatagram->Busy);
|
|
ASSERT(pDatagram->Packet.buf);
|
|
|
|
status = RPC_P_IO_PENDING;
|
|
}
|
|
|
|
// Wait for IO to complete or timeout
|
|
|
|
if (status == RPC_P_IO_PENDING)
|
|
{
|
|
status = WaitForSingleObjectEx(pDatagram->Read.ol.hEvent,
|
|
Timeout,
|
|
TRUE);
|
|
|
|
if (status != STATUS_WAIT_0)
|
|
{
|
|
// In the timeout case we just want to return and
|
|
// leave. We'll finish the receive on the next call.
|
|
if (status == WAIT_IO_COMPLETION)
|
|
{
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG received cancelled (%p)\n",
|
|
pDatagram));
|
|
}
|
|
else
|
|
{
|
|
ASSERT(status == STATUS_TIMEOUT);
|
|
}
|
|
|
|
ASSERT(pDatagram->Busy);
|
|
|
|
return(RPC_P_TIMEOUT);
|
|
}
|
|
|
|
BOOL b = GetOverlappedResult((HANDLE)pEndpoint->Socket,
|
|
&pDatagram->Read.ol,
|
|
&bytes,
|
|
FALSE);
|
|
|
|
if (!b)
|
|
{
|
|
RpcpErrorAddRecord( EEInfoGCWinsock,
|
|
GetLastError(),
|
|
EEInfoDLWinsockDatagramSend20,
|
|
pEndpoint->Socket
|
|
);
|
|
|
|
switch (GetLastError())
|
|
{
|
|
case WSAEMSGSIZE:
|
|
case ERROR_MORE_DATA:
|
|
ASSERT(bytes == pDatagram->Packet.len);
|
|
status = RPC_P_OVERSIZE_PACKET;
|
|
break;
|
|
|
|
case ERROR_PORT_UNREACHABLE:
|
|
pDatagram->Busy = 0;
|
|
return RPC_P_PORT_DOWN;
|
|
break;
|
|
|
|
case STATUS_TIMEOUT:
|
|
ASSERT(0);
|
|
|
|
case ERROR_OPERATION_ABORTED:
|
|
// ERROR_OPERATION_ABORTED can occur if one thread
|
|
// tried to make a call and failed, leaving a pending
|
|
// receive. That thread dies. Then the endpoint is
|
|
// reused by a different thread and the IO is aborted.
|
|
// Returning receive failed will cause the runtime to
|
|
// retransmit which will do the right thing.
|
|
default:
|
|
TransDbgDetail((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
RPCTRANS "DG sync recv failed %d\n",
|
|
GetLastError()));
|
|
|
|
pDatagram->Busy = 0;
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = RPC_S_OK;
|
|
}
|
|
}
|
|
|
|
ASSERT( status == RPC_S_OK
|
|
|| status == RPC_P_OVERSIZE_PACKET);
|
|
|
|
ASSERT(pDatagram->Busy);
|
|
ASSERT(pDatagram->Packet.buf);
|
|
ASSERT(bytes <= pDatagram->Packet.len);
|
|
|
|
*pBuffer = (BUFFER)pDatagram->Packet.buf;
|
|
*pBufferLength = bytes;
|
|
*pReplyAddress = pDatagram->AddressPair->RemoteAddress;
|
|
|
|
pDatagram->Packet.buf = 0;
|
|
pDatagram->Busy = 0;
|
|
|
|
return(status);
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
DG_ReceivePacket_Avrf(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
OUT DG_TRANSPORT_ADDRESS *pReplyAddress,
|
|
OUT PUINT pBufferLength,
|
|
OUT BUFFER *pBuffer,
|
|
IN LONG Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for DG_ReceivePacket implementing corruption injection
|
|
under the RPC verifier.
|
|
|
|
SyncRecv member of the transport interface may only be called
|
|
by the cliet, hence we inject the corruption for a client receive.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
Status = DG_ReceivePacket(
|
|
ThisEndpoint,
|
|
pReplyAddress,
|
|
pBufferLength,
|
|
pBuffer,
|
|
Timeout
|
|
);
|
|
|
|
if (!Status)
|
|
{
|
|
if (gfRPCVerifierEnabled)
|
|
{
|
|
CorruptionInject(ClientReceive,
|
|
pBufferLength,
|
|
(void **)pBuffer);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
RPC_STATUS
|
|
DG_CreateEndpoint(
|
|
OUT WS_DATAGRAM_ENDPOINT *pEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new endpoint.
|
|
|
|
Arguments:
|
|
|
|
pEndpoint - The runtime allocated endpoint structure to
|
|
filled in.
|
|
|
|
pSockAddr - An initialized sockaddr with the correct
|
|
(or no) endpoint.
|
|
|
|
id - The id of the protocol to use in creating the address.
|
|
|
|
fClient - If TRUE this is a client endpoint
|
|
|
|
fAsync - If TRUE this endpoint is "async" which means that
|
|
a) It should be added to the IO completion port and
|
|
b) that the transport should pend a number of receives
|
|
on the endpoint automatically.
|
|
|
|
EndpointFlags - used in allocation IP ports.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_CANT_CREATE_ENDPOINT
|
|
RPC_S_DUPLICATE_ENDPOINT
|
|
|
|
--*/
|
|
{
|
|
PWS_DATAGRAM pDatagram;
|
|
int i, err;
|
|
int length;
|
|
RPC_STATUS status = RPC_S_OK;
|
|
SOCKET sock = 0;
|
|
PDG_TRANS_INFO pInfo = GetDgTransportInfo(pEndpoint->id);
|
|
BOOL fClient = pEndpoint->fClient;
|
|
BOOL fAsync = pEndpoint->fAsync;
|
|
LPFN_WSARECVMSG WSARecvMsgFnPtr;
|
|
DWORD dwBytesReturned;
|
|
|
|
// Common stuff
|
|
|
|
pEndpoint->type = DATAGRAM | ADDRESS;
|
|
pEndpoint->Socket = 0;
|
|
pEndpoint->Endpoint = 0;
|
|
pEndpoint->pAddressVector = 0;
|
|
pEndpoint->SubmitListen = DG_SubmitReceives;
|
|
pEndpoint->InAddressList = NotInList;
|
|
pEndpoint->pNext = 0;
|
|
pEndpoint->fSubmittingIos = 0;
|
|
pEndpoint->cPendingIos = 0;
|
|
pEndpoint->cMinimumIos = 0;
|
|
pEndpoint->cMaximumIos = 0;
|
|
pEndpoint->aDatagrams = 0;
|
|
pEndpoint->pFirstAddress = pEndpoint;
|
|
pEndpoint->pNextAddress = 0;
|
|
pEndpoint->fAborted = 0;
|
|
|
|
if (fClient)
|
|
{
|
|
pEndpoint->type |= CLIENT;
|
|
}
|
|
else
|
|
{
|
|
pEndpoint->type |= SERVER;
|
|
}
|
|
|
|
//
|
|
// Check if we can use a wrapper around the AFD send/recv
|
|
// IOCTLs instead WSASendTo.
|
|
//
|
|
TryUsingAfd();
|
|
|
|
//
|
|
// Create the socket.
|
|
//
|
|
sock = WSASocketT(pInfo->AddressFamily,
|
|
pInfo->SocketType,
|
|
pInfo->Protocol,
|
|
0,
|
|
0,
|
|
WSA_FLAG_OVERLAPPED);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
RpcpErrorAddRecord( EEInfoGCWinsock,
|
|
GetLastError(),
|
|
EEInfoDLWinsockDatagramCreate10,
|
|
(ULONG) pInfo->AddressFamily,
|
|
(ULONG) pInfo->Protocol
|
|
);
|
|
|
|
switch(GetLastError())
|
|
{
|
|
case WSAEAFNOSUPPORT:
|
|
case WSAEPROTONOSUPPORT:
|
|
case WSAENETDOWN:
|
|
case WSAEINVAL:
|
|
case WSAEPROTOTYPE:
|
|
case WSAENOPROTOOPT:
|
|
case WSAESOCKTNOSUPPORT:
|
|
case WSAEPFNOSUPPORT:
|
|
case WSAEADDRNOTAVAIL:
|
|
status = RPC_S_PROTSEQ_NOT_SUPPORTED;
|
|
break;
|
|
|
|
case WSAENOBUFS:
|
|
case WSAEMFILE:
|
|
case WSA_NOT_ENOUGH_MEMORY:
|
|
// This failure is possible in low memory conditions
|
|
// or due to fault injection during registry read or
|
|
// notification creation.
|
|
case WSASYSCALLFAILURE:
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
|
|
default:
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG socket() returned 0x%lx\n",
|
|
GetLastError()));
|
|
|
|
ASSERT(0);
|
|
// no break
|
|
|
|
case WSAEPROVIDERFAILEDINIT:
|
|
status = RPC_S_OUT_OF_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
if (fWSARecvMsgFnPtrInitialized == FALSE)
|
|
{
|
|
// if the AddressChangeFn is non-default (i.e. we are in RPCSS),
|
|
// use WSARecvMsg so that we can retrieve the local address as
|
|
// well
|
|
if (AddressChangeFn && (AddressChangeFn != NullAddressChangeFn))
|
|
{
|
|
// retrieve the WSARecvMsg function pointer
|
|
err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (void *) &WSARecvMsgFnPtrUuid,
|
|
sizeof(UUID), (void *) &WSARecvMsgFnPtr, sizeof(void *), &dwBytesReturned,
|
|
NULL, NULL);
|
|
|
|
if (err == SOCKET_ERROR)
|
|
{
|
|
closesocket(sock);
|
|
return RPC_S_PROTSEQ_NOT_SUPPORTED;
|
|
}
|
|
|
|
WFT.pWSARecvMsg = WSARecvMsgFnPtr;
|
|
fWSARecvMsgFnPtrInitialized = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Make the handle non-inheritable so it goes away when we close it.
|
|
//
|
|
if (FALSE == SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0))
|
|
{
|
|
closesocket(sock);
|
|
return RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Protect the socket to prevent another server from using our port.
|
|
//
|
|
|
|
WS_ProtectListeningSocket(sock, TRUE);
|
|
|
|
//
|
|
// Bind the socket to the endpoint (or to a dynamic endpoint)
|
|
//
|
|
|
|
status = WS_Bind(sock,
|
|
&pEndpoint->ListenAddr,
|
|
(pEndpoint->id == UDP),
|
|
pEndpoint->EndpointFlags);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
closesocket(sock);
|
|
return(status);
|
|
}
|
|
|
|
pEndpoint->Socket = sock;
|
|
|
|
//
|
|
// Turn on ring buffering for server- and client-side async endpoints.
|
|
// Any error is ignored.
|
|
//
|
|
if (fAsync || !fClient)
|
|
{
|
|
DWORD BytesReturned;
|
|
if (0 != WSAIoctl( sock, SIO_ENABLE_CIRCULAR_QUEUEING, 0, 0, 0, 0, &BytesReturned, 0, 0 ))
|
|
{
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG couldn't enable circular queueing 0x%lx\n",
|
|
GetLastError()));
|
|
}
|
|
}
|
|
|
|
if (!fClient)
|
|
{
|
|
//
|
|
// Set server socket recv buffer size..
|
|
//
|
|
|
|
int size;
|
|
int PacketInfoOn = TRUE;
|
|
|
|
if (gfServerPlatform == TRUE && gPhysicalMemorySize >= 40)
|
|
{
|
|
size = pInfo->ServerBufferSize;
|
|
}
|
|
else
|
|
{
|
|
size = pInfo->WorkstationBufferSize;
|
|
}
|
|
|
|
if (fWSARecvMsgFnPtrInitialized)
|
|
{
|
|
err = setsockopt(sock,
|
|
IPPROTO_IP,
|
|
IP_PKTINFO,
|
|
(char *)&PacketInfoOn,
|
|
sizeof(PacketInfoOn)
|
|
);
|
|
if (err != 0)
|
|
{
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG couldn't set packet info %d\n",
|
|
GetLastError()));
|
|
|
|
closesocket(sock);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
err = setsockopt(sock,
|
|
SOL_SOCKET,
|
|
SO_RCVBUF,
|
|
(char *) &size,
|
|
sizeof(size)
|
|
);
|
|
#if DBG
|
|
if (err != 0)
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG couldn't set buffer size %d\n",
|
|
GetLastError()));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Enable broadcast send on the client
|
|
|
|
DWORD option = TRUE;
|
|
|
|
err = setsockopt(sock,
|
|
SOL_SOCKET,
|
|
SO_BROADCAST,
|
|
(PCHAR)&option,
|
|
sizeof(option));
|
|
|
|
ASSERT(err == 0);
|
|
}
|
|
|
|
//
|
|
// If the endpoint is going to async initialize async part
|
|
// and add the socket to the IO completion port.
|
|
//
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
int cMaxIos;
|
|
int cMinIos;
|
|
|
|
ASSERT(fAsync || fClient);
|
|
|
|
// Step one, figure out the high and low mark for ios.
|
|
|
|
if (fAsync)
|
|
{
|
|
cMinIos = 1;
|
|
cMaxIos = 2;
|
|
|
|
if (gPhysicalMemorySize >= 40) // megabytes
|
|
{
|
|
cMaxIos = 2
|
|
+ (gfServerPlatform == TRUE) * 2
|
|
+ (fClient == FALSE) * gNumberOfProcessors;
|
|
|
|
// This should be larger than zero so that we'll generally submit new
|
|
// recvs during idle time rather then just after receiving a datagram.
|
|
cMinIos = 1 + (fClient == FALSE ) * (gNumberOfProcessors/2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For sync endpoints we need to allocate a single datagram
|
|
// object for the receive.
|
|
cMinIos = 0;
|
|
cMaxIos = 1;
|
|
}
|
|
|
|
ASSERT(cMinIos < cMaxIos);
|
|
|
|
pEndpoint->cMinimumIos = cMinIos;
|
|
pEndpoint->cMaximumIos = cMaxIos;
|
|
|
|
// Allocate a chunk on memory to hold the array of datagrams
|
|
|
|
// PERF: For clients, allocate larger array but don't submit all
|
|
// the IOs unless we determine that the port is "really" active.
|
|
|
|
pEndpoint->aDatagrams = new WS_DATAGRAM[cMaxIos];
|
|
|
|
if (pEndpoint->aDatagrams)
|
|
{
|
|
UINT type;
|
|
type = DATAGRAM | RECEIVE;
|
|
type |= (fClient) ? CLIENT : SERVER;
|
|
|
|
for (i = 0; i < cMaxIos; i++)
|
|
{
|
|
pDatagram = &pEndpoint->aDatagrams[i];
|
|
|
|
pDatagram->id = pEndpoint->id;
|
|
pDatagram->type = type;
|
|
pDatagram->pEndpoint = pEndpoint;
|
|
pDatagram->Busy = 0;
|
|
pDatagram->Packet.buf = 0;
|
|
memset(&pDatagram->Read, 0, sizeof(pDatagram->Read));
|
|
pDatagram->Read.pAsyncObject = pDatagram;
|
|
}
|
|
|
|
if (fAsync)
|
|
{
|
|
status = COMMON_PrepareNewHandle((HANDLE)sock);
|
|
}
|
|
else
|
|
{
|
|
// The receive operation on sync endpoints will may span
|
|
// several receives. This means it can't use the thread
|
|
// event, so allocate an event for the receive.
|
|
HANDLE hEvent = CreateEventW(0, TRUE, FALSE, 0);
|
|
if (!hEvent)
|
|
{
|
|
status = RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pDatagram == &pEndpoint->aDatagrams[0]);
|
|
pDatagram->Read.ol.hEvent = hEvent;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// If adding a new failure case here, add code to close the sync receive event.
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
closesocket(sock);
|
|
|
|
delete pEndpoint->aDatagrams;
|
|
|
|
return(status);
|
|
}
|
|
|
|
TransportProtocol::AddObjectToProtocolList((BASE_ASYNC_OBJECT *) pEndpoint);
|
|
|
|
if (!fClient)
|
|
{
|
|
TransportProtocol::FunctionalProtocolDetected(pEndpoint->id);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
VOID
|
|
DG_DeactivateAddress (
|
|
IN WS_DATAGRAM_ENDPOINT *pEndpoint
|
|
)
|
|
/*++
|
|
Function Name:DG_DeactivateAddress
|
|
|
|
Parameters:
|
|
|
|
Description:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
if (InterlockedIncrement(&pEndpoint->fAborted) != 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pEndpoint->Socket)
|
|
{
|
|
closesocket(pEndpoint->Socket);
|
|
pEndpoint->Socket = 0;
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
DG_ReactivateAddress (
|
|
IN WS_DATAGRAM_ENDPOINT *pEndpoint
|
|
)
|
|
/*++
|
|
Function Name:DG_DeactivateAddress
|
|
|
|
Parameters:
|
|
|
|
Description:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
WS_SOCKADDR *addr = &pEndpoint->ListenAddr;
|
|
|
|
//
|
|
// If the endpoint is dynamic, clear out the endpoint
|
|
//
|
|
if (pEndpoint->fDynamicEndpoint)
|
|
{
|
|
//
|
|
// Clear out the listenaddr
|
|
//
|
|
switch (pEndpoint->id)
|
|
{
|
|
#ifdef IPX_ON
|
|
case IPX:
|
|
addr->ipxaddr.sa_socket = 0;
|
|
break;
|
|
#endif
|
|
|
|
case CDP:
|
|
CDP_InitLocalAddress(&addr->clusaddr, 0);
|
|
break;
|
|
|
|
case UDP:
|
|
addr->inetaddr.sin_port = 0;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
Status = DG_CreateEndpoint(pEndpoint);
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
pEndpoint->fAborted = 0;
|
|
DG_SubmitReceives(pEndpoint);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
void RPC_ENTRY
|
|
DG_ServerAbortListen(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback after DG_CreateEndpoint has completed successfully
|
|
but the runtime for some reason is not going to be able to
|
|
listen on the endpoint.
|
|
|
|
--*/
|
|
{
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
|
|
ASSERT(pEndpoint->cPendingIos == 0);
|
|
ASSERT(pEndpoint->Socket);
|
|
ASSERT(pEndpoint->pNext == 0);
|
|
ASSERT(pEndpoint->type & SERVER);
|
|
|
|
delete pEndpoint->pAddressVector;
|
|
delete pEndpoint->aDatagrams;
|
|
closesocket(pEndpoint->Socket);
|
|
|
|
return;
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
DG_ClientCloseEndpoint(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called on sync client endpoints when they are no longer needed.
|
|
|
|
Arguments:
|
|
|
|
ThisEndpoint
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
{
|
|
BOOL b;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
PWS_DATAGRAM pDatagram = &pEndpoint->aDatagrams[0];
|
|
|
|
ASSERT((pEndpoint->type & TYPE_MASK) == CLIENT);
|
|
ASSERT(pEndpoint->Socket); // Open must have worked
|
|
ASSERT(pEndpoint->cMinimumIos == 0);
|
|
ASSERT(pEndpoint->cMaximumIos == 1); // Must not be async!
|
|
ASSERT(pEndpoint->aDatagrams);
|
|
ASSERT(pEndpoint->aDatagrams[0].Read.ol.hEvent);
|
|
ASSERT(pEndpoint->Endpoint == 0);
|
|
ASSERT(pEndpoint->pAddressVector == 0);
|
|
ASSERT(pEndpoint->pNext == 0);
|
|
|
|
// If there is a pending receive, closing the socket will cancel the IO.
|
|
closesocket(pEndpoint->Socket);
|
|
|
|
// Wait for the pending receive to actually complete.
|
|
|
|
if (pDatagram->Busy)
|
|
{
|
|
DWORD bytes;
|
|
ASSERT(pDatagram->Busy);
|
|
ASSERT(pDatagram->Packet.buf);
|
|
|
|
GetOverlappedResult((HANDLE)pEndpoint->Socket,
|
|
&pDatagram->Read.ol,
|
|
&bytes,
|
|
TRUE);
|
|
|
|
if (GetLastError() != ERROR_OPERATION_ABORTED)
|
|
{
|
|
// Overactive output, the receive may have completed normally..
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG receive completed %d on %p after closed\n",
|
|
GetLastError(),
|
|
pDatagram));
|
|
}
|
|
}
|
|
|
|
b = CloseHandle(pEndpoint->aDatagrams[0].Read.ol.hEvent);
|
|
ASSERT(b);
|
|
|
|
TransportProtocol::RemoveObjectFromProtocolList(pEndpoint);
|
|
|
|
// Free the receive buffer if allocated
|
|
|
|
if (pDatagram->Packet.buf)
|
|
{
|
|
I_RpcTransDatagramFree(pEndpoint,
|
|
(BUFFER)pDatagram->Packet.buf
|
|
);
|
|
}
|
|
|
|
delete pDatagram;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
DG_GetEndpointStats(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
OUT DG_ENDPOINT_STATS * pStats
|
|
)
|
|
{
|
|
DWORD Status;
|
|
DWORD Data;
|
|
int Length;
|
|
BOOL Ok;
|
|
|
|
PWS_DATAGRAM_ENDPOINT Endpoint = (PWS_DATAGRAM_ENDPOINT) ThisEndpoint;
|
|
|
|
Length = sizeof(DWORD);
|
|
|
|
Status = getsockopt(Endpoint->Socket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *) &Data, &Length);
|
|
if (Status)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// jroberts, 10-Jan-2001 : I believe that getsockopt is returning 0xffffffff occasionally.
|
|
// This is an attempt to catch it.
|
|
//
|
|
if (Endpoint->id == UDP)
|
|
{
|
|
ASSERT( Data < 0x10000 );
|
|
}
|
|
|
|
Data &= ~7UL;
|
|
|
|
pStats->MaxPduSize = Data;
|
|
|
|
Length = sizeof(DWORD);
|
|
|
|
Status = getsockopt(Endpoint->Socket, SOL_SOCKET, SO_RCVBUF, (char *) &Data, &Length);
|
|
if (Status)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
Data &= ~7UL;
|
|
pStats->ReceiveBufferSize = Data;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CDP/IP specific functions.
|
|
//
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
CDP_ServerListen(
|
|
IN OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN RPC_CHAR *NetworkAddress,
|
|
IN OUT RPC_CHAR **pPort,
|
|
IN void *pSecurityDescriptor,
|
|
IN ULONG EndpointFlags,
|
|
IN ULONG NICFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a server endpoint object to receive packets. New
|
|
packets won't actually arrive until CompleteListen is
|
|
called.
|
|
|
|
Arguments:
|
|
|
|
ThisEndpoint - Storage for the server endpoint object.
|
|
pPort - The endpoint to listen on or a pointer to 0 if
|
|
the transport should choose the address.
|
|
Contains the endpoint listened to on output. The
|
|
caller should free this.
|
|
pSecurityDiscriptor - Security to attach to this endpoint (not
|
|
used by this transport).
|
|
EndpointFlags - Application flags passed into RPC via
|
|
RpcServerUseProtseq*Ex.
|
|
NICFlags - Application flags passed into RPC via
|
|
RpcServerUseProtseq*Ex.
|
|
pNetworkAddresses - A vector of the network addresses
|
|
listened on by this call. This vector does
|
|
not need to be freed.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_CANT_CREATE_ENDPOINT
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_DUPLICATE_ENDPOINT
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status;
|
|
NTSTATUS NtStatus;
|
|
USHORT port;
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AsciiString;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR *addr = &pEndpoint->ListenAddr;
|
|
NETWORK_ADDRESS_VECTOR * ServerAddress;
|
|
|
|
// Figure out the port to listen on.
|
|
|
|
if (*pPort)
|
|
{
|
|
status = EndpointToPortNumber(*pPort, port);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
pEndpoint->fDynamicEndpoint = 0;
|
|
|
|
CDP_InitLocalAddress( &addr->clusaddr, port );
|
|
}
|
|
else
|
|
{
|
|
return RPC_S_INVALID_ENDPOINT_FORMAT;
|
|
}
|
|
|
|
pEndpoint->id = CDP;
|
|
pEndpoint->fClient = FALSE;
|
|
pEndpoint->fAsync = TRUE;
|
|
pEndpoint->EndpointFlags = 0;
|
|
|
|
//
|
|
// Actually create the endpoint
|
|
//
|
|
status = DG_CreateEndpoint(pEndpoint);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
// Figure out the network addresses.
|
|
// The only way we can determine our cluster
|
|
// address is to read it out of the registry
|
|
|
|
status = CDP_BuildAddressVector(&pEndpoint->pAddressVector);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
DG_ServerAbortListen(ThisEndpoint);
|
|
return(status);
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
CDP_QueryEndpoint
|
|
(
|
|
IN void * pOriginalEndpoint,
|
|
OUT RPC_CHAR * pClientEndpoint
|
|
)
|
|
{
|
|
WS_SOCKADDR * pSockAddr = (WS_SOCKADDR *)pOriginalEndpoint;
|
|
unsigned NativeSocket = pSockAddr->clusaddr.sac_port;
|
|
char AnsiBuffer[CDP_MAXIMUM_ENDPOINT];
|
|
|
|
char * pAnsi = AnsiBuffer;
|
|
RPC_CHAR * pUni = pClientEndpoint;
|
|
|
|
//
|
|
// Convert endpoint to an ASCII string, and thence to Unicode.
|
|
//
|
|
_ultoa(NativeSocket, AnsiBuffer, 10);
|
|
|
|
while ( *pUni++ = *pAnsi++ );
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
CDP_QueryAddress
|
|
(
|
|
IN void * pOriginalEndpoint,
|
|
OUT RPC_CHAR * pClientAddress
|
|
)
|
|
{
|
|
PSOCKADDR_CLUSTER pSockAddr = (PSOCKADDR_CLUSTER) pOriginalEndpoint;
|
|
|
|
_ultow(pSockAddr->sac_node, pClientAddress, 10);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
CDP_ClientInitializeAddress
|
|
(
|
|
OUT DG_TRANSPORT_ADDRESS Address,
|
|
IN RPC_CHAR *NetworkAddress,
|
|
IN RPC_CHAR *pPort,
|
|
IN BOOL fUseCache,
|
|
IN BOOL fBroadcast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a address object for sending to a server.
|
|
|
|
Arguments:
|
|
|
|
Address - Storage for the address
|
|
NetworkAddress - The address of the server or 0 if local
|
|
Endpoint - The endpoint of the server
|
|
fUseCache - If TRUE then the transport may use a cached
|
|
value from a previous call on the same NetworkAddress.
|
|
fBroadcast - If TRUE, NetworkAddress is ignored and a broadcast
|
|
address is used.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Success, name resolved and, optionally, added to cache.
|
|
RPC_P_FOUND_IN_CACHE - Success, returned only if fUseCache is TRUE
|
|
and the was name found in local cache.
|
|
RPC_P_MATCHED_CACHE - Partial success, fUseCache is FALSE and the
|
|
result of the lookup was the same as the value previously
|
|
in the cache.
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_SERVER_UNAVAILABLE
|
|
|
|
--*/
|
|
{
|
|
WS_SOCKADDR *pAddr = (WS_SOCKADDR *)Address;
|
|
ULONG HostAddr;
|
|
ULONG Endpoint;
|
|
int i;
|
|
USHORT port;
|
|
RPC_STATUS status;
|
|
|
|
|
|
// Figure out the destination port
|
|
|
|
status = EndpointToPortNumber(pPort, port);
|
|
|
|
if (RPC_S_OK != status)
|
|
{
|
|
ASSERT( 0 );
|
|
return(status);
|
|
}
|
|
|
|
CDP_InitLocalAddress( &pAddr->clusaddr, port );
|
|
|
|
// Resolve the network address - CDP addresses are
|
|
// numbers representing a member ID in the cluster.
|
|
|
|
pAddr->clusaddr.sac_node = _wtol( NetworkAddress );
|
|
|
|
return(status);
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
CDP_ClientOpenEndpoint(
|
|
OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN BOOL fAsync,
|
|
DWORD Flags,
|
|
IN DG_TRANSPORT_ENDPOINT ServerEndpoint OPTIONAL
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
|
|
|
|
// We don't care what port we bind to, we also don't care what
|
|
// port we bind to.
|
|
// I think he's trying to say that we don't care what port
|
|
// we bind to.
|
|
|
|
CDP_InitLocalAddress(&pEndpoint->ListenAddr.clusaddr, 0);
|
|
|
|
pEndpoint->id = CDP;
|
|
pEndpoint->fClient = TRUE;
|
|
pEndpoint->fAsync = fAsync;
|
|
pEndpoint->EndpointFlags = 0;
|
|
pEndpoint->fDynamicEndpoint = 1;
|
|
|
|
Status = DG_CreateEndpoint(pEndpoint);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
CDP_InitializeSockAddr(
|
|
IN char *Endpoint,
|
|
OUT WS_SOCKADDR *pSockAddr,
|
|
DG_TRANSPORT_ENDPOINT ThisEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialized the sockaddr to be a loopback address to the
|
|
endpoint specified. Used to forward packets locally.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - The string value of the servers endpoint.
|
|
|
|
pSockAddr - The sockaddr to fill in.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
{
|
|
long port;
|
|
|
|
port = atol(Endpoint);
|
|
|
|
if (port <= 0 || port > 0xFFFF)
|
|
{
|
|
ASSERT( 0 );
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
|
|
CDP_InitLocalAddress(&pSockAddr->clusaddr, (unsigned short) port);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
CDP_GetEndpointStats(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
OUT DG_ENDPOINT_STATS * pStats
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
Status = DG_GetEndpointStats(ThisEndpoint, pStats);
|
|
if (Status)
|
|
{
|
|
pStats->MaxPduSize = 1452;
|
|
pStats->MaxPacketSize = 1452;
|
|
pStats->PreferredPduSize = 1452;
|
|
|
|
pStats->ReceiveBufferSize= 8192;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// ethernet frame (1500) - UDP/IP headers (28) - CNP/CDP headers (20)
|
|
//
|
|
|
|
pStats->MaxPacketSize = 1452;
|
|
pStats->PreferredPduSize = 4096;
|
|
if (pStats->PreferredPduSize > pStats->MaxPduSize)
|
|
{
|
|
pStats->PreferredPduSize = pStats->MaxPduSize;
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UDP/IP specific functions.
|
|
//
|
|
RPC_STATUS RPC_ENTRY
|
|
UDP_ServerListen(
|
|
IN OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN RPC_CHAR *NetworkAddress,
|
|
IN OUT RPC_CHAR **pPort,
|
|
IN void *pSecurityDescriptor,
|
|
IN ULONG EndpointFlags,
|
|
IN ULONG NICFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a server endpoint object to receive packets. New
|
|
packets won't actually arrive until CompleteListen is
|
|
called.
|
|
|
|
Arguments:
|
|
|
|
ThisEndpoint - Storage for the server endpoint object.
|
|
pPort - The endpoint to listen on or a pointer to 0 if
|
|
the transport should choose the address.
|
|
Contains the endpoint listened to on output. The
|
|
caller should free this.
|
|
pSecurityDiscriptor - Security to attach to this endpoint (not
|
|
used by UDP).
|
|
EndpointFlags - Application flags passed into RPC via
|
|
RpcServerUseProtseq*Ex.
|
|
NICFlags - Application flags passed into RPC via
|
|
RpcServerUseProtseq*Ex.
|
|
pNetworkAddresses - A vector of the network addresses
|
|
listened on by this call. This vector does
|
|
not need to be freed.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_CANT_CREATE_ENDPOINT
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_DUPLICATE_ENDPOINT
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status;
|
|
NTSTATUS NtStatus;
|
|
USHORT port;
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AsciiString;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR *addr = &pEndpoint->ListenAddr;
|
|
|
|
addr->inetaddr.sin_family = AF_INET;
|
|
|
|
if (NetworkAddress)
|
|
{
|
|
IP_ADDRESS_RESOLVER resolver(NetworkAddress,
|
|
cosServer,
|
|
ipvtuIPv4 // IP version to use
|
|
);
|
|
|
|
// Loop until success, fatal failure or we run out of addresses.
|
|
|
|
status = resolver.NextAddress(&addr->inetaddr);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return RPC_S_INVALID_NET_ADDR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addr->inetaddr.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
|
|
// Figure out the port to listen on.
|
|
|
|
if (*pPort)
|
|
{
|
|
status = EndpointToPortNumber(*pPort, port);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
pEndpoint->fDynamicEndpoint = 0;
|
|
addr->inetaddr.sin_port = htons(port);
|
|
}
|
|
else
|
|
{
|
|
addr->inetaddr.sin_port = 0;
|
|
pEndpoint->fDynamicEndpoint = 1;
|
|
}
|
|
|
|
pEndpoint->id = UDP;
|
|
pEndpoint->fClient = FALSE;
|
|
pEndpoint->fAsync = TRUE;
|
|
pEndpoint->EndpointFlags = EndpointFlags;
|
|
|
|
//
|
|
// Actually create the endpoint
|
|
//
|
|
status = DG_CreateEndpoint(pEndpoint);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
// If needed, return the endpoint.
|
|
|
|
if (!*pPort)
|
|
{
|
|
*pPort = new RPC_CHAR[IP_MAXIMUM_ENDPOINT];
|
|
if (!*pPort)
|
|
{
|
|
DG_ServerAbortListen(ThisEndpoint);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
port = ntohs(addr->inetaddr.sin_port);
|
|
|
|
PortNumberToEndpoint(port, *pPort);
|
|
}
|
|
|
|
// Figure out the network addresses
|
|
ASSERT(pEndpoint->pAddressVector == NULL);
|
|
status = IP_BuildAddressVector(&pEndpoint->pAddressVector,
|
|
NICFlags,
|
|
NetworkAddress,
|
|
NULL);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
DG_ServerAbortListen(ThisEndpoint);
|
|
return(status);
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
UDP_QueryEndpoint
|
|
(
|
|
IN void * pOriginalEndpoint,
|
|
OUT RPC_CHAR * pClientEndpoint
|
|
)
|
|
{
|
|
WS_SOCKADDR * pSockAddr = (WS_SOCKADDR *)pOriginalEndpoint;
|
|
unsigned NativeSocket = ntohs(pSockAddr->inetaddr.sin_port);
|
|
char AnsiBuffer[IP_MAXIMUM_ENDPOINT];
|
|
|
|
char * pAnsi = AnsiBuffer;
|
|
RPC_CHAR * pUni = pClientEndpoint;
|
|
|
|
//
|
|
// Convert endpoint to an ASCII string, and thence to Unicode.
|
|
//
|
|
_ultoa(NativeSocket, AnsiBuffer, 10);
|
|
|
|
while ( *pUni++ = *pAnsi++ );
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
UDP_QueryAddress
|
|
(
|
|
IN void * pOriginalEndpoint,
|
|
OUT RPC_CHAR * pClientAddress
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AsciiString;
|
|
WS_SOCKADDR *pSockAddr = (WS_SOCKADDR *)pOriginalEndpoint;
|
|
NTSTATUS NtStatus;
|
|
|
|
UnicodeString.Buffer = pClientAddress;
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = IP_MAXIMUM_RAW_NAME * sizeof(RPC_CHAR);
|
|
|
|
char *t = inet_ntoa(pSockAddr->inetaddr.sin_addr);
|
|
ASSERT(t);
|
|
|
|
RtlInitAnsiString(&AsciiString, t);
|
|
ASSERT(AsciiString.Length < IP_MAXIMUM_RAW_NAME);
|
|
|
|
NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString,
|
|
&AsciiString,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
ASSERT(0);
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
UDP_ClientInitializeAddress
|
|
(
|
|
OUT DG_TRANSPORT_ADDRESS Address,
|
|
IN RPC_CHAR *NetworkAddress,
|
|
IN RPC_CHAR *pPort,
|
|
IN BOOL fUseCache,
|
|
IN BOOL fBroadcast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a address object for sending to a server.
|
|
|
|
Arguments:
|
|
|
|
Address - Storage for the address
|
|
NetworkAddress - The address of the server or 0 if local
|
|
Endpoint - The endpoint of the server
|
|
fUseCache - If TRUE then the transport may use a cached
|
|
value from a previous call on the same NetworkAddress.
|
|
fBroadcast - If TRUE, NetworkAddress is ignored and a broadcast
|
|
address is used.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Success, name resolved and, optionally, added to cache.
|
|
RPC_P_FOUND_IN_CACHE - Success, returned only if fUseCache is TRUE
|
|
and the was name found in local cache.
|
|
RPC_P_MATCHED_CACHE - Partial success, fUseCache is FALSE and the
|
|
result of the lookup was the same as the value previously
|
|
in the cache.
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_SERVER_UNAVAILABLE
|
|
|
|
--*/
|
|
{
|
|
WS_SOCKADDR *pAddr = (WS_SOCKADDR *)Address;
|
|
ULONG HostAddr;
|
|
ULONG Endpoint;
|
|
int i;
|
|
USHORT port;
|
|
RPC_STATUS status;
|
|
|
|
// Contant part of address
|
|
memset(pAddr->inetaddr.sin_zero, 0, 8);
|
|
|
|
pAddr->inetaddr.sin_family = AF_INET;
|
|
|
|
// Figure out the destination port
|
|
|
|
status = EndpointToPortNumber(pPort, port);
|
|
|
|
if (RPC_S_OK != status)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
pAddr->inetaddr.sin_port = htons(port);
|
|
|
|
// Resolve the network address
|
|
|
|
if (fBroadcast)
|
|
{
|
|
pAddr->inetaddr.sin_addr.s_addr = INADDR_BROADCAST;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
// Multiple server address support for UDP/IP is not available.
|
|
|
|
IP_ADDRESS_RESOLVER resolver(NetworkAddress,
|
|
cosClient,
|
|
ipvtuIPv4 // IP version to use
|
|
);
|
|
|
|
status = resolver.NextAddress(&pAddr->inetaddr);
|
|
|
|
if (status)
|
|
{
|
|
RpcpErrorAddRecord( EEInfoGCWinsock,
|
|
status,
|
|
EEInfoDLWinsockDatagramResolve10,
|
|
NetworkAddress
|
|
);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
UDP_ClientOpenEndpoint(
|
|
OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN BOOL fAsync,
|
|
DWORD EndpointFlags,
|
|
IN DG_TRANSPORT_ENDPOINT ServerEndpoint OPTIONAL
|
|
)
|
|
{
|
|
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR *addr = &pEndpoint->ListenAddr;
|
|
|
|
//
|
|
// We don't care what port we bind to.
|
|
// Ordinarily, we don't care what interface we bind to. When using selective
|
|
// bindings and making a callback, we should bind to the same IP address that
|
|
// was the original target of the call. This will come from the server endpoint.
|
|
//
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
// ServerEndpoint is provided only when processing a callback with selective bindings.
|
|
if (ServerEndpoint != NULL)
|
|
{
|
|
memcpy(&(addr->inetaddr.sin_addr), &(((PWS_DATAGRAM_ENDPOINT)ServerEndpoint)->ListenAddr.inetaddr.sin_addr), sizeof(addr->inetaddr.sin_addr));
|
|
}
|
|
|
|
addr->inetaddr.sin_family = AF_INET;
|
|
pEndpoint->id = UDP;
|
|
pEndpoint->fClient = TRUE;
|
|
pEndpoint->fAsync = fAsync;
|
|
pEndpoint->EndpointFlags = EndpointFlags;
|
|
pEndpoint->fDynamicEndpoint = 1;
|
|
|
|
return(DG_CreateEndpoint(pEndpoint));
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
UDP_InitializeSockAddr(
|
|
IN char *Endpoint,
|
|
OUT WS_SOCKADDR *pSockAddr,
|
|
DG_TRANSPORT_ENDPOINT ThisEndpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialized the sockaddr to be a loopback address to the
|
|
endpoint specified or the address from ThisEndpoint to the
|
|
endpoint specified. Used to forward packets locally.
|
|
|
|
ThisEndpoint will be provided when running with selective bindings
|
|
to make sure that the packet is forwarded to the same interface
|
|
on which the endpoint mapper received it, to ensure that the reply
|
|
can reach the client.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - The string value of the servers endpoint.
|
|
|
|
pSockAddr - The sockaddr to fill in.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
{
|
|
int len;
|
|
long port;
|
|
|
|
pSockAddr->generic.sa_family = AF_INET;
|
|
if (ThisEndpoint == NULL)
|
|
{
|
|
pSockAddr->inetaddr.sin_addr.s_addr = 0x0100007F; // byte swapped, 127.0.0.1
|
|
}
|
|
else
|
|
{
|
|
memcpy(&(pSockAddr->inetaddr.sin_addr.s_addr), &(((WS_DATAGRAM_ENDPOINT *)ThisEndpoint)->ListenAddr.inetaddr.sin_addr), sizeof(in_addr));
|
|
}
|
|
|
|
port = atol(Endpoint);
|
|
|
|
if (port <= 0 || port > 0xFFFF)
|
|
{
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
|
|
pSockAddr->inetaddr.sin_port = htons((USHORT) port);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
UDP_GetEndpointStats(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
OUT DG_ENDPOINT_STATS * pStats
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
Status = DG_GetEndpointStats(ThisEndpoint, pStats);
|
|
if (Status)
|
|
{
|
|
pStats->MaxPduSize = 1472;
|
|
pStats->MaxPacketSize = 1472;
|
|
pStats->PreferredPduSize = 1472;
|
|
|
|
pStats->ReceiveBufferSize= 8192;
|
|
return Status;
|
|
}
|
|
|
|
pStats->MaxPacketSize = 1472;
|
|
pStats->PreferredPduSize = 4096;
|
|
if (pStats->PreferredPduSize > pStats->MaxPduSize)
|
|
{
|
|
pStats->PreferredPduSize = pStats->MaxPduSize;
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
#ifdef IPX_ON
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IPX specific functions.
|
|
//
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
IPX_ServerListen(
|
|
IN OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN RPC_CHAR *NetworkAddress,
|
|
IN OUT RPC_CHAR **pPort,
|
|
IN void *pSecurityDescriptor,
|
|
IN ULONG EndpointFlags,
|
|
IN ULONG NICFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a server endpoint object to receive packets. New
|
|
packets won't actually arrive until CompleteListen is
|
|
called.
|
|
|
|
Arguments:
|
|
|
|
ThisEndpoint - Storage for the server endpoint object.
|
|
pPort - The endpoint to listen on or a pointer to 0 if
|
|
the transport should choose the address.
|
|
Contains the endpoint listened to on output. The
|
|
caller should free this.
|
|
pSecurityDiscriptor - Security to attach to this endpoint (not
|
|
used by the IPX transport).
|
|
EndpointFlags - Application flags passed into RPC via
|
|
RpcServerUseProtseq*Ex.
|
|
NICFlags - Application flags passed into RPC via
|
|
RpcServerUseProtseq*Ex.
|
|
pNetworkAddresses - A vector of the network addresses
|
|
listened on by this call. This vector does
|
|
not need to be freed.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_CANT_CREATE_ENDPOINT
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_DUPLICATE_ENDPOINT
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status;
|
|
NTSTATUS NtStatus;
|
|
USHORT port;
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AsciiString;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR *addr = &pEndpoint->ListenAddr;
|
|
|
|
//
|
|
// Figure out what port to listen on.
|
|
//
|
|
if (*pPort)
|
|
{
|
|
status = EndpointToPortNumber(*pPort, port);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
pEndpoint->fDynamicEndpoint = 0;
|
|
}
|
|
else
|
|
{
|
|
port = 0;
|
|
pEndpoint->fDynamicEndpoint = 1;
|
|
}
|
|
|
|
|
|
addr->generic.sa_family = AF_IPX;
|
|
addr->ipxaddr.sa_socket = htons(port);
|
|
|
|
pEndpoint->id = IPX;
|
|
pEndpoint->fClient = FALSE;
|
|
pEndpoint->fAsync = TRUE;
|
|
pEndpoint->EndpointFlags = 0;
|
|
|
|
//
|
|
// Actually create the endpoint
|
|
//
|
|
status =
|
|
DG_CreateEndpoint(pEndpoint);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
// If needed, figure out the dynamically allocated endpoint.
|
|
|
|
if (!*pPort)
|
|
{
|
|
*pPort = new RPC_CHAR[IP_MAXIMUM_ENDPOINT];
|
|
if (!*pPort)
|
|
{
|
|
DG_ServerAbortListen(ThisEndpoint);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
port = ntohs(addr->ipxaddr.sa_socket);
|
|
|
|
PortNumberToEndpoint(port, *pPort);
|
|
}
|
|
|
|
// Update the local address cache
|
|
//
|
|
// Since there is only one addess no lock is required.
|
|
//
|
|
memcpy(IpxAddr.sa_netnum, addr->ipxaddr.sa_netnum, sizeof(IpxAddr.sa_netnum));
|
|
memcpy(IpxAddr.sa_nodenum, addr->ipxaddr.sa_nodenum, sizeof(IpxAddr.sa_nodenum));
|
|
fIpxAddrValid = TRUE;
|
|
|
|
//
|
|
// Figure out our server's raw IPX address.
|
|
//
|
|
|
|
status = IPX_BuildAddressVector(&(pEndpoint->pAddressVector));
|
|
if (status != RPC_S_OK)
|
|
{
|
|
DG_ServerAbortListen(ThisEndpoint);
|
|
delete *pPort;
|
|
return(status);
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
IPX_QueryEndpoint
|
|
(
|
|
IN void * pOriginalEndpoint,
|
|
OUT RPC_CHAR * pClientEndpoint
|
|
)
|
|
{
|
|
WS_SOCKADDR * pSockAddr = (WS_SOCKADDR *)pOriginalEndpoint;
|
|
unsigned NativeSocket = ntohs(pSockAddr->ipxaddr.sa_socket);
|
|
char AnsiBuffer[IPX_MAXIMUM_ENDPOINT];
|
|
|
|
char * pAnsi = AnsiBuffer;
|
|
RPC_CHAR * pUni = pClientEndpoint;
|
|
|
|
//
|
|
// Convert endpoint to an ASCII string, and thence to Unicode.
|
|
//
|
|
_ultoa(NativeSocket, AnsiBuffer, 10);
|
|
|
|
while ( *pUni++ = *pAnsi++ );
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
IPX_QueryAddress
|
|
(
|
|
IN void * pOriginalEndpoint,
|
|
OUT RPC_CHAR * pString
|
|
)
|
|
{
|
|
WS_SOCKADDR *pSockAddr = (WS_SOCKADDR *) pOriginalEndpoint;
|
|
|
|
IPX_AddressToName(&pSockAddr->ipxaddr, pString);
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
IPX_ClientInitializeAddress
|
|
(
|
|
OUT DG_TRANSPORT_ADDRESS Address,
|
|
IN RPC_CHAR *NetworkAddress,
|
|
IN RPC_CHAR *pPort,
|
|
IN BOOL fUseCache,
|
|
IN BOOL fBroadcast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a address object for sending to a server.
|
|
|
|
Arguments:
|
|
|
|
Address - Storage for the address
|
|
NetworkAddress - The address of the server or 0 if local
|
|
pPort - The endpoint of the server
|
|
fUseCache - If TRUE then the transport may use a cached
|
|
value from a previous call on the same NetworkAddress.
|
|
fBroadcast - If TRUE, NetworkAddress is ignored and a broadcast
|
|
address is used.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Success, name resolved and, optionally, added to cache.
|
|
RPC_P_FOUND_IN_CACHE - Success, returned only if fUseCache is TRUE
|
|
and the was name found in local cache.
|
|
RPC_P_MATCHED_CACHE - Partial success, fUseCache is FALSE and the
|
|
result of the lookup was the same as the value previously
|
|
in the cache.
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
RPC_S_OUT_OF_RESOURCES
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_SERVER_UNAVAILABLE
|
|
|
|
--*/
|
|
{
|
|
WS_SOCKADDR *pAddr = (WS_SOCKADDR *)Address;
|
|
RPC_STATUS status = RPC_S_OK;
|
|
USHORT port = 0;
|
|
|
|
pAddr->ipxaddr.sa_family = AF_IPX;
|
|
pAddr->ipxaddr.sa_socket = 0;
|
|
|
|
// Convert unicode endpoint to port number
|
|
|
|
status = EndpointToPortNumber(pPort, port);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Convert unicode network address to ipx address
|
|
//
|
|
|
|
if (FALSE == fBroadcast)
|
|
{
|
|
status = IPX_NameToAddress(NetworkAddress,
|
|
fUseCache,
|
|
&pAddr->ipxaddr
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
memset(pAddr->ipxaddr.sa_netnum, 0, sizeof(pAddr->ipxaddr.sa_netnum));
|
|
memset(pAddr->ipxaddr.sa_nodenum, 0xFF, sizeof(pAddr->ipxaddr.sa_nodenum));
|
|
}
|
|
|
|
pAddr->ipxaddr.sa_socket = htons(port);
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
IPX_ClientOpenEndpoint(
|
|
OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
IN BOOL fAsync,
|
|
DWORD Flags
|
|
)
|
|
{
|
|
RPC_STATUS status;
|
|
PWS_DATAGRAM_ENDPOINT pEndpoint = (PWS_DATAGRAM_ENDPOINT)ThisEndpoint;
|
|
WS_SOCKADDR *addr = &pEndpoint->ListenAddr;
|
|
|
|
// We don't care what port we bind to, we also don't care what
|
|
// port we bind to.
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
addr->ipxaddr.sa_family = AF_IPX;
|
|
|
|
pEndpoint->id = IPX;
|
|
pEndpoint->fClient = TRUE ;
|
|
pEndpoint->fAsync = fAsync;
|
|
pEndpoint->EndpointFlags = 0;
|
|
pEndpoint->fDynamicEndpoint = 1;
|
|
|
|
status = DG_CreateEndpoint(pEndpoint);
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
// Update cache
|
|
memcpy(IpxAddr.sa_netnum, addr->ipxaddr.sa_netnum, sizeof(IpxAddr.sa_netnum));
|
|
memcpy(IpxAddr.sa_nodenum, addr->ipxaddr.sa_nodenum, sizeof(IpxAddr.sa_nodenum));
|
|
fIpxAddrValid = TRUE;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
IPX_InitializeSockAddr(
|
|
IN char *Endpoint,
|
|
OUT WS_SOCKADDR *pSockAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialized the sockaddr to be a loopback address to the
|
|
endpoint specified. Used to forward packets locally.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - The string value of the servers endpoint.
|
|
|
|
pSockAddr - The sockaddr to fill in.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
{
|
|
int len;
|
|
long port;
|
|
|
|
pSockAddr->generic.sa_family = AF_IPX;
|
|
|
|
port = atol(Endpoint);
|
|
if (port <= 0 || port > 0xFFFF)
|
|
{
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
pSockAddr->ipxaddr.sa_socket = htons((USHORT)port);
|
|
|
|
//
|
|
// In order to get this far this server must have
|
|
// alrady listened to IPX.
|
|
//
|
|
ASSERT(fIpxAddrValid);
|
|
memcpy(pSockAddr->ipxaddr.sa_netnum, IpxAddr.sa_netnum, sizeof(pSockAddr->ipxaddr.sa_netnum));
|
|
memcpy(pSockAddr->ipxaddr.sa_nodenum, IpxAddr.sa_nodenum, sizeof(pSockAddr->ipxaddr.sa_nodenum));
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY
|
|
IPX_GetEndpointStats(
|
|
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
|
OUT DG_ENDPOINT_STATS * pStats
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
Status = DG_GetEndpointStats(ThisEndpoint, pStats);
|
|
if (Status)
|
|
{
|
|
pStats->MaxPduSize = 1478;
|
|
pStats->MaxPacketSize = 1478;
|
|
pStats->PreferredPduSize = 1478;
|
|
|
|
pStats->ReceiveBufferSize= 8192;
|
|
return Status;
|
|
}
|
|
|
|
pStats->MaxPacketSize = 1478;
|
|
pStats->PreferredPduSize = pStats->MaxPduSize;
|
|
pStats->MaxPacketSize = pStats->MaxPduSize;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Transport interface structures and loader
|
|
//
|
|
|
|
const RPC_DATAGRAM_TRANSPORT
|
|
UDP_TransportInterface = {
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
UDP_TOWER_ID,
|
|
IP_ADDRESS_ID,
|
|
RPC_STRING_LITERAL("ncadg_ip_udp"),
|
|
"135",
|
|
COMMON_ProcessCalls,
|
|
COMMON_StartPnpNotifications,
|
|
COMMON_ListenForPNPNotifications,
|
|
COMMON_TowerConstruct,
|
|
COMMON_TowerExplode,
|
|
COMMON_PostRuntimeEvent,
|
|
TRUE,
|
|
DG_GetNetworkAddressVector,
|
|
sizeof(WS_DATAGRAM_ENDPOINT),
|
|
sizeof(WS_DATAGRAM_ENDPOINT),
|
|
sizeof(WS_SOCKADDR),
|
|
IP_MAXIMUM_ENDPOINT,
|
|
IP_MAXIMUM_PRETTY_NAME,
|
|
1024,
|
|
1472,
|
|
DG_SendPacket,
|
|
UDP_ClientOpenEndpoint,
|
|
UDP_ClientInitializeAddress,
|
|
DG_ClientCloseEndpoint,
|
|
DG_ReceivePacket,
|
|
UDP_ServerListen,
|
|
DG_ServerAbortListen,
|
|
COMMON_ServerCompleteListen,
|
|
DG_ForwardPacket,
|
|
UDP_QueryAddress,
|
|
UDP_QueryEndpoint,
|
|
UDP_GetEndpointStats,
|
|
|
|
FALSE, // fIsMessageTransport (TRUE/FALSE).
|
|
|
|
0, // OptionSize
|
|
0, // InitOptions()
|
|
0, // SetOption()
|
|
0, // InqOption()
|
|
0, // ImplementOptions()
|
|
0, // AllowReceives()
|
|
0 // InquireAuthClient()
|
|
};
|
|
|
|
// When the RPC verifier is enabled and we are corrupting client receives,
|
|
// we will use a modified transport interface given below. It will have the sync
|
|
// receive members overwritten.
|
|
RPC_DATAGRAM_TRANSPORT *pUDP_TransportInterface_Avrf = NULL;
|
|
|
|
const RPC_DATAGRAM_TRANSPORT
|
|
CDP_TransportInterface = {
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
CDP_TOWER_ID,
|
|
IP_ADDRESS_ID,
|
|
RPC_STRING_LITERAL("ncadg_cluster"),
|
|
NULL,
|
|
COMMON_ProcessCalls,
|
|
COMMON_StartPnpNotifications,
|
|
COMMON_ListenForPNPNotifications,
|
|
COMMON_TowerConstruct,
|
|
COMMON_TowerExplode,
|
|
COMMON_PostRuntimeEvent,
|
|
TRUE,
|
|
DG_GetNetworkAddressVector,
|
|
sizeof(WS_DATAGRAM_ENDPOINT),
|
|
sizeof(WS_DATAGRAM_ENDPOINT),
|
|
sizeof(WS_SOCKADDR),
|
|
IP_MAXIMUM_ENDPOINT,
|
|
IP_MAXIMUM_PRETTY_NAME,
|
|
1024,
|
|
1452,
|
|
DG_SendPacket,
|
|
CDP_ClientOpenEndpoint,
|
|
CDP_ClientInitializeAddress,
|
|
DG_ClientCloseEndpoint,
|
|
DG_ReceivePacket,
|
|
CDP_ServerListen,
|
|
DG_ServerAbortListen,
|
|
COMMON_ServerCompleteListen,
|
|
DG_ForwardPacket,
|
|
CDP_QueryAddress,
|
|
CDP_QueryEndpoint,
|
|
CDP_GetEndpointStats,
|
|
|
|
FALSE, // fIsMessageTransport (TRUE/FALSE).
|
|
|
|
0, // OptionSize
|
|
0, // InitOptions()
|
|
0, // SetOption()
|
|
0, // InqOption()
|
|
0, // ImplementOptions()
|
|
0, // AllowReceives()
|
|
0 // InquireAuthClient()
|
|
};
|
|
|
|
RPC_DATAGRAM_TRANSPORT *pCDP_TransportInterface_Avrf = NULL;
|
|
|
|
#ifdef IPX_ON
|
|
const RPC_DATAGRAM_TRANSPORT
|
|
IPX_TransportInterface = {
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
IPX_TOWER_ID,
|
|
IPX_ADDRESS_ID,
|
|
RPC_STRING_LITERAL("ncadg_ipx"),
|
|
"34280",
|
|
COMMON_ProcessCalls,
|
|
COMMON_StartPnpNotifications,
|
|
COMMON_ListenForPNPNotifications,
|
|
COMMON_TowerConstruct,
|
|
COMMON_TowerExplode,
|
|
COMMON_PostRuntimeEvent,
|
|
TRUE,
|
|
DG_GetNetworkAddressVector,
|
|
sizeof(WS_DATAGRAM_ENDPOINT),
|
|
sizeof(WS_DATAGRAM_ENDPOINT),
|
|
sizeof(WS_SOCKADDR),
|
|
IPX_MAXIMUM_ENDPOINT,
|
|
IPX_MAXIMUM_PRETTY_NAME,
|
|
1024,
|
|
1464,
|
|
DG_SendPacket,
|
|
IPX_ClientOpenEndpoint,
|
|
IPX_ClientInitializeAddress,
|
|
DG_ClientCloseEndpoint,
|
|
DG_ReceivePacket,
|
|
IPX_ServerListen,
|
|
DG_ServerAbortListen,
|
|
COMMON_ServerCompleteListen,
|
|
DG_ForwardPacket,
|
|
IPX_QueryAddress,
|
|
IPX_QueryEndpoint,
|
|
IPX_GetEndpointStats,
|
|
|
|
FALSE, // fIsMessageTransport (TRUE/FALSE).
|
|
|
|
0, // OptionSize
|
|
0, // InitOptions()
|
|
0, // SetOption()
|
|
0, // InqOption()
|
|
0, // ImplementOptions()
|
|
0, // AllowReceives()
|
|
0 // InquireAuthClient()
|
|
};
|
|
#endif
|
|
|
|
|
|
#ifdef NCADG_MQ_ON
|
|
const RPC_DATAGRAM_TRANSPORT
|
|
MQ_TransportInterface = {
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
MQ_TOWER_ID,
|
|
MQ_ADDRESS_ID,
|
|
RPC_STRING_LITERAL("ncadg_mq"),
|
|
"EpMapper",
|
|
COMMON_ProcessCalls,
|
|
|
|
COMMON_StartPnpNotifications,
|
|
COMMON_ListenForPNPNotifications,
|
|
|
|
COMMON_TowerConstruct,
|
|
COMMON_TowerExplode,
|
|
COMMON_PostRuntimeEvent,
|
|
TRUE,
|
|
MQ_GetNetworkAddressVector, // Since MQ is being depricated, this is not defined.
|
|
sizeof(MQ_DATAGRAM_ENDPOINT),
|
|
sizeof(MQ_DATAGRAM_ENDPOINT),
|
|
sizeof(MQ_ADDRESS),
|
|
MQ_MAXIMUM_ENDPOINT,
|
|
MQ_MAXIMUM_PRETTY_NAME,
|
|
|
|
MQ_MAX_PDU_SIZE,
|
|
MQ_PREFERRED_PDU_SIZE,
|
|
|
|
MQ_SendPacket,
|
|
MQ_ClientOpenEndpoint,
|
|
MQ_ClientInitializeAddress,
|
|
MQ_ClientCloseEndpoint,
|
|
MQ_ReceivePacket,
|
|
MQ_ServerListen,
|
|
MQ_ServerAbortListen,
|
|
COMMON_ServerCompleteListen,
|
|
MQ_ForwardPacket,
|
|
MQ_QueryAddress,
|
|
MQ_QueryEndpoint,
|
|
MQ_GetEndpointStats,
|
|
|
|
TRUE, // fIsMessageTransport (TRUE/FALSE).
|
|
|
|
sizeof(MQ_OPTIONS), // OptionSize
|
|
MQ_InitOptions, // InitOptions()
|
|
MQ_SetOption, // SetOption()
|
|
MQ_InqOption, // InqOption()
|
|
MQ_ImplementOptions, // ImplementOptions()
|
|
MQ_AllowReceives, // AllowReceives()
|
|
MQ_InquireAuthClient
|
|
};
|
|
#endif // NCADG_MQ_ON
|
|
|
|
|
|
const RPC_DATAGRAM_TRANSPORT *
|
|
DG_TransportLoad (
|
|
IN PROTOCOL_ID index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads a datagram protocol and returns the transport interface
|
|
information for the protocol.
|
|
|
|
Arguments:
|
|
|
|
index - the PROTOCOL_ID value of the protocol to load.
|
|
|
|
Return Value:
|
|
|
|
0 - failure
|
|
!0 - success
|
|
|
|
--*/
|
|
{
|
|
const RPC_DATAGRAM_TRANSPORT *pInfo;
|
|
|
|
if (fWinsockLoaded == FALSE)
|
|
{
|
|
if (RPC_WSAStartup() == FALSE)
|
|
{
|
|
return(0);
|
|
}
|
|
fWinsockLoaded = TRUE;
|
|
}
|
|
|
|
switch(index)
|
|
{
|
|
case UDP:
|
|
if (DoFirewallInit())
|
|
{
|
|
// Overwrite the SyncReceive member of the transport interface if the
|
|
// RPC verifier is enabled.
|
|
if (gfRpcVerifierCorruptionInjectClientReceives)
|
|
{
|
|
// Check if we have previously initialized the Avrf transport interface.
|
|
if (pUDP_TransportInterface_Avrf == NULL)
|
|
{
|
|
// Allocate a transport interface structure to override the default.
|
|
pUDP_TransportInterface_Avrf = new (RPC_DATAGRAM_TRANSPORT);
|
|
if (pUDP_TransportInterface_Avrf == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
// Initialize the Avrf transport interface with the default values.
|
|
RpcpMemoryCopy(pUDP_TransportInterface_Avrf,
|
|
&UDP_TransportInterface,
|
|
sizeof(RPC_DATAGRAM_TRANSPORT));
|
|
// Override the interface function for sync receive.
|
|
ASSERT(pUDP_TransportInterface_Avrf->SyncReceive == DG_ReceivePacket);
|
|
pUDP_TransportInterface_Avrf->SyncReceive = DG_ReceivePacket_Avrf;
|
|
}
|
|
pInfo = pUDP_TransportInterface_Avrf;
|
|
}
|
|
else
|
|
{
|
|
pInfo = &UDP_TransportInterface;
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef IPX_ON
|
|
case IPX:
|
|
if (InitializeIpxNameCache() != RPC_S_OK)
|
|
{
|
|
pInfo = 0;
|
|
}
|
|
else
|
|
{
|
|
pInfo = &IPX_TransportInterface;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef NCADG_MQ_ON
|
|
case MSMQ:
|
|
if (!MQ_Initialize())
|
|
{
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
pInfo = &MQ_TransportInterface;
|
|
}
|
|
break;
|
|
#endif // NCADG_MQ_ON
|
|
|
|
case CDP:
|
|
// Overwrite the SyncReceive member of the transport interface if the
|
|
// RPC verifier is enabled.
|
|
if (gfRpcVerifierCorruptionInjectClientReceives)
|
|
{
|
|
// Check if we have previously initialized the Avrf transport interface.
|
|
if (pCDP_TransportInterface_Avrf == NULL)
|
|
{
|
|
// Allocate a transport interface structure to override the default.
|
|
pCDP_TransportInterface_Avrf = new (RPC_DATAGRAM_TRANSPORT);
|
|
if (pCDP_TransportInterface_Avrf == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
// Initialize the Avrf transport interface with the default values.
|
|
RpcpMemoryCopy(pCDP_TransportInterface_Avrf,
|
|
&CDP_TransportInterface,
|
|
sizeof(RPC_DATAGRAM_TRANSPORT));
|
|
// Override the interface function for sync receive.
|
|
ASSERT(pCDP_TransportInterface_Avrf->SyncReceive == DG_ReceivePacket);
|
|
pCDP_TransportInterface_Avrf->SyncReceive = DG_ReceivePacket_Avrf;
|
|
}
|
|
pInfo = pCDP_TransportInterface_Avrf;
|
|
}
|
|
else
|
|
{
|
|
pInfo = &CDP_TransportInterface;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
RPCTRANS "DG_TransportLoad called with index: %d\n",
|
|
index));
|
|
|
|
ASSERT(0);
|
|
pInfo = 0;
|
|
break;
|
|
}
|
|
|
|
// PERFBUG: Add code to lookup real PDU sizes
|
|
|
|
return(pInfo);
|
|
}
|