Commit d6278ea0 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

nsiproxy: Implement UDP stats get_all_parameters.

parent ec0cf434
......@@ -938,6 +938,40 @@ static void test_tcp_tables( int family, int table_type )
winetest_pop_context();
}
static void test_udp_stats( int family )
{
DWORD err;
USHORT key = family;
struct nsi_udp_stats_dynamic dyn, dyn2;
MIB_UDPSTATS table;
winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" );
err = NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_STATS_TABLE, &key, sizeof(key), NULL, 0,
&dyn, sizeof(dyn), NULL, 0 );
ok( !err, "got %x\n", err );
err = GetUdpStatisticsEx( &table, family );
ok( !err, "got %d\n", err );
err = NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_STATS_TABLE, &key, sizeof(key), NULL, 0,
&dyn2, sizeof(dyn2), NULL, 0 );
ok( !err, "got %x\n", err );
ok( bounded( table.dwInDatagrams, dyn.in_dgrams, dyn2.in_dgrams ), "%d vs [%I64d %I64d]\n",
table.dwInDatagrams, dyn.in_dgrams, dyn2.in_dgrams );
ok( bounded( table.dwNoPorts, dyn.no_ports, dyn2.no_ports ), "%d vs [%d %d]\n",
table.dwNoPorts, dyn.no_ports, dyn2.no_ports);
ok( bounded( table.dwInErrors, dyn.in_errs, dyn2.in_errs ), "%d vs [%d %d]\n",
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();
}
static void test_udp_tables( int family )
{
DWORD i, err, count, size;
......@@ -1030,6 +1064,8 @@ START_TEST( nsi )
test_tcp_tables( AF_INET6, TCP_TABLE_OWNER_MODULE_CONNECTIONS );
test_tcp_tables( AF_INET6, TCP_TABLE_OWNER_MODULE_LISTENER );
test_udp_stats( AF_INET );
test_udp_stats( AF_INET6 );
test_udp_tables( AF_INET );
test_udp_tables( AF_INET6 );
}
......@@ -73,6 +73,125 @@
WINE_DEFAULT_DEBUG_CHANNEL(nsi);
static DWORD udp_num_addrs( USHORT family )
{
DWORD endpoint_count = 0;
nsi_enumerate_all( 1, 0, &NPI_MS_UDP_MODULEID, NSI_UDP_ENDPOINT_TABLE,
NULL, 0, NULL, 0, NULL, 0, NULL, 0, &endpoint_count );
/* FIXME: actually retrieve the keys and only count endpoints which match family */
return endpoint_count;
}
static NTSTATUS udp_stats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
{
struct nsi_udp_stats_dynamic dyn;
const USHORT *family = key;
TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
static_data, static_size );
if (*family != WS_AF_INET && *family != WS_AF_INET6) return STATUS_NOT_SUPPORTED;
memset( &dyn, 0, sizeof(dyn) );
dyn.num_addrs = udp_num_addrs( *family );
#ifdef __linux__
if (*family == WS_AF_INET)
{
NTSTATUS status = STATUS_NOT_SUPPORTED;
static const char hdr[] = "Udp:";
char buf[512], *ptr;
FILE *fp;
if (!(fp = fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED;
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))
{
unsigned int in_dgrams, out_dgrams;
ptr += sizeof(hdr);
sscanf( ptr, "%u %u %u %u %u",
&in_dgrams, &dyn.no_ports, &dyn.in_errs, &out_dgrams, &dyn.num_addrs );
dyn.in_dgrams = in_dgrams;
dyn.out_dgrams = out_dgrams;
if (dynamic_data) *(struct nsi_udp_stats_dynamic *)dynamic_data = dyn;
status = STATUS_SUCCESS;
break;
}
}
fclose( fp );
return status;
}
else
{
unsigned int in_dgrams = 0, out_dgrams = 0;
struct
{
const char *name;
DWORD *elem;
} udp_stat_list[] =
{
{ "Udp6InDatagrams", &in_dgrams },
{ "Udp6NoPorts", &dyn.no_ports },
{ "Udp6InErrors", &dyn.in_errs },
{ "Udp6OutDatagrams", &out_dgrams },
};
char buf[512], *ptr, *value;
DWORD res, i;
FILE *fp;
if (!(fp = fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED;
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(udp_stat_list); i++)
if (!_strnicmp( buf, udp_stat_list[i].name, -1 ) && sscanf( value, "%d", &res ))
*udp_stat_list[i].elem = res;
}
dyn.in_dgrams = in_dgrams;
dyn.out_dgrams = out_dgrams;
if (dynamic_data) *(struct nsi_udp_stats_dynamic *)dynamic_data = dyn;
fclose( fp );
return STATUS_SUCCESS;
}
#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;
size_t needed = sizeof(udp_stat);
if (sysctl( mib, ARRAY_SIZE(mib), &udp_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
dyn.in_dgrams = udp_stat.udps_ipackets;
dyn.out_dgrams = udp_stat.udps_opackets;
dyn.no_ports = udp_stat.udps_noport;
dyn.in_errs = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
if (dynamic_data) *(struct nsi_udp_stats_dynamic *)dynamic_data = dyn;
return STATUS_SUCCESS;
}
#endif
FIXME( "Not implemented\n" );
return STATUS_NOT_SUPPORTED;
}
static NTSTATUS udp_endpoint_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
void *dynamic_data, DWORD dynamic_size,
void *static_data, DWORD static_size, DWORD_PTR *count )
......@@ -272,6 +391,15 @@ static NTSTATUS udp_endpoint_enumerate_all( void *key_data, DWORD key_size, void
static struct module_table udp_tables[] =
{
{
NSI_UDP_STATS_TABLE,
{
sizeof(USHORT), 0,
sizeof(struct nsi_udp_stats_dynamic), 0
},
NULL,
udp_stats_get_all_parameters,
},
{
NSI_UDP_ENDPOINT_TABLE,
{
sizeof(struct nsi_udp_endpoint_key), 0,
......
......@@ -347,8 +347,19 @@ struct nsi_tcp_conn_static
};
/* Undocumented NSI UDP tables */
#define NSI_UDP_STATS_TABLE 0
#define NSI_UDP_ENDPOINT_TABLE 1
struct nsi_udp_stats_dynamic
{
ULONGLONG in_dgrams;
DWORD no_ports;
DWORD in_errs;
ULONGLONG out_dgrams;
DWORD num_addrs;
DWORD unk[5];
};
struct nsi_udp_endpoint_key
{
SOCKADDR_INET local;
......
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