| /* Copyright (C) 2003 Juan Lang | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
 |  * | 
 |  * This file implements statistics getting using the /proc filesystem exported | 
 |  * by Linux, and maybe other OSes. | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 |  | 
 | #include <stdarg.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <sys/types.h> | 
 | #ifdef HAVE_SYS_SOCKET_H | 
 | #include <sys/socket.h> | 
 | #endif | 
 | #ifdef HAVE_NETINET_IN_H | 
 | #include <netinet/in.h> | 
 | #endif | 
 | #ifdef HAVE_ARPA_INET_H | 
 | #include <arpa/inet.h> | 
 | #endif | 
 | #if HAVE_NET_IF_H | 
 | #include <net/if.h> | 
 | #endif | 
 | #if HAVE_NET_IF_ARP_H | 
 | #include <net/if_arp.h> | 
 | #endif | 
 | #if HAVE_NETINET_TCP_H | 
 | #include <netinet/tcp.h> | 
 | #endif | 
 | #if HAVE_NETINET_TCP_FSM_H | 
 | #include <netinet/tcp_fsm.h> | 
 | #endif | 
 |  | 
 | #include "windef.h" | 
 | #include "winbase.h" | 
 | #include "iprtrmib.h" | 
 | #include "ifenum.h" | 
 | #include "ipstats.h" | 
 |  | 
 | #ifndef TCPS_ESTABLISHED | 
 | # define TCPS_ESTABLISHED TCP_ESTABLISHED | 
 | #endif | 
 | #ifndef TCPS_SYN_SENT | 
 | # define TCPS_SYN_SENT TCP_SYN_SENT | 
 | #endif | 
 | #ifndef TCPS_SYN_RECEIVED | 
 | # define TCPS_SYN_RECEIVED TCP_SYN_RECV | 
 | #endif | 
 | #ifndef TCPS_FIN_WAIT_1 | 
 | # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1 | 
 | #endif | 
 | #ifndef TCPS_FIN_WAIT_2 | 
 | # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2 | 
 | #endif | 
 | #ifndef TCPS_TIME_WAIT | 
 | # define TCPS_TIME_WAIT TCP_TIME_WAIT | 
 | #endif | 
 | #ifndef TCPS_CLOSED | 
 | # define TCPS_CLOSED TCP_CLOSE | 
 | #endif | 
 | #ifndef TCPS_CLOSE_WAIT | 
 | # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT | 
 | #endif | 
 | #ifndef TCPS_LAST_ACK | 
 | # define TCPS_LAST_ACK TCP_LAST_ACK | 
 | #endif | 
 | #ifndef TCPS_LISTEN | 
 | # define TCPS_LISTEN TCP_LISTEN | 
 | #endif | 
 | #ifndef TCPS_CLOSING | 
 | # define TCPS_CLOSING TCP_CLOSING | 
 | #endif | 
 |  | 
 | DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry) | 
 | { | 
 |   FILE *fp; | 
 |  | 
 |   if (!name) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |   if (!entry) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   /* get interface stats from /proc/net/dev, no error if can't | 
 |      no inUnknownProtos, outNUcastPkts, outQLen */ | 
 |   fp = fopen("/proc/net/dev", "r"); | 
 |   if (fp) { | 
 |     char buf[512] = { 0 }, *ptr; | 
 |     int nameLen = strlen(name), nameFound = 0; | 
 |  | 
 |  | 
 |     ptr = fgets(buf, sizeof(buf), fp); | 
 |     while (ptr && !nameFound) { | 
 |       while (*ptr && isspace(*ptr)) | 
 |         ptr++; | 
 |       if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':') | 
 |         nameFound = 1; | 
 |       else | 
 |         ptr = fgets(buf, sizeof(buf), fp); | 
 |     } | 
 |     if (nameFound) { | 
 |       char *endPtr; | 
 |  | 
 |       ptr += nameLen + 1; | 
 |       if (ptr && *ptr) { | 
 |         entry->dwInOctets = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwInErrors = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwInDiscards = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         strtoul(ptr, &endPtr, 10); /* skip */ | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         strtoul(ptr, &endPtr, 10); /* skip */ | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         strtoul(ptr, &endPtr, 10); /* skip */ | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwOutOctets = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwOutErrors = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |       if (ptr && *ptr) { | 
 |         entry->dwOutDiscards = strtoul(ptr, &endPtr, 10); | 
 |         ptr = endPtr; | 
 |       } | 
 |     } | 
 |     fclose(fp); | 
 |   } | 
 |   return NO_ERROR; | 
 | } | 
 |  | 
 | DWORD getICMPStats(MIB_ICMP *stats) | 
 | { | 
 |   FILE *fp; | 
 |  | 
 |   if (!stats) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   memset(stats, 0, sizeof(MIB_ICMP)); | 
 |   /* get most of these stats from /proc/net/snmp, no error if can't */ | 
 |   fp = fopen("/proc/net/snmp", "r"); | 
 |   if (fp) { | 
 |     const char hdr[] = "Icmp:"; | 
 |     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->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |       } | 
 |     } | 
 |     fclose(fp); | 
 |   } | 
 |   return NO_ERROR; | 
 | } | 
 |  | 
 | DWORD getIPStats(PMIB_IPSTATS stats) | 
 | { | 
 |   FILE *fp; | 
 |  | 
 |   if (!stats) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   memset(stats, 0, sizeof(MIB_IPSTATS)); | 
 |   stats->dwNumIf = stats->dwNumAddr = getNumInterfaces(); | 
 |   stats->dwNumRoutes = getNumRoutes(); | 
 |  | 
 |   /* get most of these stats from /proc/net/snmp, no error if can't */ | 
 |   fp = fopen("/proc/net/snmp", "r"); | 
 |   if (fp) { | 
 |     const char hdr[] = "Ip:"; | 
 |     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->dwForwarding = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInReceives = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInDiscards = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInDelivers = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwOutRequests = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwOutDiscards = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwReasmReqds = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwReasmOks = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwReasmFails = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwFragOks = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwFragFails = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwFragCreates = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         /* hmm, no routingDiscards */ | 
 |       } | 
 |     } | 
 |     fclose(fp); | 
 |   } | 
 |   return NO_ERROR; | 
 | } | 
 |  | 
 | DWORD getTCPStats(MIB_TCPSTATS *stats) | 
 | { | 
 |   FILE *fp; | 
 |  | 
 |   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) { | 
 |     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->dwRtoMin = 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; | 
 |         } | 
 |         stats->dwNumConns = getNumTcpEntries(); | 
 |       } | 
 |     } | 
 |     fclose(fp); | 
 |   } | 
 |   return NO_ERROR; | 
 | } | 
 |  | 
 | DWORD getUDPStats(MIB_UDPSTATS *stats) | 
 | { | 
 |   FILE *fp; | 
 |  | 
 |   if (!stats) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   memset(stats, 0, sizeof(MIB_UDPSTATS)); | 
 |  | 
 |   /* get from /proc/net/snmp, no error if can't */ | 
 |   fp = fopen("/proc/net/snmp", "r"); | 
 |   if (fp) { | 
 |     const char hdr[] = "Udp:"; | 
 |     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->dwInDatagrams = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwNoPorts = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwInErrors = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |         if (ptr && *ptr) { | 
 |           stats->dwNumAddrs = strtoul(ptr, &endPtr, 10); | 
 |           ptr = endPtr; | 
 |         } | 
 |       } | 
 |     } | 
 |     fclose(fp); | 
 |   } | 
 |   return NO_ERROR; | 
 | } | 
 |  | 
 | static DWORD getNumWithOneHeader(const char *filename) | 
 | { | 
 |   FILE *fp; | 
 |   int ret = 0; | 
 |  | 
 |   fp = fopen(filename, "r"); | 
 |   if (fp) { | 
 |     char buf[512] = { 0 }, *ptr; | 
 |  | 
 |  | 
 |     ptr = fgets(buf, sizeof(buf), fp); | 
 |     if (ptr) { | 
 |       do { | 
 |         ptr = fgets(buf, sizeof(buf), fp); | 
 |         if (ptr) | 
 |           ret++; | 
 |       } while (ptr); | 
 |     } | 
 |     fclose(fp); | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getNumRoutes(void) | 
 | { | 
 |   return getNumWithOneHeader("/proc/net/route"); | 
 | } | 
 |  | 
 | RouteTable *getRouteTable(void) | 
 | { | 
 |   DWORD numRoutes = getNumRoutes(); | 
 |   RouteTable *ret; | 
 |  | 
 |   ret = (RouteTable *)calloc(1, sizeof(RouteTable) + | 
 |    (numRoutes - 1) * sizeof(RouteEntry)); | 
 |   if (ret) { | 
 |     FILE *fp; | 
 |  | 
 |     /* get from /proc/net/route, no error if can't */ | 
 |     fp = fopen("/proc/net/route", "r"); | 
 |     if (fp) { | 
 |       char buf[512] = { 0 }, *ptr; | 
 |  | 
 |       /* skip header line */ | 
 |       ptr = fgets(buf, sizeof(buf), fp); | 
 |       while (ptr && ret->numRoutes < numRoutes) { | 
 |         ptr = fgets(buf, sizeof(buf), fp); | 
 |         if (ptr) { | 
 |           DWORD index; | 
 |  | 
 |           while (!isspace(*ptr)) | 
 |             ptr++; | 
 |           *ptr = '\0'; | 
 |           ptr++; | 
 |           if (getInterfaceIndexByName(buf, &index) == NO_ERROR) { | 
 |             char *endPtr; | 
 |  | 
 |             ret->routes[ret->numRoutes].ifIndex = index; | 
 |             if (*ptr) { | 
 |               ret->routes[ret->numRoutes].dest = strtoul(ptr, &endPtr, 16); | 
 |               ptr = endPtr; | 
 |             } | 
 |             if (ptr && *ptr) { | 
 |               ret->routes[ret->numRoutes].gateway = strtoul(ptr, &endPtr, 16); | 
 |               ptr = endPtr; | 
 |             } | 
 |             if (ptr && *ptr) { | 
 |               strtoul(ptr, &endPtr, 16); /* flags, skip */ | 
 |               ptr = endPtr; | 
 |             } | 
 |             if (ptr && *ptr) { | 
 |               strtoul(ptr, &endPtr, 16); /* refcount, skip */ | 
 |               ptr = endPtr; | 
 |             } | 
 |             if (ptr && *ptr) { | 
 |               strtoul(ptr, &endPtr, 16); /* use, skip */ | 
 |               ptr = endPtr; | 
 |             } | 
 |             if (ptr && *ptr) { | 
 |               ret->routes[ret->numRoutes].metric = strtoul(ptr, &endPtr, 16); | 
 |               ptr = endPtr; | 
 |             } | 
 |             if (ptr && *ptr) { | 
 |               ret->routes[ret->numRoutes].mask = strtoul(ptr, &endPtr, 16); | 
 |               ptr = endPtr; | 
 |             } | 
 |             ret->numRoutes++; | 
 |           } | 
 |         } | 
 |       } | 
 |       fclose(fp); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getNumArpEntries(void) | 
 | { | 
 |   return getNumWithOneHeader("/proc/net/arp"); | 
 | } | 
 |  | 
 | PMIB_IPNETTABLE getArpTable(void) | 
 | { | 
 |   DWORD numEntries = getNumArpEntries(); | 
 |   PMIB_IPNETTABLE ret; | 
 |  | 
 |   ret = (PMIB_IPNETTABLE)calloc(1, sizeof(MIB_IPNETTABLE) + | 
 |    (numEntries - 1) * sizeof(MIB_IPNETROW)); | 
 |   if (ret) { | 
 |     FILE *fp; | 
 |  | 
 |     /* get from /proc/net/arp, no error if can't */ | 
 |     fp = fopen("/proc/net/arp", "r"); | 
 |     if (fp) { | 
 |       char buf[512] = { 0 }, *ptr; | 
 |  | 
 |       /* skip header line */ | 
 |       ptr = fgets(buf, sizeof(buf), fp); | 
 |       while (ptr && ret->dwNumEntries < numEntries) { | 
 |         ptr = fgets(buf, sizeof(buf), fp); | 
 |         if (ptr) { | 
 |           char *endPtr; | 
 |  | 
 |           ret->table[ret->dwNumEntries].dwAddr = inet_addr(ptr); | 
 |           while (ptr && *ptr && !isspace(*ptr)) | 
 |             ptr++; | 
 |  | 
 |           if (ptr && *ptr) { | 
 |             strtoul(ptr, &endPtr, 16); /* hw type (skip) */ | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             DWORD flags = strtoul(ptr, &endPtr, 16); | 
 |  | 
 |             if (flags & ATF_COM) | 
 |               ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC; | 
 |             else if (flags & ATF_PERM) | 
 |               ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC; | 
 |             else | 
 |               ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER; | 
 |  | 
 |             ptr = endPtr; | 
 |           } | 
 |           while (ptr && *ptr && isspace(*ptr)) | 
 |             ptr++; | 
 |           while (ptr && *ptr && !isspace(*ptr)) { | 
 |             DWORD byte = strtoul(ptr, &endPtr, 16); | 
 |  | 
 |             if (endPtr && *endPtr) { | 
 |               endPtr++; | 
 |               ret->table[ret->dwNumEntries].bPhysAddr[ | 
 |                ret->table[ret->dwNumEntries].dwPhysAddrLen++] = byte & 0x0ff; | 
 |             } | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             strtoul(ptr, &endPtr, 16); /* mask (skip) */ | 
 |             ptr = endPtr; | 
 |           } | 
 |           getInterfaceIndexByName(ptr, &ret->table[ret->dwNumEntries].dwIndex); | 
 |           ret->dwNumEntries++; | 
 |         } | 
 |       } | 
 |       fclose(fp); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getNumUdpEntries(void) | 
 | { | 
 |   return getNumWithOneHeader("/proc/net/udp"); | 
 | } | 
 |  | 
 | PMIB_UDPTABLE getUdpTable(void) | 
 | { | 
 |   DWORD numEntries = getNumUdpEntries(); | 
 |   PMIB_UDPTABLE ret; | 
 |  | 
 |   ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) + | 
 |    (numEntries - 1) * sizeof(MIB_UDPROW)); | 
 |   if (ret) { | 
 |     FILE *fp; | 
 |  | 
 |     /* get from /proc/net/udp, no error if can't */ | 
 |     fp = fopen("/proc/net/udp", "r"); | 
 |     if (fp) { | 
 |       char buf[512] = { 0 }, *ptr; | 
 |  | 
 |       /* skip header line */ | 
 |       ptr = fgets(buf, sizeof(buf), fp); | 
 |       while (ptr && ret->dwNumEntries < numEntries) { | 
 |         ptr = fgets(buf, sizeof(buf), fp); | 
 |         if (ptr) { | 
 |           char *endPtr; | 
 |  | 
 |           if (ptr && *ptr) { | 
 |             strtoul(ptr, &endPtr, 16); /* skip */ | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             ptr++; | 
 |             ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr, | 
 |              16); | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             ptr++; | 
 |             ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr, | 
 |              16); | 
 |             ptr = endPtr; | 
 |           } | 
 |           ret->dwNumEntries++; | 
 |         } | 
 |       } | 
 |       fclose(fp); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getNumTcpEntries(void) | 
 | { | 
 |   return getNumWithOneHeader("/proc/net/tcp"); | 
 | } | 
 |  | 
 | PMIB_TCPTABLE getTcpTable(void) | 
 | { | 
 |   DWORD numEntries = getNumTcpEntries(); | 
 |   PMIB_TCPTABLE ret; | 
 |  | 
 |   ret = (PMIB_TCPTABLE)calloc(1, sizeof(MIB_TCPTABLE) + | 
 |    (numEntries - 1) * sizeof(MIB_TCPROW)); | 
 |   if (ret) { | 
 |     FILE *fp; | 
 |  | 
 |     /* get from /proc/net/tcp, no error if can't */ | 
 |     fp = fopen("/proc/net/tcp", "r"); | 
 |     if (fp) { | 
 |       char buf[512] = { 0 }, *ptr; | 
 |  | 
 |       /* skip header line */ | 
 |       ptr = fgets(buf, sizeof(buf), fp); | 
 |       while (ptr && ret->dwNumEntries < numEntries) { | 
 |         ptr = fgets(buf, sizeof(buf), fp); | 
 |         if (ptr) { | 
 |           char *endPtr; | 
 |  | 
 |           while (ptr && *ptr && *ptr != ':') | 
 |             ptr++; | 
 |           if (ptr && *ptr) | 
 |             ptr++; | 
 |           if (ptr && *ptr) { | 
 |             ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr, | 
 |              16); | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             ptr++; | 
 |             ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr, | 
 |              16); | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             ret->table[ret->dwNumEntries].dwRemoteAddr = strtoul(ptr, &endPtr, | 
 |              16); | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             ptr++; | 
 |             ret->table[ret->dwNumEntries].dwRemotePort = strtoul(ptr, &endPtr, | 
 |              16); | 
 |             ptr = endPtr; | 
 |           } | 
 |           if (ptr && *ptr) { | 
 |             DWORD state = strtoul(ptr, &endPtr, 16); | 
 |  | 
 |             switch (state) | 
 |             { | 
 |               case TCPS_ESTABLISHED: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_ESTAB; | 
 |                 break; | 
 |               case TCPS_SYN_SENT: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_SENT; | 
 |                 break; | 
 |               case TCPS_SYN_RECEIVED: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_RCVD; | 
 |                 break; | 
 |               case TCPS_FIN_WAIT_1: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT1; | 
 |                 break; | 
 |               case TCPS_FIN_WAIT_2: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT2; | 
 |                 break; | 
 |               case TCPS_TIME_WAIT: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_TIME_WAIT; | 
 |                 break; | 
 |               case TCPS_CLOSED: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSED; | 
 |                 break; | 
 |               case TCPS_CLOSE_WAIT: | 
 |                 ret->table[ret->dwNumEntries].dwState = | 
 |                  MIB_TCP_STATE_CLOSE_WAIT; | 
 |                 break; | 
 |               case TCPS_LAST_ACK: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LAST_ACK; | 
 |                 break; | 
 |               case TCPS_LISTEN: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LISTEN; | 
 |                 break; | 
 |               case TCPS_CLOSING: | 
 |                 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSING; | 
 |                 break; | 
 |             } | 
 |             ptr = endPtr; | 
 |           } | 
 |           ret->dwNumEntries++; | 
 |         } | 
 |       } | 
 |       fclose(fp); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } |