[PATCH 3/3] iphlpapi: Implement GetTcpStatisticsEx() on top of nsi.

Huw Davies huw at codeweavers.com
Fri Aug 13 02:35:50 CDT 2021


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/iphlpapi/iphlpapi_main.c  |  62 +++++++++++++
 dlls/iphlpapi/ipstats.c        | 161 ---------------------------------
 dlls/iphlpapi/tests/iphlpapi.c |   4 +-
 dlls/nsi/tests/nsi.c           |   3 -
 4 files changed, 64 insertions(+), 166 deletions(-)

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();
 }
 
-- 
2.23.0




More information about the wine-devel mailing list