1 /* Copyright (C) 2003 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * This file implements statistics getting using the /proc filesystem exported
18 * by Linux, and maybe other OSes.
31 #if HAVE_NETINET_TCP_H
32 #include <netinet/tcp.h>
35 #if HAVE_NETINET_TCP_FSM_H
36 #include <netinet/tcp_fsm.h>
44 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
49 return ERROR_INVALID_PARAMETER;
51 return ERROR_INVALID_PARAMETER;
53 /* get interface stats from /proc/net/dev, no error if can't
54 no inUnknownProtos, outNUcastPkts, outQLen */
55 fp = fopen("/proc/net/dev", "r");
57 char buf[512] = { 0 }, *ptr;
58 int nameLen = strlen(name), nameFound = 0;
61 ptr = fgets(buf, sizeof(buf), fp);
62 while (ptr && !nameFound) {
63 while (*ptr && isspace(*ptr))
65 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
68 ptr = fgets(buf, sizeof(buf), fp);
75 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
79 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
83 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
87 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
91 strtoul(ptr, &endPtr, 10); /* skip */
95 strtoul(ptr, &endPtr, 10); /* skip */
99 strtoul(ptr, &endPtr, 10); /* skip */
103 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
107 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
111 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
115 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
119 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
128 DWORD getICMPStats(MIB_ICMP *stats)
133 return ERROR_INVALID_PARAMETER;
135 memset(stats, 0, sizeof(MIB_ICMP));
136 /* get most of these stats from /proc/net/snmp, no error if can't */
137 fp = fopen("/proc/net/snmp", "r");
139 const char hdr[] = "Icmp:";
140 char buf[512] = { 0 }, *ptr;
143 ptr = fgets(buf, sizeof(buf), fp);
144 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
146 /* last line was a header, get another */
147 ptr = fgets(buf, sizeof(buf), fp);
148 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
153 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
157 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
161 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
165 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
169 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
173 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
177 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
181 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
185 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
189 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
193 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
197 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
201 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
205 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
209 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
213 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
217 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
221 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
225 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
229 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
233 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
237 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
241 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
245 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
255 DWORD getIPStats(PMIB_IPSTATS stats)
260 return ERROR_INVALID_PARAMETER;
262 memset(stats, 0, sizeof(MIB_IPSTATS));
263 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
264 stats->dwNumRoutes = getNumRoutes();
266 /* get most of these stats from /proc/net/snmp, no error if can't */
267 fp = fopen("/proc/net/snmp", "r");
269 const char hdr[] = "Ip:";
270 char buf[512] = { 0 }, *ptr;
273 ptr = fgets(buf, sizeof(buf), fp);
274 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
276 /* last line was a header, get another */
277 ptr = fgets(buf, sizeof(buf), fp);
278 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
283 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
287 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
291 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
295 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
299 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
303 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
307 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
311 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
315 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
319 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
323 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
327 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
331 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
335 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
339 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
343 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
347 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
351 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
355 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
358 /* hmm, no routingDiscards */
366 DWORD getTCPStats(MIB_TCPSTATS *stats)
371 return ERROR_INVALID_PARAMETER;
373 memset(stats, 0, sizeof(MIB_TCPSTATS));
375 /* get from /proc/net/snmp, no error if can't */
376 fp = fopen("/proc/net/snmp", "r");
378 const char hdr[] = "Tcp:";
379 char buf[512] = { 0 }, *ptr;
383 ptr = fgets(buf, sizeof(buf), fp);
384 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
386 /* last line was a header, get another */
387 ptr = fgets(buf, sizeof(buf), fp);
388 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
393 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
397 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
401 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
405 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
409 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
413 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
417 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
421 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
425 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
429 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
433 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
437 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
441 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
445 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
448 stats->dwNumConns = getNumTcpEntries();
456 DWORD getUDPStats(MIB_UDPSTATS *stats)
461 return ERROR_INVALID_PARAMETER;
463 memset(stats, 0, sizeof(MIB_UDPSTATS));
465 /* get from /proc/net/snmp, no error if can't */
466 fp = fopen("/proc/net/snmp", "r");
468 const char hdr[] = "Udp:";
469 char buf[512] = { 0 }, *ptr;
473 ptr = fgets(buf, sizeof(buf), fp);
474 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
476 /* last line was a header, get another */
477 ptr = fgets(buf, sizeof(buf), fp);
478 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
483 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
487 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
491 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
495 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
499 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
509 static DWORD getNumWithOneHeader(const char *filename)
514 fp = fopen(filename, "r");
516 char buf[512] = { 0 }, *ptr;
519 ptr = fgets(buf, sizeof(buf), fp);
522 ptr = fgets(buf, sizeof(buf), fp);
532 DWORD getNumRoutes(void)
534 return getNumWithOneHeader("/proc/net/route");
537 RouteTable *getRouteTable(void)
539 DWORD numRoutes = getNumRoutes();
542 ret = (RouteTable *)calloc(1, sizeof(RouteTable) +
543 (numRoutes - 1) * sizeof(RouteEntry));
547 /* get from /proc/net/route, no error if can't */
548 fp = fopen("/proc/net/route", "r");
550 char buf[512] = { 0 }, *ptr;
552 /* skip header line */
553 ptr = fgets(buf, sizeof(buf), fp);
554 while (ptr && ret->numRoutes < numRoutes) {
555 ptr = fgets(buf, sizeof(buf), fp);
559 while (!isspace(*ptr))
563 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
566 ret->routes[ret->numRoutes].ifIndex = index;
568 ret->routes[ret->numRoutes].dest = strtoul(ptr, &endPtr, 16);
572 ret->routes[ret->numRoutes].gateway = strtoul(ptr, &endPtr, 16);
576 strtoul(ptr, &endPtr, 16); /* flags, skip */
580 strtoul(ptr, &endPtr, 16); /* refcount, skip */
584 strtoul(ptr, &endPtr, 16); /* use, skip */
588 ret->routes[ret->numRoutes].metric = strtoul(ptr, &endPtr, 16);
592 ret->routes[ret->numRoutes].mask = strtoul(ptr, &endPtr, 16);
605 DWORD getNumArpEntries(void)
607 return getNumWithOneHeader("/proc/net/arp");
610 PMIB_IPNETTABLE getArpTable(void)
612 DWORD numEntries = getNumArpEntries();
615 ret = (PMIB_IPNETTABLE)calloc(1, sizeof(MIB_IPNETTABLE) +
616 (numEntries - 1) * sizeof(MIB_IPNETROW));
620 /* get from /proc/net/arp, no error if can't */
621 fp = fopen("/proc/net/arp", "r");
623 char buf[512] = { 0 }, *ptr;
625 /* skip header line */
626 ptr = fgets(buf, sizeof(buf), fp);
627 while (ptr && ret->dwNumEntries < numEntries) {
628 ptr = fgets(buf, sizeof(buf), fp);
633 ret->table[ret->dwNumEntries].dwAddr = strtoul(ptr, &endPtr, 16);
637 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
641 strtoul(ptr, &endPtr, 16); /* flags (skip) */
644 /* FIXME: maybe this comes from flags? */
645 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
646 while (ptr && *ptr && isspace(*ptr))
648 while (ptr && *ptr && !isspace(*ptr)) {
649 DWORD byte = strtoul(ptr, &endPtr, 16);
651 if (endPtr && *endPtr) {
653 ret->table[ret->dwNumEntries].bPhysAddr[
654 ret->table[ret->dwNumEntries].dwPhysAddrLen++] = byte & 0x0ff;
659 strtoul(ptr, &endPtr, 16); /* mask (skip) */
662 getInterfaceIndexByName(ptr, &ret->table[ret->dwNumEntries].dwIndex);
672 DWORD getNumUdpEntries(void)
674 return getNumWithOneHeader("/proc/net/udp");
677 PMIB_UDPTABLE getUdpTable(void)
679 DWORD numEntries = getNumUdpEntries();
682 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
683 (numEntries - 1) * sizeof(MIB_UDPROW));
687 /* get from /proc/net/udp, no error if can't */
688 fp = fopen("/proc/net/udp", "r");
690 char buf[512] = { 0 }, *ptr;
692 /* skip header line */
693 ptr = fgets(buf, sizeof(buf), fp);
694 while (ptr && ret->dwNumEntries < numEntries) {
695 ptr = fgets(buf, sizeof(buf), fp);
700 strtoul(ptr, &endPtr, 16); /* skip */
705 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
711 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
724 DWORD getNumTcpEntries(void)
726 return getNumWithOneHeader("/proc/net/tcp");
729 PMIB_TCPTABLE getTcpTable(void)
731 DWORD numEntries = getNumTcpEntries();
734 ret = (PMIB_TCPTABLE)calloc(1, sizeof(MIB_TCPTABLE) +
735 (numEntries - 1) * sizeof(MIB_TCPROW));
739 /* get from /proc/net/tcp, no error if can't */
740 fp = fopen("/proc/net/tcp", "r");
742 char buf[512] = { 0 }, *ptr;
744 /* skip header line */
745 ptr = fgets(buf, sizeof(buf), fp);
746 while (ptr && ret->dwNumEntries < numEntries) {
747 ptr = fgets(buf, sizeof(buf), fp);
751 while (ptr && *ptr && *ptr != ':')
756 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
762 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
767 ret->table[ret->dwNumEntries].dwRemoteAddr = strtoul(ptr, &endPtr,
773 ret->table[ret->dwNumEntries].dwRemotePort = strtoul(ptr, &endPtr,
778 DWORD state = strtoul(ptr, &endPtr, 16);
780 #if HAVE_NETINET_TCP_H
783 case TCP_ESTABLISHED:
784 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_ESTAB;
787 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_SENT;
790 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_RCVD;
793 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT1;
796 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT2;
799 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_TIME_WAIT;
802 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSED;
805 ret->table[ret->dwNumEntries].dwState =
806 MIB_TCP_STATE_CLOSE_WAIT;
809 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LAST_ACK;
812 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LISTEN;
815 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSING;