iphlpapi: Implement GetTcpStatisticsEx() 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
c9680e8991
commit
4716138d07
|
@ -2807,6 +2807,68 @@ BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHo
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* GetTcpStatistics (IPHLPAPI.@)
|
||||||
|
*
|
||||||
|
* Get the TCP statistics for the local computer.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* stats [Out] buffer for TCP statistics
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* Success: NO_ERROR
|
||||||
|
* Failure: error code from winerror.h
|
||||||
|
*/
|
||||||
|
DWORD WINAPI GetTcpStatistics( MIB_TCPSTATS *stats )
|
||||||
|
{
|
||||||
|
return GetTcpStatisticsEx( stats, WS_AF_INET );
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* GetTcpStatisticsEx (IPHLPAPI.@)
|
||||||
|
*
|
||||||
|
* Get the IPv4 and IPv6 TCP statistics for the local computer.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* stats [Out] buffer for TCP statistics
|
||||||
|
* family [In] specifies whether IPv4 or IPv6 statistics are returned
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* Success: NO_ERROR
|
||||||
|
* Failure: error code from winerror.h
|
||||||
|
*/
|
||||||
|
DWORD WINAPI GetTcpStatisticsEx( MIB_TCPSTATS *stats, DWORD family )
|
||||||
|
{
|
||||||
|
struct nsi_tcp_stats_dynamic dyn;
|
||||||
|
struct nsi_tcp_stats_static stat;
|
||||||
|
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_TCP_MODULEID, NSI_TCP_STATS_TABLE, &key, sizeof(key), NULL, 0,
|
||||||
|
&dyn, sizeof(dyn), &stat, sizeof(stat) );
|
||||||
|
if (err) return err;
|
||||||
|
|
||||||
|
stats->u.RtoAlgorithm = stat.rto_algo;
|
||||||
|
stats->dwRtoMin = stat.rto_min;
|
||||||
|
stats->dwRtoMax = stat.rto_max;
|
||||||
|
stats->dwMaxConn = stat.max_conns;
|
||||||
|
stats->dwActiveOpens = dyn.active_opens;
|
||||||
|
stats->dwPassiveOpens = dyn.passive_opens;
|
||||||
|
stats->dwAttemptFails = dyn.attempt_fails;
|
||||||
|
stats->dwEstabResets = dyn.est_rsts;
|
||||||
|
stats->dwCurrEstab = dyn.cur_est;
|
||||||
|
stats->dwInSegs = (DWORD)dyn.in_segs;
|
||||||
|
stats->dwOutSegs = (DWORD)dyn.out_segs;
|
||||||
|
stats->dwRetransSegs = dyn.retrans_segs;
|
||||||
|
stats->dwInErrs = dyn.in_errs;
|
||||||
|
stats->dwOutRsts = dyn.out_rsts;
|
||||||
|
stats->dwNumConns = dyn.num_conns;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* GetTcpTable (IPHLPAPI.@)
|
* GetTcpTable (IPHLPAPI.@)
|
||||||
|
|
|
@ -276,167 +276,6 @@ static void *read_mib_entry( int fd, int level, int name, int *len )
|
||||||
}
|
}
|
||||||
#endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
|
#endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
|
||||||
|
|
||||||
/******************************************************************
|
|
||||||
* GetTcpStatisticsEx (IPHLPAPI.@)
|
|
||||||
*
|
|
||||||
* Get the IPv4 and IPv6 TCP statistics for the local computer.
|
|
||||||
*
|
|
||||||
* PARAMS
|
|
||||||
* stats [Out] buffer for TCP statistics
|
|
||||||
* family [In] specifies whether IPv4 or IPv6 statistics are returned
|
|
||||||
*
|
|
||||||
* RETURNS
|
|
||||||
* Success: NO_ERROR
|
|
||||||
* Failure: error code from winerror.h
|
|
||||||
*/
|
|
||||||
DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS 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) );
|
|
||||||
|
|
||||||
if (family == WS_AF_INET6)
|
|
||||||
{
|
|
||||||
FIXME( "unimplemented for IPv6\n" );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if ((fp = fopen("/proc/net/snmp", "r")))
|
|
||||||
{
|
|
||||||
static const char hdr[] = "Tcp:";
|
|
||||||
MIB_TCPTABLE *tcp_table;
|
|
||||||
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",
|
|
||||||
&stats->u.dwRtoAlgorithm,
|
|
||||||
&stats->dwRtoMin,
|
|
||||||
&stats->dwRtoMax,
|
|
||||||
&stats->dwMaxConn,
|
|
||||||
&stats->dwActiveOpens,
|
|
||||||
&stats->dwPassiveOpens,
|
|
||||||
&stats->dwAttemptFails,
|
|
||||||
&stats->dwEstabResets,
|
|
||||||
&stats->dwCurrEstab,
|
|
||||||
&stats->dwInSegs,
|
|
||||||
&stats->dwOutSegs,
|
|
||||||
&stats->dwRetransSegs,
|
|
||||||
&stats->dwInErrs,
|
|
||||||
&stats->dwOutRsts );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
|
|
||||||
{
|
|
||||||
stats->dwNumConns = tcp_table->dwNumEntries;
|
|
||||||
HeapFree( GetProcessHeap(), 0, tcp_table );
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
ret = NO_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_LIBKSTAT)
|
|
||||||
{
|
|
||||||
static char tcp[] = "tcp";
|
|
||||||
kstat_ctl_t *kc;
|
|
||||||
kstat_t *ksp;
|
|
||||||
|
|
||||||
if ((kc = kstat_open()) &&
|
|
||||||
(ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
|
|
||||||
kstat_read( kc, ksp, NULL ) != -1 &&
|
|
||||||
ksp->ks_type == KSTAT_TYPE_NAMED)
|
|
||||||
{
|
|
||||||
stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
|
|
||||||
stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
|
|
||||||
stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
|
|
||||||
stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
|
|
||||||
stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
|
|
||||||
stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
|
|
||||||
stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
|
|
||||||
stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
|
|
||||||
stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
|
|
||||||
stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
|
|
||||||
stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
|
|
||||||
stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
|
|
||||||
stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
|
|
||||||
stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
|
|
||||||
stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
|
|
||||||
ret = NO_ERROR;
|
|
||||||
}
|
|
||||||
if (kc) kstat_close( kc );
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
|
|
||||||
{
|
|
||||||
#ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
|
|
||||||
#define TCPTV_MIN 2
|
|
||||||
#define TCPTV_REXMTMAX 128
|
|
||||||
#endif
|
|
||||||
int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
|
|
||||||
#define hz 1000
|
|
||||||
#if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
|
|
||||||
struct tcpstat tcp_stat;
|
|
||||||
#elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
|
|
||||||
struct tcp_stats tcp_stat;
|
|
||||||
#endif
|
|
||||||
size_t needed = sizeof(tcp_stat);
|
|
||||||
|
|
||||||
if(sysctl(mib, ARRAY_SIZE(mib), &tcp_stat, &needed, NULL, 0) != -1)
|
|
||||||
{
|
|
||||||
stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
|
|
||||||
stats->dwRtoMin = TCPTV_MIN;
|
|
||||||
stats->dwRtoMax = TCPTV_REXMTMAX;
|
|
||||||
stats->dwMaxConn = -1;
|
|
||||||
stats->dwActiveOpens = tcp_stat.tcps_connattempt;
|
|
||||||
stats->dwPassiveOpens = tcp_stat.tcps_accepts;
|
|
||||||
stats->dwAttemptFails = tcp_stat.tcps_conndrops;
|
|
||||||
stats->dwEstabResets = tcp_stat.tcps_drops;
|
|
||||||
stats->dwCurrEstab = 0;
|
|
||||||
stats->dwInSegs = tcp_stat.tcps_rcvtotal;
|
|
||||||
stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
|
|
||||||
stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
|
|
||||||
stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
|
|
||||||
stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
|
|
||||||
stats->dwNumConns = tcp_stat.tcps_connects;
|
|
||||||
ret = NO_ERROR;
|
|
||||||
}
|
|
||||||
else ERR ("failed to get tcpstat\n");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
FIXME( "unimplemented\n" );
|
|
||||||
#endif
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************
|
|
||||||
* GetTcpStatistics (IPHLPAPI.@)
|
|
||||||
*
|
|
||||||
* Get the TCP statistics for the local computer.
|
|
||||||
*
|
|
||||||
* PARAMS
|
|
||||||
* stats [Out] buffer for TCP statistics
|
|
||||||
*
|
|
||||||
* RETURNS
|
|
||||||
* Success: NO_ERROR
|
|
||||||
* Failure: error code from winerror.h
|
|
||||||
*/
|
|
||||||
DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
|
|
||||||
{
|
|
||||||
return GetTcpStatisticsEx(stats, WS_AF_INET);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* GetUdpStatistics (IPHLPAPI.@)
|
* GetUdpStatistics (IPHLPAPI.@)
|
||||||
*
|
*
|
||||||
|
|
|
@ -715,8 +715,8 @@ static void testGetTcpStatisticsEx(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiReturn = GetTcpStatisticsEx(&stats, AF_INET6);
|
apiReturn = GetTcpStatisticsEx(&stats, AF_INET6);
|
||||||
todo_wine ok(apiReturn == NO_ERROR || broken(apiReturn == ERROR_NOT_SUPPORTED),
|
ok(apiReturn == NO_ERROR || broken(apiReturn == ERROR_NOT_SUPPORTED),
|
||||||
"GetTcpStatisticsEx returned %d, expected NO_ERROR\n", apiReturn);
|
"GetTcpStatisticsEx returned %d, expected NO_ERROR\n", apiReturn);
|
||||||
if (apiReturn == NO_ERROR && winetest_debug > 1)
|
if (apiReturn == NO_ERROR && winetest_debug > 1)
|
||||||
{
|
{
|
||||||
trace( "TCP IPv6 Ex stats:\n" );
|
trace( "TCP IPv6 Ex stats:\n" );
|
||||||
|
|
|
@ -815,9 +815,7 @@ static void test_tcp_stats( int family )
|
||||||
ok( !err, "got %x\n", err );
|
ok( !err, "got %x\n", err );
|
||||||
|
|
||||||
err = GetTcpStatisticsEx( &table, family );
|
err = GetTcpStatisticsEx( &table, family );
|
||||||
todo_wine_if(family == AF_INET6)
|
|
||||||
ok( !err, "got %d\n", err );
|
ok( !err, "got %d\n", err );
|
||||||
if (err) goto err;
|
|
||||||
|
|
||||||
err = NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID, NSI_TCP_STATS_TABLE, &key, sizeof(key), NULL, 0,
|
err = NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID, NSI_TCP_STATS_TABLE, &key, sizeof(key), NULL, 0,
|
||||||
&dyn2, sizeof(dyn), NULL, 0 );
|
&dyn2, sizeof(dyn), NULL, 0 );
|
||||||
|
@ -847,7 +845,6 @@ todo_wine_if(family == AF_INET6)
|
||||||
table.dwOutRsts, dyn.out_rsts, dyn2.out_rsts );
|
table.dwOutRsts, dyn.out_rsts, dyn2.out_rsts );
|
||||||
ok( unstable( table.dwNumConns == dyn.num_conns ), "%d vs %d\n", table.dwNumConns, dyn.num_conns );
|
ok( unstable( table.dwNumConns == dyn.num_conns ), "%d vs %d\n", table.dwNumConns, dyn.num_conns );
|
||||||
|
|
||||||
err:
|
|
||||||
winetest_pop_context();
|
winetest_pop_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue