[PATCH resend 1/4] iphlpapi: Implement asynchronous events for IcmpSendEcho2(Ex).

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue Jun 15 07:50:24 CDT 2021


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at 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;
 }
 
 /*
-- 
2.31.1




More information about the wine-devel mailing list