nsiproxy: Implement UDP stats get_all_parameters.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ec0cf43497
commit
d6278ea021
|
@ -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 )
|
||||
|
@ -271,6 +390,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,
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue