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.
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 #include <sys/socket.h>
31 #ifdef HAVE_NETINET_IN_H
32 #include <netinet/in.h>
34 #ifdef HAVE_ARPA_INET_H
35 #include <arpa/inet.h>
40 #ifdef HAVE_NET_IF_ARP_H
41 #include <net/if_arp.h>
43 #ifdef HAVE_NETINET_TCP_H
44 #include <netinet/tcp.h>
46 #ifdef HAVE_NETINET_TCP_FSM_H
47 #include <netinet/tcp_fsm.h>
56 #ifndef TCPS_ESTABLISHED
57 # define TCPS_ESTABLISHED TCP_ESTABLISHED
60 # define TCPS_SYN_SENT TCP_SYN_SENT
62 #ifndef TCPS_SYN_RECEIVED
63 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
65 #ifndef TCPS_FIN_WAIT_1
66 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
68 #ifndef TCPS_FIN_WAIT_2
69 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
71 #ifndef TCPS_TIME_WAIT
72 # define TCPS_TIME_WAIT TCP_TIME_WAIT
75 # define TCPS_CLOSED TCP_CLOSE
77 #ifndef TCPS_CLOSE_WAIT
78 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
81 # define TCPS_LAST_ACK TCP_LAST_ACK
84 # define TCPS_LISTEN TCP_LISTEN
87 # define TCPS_CLOSING TCP_CLOSING
90 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
95 return ERROR_INVALID_PARAMETER;
97 return ERROR_INVALID_PARAMETER;
99 /* get interface stats from /proc/net/dev, no error if can't
100 no inUnknownProtos, outNUcastPkts, outQLen */
101 fp = fopen("/proc/net/dev", "r");
103 char buf[512] = { 0 }, *ptr;
104 int nameLen = strlen(name), nameFound = 0;
107 ptr = fgets(buf, sizeof(buf), fp);
108 while (ptr && !nameFound) {
109 while (*ptr && isspace(*ptr))
111 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
114 ptr = fgets(buf, sizeof(buf), fp);
121 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
125 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
129 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
133 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
137 strtoul(ptr, &endPtr, 10); /* skip */
141 strtoul(ptr, &endPtr, 10); /* skip */
145 strtoul(ptr, &endPtr, 10); /* skip */
149 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
153 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
157 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
161 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
165 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
174 DWORD getICMPStats(MIB_ICMP *stats)
179 return ERROR_INVALID_PARAMETER;
181 memset(stats, 0, sizeof(MIB_ICMP));
182 /* get most of these stats from /proc/net/snmp, no error if can't */
183 fp = fopen("/proc/net/snmp", "r");
185 const char hdr[] = "Icmp:";
186 char buf[512] = { 0 }, *ptr;
189 ptr = fgets(buf, sizeof(buf), fp);
190 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
192 /* last line was a header, get another */
193 ptr = fgets(buf, sizeof(buf), fp);
194 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
199 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
203 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
207 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
211 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
215 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
219 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
223 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
227 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
231 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
235 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
239 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
243 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
247 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
251 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
255 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
259 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
263 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
267 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
271 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
275 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
279 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
283 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
287 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
291 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
301 DWORD getIPStats(PMIB_IPSTATS stats)
306 return ERROR_INVALID_PARAMETER;
308 memset(stats, 0, sizeof(MIB_IPSTATS));
309 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
310 stats->dwNumRoutes = getNumRoutes();
312 /* get most of these stats from /proc/net/snmp, no error if can't */
313 fp = fopen("/proc/net/snmp", "r");
315 const char hdr[] = "Ip:";
316 char buf[512] = { 0 }, *ptr;
319 ptr = fgets(buf, sizeof(buf), fp);
320 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
322 /* last line was a header, get another */
323 ptr = fgets(buf, sizeof(buf), fp);
324 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
329 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
333 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
337 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
341 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
345 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
349 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
353 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
357 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
361 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
365 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
369 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
373 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
377 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
381 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
385 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
389 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
393 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
397 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
401 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
404 /* hmm, no routingDiscards */
412 DWORD getTCPStats(MIB_TCPSTATS *stats)
417 return ERROR_INVALID_PARAMETER;
419 memset(stats, 0, sizeof(MIB_TCPSTATS));
421 /* get from /proc/net/snmp, no error if can't */
422 fp = fopen("/proc/net/snmp", "r");
424 const char hdr[] = "Tcp:";
425 char buf[512] = { 0 }, *ptr;
429 ptr = fgets(buf, sizeof(buf), fp);
430 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
432 /* last line was a header, get another */
433 ptr = fgets(buf, sizeof(buf), fp);
434 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
439 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
443 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
447 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
451 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
455 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
459 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
463 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
467 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
471 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
475 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
479 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
483 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
487 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
491 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
494 stats->dwNumConns = getNumTcpEntries();
502 DWORD getUDPStats(MIB_UDPSTATS *stats)
507 return ERROR_INVALID_PARAMETER;
509 memset(stats, 0, sizeof(MIB_UDPSTATS));
511 /* get from /proc/net/snmp, no error if can't */
512 fp = fopen("/proc/net/snmp", "r");
514 const char hdr[] = "Udp:";
515 char buf[512] = { 0 }, *ptr;
519 ptr = fgets(buf, sizeof(buf), fp);
520 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
522 /* last line was a header, get another */
523 ptr = fgets(buf, sizeof(buf), fp);
524 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
529 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
533 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
537 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
541 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
545 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
555 static DWORD getNumWithOneHeader(const char *filename)
560 fp = fopen(filename, "r");
562 char buf[512] = { 0 }, *ptr;
565 ptr = fgets(buf, sizeof(buf), fp);
568 ptr = fgets(buf, sizeof(buf), fp);
578 DWORD getNumRoutes(void)
580 return getNumWithOneHeader("/proc/net/route");
583 RouteTable *getRouteTable(void)
585 DWORD numRoutes = getNumRoutes();
588 ret = (RouteTable *)calloc(1, sizeof(RouteTable) +
589 (numRoutes - 1) * sizeof(RouteEntry));
593 /* get from /proc/net/route, no error if can't */
594 fp = fopen("/proc/net/route", "r");
596 char buf[512] = { 0 }, *ptr;
598 /* skip header line */
599 ptr = fgets(buf, sizeof(buf), fp);
600 while (ptr && ret->numRoutes < numRoutes) {
601 ptr = fgets(buf, sizeof(buf), fp);
605 while (!isspace(*ptr))
609 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
612 ret->routes[ret->numRoutes].ifIndex = index;
614 ret->routes[ret->numRoutes].dest = strtoul(ptr, &endPtr, 16);
618 ret->routes[ret->numRoutes].gateway = strtoul(ptr, &endPtr, 16);
622 strtoul(ptr, &endPtr, 16); /* flags, skip */
626 strtoul(ptr, &endPtr, 16); /* refcount, skip */
630 strtoul(ptr, &endPtr, 16); /* use, skip */
634 ret->routes[ret->numRoutes].metric = strtoul(ptr, &endPtr, 16);
638 ret->routes[ret->numRoutes].mask = strtoul(ptr, &endPtr, 16);
651 DWORD getNumArpEntries(void)
653 return getNumWithOneHeader("/proc/net/arp");
656 PMIB_IPNETTABLE getArpTable(void)
658 DWORD numEntries = getNumArpEntries();
661 ret = (PMIB_IPNETTABLE)calloc(1, sizeof(MIB_IPNETTABLE) +
662 (numEntries - 1) * sizeof(MIB_IPNETROW));
666 /* get from /proc/net/arp, no error if can't */
667 fp = fopen("/proc/net/arp", "r");
669 char buf[512] = { 0 }, *ptr;
671 /* skip header line */
672 ptr = fgets(buf, sizeof(buf), fp);
673 while (ptr && ret->dwNumEntries < numEntries) {
674 ptr = fgets(buf, sizeof(buf), fp);
678 ret->table[ret->dwNumEntries].dwAddr = inet_addr(ptr);
679 while (ptr && *ptr && !isspace(*ptr))
683 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
687 DWORD flags = strtoul(ptr, &endPtr, 16);
691 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
695 if (flags & ATF_PERM)
696 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
699 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
703 while (ptr && *ptr && isspace(*ptr))
705 while (ptr && *ptr && !isspace(*ptr)) {
706 DWORD byte = strtoul(ptr, &endPtr, 16);
708 if (endPtr && *endPtr) {
710 ret->table[ret->dwNumEntries].bPhysAddr[
711 ret->table[ret->dwNumEntries].dwPhysAddrLen++] = byte & 0x0ff;
716 strtoul(ptr, &endPtr, 16); /* mask (skip) */
719 getInterfaceIndexByName(ptr, &ret->table[ret->dwNumEntries].dwIndex);
729 DWORD getNumUdpEntries(void)
731 return getNumWithOneHeader("/proc/net/udp");
734 PMIB_UDPTABLE getUdpTable(void)
736 DWORD numEntries = getNumUdpEntries();
739 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
740 (numEntries - 1) * sizeof(MIB_UDPROW));
744 /* get from /proc/net/udp, no error if can't */
745 fp = fopen("/proc/net/udp", "r");
747 char buf[512] = { 0 }, *ptr;
749 /* skip header line */
750 ptr = fgets(buf, sizeof(buf), fp);
751 while (ptr && ret->dwNumEntries < numEntries) {
752 ptr = fgets(buf, sizeof(buf), fp);
757 strtoul(ptr, &endPtr, 16); /* skip */
762 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
768 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
781 DWORD getNumTcpEntries(void)
783 return getNumWithOneHeader("/proc/net/tcp");
786 PMIB_TCPTABLE getTcpTable(void)
788 DWORD numEntries = getNumTcpEntries();
791 ret = (PMIB_TCPTABLE)calloc(1, sizeof(MIB_TCPTABLE) +
792 (numEntries - 1) * sizeof(MIB_TCPROW));
796 /* get from /proc/net/tcp, no error if can't */
797 fp = fopen("/proc/net/tcp", "r");
799 char buf[512] = { 0 }, *ptr;
801 /* skip header line */
802 ptr = fgets(buf, sizeof(buf), fp);
803 while (ptr && ret->dwNumEntries < numEntries) {
804 ptr = fgets(buf, sizeof(buf), fp);
808 while (ptr && *ptr && *ptr != ':')
813 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
819 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
824 ret->table[ret->dwNumEntries].dwRemoteAddr = strtoul(ptr, &endPtr,
830 ret->table[ret->dwNumEntries].dwRemotePort = strtoul(ptr, &endPtr,
835 DWORD state = strtoul(ptr, &endPtr, 16);
839 case TCPS_ESTABLISHED:
840 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_ESTAB;
843 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_SENT;
845 case TCPS_SYN_RECEIVED:
846 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_RCVD;
848 case TCPS_FIN_WAIT_1:
849 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT1;
851 case TCPS_FIN_WAIT_2:
852 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT2;
855 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_TIME_WAIT;
858 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSED;
860 case TCPS_CLOSE_WAIT:
861 ret->table[ret->dwNumEntries].dwState =
862 MIB_TCP_STATE_CLOSE_WAIT;
865 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LAST_ACK;
868 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LISTEN;
871 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSING;