iphlpapi: Implement GetUdpStatisticsEx() on top of nsi.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d6278ea021
commit
e91b19bf38
|
@ -5,8 +5,6 @@ EXTRALIBS = $(KSTAT_LIBS) $(PROCSTAT_LIBS)
|
|||
|
||||
C_SRCS = \
|
||||
icmp.c \
|
||||
ifenum.c \
|
||||
iphlpapi_main.c \
|
||||
ipstats.c
|
||||
iphlpapi_main.c
|
||||
|
||||
RC_SRCS = version.rc
|
||||
|
|
|
@ -1,395 +0,0 @@
|
|||
/* Copyright (C) 2003,2006,2011 Juan Lang
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_ARP_H
|
||||
#include <net/if_arp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_ROUTE_H
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSCTL_H
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKIO_H
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_DL_H
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_TYPES_H
|
||||
#include <net/if_types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
#include <linux/rtnetlink.h>
|
||||
#endif
|
||||
|
||||
#include "ifenum.h"
|
||||
#include "ws2ipdef.h"
|
||||
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
#define ifreq_len(ifr) \
|
||||
max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
|
||||
#else
|
||||
#define ifreq_len(ifr) sizeof(struct ifreq)
|
||||
#endif
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
|
||||
#ifndef IF_NAMESIZE
|
||||
#define IF_NAMESIZE 16
|
||||
#endif
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE (~0U)
|
||||
#endif
|
||||
|
||||
#define INITIAL_INTERFACES_ASSUMED 4
|
||||
|
||||
/* Functions */
|
||||
|
||||
static BOOL isLoopbackInterface(int fd, const char *name)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (name) {
|
||||
struct ifreq ifr;
|
||||
|
||||
lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
|
||||
ret = ifr.ifr_flags & IFF_LOOPBACK;
|
||||
}
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
/* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
|
||||
* bytes are necessary.
|
||||
*/
|
||||
static char *getInterfaceNameByIndex(IF_INDEX index, char *name)
|
||||
{
|
||||
return if_indextoname(index, name);
|
||||
}
|
||||
|
||||
DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index)
|
||||
{
|
||||
DWORD ret;
|
||||
unsigned int idx;
|
||||
|
||||
if (!name)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (!index)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
idx = if_nametoindex(name);
|
||||
if (idx) {
|
||||
*index = idx;
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
else
|
||||
ret = ERROR_INVALID_DATA;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL isIfIndexLoopback(ULONG idx)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
char name[IFNAMSIZ];
|
||||
int fd;
|
||||
|
||||
getInterfaceNameByIndex(idx, name);
|
||||
fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd != -1) {
|
||||
ret = isLoopbackInterface(fd, name);
|
||||
close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IF_NAMEINDEX
|
||||
DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
|
||||
{
|
||||
DWORD count = 0, i;
|
||||
struct if_nameindex *p, *indices = if_nameindex();
|
||||
InterfaceIndexTable *ret;
|
||||
|
||||
if (table) *table = NULL;
|
||||
if (!indices) return 0;
|
||||
|
||||
for (p = indices; p->if_name; p++)
|
||||
{
|
||||
if (skip_loopback && isIfIndexLoopback( p->if_index )) continue;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (table)
|
||||
{
|
||||
ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
|
||||
if (!ret)
|
||||
{
|
||||
count = 0;
|
||||
goto end;
|
||||
}
|
||||
for (p = indices, i = 0; p->if_name && i < count; p++)
|
||||
{
|
||||
if (skip_loopback && isIfIndexLoopback( p->if_index )) continue;
|
||||
ret->indexes[i++] = p->if_index;
|
||||
}
|
||||
ret->numIndexes = count = i;
|
||||
*table = ret;
|
||||
}
|
||||
|
||||
end:
|
||||
if_freenameindex( indices );
|
||||
return count;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_LINUX_RTNETLINK_H)
|
||||
static int open_netlink( int *pid )
|
||||
{
|
||||
int fd = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t len;
|
||||
|
||||
if (fd < 0) return fd;
|
||||
|
||||
memset( &addr, 0, sizeof(addr) );
|
||||
addr.nl_family = AF_NETLINK;
|
||||
|
||||
if (bind( fd, (struct sockaddr *)&addr, sizeof(addr) ) < 0)
|
||||
goto fail;
|
||||
|
||||
len = sizeof(addr);
|
||||
if (getsockname( fd, (struct sockaddr *)&addr, &len ) < 0)
|
||||
goto fail;
|
||||
|
||||
*pid = addr.nl_pid;
|
||||
return fd;
|
||||
fail:
|
||||
close( fd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int send_netlink_req( int fd, int pid, int type, int *seq_no )
|
||||
{
|
||||
static LONG seq;
|
||||
struct request
|
||||
{
|
||||
struct nlmsghdr hdr;
|
||||
struct rtgenmsg gen;
|
||||
} req;
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
req.hdr.nlmsg_len = sizeof(req);
|
||||
req.hdr.nlmsg_type = type;
|
||||
req.hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
req.hdr.nlmsg_pid = pid;
|
||||
req.hdr.nlmsg_seq = InterlockedIncrement( &seq );
|
||||
req.gen.rtgen_family = AF_UNSPEC;
|
||||
|
||||
memset( &addr, 0, sizeof(addr) );
|
||||
addr.nl_family = AF_NETLINK;
|
||||
if (sendto( fd, &req, sizeof(req), 0, (struct sockaddr *)&addr, sizeof(addr) ) != sizeof(req))
|
||||
return -1;
|
||||
*seq_no = req.hdr.nlmsg_seq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct netlink_reply
|
||||
{
|
||||
struct netlink_reply *next;
|
||||
int size;
|
||||
struct nlmsghdr *hdr;
|
||||
};
|
||||
|
||||
static void free_netlink_reply( struct netlink_reply *data )
|
||||
{
|
||||
struct netlink_reply *ptr;
|
||||
while( data )
|
||||
{
|
||||
ptr = data->next;
|
||||
HeapFree( GetProcessHeap(), 0, data );
|
||||
data = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
static int recv_netlink_reply( int fd, int pid, int seq, struct netlink_reply **data )
|
||||
{
|
||||
int bufsize = getpagesize();
|
||||
int left, read;
|
||||
BOOL done = FALSE;
|
||||
socklen_t sa_len;
|
||||
struct sockaddr_nl addr;
|
||||
struct netlink_reply *cur, *last = NULL;
|
||||
struct nlmsghdr *hdr;
|
||||
char *buf;
|
||||
|
||||
*data = NULL;
|
||||
buf = HeapAlloc( GetProcessHeap(), 0, bufsize );
|
||||
if (!buf) return -1;
|
||||
|
||||
do
|
||||
{
|
||||
left = read = recvfrom( fd, buf, bufsize, 0, (struct sockaddr *)&addr, &sa_len );
|
||||
if (read < 0) goto fail;
|
||||
if (addr.nl_pid != 0) continue; /* not from kernel */
|
||||
|
||||
for (hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, left); hdr = NLMSG_NEXT(hdr, left))
|
||||
{
|
||||
if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
|
||||
if (hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
done = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cur = HeapAlloc( GetProcessHeap(), 0, sizeof(*cur) + read );
|
||||
if (!cur) goto fail;
|
||||
cur->next = NULL;
|
||||
cur->size = read;
|
||||
cur->hdr = (struct nlmsghdr *)(cur + 1);
|
||||
memcpy( cur->hdr, buf, read );
|
||||
if (last) last->next = cur;
|
||||
else *data = cur;
|
||||
last = cur;
|
||||
} while (!done);
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, buf );
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free_netlink_reply( *data );
|
||||
HeapFree( GetProcessHeap(), 0, buf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static DWORD get_indices_from_reply( struct netlink_reply *reply, int pid, int seq,
|
||||
BOOL skip_loopback, InterfaceIndexTable *table )
|
||||
{
|
||||
struct nlmsghdr *hdr;
|
||||
struct netlink_reply *r;
|
||||
int count = 0;
|
||||
|
||||
for (r = reply; r; r = r->next)
|
||||
{
|
||||
int size = r->size;
|
||||
for (hdr = r->hdr; NLMSG_OK(hdr, size); hdr = NLMSG_NEXT(hdr, size))
|
||||
{
|
||||
if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
|
||||
if (hdr->nlmsg_type == NLMSG_DONE) break;
|
||||
|
||||
if (hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
struct ifinfomsg *info = NLMSG_DATA(hdr);
|
||||
|
||||
if (skip_loopback && (info->ifi_flags & IFF_LOOPBACK)) continue;
|
||||
if (table) table->indexes[count] = info->ifi_index;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
|
||||
{
|
||||
int fd, pid, seq;
|
||||
struct netlink_reply *reply = NULL;
|
||||
DWORD count = 0;
|
||||
|
||||
if (table) *table = NULL;
|
||||
fd = open_netlink( &pid );
|
||||
if (fd < 0) return 0;
|
||||
|
||||
if (send_netlink_req( fd, pid, RTM_GETLINK, &seq ) < 0)
|
||||
goto end;
|
||||
|
||||
if (recv_netlink_reply( fd, pid, seq, &reply ) < 0)
|
||||
goto end;
|
||||
|
||||
count = get_indices_from_reply( reply, pid, seq, skip_loopback, NULL );
|
||||
|
||||
if (table)
|
||||
{
|
||||
InterfaceIndexTable *ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
|
||||
if (!ret)
|
||||
{
|
||||
count = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret->numIndexes = count;
|
||||
get_indices_from_reply( reply, pid, seq, skip_loopback, ret );
|
||||
*table = ret;
|
||||
}
|
||||
|
||||
end:
|
||||
free_netlink_reply( reply );
|
||||
close( fd );
|
||||
return count;
|
||||
}
|
||||
|
||||
#else
|
||||
DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
|
||||
{
|
||||
if (table) *table = NULL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,66 +0,0 @@
|
|||
/* ifenum.h
|
||||
* Copyright (C) 2003,2006 Juan Lang
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* This module implements network interface and address enumeration. It's
|
||||
* meant to hide some problematic defines like socket(), and make iphlpapi
|
||||
* more portable.
|
||||
*
|
||||
* Like Windows, it uses a numeric index to identify an interface uniquely.
|
||||
* As implemented, an interface represents a UNIX network interface, virtual
|
||||
* or real, and thus can have 0 or 1 IP addresses associated with it. (This
|
||||
* only supports IPv4.)
|
||||
* The indexes returned are not guaranteed to be contiguous, so don't call
|
||||
* getNumInterfaces() and assume the values [0,getNumInterfaces() - 1] will be
|
||||
* valid indexes; use getInterfaceIndexTable() instead.
|
||||
*
|
||||
* See also the companion file, ipstats.h, for functions related to getting
|
||||
* statistics.
|
||||
*/
|
||||
#ifndef WINE_IFENUM_H_
|
||||
#define WINE_IFENUM_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#define USE_WS_PREFIX
|
||||
#include "iprtrmib.h"
|
||||
#include "winsock2.h"
|
||||
|
||||
#define MAX_INTERFACE_PHYSADDR 8
|
||||
#define MAX_INTERFACE_DESCRIPTION 256
|
||||
|
||||
/* A table of interface indexes, see get_interface_indices(). */
|
||||
typedef struct _InterfaceIndexTable {
|
||||
DWORD numIndexes;
|
||||
IF_INDEX indexes[1];
|
||||
} InterfaceIndexTable;
|
||||
|
||||
/* Returns the count of all interface indexes and optionally a ptr to an interface table.
|
||||
* HeapFree() the returned table. Will optionally ignore loopback devices.
|
||||
*/
|
||||
DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table ) DECLSPEC_HIDDEN;
|
||||
|
||||
/* ByName/ByIndex versions of various getter functions. */
|
||||
|
||||
/* Fills index with the index of name, if found. Returns
|
||||
* ERROR_INVALID_PARAMETER if name or index is NULL, ERROR_INVALID_DATA if name
|
||||
* is not found, and NO_ERROR on success.
|
||||
*/
|
||||
DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif /* ndef WINE_IFENUM_H_ */
|
|
@ -42,7 +42,6 @@
|
|||
#include "ws2ipdef.h"
|
||||
#include "windns.h"
|
||||
#include "iphlpapi.h"
|
||||
#include "ifenum.h"
|
||||
#include "ipifcons.h"
|
||||
#include "fltdefs.h"
|
||||
#include "ifdef.h"
|
||||
|
@ -3282,6 +3281,53 @@ DWORD WINAPI AllocateAndGetTcpExTableFromStack( void **table, BOOL sort, HANDLE
|
|||
return allocate_tcp_table( table, sort, heap, flags, family, TCP_TABLE_OWNER_PID_ALL );
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetUdpStatistics (IPHLPAPI.@)
|
||||
*
|
||||
* Get the UDP statistics for the local computer.
|
||||
*
|
||||
* PARAMS
|
||||
* stats [Out] buffer for UDP statistics
|
||||
*/
|
||||
DWORD WINAPI GetUdpStatistics( MIB_UDPSTATS *stats )
|
||||
{
|
||||
return GetUdpStatisticsEx( stats, WS_AF_INET );
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetUdpStatisticsEx (IPHLPAPI.@)
|
||||
*
|
||||
* Get the IPv4 and IPv6 UDP statistics for the local computer.
|
||||
*
|
||||
* PARAMS
|
||||
* stats [Out] buffer for UDP statistics
|
||||
* family [In] specifies whether IPv4 or IPv6 statistics are returned
|
||||
*
|
||||
* RETURNS
|
||||
* Success: NO_ERROR
|
||||
* Failure: error code from winerror.h
|
||||
*/
|
||||
DWORD WINAPI GetUdpStatisticsEx( MIB_UDPSTATS *stats, DWORD family )
|
||||
{
|
||||
struct nsi_udp_stats_dynamic dyn;
|
||||
USHORT key = (USHORT)family;
|
||||
DWORD err;
|
||||
|
||||
if (!stats || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
|
||||
memset( stats, 0, sizeof(*stats) );
|
||||
|
||||
err = NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_STATS_TABLE, &key, sizeof(key), NULL, 0,
|
||||
&dyn, sizeof(dyn), NULL, 0 );
|
||||
if (err) return err;
|
||||
|
||||
stats->dwInDatagrams = dyn.in_dgrams;
|
||||
stats->dwNoPorts = dyn.no_ports;
|
||||
stats->dwInErrors = dyn.in_errs;
|
||||
stats->dwOutDatagrams = dyn.out_dgrams;
|
||||
stats->dwNumAddrs = dyn.num_addrs;
|
||||
return err;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetUdpTable (IPHLPAPI.@)
|
||||
*
|
||||
|
|
|
@ -1,370 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003,2006 Juan Lang
|
||||
* Copyright (C) 2007 TransGaming Technologies Inc.
|
||||
* Copyright (C) 2009 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_DIRENT_H
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#ifdef HAVE_ALIAS_H
|
||||
#include <alias.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKETVAR_H
|
||||
#include <sys/socketvar.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIMEOUT_H
|
||||
#include <sys/timeout.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_SYSTM_H
|
||||
#include <netinet/in_systm.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_DL_H
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_TYPES_H
|
||||
#include <net/if_types.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_ROUTE_H
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_ARP_H
|
||||
#include <net/if_arp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IF_ETHER_H
|
||||
#include <netinet/if_ether.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IF_INARP_H
|
||||
#include <netinet/if_inarp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IP_H
|
||||
#include <netinet/ip.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IP_VAR_H
|
||||
#include <netinet/ip_var.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_TCP_FSM_H
|
||||
#include <netinet/tcp_fsm.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_PCB_H
|
||||
#include <netinet/in_pcb.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_TCP_TIMER_H
|
||||
#include <netinet/tcp_timer.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_TCP_VAR_H
|
||||
#include <netinet/tcp_var.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IP_ICMP_H
|
||||
#include <netinet/ip_icmp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_ICMP_VAR_H
|
||||
#include <netinet/icmp_var.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
#include <netinet/udp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_UDP_VAR_H
|
||||
#include <netinet/udp_var.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PROTOSW_H
|
||||
#include <sys/protosw.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSCTL_H
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_KSTAT_H
|
||||
#include <kstat.h>
|
||||
#endif
|
||||
#ifdef HAVE_INET_MIB2_H
|
||||
#include <inet/mib2.h>
|
||||
#endif
|
||||
#ifdef HAVE_STROPTS_H
|
||||
#include <stropts.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIHDR_H
|
||||
#include <sys/tihdr.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_QUEUE_H
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_USER_H
|
||||
/* Make sure the definitions of struct kinfo_proc are the same. */
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBPROCSTAT_H
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBPROC_H
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#ifndef ROUNDUP
|
||||
#define ROUNDUP(a) \
|
||||
((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int))
|
||||
#endif
|
||||
#ifndef ADVANCE
|
||||
#define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#define NONAMELESSUNION
|
||||
#define USE_WS_PREFIX
|
||||
#include "winsock2.h"
|
||||
#include "ws2ipdef.h"
|
||||
#include "ifenum.h"
|
||||
#include "iphlpapi.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#ifndef HAVE_NETINET_TCP_FSM_H
|
||||
#define TCPS_ESTABLISHED 1
|
||||
#define TCPS_SYN_SENT 2
|
||||
#define TCPS_SYN_RECEIVED 3
|
||||
#define TCPS_FIN_WAIT_1 4
|
||||
#define TCPS_FIN_WAIT_2 5
|
||||
#define TCPS_TIME_WAIT 6
|
||||
#define TCPS_CLOSED 7
|
||||
#define TCPS_CLOSE_WAIT 8
|
||||
#define TCPS_LAST_ACK 9
|
||||
#define TCPS_LISTEN 10
|
||||
#define TCPS_CLOSING 11
|
||||
#endif
|
||||
|
||||
#ifndef RTF_MULTICAST
|
||||
#define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
|
||||
#endif
|
||||
|
||||
#ifndef RTF_LLINFO
|
||||
#define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
|
||||
#endif
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
|
||||
|
||||
#ifdef HAVE_LIBKSTAT
|
||||
static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
|
||||
{
|
||||
unsigned int i;
|
||||
kstat_named_t *data = ksp->ks_data;
|
||||
|
||||
for (i = 0; i < ksp->ks_ndata; i++)
|
||||
if (!strcmp( data[i].name, name )) return data[i].value.ui32;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************
|
||||
* GetUdpStatistics (IPHLPAPI.@)
|
||||
*
|
||||
* Get the IPv4 and IPv6 UDP statistics for the local computer.
|
||||
*
|
||||
* PARAMS
|
||||
* stats [Out] buffer for UDP statistics
|
||||
* family [In] specifies whether IPv4 or IPv6 statistics are returned
|
||||
*
|
||||
* RETURNS
|
||||
* Success: NO_ERROR
|
||||
* Failure: error code from winerror.h
|
||||
*/
|
||||
DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS stats, DWORD family)
|
||||
{
|
||||
DWORD ret = ERROR_NOT_SUPPORTED;
|
||||
|
||||
if (!stats) return ERROR_INVALID_PARAMETER;
|
||||
if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
|
||||
memset( stats, 0, sizeof(*stats) );
|
||||
|
||||
stats->dwNumAddrs = get_interface_indices( FALSE, NULL );
|
||||
|
||||
if (family == WS_AF_INET6)
|
||||
{
|
||||
#ifdef __linux__
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen("/proc/net/snmp6", "r")))
|
||||
{
|
||||
struct {
|
||||
const char *name;
|
||||
DWORD *elem;
|
||||
} udpstatlist[] = {
|
||||
{ "Udp6InDatagrams", &stats->dwInDatagrams },
|
||||
{ "Udp6NoPorts", &stats->dwNoPorts },
|
||||
{ "Udp6InErrors", &stats->dwInErrors },
|
||||
{ "Udp6OutDatagrams", &stats->dwOutDatagrams },
|
||||
};
|
||||
char buf[512], *ptr, *value;
|
||||
DWORD res, i;
|
||||
|
||||
while ((ptr = fgets(buf, sizeof(buf), fp)))
|
||||
{
|
||||
if (!(value = strchr(buf, ' ')))
|
||||
continue;
|
||||
|
||||
/* terminate the valuename */
|
||||
ptr = value - 1;
|
||||
*(ptr + 1) = '\0';
|
||||
|
||||
/* and strip leading spaces from value */
|
||||
value += 1;
|
||||
while (*value==' ') value++;
|
||||
if ((ptr = strchr(value, '\n')))
|
||||
*ptr='\0';
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(udpstatlist); i++)
|
||||
if (!_strnicmp(buf, udpstatlist[i].name, -1) && sscanf(value, "%d", &res))
|
||||
*udpstatlist[i].elem = res;
|
||||
}
|
||||
fclose(fp);
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
}
|
||||
#else
|
||||
FIXME( "unimplemented for IPv6\n" );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen("/proc/net/snmp", "r")))
|
||||
{
|
||||
static const char hdr[] = "Udp:";
|
||||
char buf[512], *ptr;
|
||||
|
||||
while ((ptr = fgets(buf, sizeof(buf), fp)))
|
||||
{
|
||||
if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
|
||||
/* last line was a header, get another */
|
||||
if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
|
||||
if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
|
||||
{
|
||||
ptr += sizeof(hdr);
|
||||
sscanf( ptr, "%u %u %u %u %u",
|
||||
&stats->dwInDatagrams, &stats->dwNoPorts,
|
||||
&stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_LIBKSTAT)
|
||||
{
|
||||
static char udp[] = "udp";
|
||||
kstat_ctl_t *kc;
|
||||
kstat_t *ksp;
|
||||
MIB_UDPTABLE *udp_table;
|
||||
|
||||
if ((kc = kstat_open()) &&
|
||||
(ksp = kstat_lookup( kc, udp, 0, udp )) &&
|
||||
kstat_read( kc, ksp, NULL ) != -1 &&
|
||||
ksp->ks_type == KSTAT_TYPE_NAMED)
|
||||
{
|
||||
stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
|
||||
stats->dwNoPorts = 0; /* FIXME */
|
||||
stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
|
||||
stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
|
||||
if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
|
||||
{
|
||||
stats->dwNumAddrs = udp_table->dwNumEntries;
|
||||
HeapFree( GetProcessHeap(), 0, udp_table );
|
||||
}
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
if (kc) kstat_close( kc );
|
||||
}
|
||||
#elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
|
||||
{
|
||||
int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
|
||||
struct udpstat udp_stat;
|
||||
MIB_UDPTABLE *udp_table;
|
||||
size_t needed = sizeof(udp_stat);
|
||||
|
||||
if(sysctl(mib, ARRAY_SIZE(mib), &udp_stat, &needed, NULL, 0) != -1)
|
||||
{
|
||||
stats->dwInDatagrams = udp_stat.udps_ipackets;
|
||||
stats->dwOutDatagrams = udp_stat.udps_opackets;
|
||||
stats->dwNoPorts = udp_stat.udps_noport;
|
||||
stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
|
||||
if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
|
||||
{
|
||||
stats->dwNumAddrs = udp_table->dwNumEntries;
|
||||
HeapFree( GetProcessHeap(), 0, udp_table );
|
||||
}
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
else ERR ("failed to get udpstat\n");
|
||||
}
|
||||
#else
|
||||
FIXME( "unimplemented for IPv4\n" );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetUdpStatistics (IPHLPAPI.@)
|
||||
*
|
||||
* Get the UDP statistics for the local computer.
|
||||
*
|
||||
* PARAMS
|
||||
* stats [Out] buffer for UDP statistics
|
||||
*
|
||||
* RETURNS
|
||||
* Success: NO_ERROR
|
||||
* Failure: error code from winerror.h
|
||||
*/
|
||||
DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
|
||||
{
|
||||
return GetUdpStatisticsEx(stats, WS_AF_INET);
|
||||
}
|
|
@ -966,7 +966,6 @@ static void test_udp_stats( int family )
|
|||
table.dwInErrors, dyn.in_errs, dyn2.in_errs );
|
||||
ok( bounded( table.dwOutDatagrams, dyn.out_dgrams, dyn2.out_dgrams ), "%d vs [%I64d %I64d]\n",
|
||||
table.dwOutDatagrams, dyn.out_dgrams, dyn2.out_dgrams );
|
||||
todo_wine_if(!unstable(0) && table.dwNumAddrs != dyn.num_addrs)
|
||||
ok( unstable( table.dwNumAddrs == dyn.num_addrs ), "%d %d\n", table.dwNumAddrs, dyn.num_addrs );
|
||||
|
||||
winetest_pop_context();
|
||||
|
|
Loading…
Reference in New Issue