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.
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_SOCKET_H
28 # include <sys/socket.h>
33 #if HAVE_NETINET_TCP_H
34 #include <netinet/tcp.h>
36 #if HAVE_NETINET_TCP_FSM_H
37 #include <netinet/tcp_fsm.h>
45 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
50 return ERROR_INVALID_PARAMETER;
52 return ERROR_INVALID_PARAMETER;
54 /* get interface stats from /proc/net/dev, no error if can't
55 no inUnknownProtos, outNUcastPkts, outQLen */
56 fp = fopen("/proc/net/dev", "r");
58 char buf[512] = { 0 }, *ptr;
59 int nameLen = strlen(name), nameFound = 0;
62 ptr = fgets(buf, sizeof(buf), fp);
63 while (ptr && !nameFound) {
64 while (*ptr && isspace(*ptr))
66 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
69 ptr = fgets(buf, sizeof(buf), fp);
76 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
80 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
84 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
88 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
92 strtoul(ptr, &endPtr, 10); /* skip */
96 strtoul(ptr, &endPtr, 10); /* skip */
100 strtoul(ptr, &endPtr, 10); /* skip */
104 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
108 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
112 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
116 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
120 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
129 DWORD getICMPStats(MIB_ICMP *stats)
134 return ERROR_INVALID_PARAMETER;
136 memset(stats, 0, sizeof(MIB_ICMP));
137 /* get most of these stats from /proc/net/snmp, no error if can't */
138 fp = fopen("/proc/net/snmp", "r");
140 const char hdr[] = "Icmp:";
141 char buf[512] = { 0 }, *ptr;
144 ptr = fgets(buf, sizeof(buf), fp);
145 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
147 /* last line was a header, get another */
148 ptr = fgets(buf, sizeof(buf), fp);
149 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
154 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
158 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
162 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
166 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
170 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
174 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
178 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
182 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
186 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
190 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
194 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
198 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
202 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
206 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
210 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
214 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
218 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
222 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
226 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
230 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
234 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
238 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
242 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
246 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
256 DWORD getIPStats(PMIB_IPSTATS stats)
261 return ERROR_INVALID_PARAMETER;
263 memset(stats, 0, sizeof(MIB_IPSTATS));
264 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
265 stats->dwNumRoutes = getNumRoutes();
267 /* get most of these stats from /proc/net/snmp, no error if can't */
268 fp = fopen("/proc/net/snmp", "r");
270 const char hdr[] = "Ip:";
271 char buf[512] = { 0 }, *ptr;
274 ptr = fgets(buf, sizeof(buf), fp);
275 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
277 /* last line was a header, get another */
278 ptr = fgets(buf, sizeof(buf), fp);
279 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
284 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
288 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
292 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
296 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
300 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
304 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
308 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
312 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
316 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
320 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
324 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
328 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
332 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
336 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
340 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
344 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
348 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
352 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
356 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
359 /* hmm, no routingDiscards */
367 DWORD getTCPStats(MIB_TCPSTATS *stats)
372 return ERROR_INVALID_PARAMETER;
374 memset(stats, 0, sizeof(MIB_TCPSTATS));
376 /* get from /proc/net/snmp, no error if can't */
377 fp = fopen("/proc/net/snmp", "r");
379 const char hdr[] = "Tcp:";
380 char buf[512] = { 0 }, *ptr;
384 ptr = fgets(buf, sizeof(buf), fp);
385 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
387 /* last line was a header, get another */
388 ptr = fgets(buf, sizeof(buf), fp);
389 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
394 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
398 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
402 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
406 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
410 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
414 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
418 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
422 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
426 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
430 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
434 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
438 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
442 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
446 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
449 stats->dwNumConns = getNumTcpEntries();
457 DWORD getUDPStats(MIB_UDPSTATS *stats)
462 return ERROR_INVALID_PARAMETER;
464 memset(stats, 0, sizeof(MIB_UDPSTATS));
466 /* get from /proc/net/snmp, no error if can't */
467 fp = fopen("/proc/net/snmp", "r");
469 const char hdr[] = "Udp:";
470 char buf[512] = { 0 }, *ptr;
474 ptr = fgets(buf, sizeof(buf), fp);
475 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
477 /* last line was a header, get another */
478 ptr = fgets(buf, sizeof(buf), fp);
479 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
484 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
488 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
492 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
496 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
500 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
510 static DWORD getNumWithOneHeader(const char *filename)
515 fp = fopen(filename, "r");
517 char buf[512] = { 0 }, *ptr;
520 ptr = fgets(buf, sizeof(buf), fp);
523 ptr = fgets(buf, sizeof(buf), fp);
533 DWORD getNumRoutes(void)
535 return getNumWithOneHeader("/proc/net/route");
538 RouteTable *getRouteTable(void)
540 DWORD numRoutes = getNumRoutes();
543 ret = (RouteTable *)calloc(1, sizeof(RouteTable) +
544 (numRoutes - 1) * sizeof(RouteEntry));
548 /* get from /proc/net/route, no error if can't */
549 fp = fopen("/proc/net/route", "r");
551 char buf[512] = { 0 }, *ptr;
553 /* skip header line */
554 ptr = fgets(buf, sizeof(buf), fp);
555 while (ptr && ret->numRoutes < numRoutes) {
556 ptr = fgets(buf, sizeof(buf), fp);
560 while (!isspace(*ptr))
564 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
567 ret->routes[ret->numRoutes].ifIndex = index;
569 ret->routes[ret->numRoutes].dest = strtoul(ptr, &endPtr, 16);
573 ret->routes[ret->numRoutes].gateway = strtoul(ptr, &endPtr, 16);
577 strtoul(ptr, &endPtr, 16); /* flags, skip */
581 strtoul(ptr, &endPtr, 16); /* refcount, skip */
585 strtoul(ptr, &endPtr, 16); /* use, skip */
589 ret->routes[ret->numRoutes].metric = strtoul(ptr, &endPtr, 16);
593 ret->routes[ret->numRoutes].mask = strtoul(ptr, &endPtr, 16);
606 DWORD getNumArpEntries(void)
608 return getNumWithOneHeader("/proc/net/arp");
611 PMIB_IPNETTABLE getArpTable(void)
613 DWORD numEntries = getNumArpEntries();
616 ret = (PMIB_IPNETTABLE)calloc(1, sizeof(MIB_IPNETTABLE) +
617 (numEntries - 1) * sizeof(MIB_IPNETROW));
621 /* get from /proc/net/arp, no error if can't */
622 fp = fopen("/proc/net/arp", "r");
624 char buf[512] = { 0 }, *ptr;
626 /* skip header line */
627 ptr = fgets(buf, sizeof(buf), fp);
628 while (ptr && ret->dwNumEntries < numEntries) {
629 ptr = fgets(buf, sizeof(buf), fp);
634 ret->table[ret->dwNumEntries].dwAddr = strtoul(ptr, &endPtr, 16);
638 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
642 strtoul(ptr, &endPtr, 16); /* flags (skip) */
645 /* FIXME: maybe this comes from flags? */
646 ret->table[ret->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
647 while (ptr && *ptr && isspace(*ptr))
649 while (ptr && *ptr && !isspace(*ptr)) {
650 DWORD byte = strtoul(ptr, &endPtr, 16);
652 if (endPtr && *endPtr) {
654 ret->table[ret->dwNumEntries].bPhysAddr[
655 ret->table[ret->dwNumEntries].dwPhysAddrLen++] = byte & 0x0ff;
660 strtoul(ptr, &endPtr, 16); /* mask (skip) */
663 getInterfaceIndexByName(ptr, &ret->table[ret->dwNumEntries].dwIndex);
673 DWORD getNumUdpEntries(void)
675 return getNumWithOneHeader("/proc/net/udp");
678 PMIB_UDPTABLE getUdpTable(void)
680 DWORD numEntries = getNumUdpEntries();
683 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
684 (numEntries - 1) * sizeof(MIB_UDPROW));
688 /* get from /proc/net/udp, no error if can't */
689 fp = fopen("/proc/net/udp", "r");
691 char buf[512] = { 0 }, *ptr;
693 /* skip header line */
694 ptr = fgets(buf, sizeof(buf), fp);
695 while (ptr && ret->dwNumEntries < numEntries) {
696 ptr = fgets(buf, sizeof(buf), fp);
701 strtoul(ptr, &endPtr, 16); /* skip */
706 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
712 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
725 DWORD getNumTcpEntries(void)
727 return getNumWithOneHeader("/proc/net/tcp");
730 PMIB_TCPTABLE getTcpTable(void)
732 DWORD numEntries = getNumTcpEntries();
735 ret = (PMIB_TCPTABLE)calloc(1, sizeof(MIB_TCPTABLE) +
736 (numEntries - 1) * sizeof(MIB_TCPROW));
740 /* get from /proc/net/tcp, no error if can't */
741 fp = fopen("/proc/net/tcp", "r");
743 char buf[512] = { 0 }, *ptr;
745 /* skip header line */
746 ptr = fgets(buf, sizeof(buf), fp);
747 while (ptr && ret->dwNumEntries < numEntries) {
748 ptr = fgets(buf, sizeof(buf), fp);
752 while (ptr && *ptr && *ptr != ':')
757 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
763 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
768 ret->table[ret->dwNumEntries].dwRemoteAddr = strtoul(ptr, &endPtr,
774 ret->table[ret->dwNumEntries].dwRemotePort = strtoul(ptr, &endPtr,
779 DWORD state = strtoul(ptr, &endPtr, 16);
781 #if HAVE_NETINET_TCP_H
784 #ifdef TCP_ESTABLISHED
785 case TCP_ESTABLISHED:
786 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_ESTAB;
791 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_SENT;
796 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_SYN_RCVD;
801 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT1;
806 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_FIN_WAIT2;
811 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_TIME_WAIT;
816 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSED;
819 #ifdef TCP_CLOSE_WAIT
821 ret->table[ret->dwNumEntries].dwState =
822 MIB_TCP_STATE_CLOSE_WAIT;
827 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LAST_ACK;
832 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_LISTEN;
837 ret->table[ret->dwNumEntries].dwState = MIB_TCP_STATE_CLOSING;