/* 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 #include #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_NET_IF_ARP_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_NETINET_TCP_FSM_H #include #endif #include "windef.h" #include "winbase.h" #include "iprtrmib.h" #include "ifenum.h" #include "ipstats.h" #ifdef linux #define TCPS_ESTABLISHED 1 #define TCPS_SYN_SENT 2 #define TCPS_SYN_RECEIVED 3 #define TCPS_FIN_WAIT_1 4 #define TCPS_FIN_WAIT_2 5 #define TCPS_TIME_WAIT 6 #define TCPS_CLOSED 7 #define TCPS_CLOSE_WAIT 8 #define TCPS_LAST_ACK 9 #define TCPS_LISTEN 10 #define TCPS_CLOSING 11 #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) { static 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) { static 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) { 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->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) { static 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); #ifdef ATF_COM if (flags & ATF_COM) ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC; else #endif #ifdef ATF_PERM if (flags & ATF_PERM) ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC; else #endif 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; }