Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/iphlpapi/icmp.c | 108 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 8 deletions(-)
diff --git a/dlls/iphlpapi/icmp.c b/dlls/iphlpapi/icmp.c index 8ef0321..ceeab69 100644 --- a/dlls/iphlpapi/icmp.c +++ b/dlls/iphlpapi/icmp.c @@ -106,9 +106,42 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
typedef struct { int sid; + LONG lock_count; + HANDLE lock_event; 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) + { + if (icp->lock_event) + SetEvent(icp->lock_event); + } +} + +static void icmp_wait_for_released_locks(icmp_t *icp) +{ + HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL); + + icp->lock_event = event; + if (InterlockedExchangeAdd(&icp->lock_count, 0x80000000) != 0) + { + do + { + if (event) WaitForSingleObjectEx(event, INFINITE, TRUE); + else SleepEx(1, TRUE); + } + while (icp->lock_count != 0x80000000); + } + if (event) CloseHandle(event); +} + #define IP_OPTS_UNKNOWN 0 #define IP_OPTS_DEFAULT 1 #define IP_OPTS_CUSTOM 2 @@ -347,6 +380,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 +438,7 @@ HANDLE WINAPI Icmp6CreateFile(VOID) } icp->sid=sid; icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; + icp->lock_count=0; return (HANDLE)icp; }
@@ -439,6 +497,7 @@ HANDLE WINAPI IcmpCreateFile(VOID) } icp->sid=sid; icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; + icp->lock_count=0; return (HANDLE)icp; }
@@ -455,6 +514,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 +588,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 +616,6 @@ DWORD WINAPI IcmpSendEcho2Ex( return 0; }
- if (Event) - { - FIXME("unsupported for events\n"); - return 0; - } if (ApcRoutine) { FIXME("unsupported for APCs\n"); @@ -569,6 +627,8 @@ DWORD WINAPI IcmpSendEcho2Ex( return 0; }
+ icmp_lock(icp); + /* Prepare the request */ id=getpid() & 0xFFFF; seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF; @@ -580,7 +640,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 +721,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; }
/*