iphlpapi: Implement GetUdp6Table().
Signed-off-by: Guillaume Charifi <guillaume.charifi@sfr.fr> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ad8f450957
commit
88e44332fe
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -151,6 +151,9 @@
|
|||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#define NONAMELESSUNION
|
||||
#define USE_WS_PREFIX
|
||||
#include "winsock2.h"
|
||||
#include "ws2ipdef.h"
|
||||
#include "ifenum.h"
|
||||
#include "ipstats.h"
|
||||
#include "iphlpapi.h"
|
||||
|
@ -2565,6 +2568,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 NULL;
|
||||
|
||||
#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, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*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(const IN6_ADDR *addr, const 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 (WS_IN6_IS_ADDR_UNSPECIFIED(addr))
|
||||
return 0;
|
||||
|
||||
if (WS_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((const IN6_ADDR *)&row.ucLocalAddr, 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.@)
|
||||
*
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -71,6 +71,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
|
||||
|
|
|
@ -284,16 +284,33 @@ typedef struct WS(in_pktinfo) {
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline BOOL WS(IN6_IS_ADDR_LOOPBACK) ( const IN6_ADDR *a )
|
||||
static inline BOOLEAN WS(IN6_IS_ADDR_LOOPBACK) ( const IN6_ADDR *a )
|
||||
{
|
||||
return (BOOL)((a->s6_words[0] == 0) &&
|
||||
(a->s6_words[1] == 0) &&
|
||||
(a->s6_words[2] == 0) &&
|
||||
(a->s6_words[3] == 0) &&
|
||||
(a->s6_words[4] == 0) &&
|
||||
(a->s6_words[5] == 0) &&
|
||||
(a->s6_words[6] == 0) &&
|
||||
(a->s6_words[7] == 0x0100));
|
||||
return ((a->s6_words[0] == 0) &&
|
||||
(a->s6_words[1] == 0) &&
|
||||
(a->s6_words[2] == 0) &&
|
||||
(a->s6_words[3] == 0) &&
|
||||
(a->s6_words[4] == 0) &&
|
||||
(a->s6_words[5] == 0) &&
|
||||
(a->s6_words[6] == 0) &&
|
||||
(a->s6_words[7] == 0x0100));
|
||||
}
|
||||
|
||||
static inline BOOLEAN WS(IN6_IS_ADDR_MULTICAST) ( const IN6_ADDR *a )
|
||||
{
|
||||
return (a->s6_bytes[0] == 0xff);
|
||||
}
|
||||
|
||||
static inline BOOLEAN WS(IN6_IS_ADDR_UNSPECIFIED) ( const IN6_ADDR *a )
|
||||
{
|
||||
return ((a->s6_words[0] == 0) &&
|
||||
(a->s6_words[1] == 0) &&
|
||||
(a->s6_words[2] == 0) &&
|
||||
(a->s6_words[3] == 0) &&
|
||||
(a->s6_words[4] == 0) &&
|
||||
(a->s6_words[5] == 0) &&
|
||||
(a->s6_words[6] == 0) &&
|
||||
(a->s6_words[7] == 0));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Reference in New Issue