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();
|
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 )
|
static void test_udp_tables( int family )
|
||||||
{
|
{
|
||||||
DWORD i, err, count, size;
|
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_CONNECTIONS );
|
||||||
test_tcp_tables( AF_INET6, TCP_TABLE_OWNER_MODULE_LISTENER );
|
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_INET );
|
||||||
test_udp_tables( AF_INET6 );
|
test_udp_tables( AF_INET6 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,125 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(nsi);
|
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,
|
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 *dynamic_data, DWORD dynamic_size,
|
||||||
void *static_data, DWORD static_size, DWORD_PTR *count )
|
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[] =
|
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,
|
NSI_UDP_ENDPOINT_TABLE,
|
||||||
{
|
{
|
||||||
|
|
|
@ -347,8 +347,19 @@ struct nsi_tcp_conn_static
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Undocumented NSI UDP tables */
|
/* Undocumented NSI UDP tables */
|
||||||
|
#define NSI_UDP_STATS_TABLE 0
|
||||||
#define NSI_UDP_ENDPOINT_TABLE 1
|
#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
|
struct nsi_udp_endpoint_key
|
||||||
{
|
{
|
||||||
SOCKADDR_INET local;
|
SOCKADDR_INET local;
|
||||||
|
|
Loading…
Reference in New Issue