Commit 91494ae6 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

iphlpapi: Implement GetIpStatisticsEx() on top of nsi.

parent a7849502
......@@ -2436,6 +2436,88 @@ err:
return err;
}
/******************************************************************
* GetIpStatistics (IPHLPAPI.@)
*
* Get the IP statistics for the local computer.
*
* PARAMS
* stats [Out] buffer for IP statistics
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI GetIpStatistics( MIB_IPSTATS *stats )
{
return GetIpStatisticsEx( stats, WS_AF_INET );
}
/******************************************************************
* GetIpStatisticsEx (IPHLPAPI.@)
*
* Get the IPv4 and IPv6 statistics for the local computer.
*
* PARAMS
* stats [Out] buffer for IP statistics
* family [In] specifies whether IPv4 or IPv6 statistics are returned
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI GetIpStatisticsEx( MIB_IPSTATS *stats, DWORD family )
{
struct nsi_ip_ipstats_dynamic dyn;
struct nsi_ip_ipstats_static stat;
struct nsi_ip_cmpt_rw cmpt_rw;
struct nsi_ip_cmpt_dynamic cmpt_dyn;
const NPI_MODULEID *mod;
DWORD err, cmpt = 1;
TRACE( "%p %d\n", stats, family );
if (!stats) return ERROR_INVALID_PARAMETER;
mod = ip_module_id( family );
if (!mod) return ERROR_INVALID_PARAMETER;
memset( stats, 0, sizeof(*stats) );
err = NsiGetAllParameters( 1, mod, NSI_IP_IPSTATS_TABLE, NULL, 0, NULL, 0,
&dyn, sizeof(dyn), &stat, sizeof(stat) );
if (err) return err;
err = NsiGetAllParameters( 1, mod, NSI_IP_COMPARTMENT_TABLE, &cmpt, sizeof(cmpt), &cmpt_rw, sizeof(cmpt_rw),
&cmpt_dyn, sizeof(cmpt_dyn), NULL, 0 );
if (err) return err;
stats->u.Forwarding = cmpt_rw.not_forwarding + 1;
stats->dwDefaultTTL = cmpt_rw.default_ttl;
stats->dwInReceives = dyn.in_recv;
stats->dwInHdrErrors = dyn.in_hdr_errs;
stats->dwInAddrErrors = dyn.in_addr_errs;
stats->dwForwDatagrams = dyn.fwd_dgrams;
stats->dwInUnknownProtos = dyn.in_unk_protos;
stats->dwInDiscards = dyn.in_discards;
stats->dwInDelivers = dyn.in_delivers;
stats->dwOutRequests = dyn.out_reqs;
stats->dwRoutingDiscards = dyn.routing_discards;
stats->dwOutDiscards = dyn.out_discards;
stats->dwOutNoRoutes = dyn.out_no_routes;
stats->dwReasmTimeout = stat.reasm_timeout;
stats->dwReasmReqds = dyn.reasm_reqds;
stats->dwReasmOks = dyn.reasm_oks;
stats->dwReasmFails = dyn.reasm_fails;
stats->dwFragOks = dyn.frag_oks;
stats->dwFragFails = dyn.frag_fails;
stats->dwFragCreates = dyn.frag_creates;
stats->dwNumIf = cmpt_dyn.num_ifs;
stats->dwNumAddr = cmpt_dyn.num_addrs;
stats->dwNumRoutes = cmpt_dyn.num_routes;
return err;
}
/* Gets the DNS server list into the list beginning at list. Assumes that
* a single server address may be placed at list if *len is at least
* sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
......
......@@ -618,258 +618,6 @@ DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX stats, DWORD family)
}
/******************************************************************
* GetIpStatisticsEx (IPHLPAPI.@)
*
* Get the IPv4 and IPv6 statistics for the local computer.
*
* PARAMS
* stats [Out] buffer for IP statistics
* family [In] specifies whether IPv4 or IPv6 statistics are returned
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS stats, DWORD family)
{
DWORD ret = ERROR_NOT_SUPPORTED;
MIB_IPFORWARDTABLE *fwd_table;
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->dwNumIf = stats->dwNumAddr = get_interface_indices( FALSE, NULL );
if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
{
stats->dwNumRoutes = fwd_table->dwNumEntries;
HeapFree( GetProcessHeap(), 0, fwd_table );
}
if (family == WS_AF_INET6)
{
#ifdef __linux__
{
FILE *fp;
if ((fp = fopen("/proc/net/snmp6", "r")))
{
struct {
const char *name;
DWORD *elem;
} ipstatlist[] = {
{ "Ip6InReceives", &stats->dwInReceives },
{ "Ip6InHdrErrors", &stats->dwInHdrErrors },
{ "Ip6InAddrErrors", &stats->dwInAddrErrors },
{ "Ip6OutForwDatagrams", &stats->dwForwDatagrams },
{ "Ip6InUnknownProtos", &stats->dwInUnknownProtos },
{ "Ip6InDiscards", &stats->dwInDiscards },
{ "Ip6InDelivers", &stats->dwInDelivers },
{ "Ip6OutRequests", &stats->dwOutRequests },
{ "Ip6OutDiscards", &stats->dwOutDiscards },
{ "Ip6OutNoRoutes", &stats->dwOutNoRoutes },
{ "Ip6ReasmTimeout", &stats->dwReasmTimeout },
{ "Ip6ReasmReqds", &stats->dwReasmReqds },
{ "Ip6ReasmOKs", &stats->dwReasmOks },
{ "Ip6ReasmFails", &stats->dwReasmFails },
{ "Ip6FragOKs", &stats->dwFragOks },
{ "Ip6FragFails", &stats->dwFragFails },
{ "Ip6FragCreates", &stats->dwFragCreates },
/* hmm, no routingDiscards, defaultTTL and forwarding? */
};
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(ipstatlist); i++)
if (!_strnicmp(buf, ipstatlist[i].name, -1) && sscanf(value, "%d", &res))
*ipstatlist[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[] = "Ip:";
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 %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
&stats->u.dwForwarding,
&stats->dwDefaultTTL,
&stats->dwInReceives,
&stats->dwInHdrErrors,
&stats->dwInAddrErrors,
&stats->dwForwDatagrams,
&stats->dwInUnknownProtos,
&stats->dwInDiscards,
&stats->dwInDelivers,
&stats->dwOutRequests,
&stats->dwOutDiscards,
&stats->dwOutNoRoutes,
&stats->dwReasmTimeout,
&stats->dwReasmReqds,
&stats->dwReasmOks,
&stats->dwReasmFails,
&stats->dwFragOks,
&stats->dwFragFails,
&stats->dwFragCreates );
/* hmm, no routingDiscards */
break;
}
}
fclose(fp);
ret = NO_ERROR;
}
}
#elif defined(HAVE_LIBKSTAT)
{
static char ip[] = "ip";
kstat_ctl_t *kc;
kstat_t *ksp;
if ((kc = kstat_open()) &&
(ksp = kstat_lookup( kc, ip, 0, ip )) &&
kstat_read( kc, ksp, NULL ) != -1 &&
ksp->ks_type == KSTAT_TYPE_NAMED)
{
stats->u.dwForwarding = kstat_get_ui32( ksp, "forwarding" );
stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
ret = NO_ERROR;
}
if (kc) kstat_close( kc );
}
#elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
{
int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
int ip_ttl, ip_forwarding;
#if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
struct ipstat ip_stat;
#elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
struct ip_stats ip_stat;
#endif
size_t needed;
needed = sizeof(ip_stat);
if(sysctl(mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0) == -1)
{
ERR ("failed to get ipstat\n");
return ERROR_NOT_SUPPORTED;
}
needed = sizeof(ip_ttl);
if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
{
ERR ("failed to get ip Default TTL\n");
return ERROR_NOT_SUPPORTED;
}
needed = sizeof(ip_forwarding);
if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
{
ERR ("failed to get ip forwarding\n");
return ERROR_NOT_SUPPORTED;
}
/* ip.forwarding is 0 or 1 on BSD */
stats->u.dwForwarding = ip_forwarding+1;
stats->dwDefaultTTL = ip_ttl;
stats->dwInReceives = ip_stat.ips_total;
stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen +
ip_stat.ips_badvers + ip_stat.ips_badoptions;
/* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
stats->dwInAddrErrors = ip_stat.ips_cantforward + ip_stat.ips_badaddr + ip_stat.ips_notmember;
stats->dwForwDatagrams = ip_stat.ips_forward;
stats->dwInUnknownProtos = ip_stat.ips_noproto;
stats->dwInDiscards = ip_stat.ips_fragdropped;
stats->dwInDelivers = ip_stat.ips_delivered;
stats->dwOutRequests = ip_stat.ips_localout;
/*stats->dwRoutingDiscards = 0;*/ /* FIXME */
stats->dwOutDiscards = ip_stat.ips_odropped;
stats->dwOutNoRoutes = ip_stat.ips_noroute;
stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
stats->dwReasmReqds = ip_stat.ips_fragments;
stats->dwReasmOks = ip_stat.ips_reassembled;
stats->dwReasmFails = ip_stat.ips_fragments - ip_stat.ips_reassembled;
stats->dwFragOks = ip_stat.ips_fragmented;
stats->dwFragFails = ip_stat.ips_cantfrag;
stats->dwFragCreates = ip_stat.ips_ofragments;
ret = NO_ERROR;
}
#else
FIXME( "unimplemented for IPv4\n" );
#endif
return ret;
}
/******************************************************************
* GetIpStatistics (IPHLPAPI.@)
*
* Get the IP statistics for the local computer.
*
* PARAMS
* stats [Out] buffer for IP statistics
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
{
return GetIpStatisticsEx(stats, WS_AF_INET);
}
/******************************************************************
* GetTcpStatisticsEx (IPHLPAPI.@)
*
* Get the IPv4 and IPv6 TCP statistics for the local computer.
......
......@@ -436,14 +436,10 @@ static void test_ip_cmpt( int family )
ok( !err, "got %d\n", err );
if (err) goto err;
todo_wine_if(family == AF_INET6 && table.dwForwarding - 1 != rw.not_forwarding)
ok( table.dwForwarding - 1 == rw.not_forwarding, "%x vs %x\n", table.dwForwarding, rw.not_forwarding );
todo_wine_if(family == AF_INET6 && table.dwDefaultTTL != rw.default_ttl)
ok( table.dwDefaultTTL == rw.default_ttl, "%x vs %x\n", table.dwDefaultTTL, rw.default_ttl );
ok( table.dwNumIf == dyn.num_ifs, "%x vs %x\n", table.dwNumIf, dyn.num_ifs );
todo_wine_if(table.dwNumAddr != dyn.num_addrs)
ok( table.dwNumAddr == dyn.num_addrs, "%x vs %x\n", table.dwNumAddr, dyn.num_addrs );
todo_wine_if(family == AF_INET6 && table.dwNumRoutes != dyn.num_routes)
ok( table.dwNumRoutes == dyn.num_routes, "%x vs %x\n", table.dwNumRoutes, dyn.num_routes );
err:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment