342 lines
8.7 KiB
C++
342 lines
8.7 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) Microsoft Corporation, 1997 - 1999
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Afd.cxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Wrappers to simulate winsock API directly on top of AFD IOCTLS.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Mario Goertzel [MarioGo]
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
MarioGo 4/4/1997 Based on NT 4 DG code.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <precomp.hxx>
|
||
|
#include <tdi.h>
|
||
|
#include <clustdi.h>
|
||
|
#include <afd.h>
|
||
|
|
||
|
void
|
||
|
InitializeRawAddress(
|
||
|
IN WS_SOCKADDR *pSockAddr,
|
||
|
OUT PVOID pRawAddress,
|
||
|
OUT DWORD *pdwRawAddressSize
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Converts from a winsock sockaddr to a TDI format address.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pSockAddr - The address to convert from, must be either a
|
||
|
AF_INET (IP), AF_IPX, or AF_CLUSTER family address.
|
||
|
|
||
|
pRawAddress - The buffer to store the TDI format address.
|
||
|
pdwRawAddressSize - On return, the size of the TDI format address.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
#ifdef IPX_ON
|
||
|
ASSERT( pSockAddr->generic.sa_family == AF_INET
|
||
|
|| pSockAddr->generic.sa_family == AF_IPX
|
||
|
|| pSockAddr->generic.sa_family == AF_CLUSTER);
|
||
|
#else
|
||
|
ASSERT( pSockAddr->generic.sa_family == AF_INET
|
||
|
|| pSockAddr->generic.sa_family == AF_CLUSTER);
|
||
|
#endif
|
||
|
|
||
|
switch (pSockAddr->generic.sa_family) {
|
||
|
case AF_INET:
|
||
|
{
|
||
|
// UDP
|
||
|
|
||
|
TA_IP_ADDRESS *pra = (TA_IP_ADDRESS *)pRawAddress;
|
||
|
|
||
|
pra->TAAddressCount = 1;
|
||
|
pra->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
||
|
pra->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
||
|
pra->Address[0].Address[0].sin_port = pSockAddr->inetaddr.sin_port;
|
||
|
pra->Address[0].Address[0].in_addr = pSockAddr->inetaddr.sin_addr.s_addr;
|
||
|
memset(pra->Address[0].Address[0].sin_zero, 0, 8);
|
||
|
|
||
|
*pdwRawAddressSize = sizeof(TA_IP_ADDRESS);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifdef IPX_ON
|
||
|
case AF_IPX:
|
||
|
{
|
||
|
// IPX
|
||
|
|
||
|
TA_IPX_ADDRESS *pra = (TA_IPX_ADDRESS *)pRawAddress;
|
||
|
|
||
|
pra->TAAddressCount = 1;
|
||
|
pra->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IPX;
|
||
|
pra->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
|
||
|
memcpy(&pra->Address[0].Address[0].NetworkAddress, pSockAddr->ipxaddr.sa_netnum, 4);
|
||
|
memcpy(&pra->Address[0].Address[0].NodeAddress, pSockAddr->ipxaddr.sa_nodenum, 6);
|
||
|
pra->Address[0].Address[0].Socket = pSockAddr->ipxaddr.sa_socket;
|
||
|
|
||
|
*pdwRawAddressSize = sizeof(TA_IPX_ADDRESS);
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
case AF_CLUSTER:
|
||
|
{
|
||
|
// Clusters
|
||
|
|
||
|
TA_CLUSTER_ADDRESS *pra = (TA_CLUSTER_ADDRESS *)pRawAddress;
|
||
|
|
||
|
pra->TAAddressCount = 1;
|
||
|
pra->Address[0].AddressLength = TDI_ADDRESS_LENGTH_CLUSTER;
|
||
|
pra->Address[0].AddressType = TDI_ADDRESS_TYPE_CLUSTER;
|
||
|
pra->Address[0].Address[0].Port = pSockAddr->clusaddr.sac_port;
|
||
|
pra->Address[0].Address[0].Node = pSockAddr->clusaddr.sac_node;
|
||
|
pra->Address[0].Address[0].ReservedMBZ = 0;
|
||
|
|
||
|
*pdwRawAddressSize = sizeof(TA_CLUSTER_ADDRESS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
WSAAPI
|
||
|
AFD_SendTo(
|
||
|
SOCKET s,
|
||
|
LPWSABUF lpBuffers,
|
||
|
DWORD dwBufferCount,
|
||
|
LPDWORD lpNumberOfBytesSent,
|
||
|
DWORD dwFlags,
|
||
|
const struct sockaddr FAR * lpTo,
|
||
|
int iTolen,
|
||
|
LPWSAOVERLAPPED lpOverlapped,
|
||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Implement's a wrapper around the AFD recv IOCTL which looks like WSASendTo.
|
||
|
RPC uses this when MSAFD is the network provider.
|
||
|
|
||
|
Note:
|
||
|
|
||
|
Try reading private\net\sockets\winsock2\wsp\msafd\send.c if you want
|
||
|
more information.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
WSASendTo arguments
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 - success
|
||
|
ERROR_IO_PENDING - IO submitted
|
||
|
|
||
|
non-zero - error
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PIO_STATUS_BLOCK pIoStatus = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
|
||
|
AFD_SEND_DATAGRAM_INFO sendInfo;
|
||
|
UCHAR abRawAddress[max(sizeof(TA_IP_ADDRESS),sizeof(TA_IPX_ADDRESS))];
|
||
|
DWORD dwRawAddressSize;
|
||
|
int status;
|
||
|
NTSTATUS NtStatus;
|
||
|
|
||
|
ASSERT(lpCompletionRoutine == 0);
|
||
|
ASSERT(lpOverlapped);
|
||
|
|
||
|
InitializeRawAddress((WS_SOCKADDR *)lpTo, abRawAddress, &dwRawAddressSize);
|
||
|
|
||
|
sendInfo.AfdFlags = AFD_OVERLAPPED;
|
||
|
sendInfo.BufferArray = lpBuffers;
|
||
|
sendInfo.BufferCount = dwBufferCount;
|
||
|
sendInfo.TdiRequest.SendDatagramInformation = &sendInfo.TdiConnInfo;
|
||
|
sendInfo.TdiConnInfo.UserDataLength = 0;
|
||
|
sendInfo.TdiConnInfo.UserData = 0;
|
||
|
sendInfo.TdiConnInfo.OptionsLength = 0;
|
||
|
sendInfo.TdiConnInfo.Options = 0;
|
||
|
sendInfo.TdiConnInfo.RemoteAddressLength = dwRawAddressSize;
|
||
|
sendInfo.TdiConnInfo.RemoteAddress = abRawAddress;
|
||
|
|
||
|
pIoStatus->Status = STATUS_PENDING;
|
||
|
|
||
|
NtStatus = NtDeviceIoControlFile(
|
||
|
(HANDLE)s,
|
||
|
lpOverlapped->hEvent,
|
||
|
NULL,
|
||
|
( PtrToUlong(lpOverlapped->hEvent) & 1 ) ? NULL : lpOverlapped,
|
||
|
pIoStatus,
|
||
|
IOCTL_AFD_SEND_DATAGRAM,
|
||
|
&sendInfo,
|
||
|
sizeof(sendInfo),
|
||
|
NULL,
|
||
|
0
|
||
|
);
|
||
|
|
||
|
if (NtStatus == STATUS_PENDING)
|
||
|
{
|
||
|
SetLastError(WSA_IO_PENDING);
|
||
|
*lpNumberOfBytesSent = 0;
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
if (NtStatus == STATUS_HOST_DOWN)
|
||
|
{
|
||
|
SetLastError(WSAEHOSTDOWN);
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(NtStatus))
|
||
|
{
|
||
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
|
DPFLTR_WARNING_LEVEL,
|
||
|
RPCTRANS "Afd send failed: 0x%x\n",
|
||
|
NtStatus));
|
||
|
|
||
|
SetLastError(RtlNtStatusToDosError(NtStatus));
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
*lpNumberOfBytesSent = ULONG(pIoStatus->Information);
|
||
|
|
||
|
ASSERT(*lpNumberOfBytesSent);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
WSAAPI
|
||
|
AFD_RecvFrom(
|
||
|
SOCKET s,
|
||
|
LPWSABUF lpBuffers,
|
||
|
DWORD dwBufferCount,
|
||
|
LPDWORD lpNumberOfBytesRecvd,
|
||
|
LPDWORD lpFlags,
|
||
|
struct sockaddr FAR * lpFrom,
|
||
|
LPINT lpFromlen,
|
||
|
LPWSAOVERLAPPED lpOverlapped,
|
||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Implement's a wrapper around the AFD recv IOCTL which looks like WSARecvFrom.
|
||
|
RPC uses this when MSAFD is the network provider.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Try reading private\net\sockets\winsock2\wsp\msafd\recv.c if you want
|
||
|
more information.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
WSARecvFrom arguments
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 - success
|
||
|
ERROR_IO_PENDING - IO submitted
|
||
|
|
||
|
non-zero - error
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PIO_STATUS_BLOCK pIoStatus = (PIO_STATUS_BLOCK )&lpOverlapped->Internal;
|
||
|
AFD_RECV_DATAGRAM_INFO recvInfo;
|
||
|
int status;
|
||
|
NTSTATUS NtStatus;
|
||
|
|
||
|
ASSERT(lpCompletionRoutine == 0);
|
||
|
ASSERT(lpOverlapped);
|
||
|
|
||
|
recvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
|
||
|
recvInfo.AfdFlags = AFD_OVERLAPPED;
|
||
|
recvInfo.BufferArray = lpBuffers;
|
||
|
recvInfo.BufferCount = dwBufferCount;
|
||
|
recvInfo.Address = lpFrom;
|
||
|
recvInfo.AddressLength = (PULONG)lpFromlen;
|
||
|
|
||
|
pIoStatus->Status = STATUS_PENDING;
|
||
|
|
||
|
NtStatus = NtDeviceIoControlFile((HANDLE)s,
|
||
|
lpOverlapped->hEvent,
|
||
|
0,
|
||
|
( PtrToUlong(lpOverlapped->hEvent) & 1 ) ? NULL : lpOverlapped,
|
||
|
pIoStatus,
|
||
|
IOCTL_AFD_RECEIVE_DATAGRAM,
|
||
|
&recvInfo,
|
||
|
sizeof(recvInfo),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
if (NtStatus == STATUS_PENDING)
|
||
|
{
|
||
|
SetLastError(ERROR_IO_PENDING);
|
||
|
return(ERROR_IO_PENDING);
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(NtStatus))
|
||
|
{
|
||
|
switch (NtStatus)
|
||
|
{
|
||
|
case STATUS_PORT_UNREACHABLE: status = WSAECONNRESET; break;
|
||
|
case STATUS_HOST_UNREACHABLE: status = WSAEHOSTUNREACH; break;
|
||
|
case STATUS_NETWORK_UNREACHABLE: status = WSAENETUNREACH; break;
|
||
|
|
||
|
case STATUS_BUFFER_OVERFLOW:
|
||
|
case STATUS_RECEIVE_PARTIAL:
|
||
|
{
|
||
|
*lpNumberOfBytesRecvd = -1 * ULONG(pIoStatus->Information);
|
||
|
status = WSAEMSGSIZE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
|
DPFLTR_WARNING_LEVEL,
|
||
|
RPCTRANS "Afd recv failed: 0x%x\n",
|
||
|
NtStatus));
|
||
|
|
||
|
status = RPC_S_OUT_OF_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetLastError( status );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*lpNumberOfBytesRecvd = ULONG(pIoStatus->Information);
|
||
|
status = NO_ERROR;
|
||
|
}
|
||
|
|
||
|
return(status);
|
||
|
}
|
||
|
|