diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 14a2c719b95..b45bcc41724 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -2807,6 +2807,68 @@ BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHo 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.@) diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c index c5621b52dd7..ececfcdcecd 100644 --- a/dlls/iphlpapi/ipstats.c +++ b/dlls/iphlpapi/ipstats.c @@ -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 */ -/****************************************************************** - * 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.@) * diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index d439f71069b..5ec2f2eaba2 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -715,8 +715,8 @@ static void testGetTcpStatisticsEx(void) } apiReturn = GetTcpStatisticsEx(&stats, AF_INET6); - todo_wine ok(apiReturn == NO_ERROR || broken(apiReturn == ERROR_NOT_SUPPORTED), - "GetTcpStatisticsEx returned %d, expected NO_ERROR\n", apiReturn); + ok(apiReturn == NO_ERROR || broken(apiReturn == ERROR_NOT_SUPPORTED), + "GetTcpStatisticsEx returned %d, expected NO_ERROR\n", apiReturn); if (apiReturn == NO_ERROR && winetest_debug > 1) { trace( "TCP IPv6 Ex stats:\n" ); diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c index fb95ab67d3b..33b4e9e6d97 100644 --- a/dlls/nsi/tests/nsi.c +++ b/dlls/nsi/tests/nsi.c @@ -815,9 +815,7 @@ static void test_tcp_stats( int family ) ok( !err, "got %x\n", err ); err = GetTcpStatisticsEx( &table, family ); -todo_wine_if(family == AF_INET6) 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, &dyn2, sizeof(dyn), NULL, 0 ); @@ -847,7 +845,6 @@ todo_wine_if(family == AF_INET6) table.dwOutRsts, dyn.out_rsts, dyn2.out_rsts ); ok( unstable( table.dwNumConns == dyn.num_conns ), "%d vs %d\n", table.dwNumConns, dyn.num_conns ); -err: winetest_pop_context(); }