mirror of
https://github.com/reactos/reactos.git
synced 2024-07-30 16:18:43 +00:00
985 lines
26 KiB
C
985 lines
26 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS WinSock 2 API
|
|
* FILE: dll/win32/ws2_32_new/src/async.c
|
|
* PURPOSE: Async Block Object and Async Thread Management
|
|
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ws2_32.h>
|
|
|
|
/* DATA **********************************************************************/
|
|
|
|
BOOLEAN WsAsyncThreadInitialized;
|
|
LONG WsAsyncTaskHandle;
|
|
PLIST_ENTRY WsAsyncQueue;
|
|
CRITICAL_SECTION WsAsyncCritSect;
|
|
HANDLE WsAsyncEvent;
|
|
HANDLE WsAsyncCurrentTaskHandle;
|
|
HANDLE WsAsyncCancelledTaskHandle;
|
|
HINSTANCE WsAsyncDllHandle;
|
|
|
|
#define WsAsyncLock() EnterCriticalSection(&WsAsyncCritSect)
|
|
#define WsAsyncUnlock() LeaveCriticalSection(&WsAsyncCritSect)
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncGlobalInitialize(VOID)
|
|
{
|
|
/* Initialize the async lock */
|
|
InitializeCriticalSection(&WsAsyncCritSect);
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncGlobalTerminate(VOID)
|
|
{
|
|
/* Destroy the async lock */
|
|
DeleteCriticalSection(&WsAsyncCritSect);
|
|
}
|
|
|
|
|
|
SIZE_T
|
|
WSAAPI
|
|
BytesInHostent(PHOSTENT Hostent)
|
|
{
|
|
SIZE_T Bytes;
|
|
INT i;
|
|
|
|
/* Start with the static stuff */
|
|
Bytes = sizeof(HOSTENT) + strlen(Hostent->h_name) + sizeof(CHAR);
|
|
|
|
/* Add 2 pointers for the list-terminators */
|
|
Bytes += 2 * sizeof(ULONG_PTR);
|
|
|
|
/* Now loop for the aliases */
|
|
for (i = 0; Hostent->h_aliases[i]; i++)
|
|
{
|
|
/* Add the alias size, plus the space its pointer takes */
|
|
Bytes += strlen(Hostent->h_aliases[i]) + sizeof(CHAR) + sizeof(ULONG_PTR);
|
|
}
|
|
|
|
/* Now loop for the hostnames */
|
|
for (i = 0; Hostent->h_addr_list[i]; i++)
|
|
{
|
|
/* Add the alias size, plus the space its pointer takes */
|
|
Bytes += Hostent->h_length + sizeof(ULONG_PTR);
|
|
}
|
|
|
|
/* Align to 8 bytes */
|
|
return (Bytes + 7) & ~7;
|
|
}
|
|
|
|
SIZE_T
|
|
WSAAPI
|
|
BytesInServent(PSERVENT Servent)
|
|
{
|
|
SIZE_T Bytes;
|
|
INT i;
|
|
|
|
/* Start with the static stuff */
|
|
Bytes = sizeof(SERVENT) +
|
|
strlen(Servent->s_name) + sizeof(CHAR) +
|
|
strlen(Servent->s_proto) + sizeof(CHAR);
|
|
|
|
/* Add 1 pointers for the list terminator */
|
|
Bytes += sizeof(ULONG_PTR);
|
|
|
|
/* Now loop for the aliases */
|
|
for (i = 0; Servent->s_aliases[i]; i++)
|
|
{
|
|
/* Add the alias size, plus the space its pointer takes */
|
|
Bytes += strlen(Servent->s_aliases[i]) + sizeof(CHAR) + sizeof(ULONG_PTR);
|
|
}
|
|
|
|
/* return */
|
|
return Bytes;
|
|
}
|
|
|
|
SIZE_T
|
|
WSAAPI
|
|
BytesInProtoent(PPROTOENT Protoent)
|
|
{
|
|
SIZE_T Bytes;
|
|
INT i;
|
|
|
|
/* Start with the static stuff */
|
|
Bytes = sizeof(SERVENT) + strlen(Protoent->p_name) + sizeof(CHAR);
|
|
|
|
/* Add 1 pointers for the list terminator */
|
|
Bytes += sizeof(ULONG_PTR);
|
|
|
|
/* Now loop for the aliases */
|
|
for (i = 0; Protoent->p_aliases[i]; i++)
|
|
{
|
|
/* Add the alias size, plus the space its pointer takes */
|
|
Bytes += strlen(Protoent->p_aliases[i]) + sizeof(CHAR) + sizeof(ULONG_PTR);
|
|
}
|
|
|
|
/* return */
|
|
return Bytes;
|
|
}
|
|
|
|
SIZE_T
|
|
WSAAPI
|
|
CopyHostentToBuffer(IN PCHAR Buffer,
|
|
IN INT BufferLength,
|
|
IN PHOSTENT Hostent)
|
|
{
|
|
SIZE_T BufferSize, CurrentSize, NameSize;
|
|
PCHAR p = Buffer;
|
|
DWORD Aliases = 0, Names = 0;
|
|
DWORD i;
|
|
PHOSTENT ReturnedHostent = (PHOSTENT)Buffer;
|
|
|
|
/* Determine the buffer size required */
|
|
BufferSize = BytesInHostent(Hostent);
|
|
|
|
/* Check which size to use */
|
|
if ((DWORD)BufferLength > BufferSize)
|
|
{
|
|
/* Zero the buffer */
|
|
RtlZeroMemory(Buffer, BufferSize);
|
|
}
|
|
else
|
|
{
|
|
/* Zero the buffer */
|
|
RtlZeroMemory(Buffer, BufferLength);
|
|
}
|
|
|
|
/* Start with the raw Hostent */
|
|
CurrentSize = sizeof(HOSTENT);
|
|
|
|
/* Return the size needed now */
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Copy the Hostent and initialize it */
|
|
CopyMemory(p, Hostent, sizeof(HOSTENT));
|
|
p = Buffer + CurrentSize;
|
|
ReturnedHostent->h_name = NULL;
|
|
ReturnedHostent->h_aliases = NULL;
|
|
ReturnedHostent->h_addr_list = NULL;
|
|
|
|
/* Find out how many aliases there are */
|
|
while (Hostent->h_aliases[Aliases])
|
|
{
|
|
/* Increase the alias count */
|
|
Aliases++;
|
|
}
|
|
|
|
/* Add the aliases to the size, and validate it */
|
|
CurrentSize += (Aliases + 1) * sizeof(ULONG_PTR);
|
|
if (CurrentSize > (DWORD)BufferLength)
|
|
{
|
|
/* Clear the aliases and return */
|
|
Hostent->h_aliases = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
/* Write the aliases, update the pointer */
|
|
ReturnedHostent->h_aliases = (PCHAR*)p;
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Find out how many names there are */
|
|
while (Hostent->h_addr_list[Names])
|
|
{
|
|
/* Increase the alias count */
|
|
Names++;
|
|
}
|
|
|
|
/* Add the names to the size, and validate it */
|
|
CurrentSize += (Names + 1) * sizeof(ULONG_PTR);
|
|
if (CurrentSize > (DWORD)BufferLength)
|
|
{
|
|
/* Clear the aliases and return */
|
|
Hostent->h_addr_list = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
/* Write the names, update the pointer */
|
|
ReturnedHostent->h_addr_list = (PCHAR*)p;
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Now add the names */
|
|
for (i = 0; i < Names; i++)
|
|
{
|
|
/* Update size and validate */
|
|
CurrentSize += Hostent->h_length;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write pointer and copy */
|
|
ReturnedHostent->h_addr_list[i] = p;
|
|
CopyMemory(p, Hostent->h_addr_list[i], Hostent->h_length);
|
|
|
|
/* Update pointer */
|
|
p = Buffer + CurrentSize;
|
|
}
|
|
|
|
/* Finalize the list */
|
|
ReturnedHostent->h_addr_list[i] = NULL;
|
|
|
|
/* Add the service name to the size, and validate it */
|
|
NameSize = strlen(Hostent->h_name) + sizeof(CHAR);
|
|
CurrentSize += NameSize;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write the service name and update the pointer */
|
|
ReturnedHostent->h_name = p;
|
|
CopyMemory(p, Hostent->h_name, NameSize);
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Now add the aliases */
|
|
for (i = 0; i < Aliases; i++)
|
|
{
|
|
/* Update size and validate */
|
|
NameSize = strlen(Hostent->h_aliases[i]) + sizeof(CHAR);
|
|
CurrentSize += NameSize;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write pointer and copy */
|
|
ReturnedHostent->h_aliases[i] = p;
|
|
CopyMemory(p, Hostent->h_aliases[i], NameSize);
|
|
|
|
/* Update pointer */
|
|
p = Buffer + CurrentSize;
|
|
}
|
|
|
|
/* Finalize the list and return */
|
|
ReturnedHostent->h_aliases[i] = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
SIZE_T
|
|
WSAAPI
|
|
CopyServentToBuffer(IN PCHAR Buffer,
|
|
IN INT BufferLength,
|
|
IN PSERVENT Servent)
|
|
{
|
|
SIZE_T BufferSize, CurrentSize, NameSize;
|
|
PCHAR p = Buffer;
|
|
DWORD Aliases = 0;
|
|
DWORD i;
|
|
PSERVENT ReturnedServent = (PSERVENT)Buffer;
|
|
|
|
/* Determine the buffer size required */
|
|
BufferSize = BytesInServent(Servent);
|
|
|
|
/* Check which size to use */
|
|
if ((DWORD)BufferLength > BufferSize)
|
|
{
|
|
/* Zero the buffer */
|
|
ZeroMemory(Buffer, BufferSize);
|
|
}
|
|
else
|
|
{
|
|
/* Zero the buffer */
|
|
ZeroMemory(Buffer, BufferLength);
|
|
}
|
|
|
|
/* Start with the raw servent */
|
|
CurrentSize = sizeof(SERVENT);
|
|
|
|
/* Return the size needed now */
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Copy the servent and initialize it */
|
|
CopyMemory(p, Servent, sizeof(SERVENT));
|
|
p = Buffer + CurrentSize;
|
|
ReturnedServent->s_name = NULL;
|
|
ReturnedServent->s_aliases = NULL;
|
|
ReturnedServent->s_proto = NULL;
|
|
|
|
/* Find out how many aliases there are */
|
|
while (Servent->s_aliases[Aliases])
|
|
{
|
|
/* Increase the alias count */
|
|
Aliases++;
|
|
}
|
|
|
|
/* Add the aliases to the size, and validate it */
|
|
CurrentSize += (Aliases + 1) * sizeof(ULONG_PTR);
|
|
if (CurrentSize > (DWORD)BufferLength)
|
|
{
|
|
/* Clear the aliases and return */
|
|
Servent->s_aliases = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
/* Write the aliases, update the pointer */
|
|
ReturnedServent->s_aliases = (PCHAR*)p;
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Add the service name to the size, and validate it */
|
|
NameSize = strlen(Servent->s_name) + sizeof(CHAR);
|
|
CurrentSize += NameSize;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write the service name and update the pointer */
|
|
ReturnedServent->s_name = p;
|
|
CopyMemory(p, Servent->s_name, NameSize);
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Now add the aliases */
|
|
for (i = 0; i < Aliases; i++)
|
|
{
|
|
/* Update size and validate */
|
|
NameSize = strlen(Servent->s_aliases[i]) + sizeof(CHAR);
|
|
CurrentSize += NameSize;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write pointer and copy */
|
|
ReturnedServent->s_aliases[i] = p;
|
|
CopyMemory(p, Servent->s_aliases[i], NameSize);
|
|
|
|
/* Update pointer */
|
|
p = Buffer + CurrentSize;
|
|
}
|
|
|
|
/* Finalize the list and return */
|
|
ReturnedServent->s_aliases[i] = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
SIZE_T
|
|
WSAAPI
|
|
CopyProtoentToBuffer(IN PCHAR Buffer,
|
|
IN INT BufferLength,
|
|
IN PPROTOENT Protoent)
|
|
{
|
|
SIZE_T BufferSize, CurrentSize, NameSize;
|
|
PCHAR p = Buffer;
|
|
DWORD Aliases = 0;
|
|
DWORD i;
|
|
PPROTOENT ReturnedProtoent = (PPROTOENT)Buffer;
|
|
|
|
/* Determine the buffer size required */
|
|
BufferSize = BytesInProtoent(Protoent);
|
|
|
|
/* Check which size to use */
|
|
if ((DWORD)BufferLength > BufferSize)
|
|
{
|
|
/* Zero the buffer */
|
|
ZeroMemory(Buffer, BufferSize);
|
|
}
|
|
else
|
|
{
|
|
/* Zero the buffer */
|
|
ZeroMemory(Buffer, BufferLength);
|
|
}
|
|
|
|
/* Start with the raw servent */
|
|
CurrentSize = sizeof(PROTOENT);
|
|
|
|
/* Return the size needed now */
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Copy the servent and initialize it */
|
|
CopyMemory(p, Protoent, sizeof(PROTOENT));
|
|
p = Buffer + CurrentSize;
|
|
ReturnedProtoent->p_name = NULL;
|
|
ReturnedProtoent->p_aliases = NULL;
|
|
|
|
/* Find out how many aliases there are */
|
|
while (Protoent->p_aliases[Aliases])
|
|
{
|
|
/* Increase the alias count */
|
|
Aliases++;
|
|
}
|
|
|
|
/* Add the aliases to the size, and validate it */
|
|
CurrentSize += (Aliases + 1) * sizeof(ULONG_PTR);
|
|
if (CurrentSize > (DWORD)BufferLength)
|
|
{
|
|
/* Clear the aliases and return */
|
|
Protoent->p_aliases = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
/* Write the aliases, update the pointer */
|
|
ReturnedProtoent->p_aliases = (PCHAR*)p;
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Add the service name to the size, and validate it */
|
|
NameSize = strlen(Protoent->p_name) + sizeof(CHAR);
|
|
CurrentSize += NameSize;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write the service name and update the pointer */
|
|
ReturnedProtoent->p_name = p;
|
|
CopyMemory(p, Protoent->p_name, NameSize);
|
|
p = Buffer + CurrentSize;
|
|
|
|
/* Now add the aliases */
|
|
for (i = 0; i < Aliases; i++)
|
|
{
|
|
/* Update size and validate */
|
|
NameSize = strlen(Protoent->p_aliases[i]) + sizeof(CHAR);
|
|
CurrentSize += NameSize;
|
|
if (CurrentSize > (DWORD)BufferLength) return BufferSize;
|
|
|
|
/* Write pointer and copy */
|
|
ReturnedProtoent->p_aliases[i] = p;
|
|
CopyMemory(p, Protoent->p_aliases[i], NameSize);
|
|
|
|
/* Update pointer */
|
|
p = Buffer + CurrentSize;
|
|
}
|
|
|
|
/* Finalize the list and return */
|
|
ReturnedProtoent->p_aliases[i] = NULL;
|
|
return BufferSize;
|
|
}
|
|
|
|
PWSASYNCBLOCK
|
|
WSAAPI
|
|
WsAsyncAllocateBlock(IN SIZE_T ExtraLength)
|
|
{
|
|
PWSASYNCBLOCK AsyncBlock;
|
|
|
|
/* Add the size of the block */
|
|
ExtraLength += sizeof(WSASYNCBLOCK);
|
|
|
|
/* Allocate it */
|
|
AsyncBlock = HeapAlloc(WsSockHeap, 0, ExtraLength);
|
|
|
|
/* Get a handle to it */
|
|
AsyncBlock->TaskHandle = UlongToPtr(InterlockedIncrement(&WsAsyncTaskHandle));
|
|
|
|
/* Return it */
|
|
return AsyncBlock;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
WsAsyncThreadBlockingHook(VOID)
|
|
{
|
|
/* Check if this task is being cancelled */
|
|
if (WsAsyncCurrentTaskHandle == WsAsyncCancelledTaskHandle)
|
|
{
|
|
/* Cancel the blocking call so we can get back */
|
|
WSACancelBlockingCall();
|
|
}
|
|
|
|
/* Return to system */
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncFreeBlock(IN PWSASYNCBLOCK AsyncBlock)
|
|
{
|
|
/* Free it */
|
|
HeapFree(WsSockHeap, 0, AsyncBlock);
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncGetServ(IN HANDLE TaskHandle,
|
|
IN DWORD Operation,
|
|
IN HWND hWnd,
|
|
IN UINT wMsg,
|
|
IN CHAR FAR *ByWhat,
|
|
IN CHAR FAR *Protocol,
|
|
IN CHAR FAR *Buffer,
|
|
IN INT BufferLength)
|
|
{
|
|
PSERVENT Servent;
|
|
SIZE_T BufferSize = 0;
|
|
LPARAM lParam;
|
|
INT ErrorCode = 0;
|
|
|
|
/* Check the operation */
|
|
if (Operation == WsAsyncGetServByName)
|
|
{
|
|
/* Call the API */
|
|
Servent = getservbyname(ByWhat, Protocol);
|
|
}
|
|
else
|
|
{
|
|
/* Call the API */
|
|
Servent = getservbyport(PtrToUlong(ByWhat), Protocol);
|
|
}
|
|
|
|
/* Make sure we got one */
|
|
if (!Servent) ErrorCode = GetLastError();
|
|
|
|
/* Acquire the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Check if this task got cancelled */
|
|
if (TaskHandle == WsAsyncCancelledTaskHandle)
|
|
{
|
|
/* Return */
|
|
WsAsyncUnlock();
|
|
return;
|
|
}
|
|
|
|
/* If we got a Servent back, copy it */
|
|
if (Servent)
|
|
{
|
|
/* Copy it into the buffer */
|
|
BufferSize = CopyServentToBuffer(Buffer, BufferLength, Servent);
|
|
|
|
/* Check if we had enough space */
|
|
if (BufferSize > (DWORD)BufferLength)
|
|
{
|
|
/* Not enough */
|
|
ErrorCode = WSAENOBUFS;
|
|
}
|
|
else
|
|
{
|
|
/* Perfect */
|
|
ErrorCode = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Not processing anymore */
|
|
WsAsyncCurrentTaskHandle = NULL;
|
|
|
|
/* Release the lock */
|
|
WsAsyncUnlock();
|
|
|
|
/* Make the messed-up lParam reply */
|
|
lParam = WSAMAKEASYNCREPLY(BufferSize, ErrorCode);
|
|
|
|
/* Sent it through the Upcall API */
|
|
WPUPostMessage(hWnd, wMsg, (WPARAM)TaskHandle, lParam);
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncGetProto(IN HANDLE TaskHandle,
|
|
IN DWORD Operation,
|
|
IN HWND hWnd,
|
|
IN UINT wMsg,
|
|
IN CHAR FAR *ByWhat,
|
|
IN CHAR FAR *Buffer,
|
|
IN INT BufferLength)
|
|
{
|
|
PPROTOENT Protoent;
|
|
SIZE_T BufferSize = 0;
|
|
LPARAM lParam;
|
|
INT ErrorCode = 0;
|
|
|
|
/* Check the operation */
|
|
if (Operation == WsAsyncGetProtoByName)
|
|
{
|
|
/* Call the API */
|
|
Protoent = getprotobyname(ByWhat);
|
|
}
|
|
else
|
|
{
|
|
/* Call the API */
|
|
Protoent = getprotobynumber(PtrToUlong(ByWhat));
|
|
}
|
|
|
|
/* Make sure we got one */
|
|
if (!Protoent) ErrorCode = GetLastError();
|
|
|
|
/* Acquire the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Check if this task got cancelled */
|
|
if (TaskHandle == WsAsyncCancelledTaskHandle)
|
|
{
|
|
/* Return */
|
|
WsAsyncUnlock();
|
|
return;
|
|
}
|
|
|
|
/* If we got a Servent back, copy it */
|
|
if (Protoent)
|
|
{
|
|
/* Copy it into the buffer */
|
|
BufferSize = CopyProtoentToBuffer(Buffer, BufferLength, Protoent);
|
|
|
|
/* Check if we had enough space */
|
|
if (BufferSize > (DWORD)BufferLength)
|
|
{
|
|
/* Not enough */
|
|
ErrorCode = WSAENOBUFS;
|
|
}
|
|
else
|
|
{
|
|
/* Perfect */
|
|
ErrorCode = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Not processing anymore */
|
|
WsAsyncCurrentTaskHandle = NULL;
|
|
|
|
/* Release the lock */
|
|
WsAsyncUnlock();
|
|
|
|
/* Make the messed-up lParam reply */
|
|
lParam = WSAMAKEASYNCREPLY(BufferSize, ErrorCode);
|
|
|
|
/* Sent it through the Upcall API */
|
|
WPUPostMessage(hWnd, wMsg, (WPARAM)TaskHandle, lParam);
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncGetHost(IN HANDLE TaskHandle,
|
|
IN DWORD Operation,
|
|
IN HWND hWnd,
|
|
IN UINT wMsg,
|
|
IN CHAR FAR *ByWhat,
|
|
IN INT Length,
|
|
IN INT Type,
|
|
IN CHAR FAR *Buffer,
|
|
IN INT BufferLength)
|
|
{
|
|
PHOSTENT Hostent;
|
|
SIZE_T BufferSize = 0;
|
|
LPARAM lParam;
|
|
INT ErrorCode = 0;
|
|
|
|
/* Check the operation */
|
|
if (Operation == WsAsyncGetHostByAddr)
|
|
{
|
|
/* Call the API */
|
|
Hostent = gethostbyaddr(ByWhat, Length, Type);
|
|
}
|
|
else
|
|
{
|
|
/* Call the API */
|
|
Hostent = gethostbyname(ByWhat);
|
|
}
|
|
|
|
/* Make sure we got one */
|
|
if (!Hostent) ErrorCode = GetLastError();
|
|
|
|
/* Acquire the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Check if this task got cancelled */
|
|
if (TaskHandle == WsAsyncCancelledTaskHandle)
|
|
{
|
|
/* Return */
|
|
WsAsyncUnlock();
|
|
return;
|
|
}
|
|
|
|
/* If we got a Servent back, copy it */
|
|
if (Hostent)
|
|
{
|
|
/* Copy it into the buffer */
|
|
BufferSize = CopyHostentToBuffer(Buffer, BufferLength, Hostent);
|
|
|
|
/* Check if we had enough space */
|
|
if (BufferSize > (DWORD)BufferLength)
|
|
{
|
|
/* Not enough */
|
|
ErrorCode = WSAENOBUFS;
|
|
}
|
|
else
|
|
{
|
|
/* Perfect */
|
|
ErrorCode = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Not processing anymore */
|
|
WsAsyncCurrentTaskHandle = NULL;
|
|
|
|
/* Release the lock */
|
|
WsAsyncUnlock();
|
|
|
|
/* Make the messed-up lParam reply */
|
|
lParam = WSAMAKEASYNCREPLY(BufferSize, ErrorCode);
|
|
|
|
/* Sent it through the Upcall API */
|
|
WPUPostMessage(hWnd, wMsg, (WPARAM)TaskHandle, lParam);
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
WsAsyncThread(IN PVOID ThreadContext)
|
|
{
|
|
PWSASYNCCONTEXT Context = ThreadContext;
|
|
PWSASYNCBLOCK AsyncBlock;
|
|
PLIST_ENTRY Entry;
|
|
HANDLE AsyncEvent = Context->AsyncEvent;
|
|
PLIST_ENTRY ListHead = &Context->AsyncQueue;
|
|
|
|
/* Set the blocking hook */
|
|
WSASetBlockingHook((FARPROC)WsAsyncThreadBlockingHook);
|
|
|
|
/* Loop */
|
|
while (TRUE)
|
|
{
|
|
/* Wait for the event */
|
|
WaitForSingleObject(AsyncEvent, INFINITE);
|
|
|
|
/* Get the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Process the queue */
|
|
while (!IsListEmpty(ListHead))
|
|
{
|
|
/* Remove this entry and get the async block */
|
|
Entry = RemoveHeadList(ListHead);
|
|
AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue);
|
|
|
|
/* Save the current task handle */
|
|
WsAsyncCurrentTaskHandle = AsyncBlock->TaskHandle;
|
|
|
|
/* Release the lock */
|
|
WsAsyncUnlock();
|
|
|
|
/* Check which operation to do */
|
|
switch (AsyncBlock->Operation)
|
|
{
|
|
/* Get Host by Y */
|
|
case WsAsyncGetHostByAddr: case WsAsyncGetHostByName:
|
|
|
|
/* Call the handler */
|
|
WsAsyncGetHost(AsyncBlock->TaskHandle,
|
|
AsyncBlock->Operation,
|
|
AsyncBlock->GetHost.hWnd,
|
|
AsyncBlock->GetHost.wMsg,
|
|
AsyncBlock->GetHost.ByWhat,
|
|
AsyncBlock->GetHost.Length,
|
|
AsyncBlock->GetHost.Type,
|
|
AsyncBlock->GetHost.Buffer,
|
|
AsyncBlock->GetHost.BufferLength);
|
|
break;
|
|
|
|
/* Get Proto by Y */
|
|
case WsAsyncGetProtoByNumber: case WsAsyncGetProtoByName:
|
|
|
|
/* Call the handler */
|
|
WsAsyncGetProto(AsyncBlock->TaskHandle,
|
|
AsyncBlock->Operation,
|
|
AsyncBlock->GetProto.hWnd,
|
|
AsyncBlock->GetProto.wMsg,
|
|
AsyncBlock->GetHost.ByWhat,
|
|
AsyncBlock->GetProto.Buffer,
|
|
AsyncBlock->GetProto.BufferLength);
|
|
break;
|
|
|
|
/* Get Serv by Y */
|
|
case WsAsyncGetServByPort: case WsAsyncGetServByName:
|
|
|
|
/* Call the handler */
|
|
WsAsyncGetServ(AsyncBlock->TaskHandle,
|
|
AsyncBlock->Operation,
|
|
AsyncBlock->GetServ.hWnd,
|
|
AsyncBlock->GetServ.wMsg,
|
|
AsyncBlock->GetServ.ByWhat,
|
|
AsyncBlock->GetServ.Protocol,
|
|
AsyncBlock->GetServ.Buffer,
|
|
AsyncBlock->GetServ.BufferLength);
|
|
break;
|
|
|
|
/* Termination */
|
|
case WsAsyncTerminate:
|
|
|
|
/* Clean up the extra reference */
|
|
WSACleanup();
|
|
|
|
/* Free the context block */
|
|
WsAsyncFreeBlock(AsyncBlock);
|
|
|
|
/* Acquire the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Loop the queue and flush it */
|
|
while (!IsListEmpty(ListHead))
|
|
{
|
|
Entry = RemoveHeadList(ListHead);
|
|
AsyncBlock = CONTAINING_RECORD(Entry,
|
|
WSASYNCBLOCK,
|
|
AsyncQueue);
|
|
WsAsyncFreeBlock(AsyncBlock);
|
|
}
|
|
|
|
/* Release lock */
|
|
WsAsyncUnlock();
|
|
|
|
/* Close the event, free the Context */
|
|
CloseHandle(AsyncEvent);
|
|
HeapFree(WsSockHeap, 0, Context);
|
|
|
|
/* Remove the extra DLL reference and kill us */
|
|
FreeLibraryAndExitThread(WsAsyncDllHandle, 0);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Done processing */
|
|
WsAsyncCurrentTaskHandle = NULL;
|
|
|
|
/* Free this block, get lock and reloop */
|
|
WsAsyncFreeBlock(AsyncBlock);
|
|
WsAsyncLock();
|
|
}
|
|
|
|
/* Release the lock */
|
|
WsAsyncUnlock();
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WSAAPI
|
|
WsAsyncCheckAndInitThread(VOID)
|
|
{
|
|
HANDLE ThreadHandle;
|
|
DWORD Tid;
|
|
PWSASYNCCONTEXT Context = NULL;
|
|
WSADATA WsaData;
|
|
|
|
/* Make sure we're not initialized */
|
|
if (WsAsyncThreadInitialized) return TRUE;
|
|
|
|
/* Acquire the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Make sure we're not initialized */
|
|
if (!WsAsyncThreadInitialized)
|
|
{
|
|
/* Initialize Thread Context */
|
|
Context = HeapAlloc(WsSockHeap, 0, sizeof(*Context));
|
|
if (!Context)
|
|
goto Exit;
|
|
|
|
/* Initialize the Queue and event */
|
|
WsAsyncQueue = &Context->AsyncQueue;
|
|
InitializeListHead(WsAsyncQueue);
|
|
Context->AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
WsAsyncEvent = Context->AsyncEvent;
|
|
|
|
/* Prevent us from ever being killed while running */
|
|
if (WSAStartup(MAKEWORD(2,2), &WsaData) != ERROR_SUCCESS)
|
|
goto Fail;
|
|
|
|
/* Create the thread */
|
|
ThreadHandle = CreateThread(NULL,
|
|
0,
|
|
WsAsyncThread,
|
|
Context,
|
|
0,
|
|
&Tid);
|
|
if (ThreadHandle == NULL)
|
|
{
|
|
/* Cleanup and fail */
|
|
WSACleanup();
|
|
goto Fail;
|
|
}
|
|
|
|
/* Close the handle and set init */
|
|
CloseHandle(ThreadHandle);
|
|
WsAsyncThreadInitialized = TRUE;
|
|
}
|
|
|
|
Exit:
|
|
/* Release the lock */
|
|
WsAsyncUnlock();
|
|
return WsAsyncThreadInitialized;
|
|
|
|
Fail:
|
|
/* Close the event, free the Context */
|
|
if (Context->AsyncEvent)
|
|
CloseHandle(Context->AsyncEvent);
|
|
HeapFree(WsSockHeap, 0, Context);
|
|
|
|
/* Bail out */
|
|
goto Exit;
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncTerminateThread(VOID)
|
|
{
|
|
PWSASYNCBLOCK AsyncBlock;
|
|
|
|
/* Make sure we're initialized */
|
|
if (!WsAsyncThreadInitialized) return;
|
|
|
|
/* Allocate a block */
|
|
AsyncBlock = WsAsyncAllocateBlock(0);
|
|
|
|
/* Initialize it for termination */
|
|
AsyncBlock->Operation = WsAsyncTerminate;
|
|
|
|
/* Queue the request and return */
|
|
WsAsyncQueueRequest(AsyncBlock);
|
|
WsAsyncThreadInitialized = FALSE;
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsAsyncQueueRequest(IN PWSASYNCBLOCK AsyncBlock)
|
|
{
|
|
/* Get the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Insert it into the queue */
|
|
InsertTailList(WsAsyncQueue, &AsyncBlock->AsyncQueue);
|
|
|
|
/* Wake up the thread */
|
|
SetEvent(WsAsyncEvent);
|
|
|
|
/* Release lock and return */
|
|
WsAsyncUnlock();
|
|
}
|
|
|
|
INT
|
|
WSAAPI
|
|
WsAsyncCancelRequest(IN HANDLE TaskHandle)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PWSASYNCBLOCK AsyncBlock;
|
|
|
|
/* Make sure we're initialized */
|
|
if (!WsAsyncThreadInitialized) return WSAEINVAL;
|
|
|
|
/* Acquire the lock */
|
|
WsAsyncLock();
|
|
|
|
/* Check if we're cancelling the current task */
|
|
if (TaskHandle == WsAsyncCurrentTaskHandle)
|
|
{
|
|
/* Mark us as cancelled, the async thread will see this later */
|
|
WsAsyncCancelledTaskHandle = TaskHandle;
|
|
|
|
/* Release lock and return */
|
|
WsAsyncUnlock();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* Loop the queue */
|
|
Entry = WsAsyncQueue->Flink;
|
|
while (Entry != WsAsyncQueue)
|
|
{
|
|
/* Get the Async Block */
|
|
AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue);
|
|
|
|
/* Check if this is the one */
|
|
if (TaskHandle == AsyncBlock->TaskHandle)
|
|
{
|
|
/* It is, remove it */
|
|
RemoveEntryList(Entry);
|
|
|
|
/* Release the lock, free the block, and return */
|
|
WsAsyncUnlock();
|
|
WsAsyncFreeBlock(AsyncBlock);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* Move to the next entry */
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
/* Nothing found, fail */
|
|
WsAsyncUnlock();
|
|
return WSAEINVAL;
|
|
}
|