📄 dllmain.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Ancillary Function Driver DLL
* FILE: misc/dllmain.c
* PURPOSE: DLL entry point
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Alex Ionescu (alex@relsoft.net)
* REVISIONS:
* CSH 01/09-2000 Created
* Alex 16/07/2004 - Complete Rewrite
*/
#include <msafd.h>
#include <debug.h>
#ifdef DBG
//DWORD DebugTraceLevel = DEBUG_ULTRA;
DWORD DebugTraceLevel = 0;
#endif /* DBG */
HANDLE GlobalHeap;
WSPUPCALLTABLE Upcalls;
LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
ULONG SocketCount = 0;
PSOCKET_INFORMATION *Sockets = NULL;
LIST_ENTRY SockHelpersListHead = {NULL};
ULONG SockAsyncThreadRefCount;
HANDLE SockAsyncHelperAfdHandle;
HANDLE SockAsyncCompletionPort;
BOOLEAN SockAsyncSelectCalled;
SOCKET
WSPAPI
WSPSocket(
int AddressFamily,
int SocketType,
int Protocol,
LPWSAPROTOCOL_INFOW lpProtocolInfo,
GROUP g,
DWORD dwFlags,
LPINT lpErrno)
/*
* FUNCTION: Creates a new socket
* ARGUMENTS:
* af = Address family
* type = Socket type
* protocol = Protocol type
* lpProtocolInfo = Pointer to protocol information
* g = Reserved
* dwFlags = Socket flags
* lpErrno = Address of buffer for error information
* RETURNS:
* Created socket, or INVALID_SOCKET if it could not be created
*/
{
OBJECT_ATTRIBUTES Object;
IO_STATUS_BLOCK IOSB;
USHORT SizeOfPacket;
ULONG SizeOfEA;
PAFD_CREATE_PACKET AfdPacket;
HANDLE Sock;
PSOCKET_INFORMATION Socket = NULL, PrevSocket = NULL;
PFILE_FULL_EA_INFORMATION EABuffer = NULL;
PHELPER_DATA HelperData;
PVOID HelperDLLContext;
DWORD HelperEvents;
UNICODE_STRING TransportName;
UNICODE_STRING DevName;
LARGE_INTEGER GroupData;
INT Status;
AFD_DbgPrint(MAX_TRACE, ("Creating Socket, getting TDI Name\n"));
AFD_DbgPrint(MAX_TRACE, ("AddressFamily (%d) SocketType (%d) Protocol (%d).\n",
AddressFamily, SocketType, Protocol));
/* Get Helper Data and Transport */
Status = SockGetTdiName (&AddressFamily,
&SocketType,
&Protocol,
g,
dwFlags,
&TransportName,
&HelperDLLContext,
&HelperData,
&HelperEvents);
/* Check for error */
if (Status != NO_ERROR) {
AFD_DbgPrint(MID_TRACE,("SockGetTdiName: Status %x\n", Status));
goto error;
}
/* AFD Device Name */
RtlInitUnicodeString(&DevName, L"\\Device\\Afd\\Endpoint");
/* Set Socket Data */
Socket = HeapAlloc(GlobalHeap, 0, sizeof(*Socket));
RtlZeroMemory(Socket, sizeof(*Socket));
Socket->RefCount = 2;
Socket->Handle = -1;
Socket->SharedData.State = SocketOpen;
Socket->SharedData.AddressFamily = AddressFamily;
Socket->SharedData.SocketType = SocketType;
Socket->SharedData.Protocol = Protocol;
Socket->HelperContext = HelperDLLContext;
Socket->HelperData = HelperData;
Socket->HelperEvents = HelperEvents;
Socket->LocalAddress = &Socket->WSLocalAddress;
Socket->SharedData.SizeOfLocalAddress = HelperData->MaxWSAddressLength;
Socket->RemoteAddress = &Socket->WSRemoteAddress;
Socket->SharedData.SizeOfRemoteAddress = HelperData->MaxWSAddressLength;
Socket->SharedData.UseDelayedAcceptance = HelperData->UseDelayedAcceptance;
Socket->SharedData.CreateFlags = dwFlags;
Socket->SharedData.CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
Socket->SharedData.ServiceFlags1 = lpProtocolInfo->dwServiceFlags1;
Socket->SharedData.ProviderFlags = lpProtocolInfo->dwProviderFlags;
Socket->SharedData.GroupID = g;
Socket->SharedData.GroupType = 0;
Socket->SharedData.UseSAN = FALSE;
Socket->SharedData.NonBlocking = FALSE; /* Sockets start blocking */
Socket->SanData = NULL;
/* Ask alex about this */
if( Socket->SharedData.SocketType == SOCK_DGRAM ||
Socket->SharedData.SocketType == SOCK_RAW ) {
AFD_DbgPrint(MID_TRACE,("Connectionless socket\n"));
Socket->SharedData.ServiceFlags1 |= XP1_CONNECTIONLESS;
}
/* Packet Size */
SizeOfPacket = TransportName.Length + sizeof(AFD_CREATE_PACKET) + sizeof(WCHAR);
/* EA Size */
SizeOfEA = SizeOfPacket + sizeof(FILE_FULL_EA_INFORMATION) + AFD_PACKET_COMMAND_LENGTH;
/* Set up EA Buffer */
EABuffer = HeapAlloc(GlobalHeap, 0, SizeOfEA);
RtlZeroMemory(EABuffer, SizeOfEA);
EABuffer->NextEntryOffset = 0;
EABuffer->Flags = 0;
EABuffer->EaNameLength = AFD_PACKET_COMMAND_LENGTH;
RtlCopyMemory (EABuffer->EaName,
AfdCommand,
AFD_PACKET_COMMAND_LENGTH + 1);
EABuffer->EaValueLength = SizeOfPacket;
/* Set up AFD Packet */
AfdPacket = (PAFD_CREATE_PACKET)(EABuffer->EaName + EABuffer->EaNameLength + 1);
AfdPacket->SizeOfTransportName = TransportName.Length;
RtlCopyMemory (AfdPacket->TransportName,
TransportName.Buffer,
TransportName.Length + sizeof(WCHAR));
AfdPacket->GroupID = g;
/* Set up Endpoint Flags */
if ((Socket->SharedData.ServiceFlags1 & XP1_CONNECTIONLESS) != 0) {
if ((SocketType != SOCK_DGRAM) && (SocketType != SOCK_RAW)) {
goto error; /* Only RAW or UDP can be Connectionless */
}
AfdPacket->EndpointFlags |= AFD_ENDPOINT_CONNECTIONLESS;
}
if ((Socket->SharedData.ServiceFlags1 & XP1_MESSAGE_ORIENTED) != 0) {
if (SocketType == SOCK_STREAM) {
if ((Socket->SharedData.ServiceFlags1 & XP1_PSEUDO_STREAM) == 0) {
goto error; /* The Provider doesn't actually support Message Oriented Streams */
}
}
AfdPacket->EndpointFlags |= AFD_ENDPOINT_MESSAGE_ORIENTED;
}
if (SocketType == SOCK_RAW) AfdPacket->EndpointFlags |= AFD_ENDPOINT_RAW;
if (dwFlags & (WSA_FLAG_MULTIPOINT_C_ROOT |
WSA_FLAG_MULTIPOINT_C_LEAF |
WSA_FLAG_MULTIPOINT_D_ROOT |
WSA_FLAG_MULTIPOINT_D_LEAF)) {
if ((Socket->SharedData.ServiceFlags1 & XP1_SUPPORT_MULTIPOINT) == 0) {
goto error; /* The Provider doesn't actually support Multipoint */
}
AfdPacket->EndpointFlags |= AFD_ENDPOINT_MULTIPOINT;
if (dwFlags & WSA_FLAG_MULTIPOINT_C_ROOT) {
if (((Socket->SharedData.ServiceFlags1 & XP1_MULTIPOINT_CONTROL_PLANE) == 0)
|| ((dwFlags & WSA_FLAG_MULTIPOINT_C_LEAF) != 0)) {
goto error; /* The Provider doesn't support Control Planes, or you already gave a leaf */
}
AfdPacket->EndpointFlags |= AFD_ENDPOINT_C_ROOT;
}
if (dwFlags & WSA_FLAG_MULTIPOINT_D_ROOT) {
if (((Socket->SharedData.ServiceFlags1 & XP1_MULTIPOINT_DATA_PLANE) == 0)
|| ((dwFlags & WSA_FLAG_MULTIPOINT_D_LEAF) != 0)) {
goto error; /* The Provider doesn't support Data Planes, or you already gave a leaf */
}
AfdPacket->EndpointFlags |= AFD_ENDPOINT_D_ROOT;
}
}
/* Set up Object Attributes */
InitializeObjectAttributes (&Object,
&DevName,
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
0,
0);
/* Create the Socket as asynchronous. That means we have to block
ourselves after every call to NtDeviceIoControlFile. This is
because the kernel doesn't support overlapping synchronous I/O
requests (made from multiple threads) at this time (Sep 2005) */
ZwCreateFile(&Sock,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&Object,
&IOSB,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
EABuffer,
SizeOfEA);
/* Save Handle */
Socket->Handle = (SOCKET)Sock;
/* XXX See if there's a structure we can reuse -- We need to do this
* more properly. */
PrevSocket = GetSocketStructure( (SOCKET)Sock );
if( PrevSocket ) {
RtlCopyMemory( PrevSocket, Socket, sizeof(*Socket) );
RtlFreeHeap( GlobalHeap, 0, Socket );
Socket = PrevSocket;
}
/* Save Group Info */
if (g != 0) {
GetSocketInformation(Socket, AFD_INFO_GROUP_ID_TYPE, 0, &GroupData);
Socket->SharedData.GroupID = GroupData.u.LowPart;
Socket->SharedData.GroupType = GroupData.u.HighPart;
}
/* Get Window Sizes and Save them */
GetSocketInformation (Socket,
AFD_INFO_SEND_WINDOW_SIZE,
&Socket->SharedData.SizeOfSendBuffer,
NULL);
GetSocketInformation (Socket,
AFD_INFO_RECEIVE_WINDOW_SIZE,
&Socket->SharedData.SizeOfRecvBuffer,
NULL);
/* Save in Process Sockets List */
Sockets[SocketCount] = Socket;
SocketCount ++;
/* Create the Socket Context */
CreateContext(Socket);
/* Notify Winsock */
Upcalls.lpWPUModifyIFSHandle(1, (SOCKET)Sock, lpErrno);
/* Return Socket Handle */
AFD_DbgPrint(MID_TRACE,("Success %x\n", Sock));
return (SOCKET)Sock;
error:
AFD_DbgPrint(MID_TRACE,("Ending %x\n", Status));
if( lpErrno ) *lpErrno = Status;
return INVALID_SOCKET;
}
DWORD MsafdReturnWithErrno( NTSTATUS Status, LPINT Errno, DWORD Received,
LPDWORD ReturnedBytes ) {
if( ReturnedBytes ) *ReturnedBytes = 0;
if( Errno ) {
switch (Status) {
case STATUS_CANT_WAIT: *Errno = WSAEWOULDBLOCK; break;
case STATUS_TIMEOUT:
case STATUS_SUCCESS:
/* Return Number of bytes Read */
if( ReturnedBytes ) *ReturnedBytes = Received; break;
case STATUS_END_OF_FILE: *Errno = WSAESHUTDOWN; *ReturnedBytes = 0; break;
case STATUS_PENDING: *Errno = WSA_IO_PENDING; break;
case STATUS_BUFFER_OVERFLOW: *Errno = WSAEMSGSIZE; break;
default: {
DbgPrint("MSAFD: Error %x is unknown\n", Status);
*Errno = WSAEINVAL; break;
} break;
}
}
/* Success */
return Status == STATUS_SUCCESS ? 0 : SOCKET_ERROR;
}
INT
WSPAPI
WSPCloseSocket(
IN SOCKET Handle,
OUT LPINT lpErrno)
/*
* FUNCTION: Closes an open socket
* ARGUMENTS:
* s = Socket descriptor
* lpErrno = Address of buffer for error information
* RETURNS:
* NO_ERROR, or SOCKET_ERROR if the socket could not be closed
*/
{
IO_STATUS_BLOCK IoStatusBlock;
PSOCKET_INFORMATION Socket = NULL;
NTSTATUS Status;
HANDLE SockEvent;
AFD_DISCONNECT_INFO DisconnectInfo;
SOCKET_STATE OldState;
/* Create the Wait Event */
Status = NtCreateEvent(&SockEvent,
GENERIC_READ | GENERIC_WRITE,
NULL,
1,
FALSE);
if(!NT_SUCCESS(Status)) return SOCKET_ERROR;
/* Get the Socket Structure associate to this Socket*/
Socket = GetSocketStructure(Handle);
/* If a Close is already in Process, give up */
if (Socket->SharedData.State == SocketClosed) {
*lpErrno = WSAENOTSOCK;
return SOCKET_ERROR;
}
/* Set the state to close */
OldState = Socket->SharedData.State;
Socket->SharedData.State = SocketClosed;
/* If SO_LINGER is ON and the Socket is connected, we need to disconnect */
/* FIXME: Should we do this on Datagram Sockets too? */
if ((OldState == SocketConnected) && (Socket->SharedData.LingerData.l_onoff)) {
ULONG LingerWait;
ULONG SendsInProgress;
ULONG SleepWait;
/* We need to respect the timeout */
SleepWait = 100;
LingerWait = Socket->SharedData.LingerData.l_linger * 1000;
/* Loop until no more sends are pending, within the timeout */
while (LingerWait) {
/* Find out how many Sends are in Progress */
if (GetSocketInformation(Socket,
AFD_INFO_SENDS_IN_PROGRESS,
&SendsInProgress,
NULL)) {
/* Bail out if anything but NO_ERROR */
LingerWait = 0;
break;
}
/* Bail out if no more sends are pending */
if (!SendsInProgress) break;
/*
* We have to execute a sleep, so it's kind of like
* a block. If the socket is Nonblock, we cannot
* go on since asyncronous operation is expected
* and we cannot offer it
*/
if (Socket->SharedData.NonBlocking) {
Socket->SharedData.State = OldState;
*lpErrno = WSAEWOULDBLOCK;
return SOCKET_ERROR;
}
/* Now we can sleep, and decrement the linger wait */
/*
* FIXME: It seems Windows does some funky acceleration
* since the waiting seems to be longer and longer. I
* don't think this improves performance so much, so we
* wait a fixed time instead.
*/
Sleep(SleepWait);
LingerWait -= SleepWait;
}
/*
* We have reached the timeout or sends are over.
* Disconnect if the timeout has been reached.
*/
if (LingerWait <= 0) {
DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(0);
DisconnectInfo.DisconnectType = AFD_DISCONNECT_ABORT;
/* Send IOCTL */
Status = NtDeviceIoControlFile((HANDLE)Handle,
SockEvent,
NULL,
NULL,
&IoStatusBlock,
IOCTL_AFD_DISCONNECT,
&DisconnectInfo,
sizeof(DisconnectInfo),
NULL,
0);
/* Wait for return */
if (Status == STATUS_PENDING) {
WaitForSingleObject(SockEvent, INFINITE);
}
}
}
/* FIXME: We should notify the Helper DLL of WSH_NOTIFY_CLOSE */
/* Cleanup Time! */
Socket->HelperContext = NULL;
Socket->SharedData.AsyncDisabledEvents = -1;
NtClose(Socket->TdiAddressHandle);
Socket->TdiAddressHandle = NULL;
NtClose(Socket->TdiConnectionHandle);
Socket->TdiConnectionHandle = NULL;
/* Close the handle */
NtClose((HANDLE)Handle);
return NO_ERROR;
}
INT
WSPAPI
WSPBind(
SOCKET Handle,
const struct sockaddr *SocketAddress,
int SocketAddressLength,
LPINT lpErrno)
/*
* FUNCTION: Associates a local address with a socket
* ARGUMENTS:
* s = Socket descriptor
* name = Pointer to local address
* namelen = Length of name
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -