iphlpapi: Simplify parsing of TCP stats. Only try to open /proc on Linux.

This commit is contained in:
Alexandre Julliard 2009-03-05 14:24:29 +01:00
parent 988f6b50c7
commit 3a60d69b47
1 changed files with 76 additions and 127 deletions

View File

@ -508,144 +508,93 @@ DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
*/
DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
{
#if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
DWORD ret = ERROR_NOT_SUPPORTED;
if (!stats) return ERROR_INVALID_PARAMETER;
memset( stats, 0, sizeof(*stats) );
#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 (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
/* last line was a header, get another */
if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
if (!strncasecmp(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->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_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
{
#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};
int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
#define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
#define hz 1000
struct tcpstat tcp_stat;
size_t needed;
struct tcpstat tcp_stat;
size_t needed = sizeof(tcp_stat);
if (!stats)
return ERROR_INVALID_PARAMETER;
needed = sizeof(tcp_stat);
if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
{
ERR ("failed to get tcpstat\n");
return ERROR_NOT_SUPPORTED;
}
stats->dwRtoAlgorithm = 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;
return NO_ERROR;
#else
FILE *fp;
MIB_TCPTABLE *tcp_table;
if (!stats)
return ERROR_INVALID_PARAMETER;
memset(stats, 0, sizeof(MIB_TCPSTATS));
/* get from /proc/net/snmp, no error if can't */
fp = fopen("/proc/net/snmp", "r");
if (fp) {
static const char hdr[] = "Tcp:";
char buf[512] = { 0 }, *ptr;
do {
ptr = fgets(buf, sizeof(buf), fp);
} while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
if (ptr) {
/* last line was a header, get another */
ptr = fgets(buf, sizeof(buf), fp);
if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
char *endPtr;
ptr += sizeof(hdr);
if (ptr && *ptr) {
stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwInSegs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwInErrs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
{
stats->dwNumConns = tcp_table->dwNumEntries;
HeapFree( GetProcessHeap(), 0, tcp_table );
stats->dwRtoAlgorithm = 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");
}
fclose(fp);
}
else
{
ERR ("unimplemented!\n");
return ERROR_NOT_SUPPORTED;
}
return NO_ERROR;
#else
FIXME( "unimplemented\n" );
#endif
return ret;
}