From: "Gabriel Ivăncescu" Subject: [PATCH 09/12] iphlpapi: Implement asynchronous events for IcmpSendEcho2(Ex). Message-Id: <38b43e77d679e05b1b1677dceaa332e320e0e0cb.1600871233.git.gabrielopcode@gmail.com> Date: Wed, 23 Sep 2020 17:28:30 +0300 In-Reply-To: References: Signed-off-by: Gabriel Ivăncescu --- dlls/iphlpapi/icmp.c | 117 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 8 deletions(-) diff --git a/dlls/iphlpapi/icmp.c b/dlls/iphlpapi/icmp.c index 8ef0321..722620a 100644 --- a/dlls/iphlpapi/icmp.c +++ b/dlls/iphlpapi/icmp.c @@ -106,9 +106,51 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag); typedef struct { int sid; + LONG lock_count; + HANDLE lock_thread; IP_OPTION_INFORMATION default_opts; } icmp_t; +static void icmp_lock(icmp_t *icp) +{ + InterlockedIncrement(&icp->lock_count); +} + +static void icmp_unlock(icmp_t *icp) +{ + if (InterlockedDecrement(&icp->lock_count) == 0x80000000) + { + HANDLE thread = InterlockedExchangePointer(&icp->lock_thread, NULL); + + if (thread) + { + NtAlertThread(thread); + CloseHandle(thread); + } + } +} + +static void icmp_wait_for_released_locks(icmp_t *icp) +{ + DWORD wait = INFINITE; + + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &icp->lock_thread, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + icp->lock_thread = NULL; + wait = 1; + } + + if (InterlockedExchangeAdd(&icp->lock_count, 0x80000000) != 0) + { + do + SleepEx(wait, TRUE); + while (icp->lock_count != 0x80000000 || icp->lock_thread); + } + else + if (icp->lock_thread) CloseHandle(icp->lock_thread); +} + #define IP_OPTS_UNKNOWN 0 #define IP_OPTS_DEFAULT 1 #define IP_OPTS_CUSTOM 2 @@ -347,6 +389,30 @@ done: return res; } +struct icmp_get_reply_async_ctx +{ + icmp_t *icp; + HANDLE event; + unsigned char *buffer; + void *reply_buf; + DWORD reply_size; + DWORD send_time; + DWORD timeout; +}; + +static DWORD WINAPI icmp_get_reply_async_func(VOID *parameter) +{ + struct icmp_get_reply_async_ctx *ctx = parameter; + + icmp_get_reply(ctx->icp->sid, ctx->buffer, ctx->send_time, ctx->reply_buf, ctx->reply_size, ctx->timeout); + + SetEvent(ctx->event); + + icmp_unlock(ctx->icp); + HeapFree(GetProcessHeap(), 0, ctx); + return 0; +} + /* @@ -381,6 +447,7 @@ HANDLE WINAPI Icmp6CreateFile(VOID) } icp->sid=sid; icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; + icp->lock_count=0; return (HANDLE)icp; } @@ -439,6 +506,7 @@ HANDLE WINAPI IcmpCreateFile(VOID) } icp->sid=sid; icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; + icp->lock_count=0; return (HANDLE)icp; } @@ -455,6 +523,9 @@ BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle) return FALSE; } + /* Windows waits until all outstanding async requests are complete or timed out */ + icmp_wait_for_released_locks(icp); + close( icp->sid ); HeapFree(GetProcessHeap (), 0, icp); return TRUE; @@ -526,6 +597,7 @@ DWORD WINAPI IcmpSendEcho2Ex( unsigned char *buffer; int reqsize, repsize; DWORD send_time; + DWORD res = 0; TRACE("(%p, %p, %p, %p, %08x, %08x, %p, %d, %p, %p, %d, %d)\n", IcmpHandle, Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData, @@ -553,11 +625,6 @@ DWORD WINAPI IcmpSendEcho2Ex( return 0; } - if (Event) - { - FIXME("unsupported for events\n"); - return 0; - } if (ApcRoutine) { FIXME("unsupported for APCs\n"); @@ -569,6 +636,8 @@ DWORD WINAPI IcmpSendEcho2Ex( return 0; } + icmp_lock(icp); + /* Prepare the request */ id=getpid() & 0xFFFF; seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF; @@ -580,7 +649,7 @@ DWORD WINAPI IcmpSendEcho2Ex( buffer = HeapAlloc(GetProcessHeap(), 0, max( repsize, reqsize )); if (buffer == NULL) { SetLastError(ERROR_OUTOFMEMORY); - return 0; + goto done; } icmp_header=(struct icmp*)buffer; @@ -661,10 +730,42 @@ DWORD WINAPI IcmpSendEcho2Ex( } } HeapFree(GetProcessHeap(), 0, buffer); - return 0; + goto done; } - return icmp_get_reply(icp->sid, buffer, send_time, ReplyBuffer, ReplySize, Timeout); + if (Event) + { + struct icmp_get_reply_async_ctx *ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(*ctx)); + + if (ctx) + { + ctx->icp = icp; + ctx->event = Event; + ctx->buffer = buffer; + ctx->reply_buf = ReplyBuffer; + ctx->reply_size = ReplySize; + ctx->send_time = send_time; + ctx->timeout = Timeout; + if (QueueUserWorkItem(icmp_get_reply_async_func, ctx, WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION)) + { + SetLastError(ERROR_IO_PENDING); + return 0; + } + + HeapFree(GetProcessHeap(), 0, ctx); + } + else + SetLastError(ERROR_OUTOFMEMORY); + + HeapFree(GetProcessHeap(), 0, buffer); + goto done; + } + + res = icmp_get_reply(icp->sid, buffer, send_time, ReplyBuffer, ReplySize, Timeout); + +done: + icmp_unlock(icp); + return res; } /* -- 2.21.0