[PATCH v2 1/2] iphlpapi: Implement GetUdp6Table().

Guillaume Charifi guillaume.charifi at sfr.fr
Sun Aug 19 00:15:46 CDT 2018


Signed-off-by: Guillaume Charifi <guillaume.charifi at sfr.fr>
---
 dlls/iphlpapi/iphlpapi.spec   |   2 +-
 dlls/iphlpapi/iphlpapi_main.c |  30 ++++-
 dlls/iphlpapi/ipstats.c       | 241 ++++++++++++++++++++++++++++++++++
 dlls/iphlpapi/ipstats.h       |   1 +
 include/iphlpapi.h            |   2 +
 include/udpmib.h              |  53 ++++++++
 6 files changed, 322 insertions(+), 7 deletions(-)

diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec
index 1686644de0..fd00cc093a 100644
--- a/dlls/iphlpapi/iphlpapi.spec
+++ b/dlls/iphlpapi/iphlpapi.spec
@@ -141,7 +141,7 @@
 @ stdcall GetTcpTable2( ptr ptr long )
 @ stub GetTcpTableFromStack
 #@ stub GetTeredoPort
-#@ stub GetUdp6Table
+@ stdcall GetUdp6Table( ptr ptr long )
 @ stdcall GetUdpStatisticsEx( ptr long )
 @ stdcall GetUdpStatistics( ptr )
 @ stub GetUdpStatsFromStack
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 7de70c9ef4..c7140cd974 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -2442,6 +2442,14 @@ DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
     return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET, UDP_TABLE_BASIC, 0);
 }
 
+/******************************************************************
+ *    GetUdp6Table (IPHLPAPI.@)
+ */
+DWORD WINAPI GetUdp6Table(PMIB_UDP6TABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
+{
+    return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET6, UDP_TABLE_BASIC, 0);
+}
+
 /******************************************************************
  *    GetExtendedUdpTable (IPHLPAPI.@)
  */
@@ -2456,15 +2464,25 @@ DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder,
 
     if (!pdwSize) return ERROR_INVALID_PARAMETER;
 
-    if (ulAf != WS_AF_INET)
-    {
-        FIXME("ulAf = %u not supported\n", ulAf);
-        return ERROR_NOT_SUPPORTED;
-    }
     if (TableClass == UDP_TABLE_OWNER_MODULE)
         FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
 
-    if ((ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size)))
+    switch (ulAf)
+    {
+        case WS_AF_INET:
+            ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
+            break;
+
+        case WS_AF_INET6:
+            ret = build_udp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
+            break;
+
+        default:
+            FIXME("ulAf = %u not supported\n", ulAf);
+            ret = ERROR_NOT_SUPPORTED;
+    }
+
+    if (ret)
         return ret;
 
     if (!pUdpTable || *pdwSize < size)
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
index 799d03d574..0c19d4abb0 100644
--- a/dlls/iphlpapi/ipstats.c
+++ b/dlls/iphlpapi/ipstats.c
@@ -2565,6 +2565,247 @@ DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE
     return ret;
 }
 
+static DWORD get_udp6_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
+{
+    DWORD table_size;
+
+    switch (class)
+    {
+    case UDP_TABLE_BASIC:
+    {
+        table_size = FIELD_OFFSET(MIB_UDP6TABLE, table[row_count]);
+        if (row_size) *row_size = sizeof(MIB_UDP6ROW);
+        break;
+    }
+    case UDP_TABLE_OWNER_PID:
+    {
+        table_size = FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID, table[row_count]);
+        if (row_size) *row_size = sizeof(MIB_UDP6ROW_OWNER_PID);
+        break;
+    }
+    case UDP_TABLE_OWNER_MODULE:
+    {
+        table_size = FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE, table[row_count]);
+        if (row_size) *row_size = sizeof(MIB_UDP6ROW_OWNER_MODULE);
+        break;
+    }
+    default:
+        ERR("unhandled class %u\n", class);
+        return 0;
+    }
+    return table_size;
+}
+
+static MIB_UDP6TABLE *append_udp6_row( UDP_TABLE_CLASS class, HANDLE heap, DWORD flags,
+                                     MIB_UDP6TABLE *table, DWORD *count,
+                                     const MIB_UDP6ROW_OWNER_MODULE *row, DWORD row_size )
+{
+    if (table->dwNumEntries >= *count)
+    {
+        MIB_UDP6TABLE *new_table;
+        DWORD new_count = table->dwNumEntries * 2, new_table_size;
+
+        new_table_size = get_udp6_table_sizes( class, new_count, NULL );
+        if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
+        {
+            HeapFree( heap, 0, table );
+            return NULL;
+        }
+        *count = new_count;
+        table = new_table;
+    }
+    memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
+    table->dwNumEntries++;
+    return table;
+}
+
+static int compare_udp6_rows(const void *a, const void *b)
+{
+    const MIB_UDP6ROW *rowA = a;
+    const MIB_UDP6ROW *rowB = b;
+    int ret;
+
+    if ((ret = memcmp(&rowA->dwLocalAddr, &rowB->dwLocalAddr, sizeof(rowA->dwLocalAddr)) != 0)) return ret;
+    if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
+    return rowA->dwLocalPort - rowB->dwLocalPort;
+}
+
+struct ipv6_addr_scope
+{
+    IN6_ADDR addr;
+    DWORD scope;
+};
+
+static struct ipv6_addr_scope *get_ipv6_addr_scope_table(unsigned int *size)
+{
+    struct ipv6_addr_scope *table = NULL;
+    unsigned int table_size = 0;
+
+    if (!(table = HeapAlloc( GetProcessHeap(), 0, sizeof(table[0]) )))
+        return ERROR_OUTOFMEMORY;
+
+#ifdef __linux__
+    {
+        FILE *fp;
+        char buf[512], *ptr;
+
+        if (!(fp = fopen( "/proc/net/if_inet6", "r" )))
+            goto failed;
+
+        while ((ptr = fgets( buf, sizeof(buf), fp )))
+        {
+            WORD a[8];
+            DWORD scope;
+            struct ipv6_addr_scope *new_table;
+            struct ipv6_addr_scope *entry;
+            unsigned int i;
+
+            if (sscanf( ptr, "%4x%4x%4x%4x%4x%4x%4x%4x %*s %*s %x",
+                &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &scope ) != 9)
+                continue;
+
+            table_size++;
+            if (!(new_table = HeapReAlloc( GetProcessHeap(), 0, table, table_size * sizeof(table[0]) )))
+            {
+                fclose(fp);
+                goto failed;
+            }
+
+            table = new_table;
+            entry = &table[table_size - 1];
+
+            i = 0;
+            while (i < 8)
+            {
+                entry->addr.u.Word[i] = htons(a[i]);
+                i++;
+            }
+
+            entry->scope = htons(scope);
+        }
+    }
+#else
+    FIXME( "not implemented\n" );
+    goto failed;
+#endif
+
+    *size = table_size;
+    return table;
+
+failed:
+    HeapFree( GetProcessHeap(), 0, table );
+    return NULL;
+}
+
+static DWORD find_ipv6_addr_scope(IN6_ADDR *addr, struct ipv6_addr_scope *table, unsigned int size)
+{
+    const BYTE multicast_scope_mask = 0x0F;
+    const BYTE multicast_scope_shift = 0;
+    unsigned int i = 0;
+
+    if (IN6_IS_ADDR_UNSPECIFIED(addr))
+        return 0;
+
+    if (IN6_IS_ADDR_MULTICAST(addr))
+        return htons((addr->u.Byte[1] & multicast_scope_mask) >> multicast_scope_shift);
+
+    if (!table)
+        return -1;
+
+    while (i < size)
+    {
+        if (memcmp(&table[i].addr, addr, sizeof(table[i].addr)) == 0)
+            return table[i].scope;
+        i++;
+    }
+
+    return -1;
+}
+
+DWORD build_udp6_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
+                       DWORD *size )
+{
+    MIB_UDP6TABLE *table;
+    MIB_UDP6ROW_OWNER_MODULE row;
+    DWORD ret = NO_ERROR, count = 16, table_size, row_size;
+
+    if (!(table_size = get_udp6_table_sizes( class, count, &row_size )))
+        return ERROR_INVALID_PARAMETER;
+
+    if (!(table = HeapAlloc( heap, flags, table_size )))
+         return ERROR_OUTOFMEMORY;
+
+    table->dwNumEntries = 0;
+    memset( &row, 0, sizeof(row) );
+
+#ifdef __linux__
+    {
+        FILE *fp;
+
+        if ((fp = fopen( "/proc/net/udp6", "r" )))
+        {
+            char buf[512], *ptr;
+            struct pid_map *map = NULL;
+            unsigned int num_entries = 0;
+            struct ipv6_addr_scope *addr_scopes;
+            unsigned int addr_scopes_size = 0;
+            unsigned int dummy;
+            int inode;
+
+            addr_scopes = get_ipv6_addr_scope_table(&addr_scopes_size);
+
+            if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
+
+            /* skip header line */
+            ptr = fgets( buf, sizeof(buf), fp );
+            while ((ptr = fgets( buf, sizeof(buf), fp )))
+            {
+                DWORD in6_addr32[4];
+
+                if (sscanf( ptr, "%u: %8x%8x%8x%8x:%x %*s %*s %*s %*s %*s %*s %*s %d", &dummy,
+                    &in6_addr32[0], &in6_addr32[1], &in6_addr32[2], &in6_addr32[3],
+                    &row.dwLocalPort, &inode ) != 7)
+                    continue;
+                memcpy(&row.ucLocalAddr, in6_addr32, sizeof(row.ucLocalAddr));
+                row.dwLocalScopeId = find_ipv6_addr_scope(&row, addr_scopes, addr_scopes_size);
+                row.dwLocalPort = htons( row.dwLocalPort );
+
+                if (class >= UDP_TABLE_OWNER_PID)
+                    row.dwOwningPid = find_owning_pid( map, num_entries, inode );
+                if (class >= UDP_TABLE_OWNER_MODULE)
+                {
+                    row.liCreateTimestamp.QuadPart = 0; /* FIXME */
+                    row.u.dwFlags = 0;
+                    memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
+                }
+                if (!(table = append_udp6_row( class, heap, flags, table, &count, &row, row_size )))
+                    break;
+            }
+            HeapFree( GetProcessHeap(), 0, map );
+            if (addr_scopes)
+                HeapFree( GetProcessHeap(), 0, addr_scopes );
+            fclose( fp );
+        }
+        else ret = ERROR_NOT_SUPPORTED;
+    }
+#else
+    FIXME( "not implemented\n" );
+    ret = ERROR_NOT_SUPPORTED;
+#endif
+
+    if (!table) return ERROR_OUTOFMEMORY;
+    if (!ret)
+    {
+        if (order && table->dwNumEntries)
+            qsort( table->table, table->dwNumEntries, row_size, compare_udp6_rows );
+        *tablep = table;
+    }
+    else HeapFree( heap, flags, table );
+    if (size) *size = get_udp6_table_sizes( class, count, NULL );
+    TRACE( "returning ret %u table %p\n", ret, table );
+    return ret;
+}
+
 /******************************************************************
  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
  *
diff --git a/dlls/iphlpapi/ipstats.h b/dlls/iphlpapi/ipstats.h
index d742d6380a..acf43ee27c 100644
--- a/dlls/iphlpapi/ipstats.h
+++ b/dlls/iphlpapi/ipstats.h
@@ -34,5 +34,6 @@ DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry) DECLSPEC_HIDDE
 
 DWORD build_tcp_table(TCP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
 DWORD build_udp_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
+DWORD build_udp6_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
 
 #endif /* ndef WINE_IPSTATS_H_ */
diff --git a/include/iphlpapi.h b/include/iphlpapi.h
index 54d93d1c9c..86507dfd4d 100644
--- a/include/iphlpapi.h
+++ b/include/iphlpapi.h
@@ -51,6 +51,8 @@ DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder);
 
 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder);
 
+DWORD WINAPI GetUdp6Table(PMIB_UDP6TABLE pUdpTable, PDWORD pdwSize, BOOL bOrder);
+
 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats);
 
 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily);
diff --git a/include/udpmib.h b/include/udpmib.h
index 6b3f51cf2f..3d1bba5ee5 100644
--- a/include/udpmib.h
+++ b/include/udpmib.h
@@ -18,6 +18,8 @@
 #ifndef __WINE_UDPMIB_H
 #define __WINE_UDPMIB_H
 
+#include <in6addr.h>
+
 #define TCPIP_OWNING_MODULE_SIZE 16
 
 
@@ -71,6 +73,57 @@ typedef struct _MIB_UDPTABLE_OWNER_MODULE
     MIB_UDPROW_OWNER_MODULE table[1];
 } MIB_UDPTABLE_OWNER_MODULE, *PMIB_UDPTABLE_OWNER_MODULE;
 
+typedef struct _MIB_UDP6ROW
+{
+    IN6_ADDR dwLocalAddr;
+    DWORD    dwLocalScopeId;
+    DWORD    dwLocalPort;
+} MIB_UDP6ROW, *PMIB_UDP6ROW;
+
+typedef struct _MIB_UDP6TABLE
+{
+    DWORD       dwNumEntries;
+    MIB_UDP6ROW table[1];
+} MIB_UDP6TABLE, *PMIB_UDP6TABLE;
+
+typedef struct _MIB_UDP6ROW_OWNER_PID
+{
+    UCHAR ucLocalAddr[16];
+    DWORD dwLocalScopeId;
+    DWORD dwLocalPort;
+    DWORD dwOwningPid;
+} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID;
+
+typedef struct _MIB_UDP6TABLE_OWNER_PID
+{
+    DWORD                 dwNumEntries;
+    MIB_UDP6ROW_OWNER_PID table[1];
+} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID;
+
+typedef struct _MIB_UDP6ROW_OWNER_MODULE
+{
+    UCHAR         ucLocalAddr[16];
+    DWORD         dwLocalScopeId;
+    DWORD         dwLocalPort;
+    DWORD         dwOwningPid;
+    LARGE_INTEGER liCreateTimestamp;
+    __C89_NAMELESS union
+    {
+        __C89_NAMELESS struct
+        {
+            int SpecificPortBind:1;
+        } __C89_NAMELESSSTRUCTNAME;
+        int dwFlags;
+    } __C89_NAMELESSUNIONNAME;
+    ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];
+} MIB_UDP6ROW_OWNER_MODULE, *PMIB_UDP6ROW_OWNER_MODULE;
+
+typedef struct _MIB_UDP6TABLE_OWNER_MODULE
+{
+    DWORD                    dwNumEntries;
+    MIB_UDP6ROW_OWNER_MODULE table[1];
+} MIB_UDP6TABLE_OWNER_MODULE, *PMIB_UDP6TABLE_OWNER_MODULE;
+
 /* UDP statistics */
 
 typedef struct _MIB_UDPSTATS
-- 
Guillaume Charifi <guillaume.charifi at sfr.fr>




More information about the wine-devel mailing list