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>
57 #define TCPS_ESTABLISHED 1
58 #define TCPS_SYN_SENT 2
59 #define TCPS_SYN_RECEIVED 3
60 #define TCPS_FIN_WAIT_1 4
61 #define TCPS_FIN_WAIT_2 5
62 #define TCPS_TIME_WAIT 6
64 #define TCPS_CLOSE_WAIT 8
65 #define TCPS_LAST_ACK 9
66 #define TCPS_LISTEN 10
67 #define TCPS_CLOSING 11
70 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
75 return ERROR_INVALID_PARAMETER;
77 return ERROR_INVALID_PARAMETER;
79 /* get interface stats from /proc/net/dev, no error if can't
80 no inUnknownProtos, outNUcastPkts, outQLen */
81 fp = fopen("/proc/net/dev", "r");
83 char buf[512] = { 0 }, *ptr;
84 int nameLen = strlen(name), nameFound = 0;
87 ptr = fgets(buf, sizeof(buf), fp);
88 while (ptr && !nameFound) {
89 while (*ptr && isspace(*ptr))
91 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
94 ptr = fgets(buf, sizeof(buf), fp);
101 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
105 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
109 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
113 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
117 strtoul(ptr, &endPtr, 10); /* skip */
121 strtoul(ptr, &endPtr, 10); /* skip */
125 strtoul(ptr, &endPtr, 10); /* skip */
129 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
133 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
137 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
141 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
145 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
154 DWORD getICMPStats(MIB_ICMP *stats)
159 return ERROR_INVALID_PARAMETER;
161 memset(stats, 0, sizeof(MIB_ICMP));
162 /* get most of these stats from /proc/net/snmp, no error if can't */
163 fp = fopen("/proc/net/snmp", "r");
165 static const char hdr[] = "Icmp:";
166 char buf[512] = { 0 }, *ptr;
169 ptr = fgets(buf, sizeof(buf), fp);
170 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
172 /* last line was a header, get another */
173 ptr = fgets(buf, sizeof(buf), fp);
174 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
179 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
183 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
187 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
191 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
195 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
199 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
203 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
207 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
211 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
215 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
219 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
223 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
227 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
231 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
235 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
239 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
243 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
247 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
251 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
255 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
259 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
263 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
267 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
271 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
281 DWORD getIPStats(PMIB_IPSTATS stats)
286 return ERROR_INVALID_PARAMETER;
288 memset(stats, 0, sizeof(MIB_IPSTATS));
289 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
290 stats->dwNumRoutes = getNumRoutes();
292 /* get most of these stats from /proc/net/snmp, no error if can't */
293 fp = fopen("/proc/net/snmp", "r");
295 static const char hdr[] = "Ip:";
296 char buf[512] = { 0 }, *ptr;
299 ptr = fgets(buf, sizeof(buf), fp);
300 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
302 /* last line was a header, get another */
303 ptr = fgets(buf, sizeof(buf), fp);
304 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
309 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
313 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
317 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
321 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
325 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
329 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
333 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
337 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
341 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
345 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
349 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
353 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
357 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
361 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
365 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
369 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
373 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
377 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
381 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
384 /* hmm, no routingDiscards */
392 DWORD getTCPStats(MIB_TCPSTATS *stats)
397 return ERROR_INVALID_PARAMETER;
399 memset(stats, 0, sizeof(MIB_TCPSTATS));
401 /* get from /proc/net/snmp, no error if can't */
402 fp = fopen("/proc/net/snmp", "r");
404 static const char hdr[] = "Tcp:";
405 char buf[512] = { 0 }, *ptr;
409 ptr = fgets(buf, sizeof(buf), fp);
410 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
412 /* last line was a header, get another */
413 ptr = fgets(buf, sizeof(buf), fp);
414 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
419 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
423 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
427 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
431 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
435 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
439 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
443 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
447 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
451 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
455 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
459 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
463 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
467 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
471 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
474 stats->dwNumConns = getNumTcpEntries();
482 DWORD getUDPStats(MIB_UDPSTATS *stats)
487 return ERROR_INVALID_PARAMETER;
489 memset(stats, 0, sizeof(MIB_UDPSTATS));
491 /* get from /proc/net/snmp, no error if can't */
492 fp = fopen("/proc/net/snmp", "r");
494 static const char hdr[] = "Udp:";
495 char buf[512] = { 0 }, *ptr;
499 ptr = fgets(buf, sizeof(buf), fp);
500 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
502 /* last line was a header, get another */
503 ptr = fgets(buf, sizeof(buf), fp);
504 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
509 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
513 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
517 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
521 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
525 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
535 static DWORD getNumWithOneHeader(const char *filename)
540 fp = fopen(filename, "r");
542 char buf[512] = { 0 }, *ptr;
545 ptr = fgets(buf, sizeof(buf), fp);
548 ptr = fgets(buf, sizeof(buf), fp);
558 DWORD getNumRoutes(void)
560 return getNumWithOneHeader("/proc/net/route");
563 RouteTable *getRouteTable(void)
565 DWORD numRoutes = getNumRoutes();
568 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
569 sizeof(RouteTable) + (numRoutes - 1) * sizeof(RouteEntry));
573 /* get from /proc/net/route, no error if can't */
574 fp = fopen("/proc/net/route", "r");
576 char buf[512] = { 0 }, *ptr;
578 /* skip header line */
579 ptr = fgets(buf, sizeof(buf), fp);
580 while (ptr && ret->numRoutes < numRoutes) {
581 ptr = fgets(buf, sizeof(buf), fp);
585 while (!isspace(*ptr))
589 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
592 ret->routes[ret->numRoutes].ifIndex = index;
594 ret->routes[ret->numRoutes].dest = strtoul(ptr, &endPtr, 16);
598 ret->routes[ret->numRoutes].gateway = strtoul(ptr, &endPtr, 16);
602 strtoul(ptr, &endPtr, 16); /* flags, skip */
606 strtoul(ptr, &endPtr, 16); /* refcount, skip */
610 strtoul(ptr, &endPtr, 16); /* use, skip */
614 ret->routes[ret->numRoutes].metric = strtoul(ptr, &endPtr, 16);
618 ret->routes[ret->numRoutes].mask = strtoul(ptr, &endPtr, 16);
631 DWORD getNumArpEntries(void)
633 return getNumWithOneHeader("/proc/net/arp");
636 PMIB_IPNETTABLE getArpTable(void)
638 DWORD numEntries = getNumArpEntries();
641 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
642 sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
646 /* get from /proc/net/arp, no error if can't */
647 fp = fopen("/proc/net/arp", "r");
649 char buf[512] = { 0 }, *ptr;
651 /* skip header line */
652 ptr = fgets(buf, sizeof(buf), fp);
653 while (ptr && ret->dwNumEntries < numEntries) {
654 ptr = fgets(buf, sizeof(buf), fp);
658 ret->table[ret->dwNumEntries].dwAddr = inet_addr(ptr);
659 while (ptr && *ptr && !isspace(*ptr))
663 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
667 DWORD flags = strtoul(ptr, &endPtr, 16);
671 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
675 if (flags & ATF_PERM)
676 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
679 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
683 while (ptr && *ptr && isspace(*ptr))
685 while (ptr && *ptr && !isspace(*ptr)) {
686 DWORD byte = strtoul(ptr, &endPtr, 16);
688 if (endPtr && *endPtr) {
690 ret->table[ret->dwNumEntries].bPhysAddr[
691 ret->table[ret->dwNumEntries].dwPhysAddrLen++] = byte & 0x0ff;
696 strtoul(ptr, &endPtr, 16); /* mask (skip) */
699 getInterfaceIndexByName(ptr, &ret->table[ret->dwNumEntries].dwIndex);
709 DWORD getNumUdpEntries(void)
711 return getNumWithOneHeader("/proc/net/udp");
714 PMIB_UDPTABLE getUdpTable(void)
716 DWORD numEntries = getNumUdpEntries();
719 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
720 sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
724 /* get from /proc/net/udp, no error if can't */
725 fp = fopen("/proc/net/udp", "r");
727 char buf[512] = { 0 }, *ptr;
729 /* skip header line */
730 ptr = fgets(buf, sizeof(buf), fp);
731 while (ptr && ret->dwNumEntries < numEntries) {
732 ptr = fgets(buf, sizeof(buf), fp);
737 strtoul(ptr, &endPtr, 16); /* skip */
742 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
748 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
761 DWORD getNumTcpEntries(void)
763 return getNumWithOneHeader("/proc/net/tcp");
766 PMIB_TCPTABLE getTcpTable(void)
768 DWORD numEntries = getNumTcpEntries();
771 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
772 sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW));
776 /* get from /proc/net/tcp, no error if can't */
777 fp = fopen("/proc/net/tcp", "r");
779 char buf[512] = { 0 }, *ptr;
781 /* skip header line */
782 ptr = fgets(buf, sizeof(buf), fp);
783 while (ptr && ret->dwNumEntries < numEntries) {
784 ptr = fgets(buf, sizeof(buf), fp);
788 while (ptr && *ptr && *ptr != ':')
793 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
799 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
804 ret->table[ret->dwNumEntries].dwRemoteAddr = strtoul(ptr, &endPtr,
810 ret->table[ret->dwNumEntries].dwRemotePort = strtoul(ptr, &endPtr,
815 DWORD state = strtoul(ptr, &endPtr, 16);
819 case TCPS_ESTABLISHED:
820 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_ESTAB;
823 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_SENT;
825 case TCPS_SYN_RECEIVED:
826 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_RCVD;
828 case TCPS_FIN_WAIT_1:
829 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT1;
831 case TCPS_FIN_WAIT_2:
832 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT2;
835 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_TIME_WAIT;
838 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSED;
840 case TCPS_CLOSE_WAIT:
841 ret->table[ret->dwNumEntries].dwState =
842 MIB_TCP_STATE_CLOSE_WAIT;
845 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LAST_ACK;
848 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LISTEN;
851 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSING;