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.
22 #include "wine/port.h"
28 #include <sys/types.h>
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
35 #ifdef HAVE_ARPA_INET_H
36 #include <arpa/inet.h>
41 #ifdef HAVE_NET_IF_ARP_H
42 #include <net/if_arp.h>
44 #ifdef HAVE_NETINET_TCP_H
45 #include <netinet/tcp.h>
47 #ifdef HAVE_NETINET_TCP_FSM_H
48 #include <netinet/tcp_fsm.h>
58 #define TCPS_ESTABLISHED 1
59 #define TCPS_SYN_SENT 2
60 #define TCPS_SYN_RECEIVED 3
61 #define TCPS_FIN_WAIT_1 4
62 #define TCPS_FIN_WAIT_2 5
63 #define TCPS_TIME_WAIT 6
65 #define TCPS_CLOSE_WAIT 8
66 #define TCPS_LAST_ACK 9
67 #define TCPS_LISTEN 10
68 #define TCPS_CLOSING 11
71 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
76 return ERROR_INVALID_PARAMETER
;
78 return ERROR_INVALID_PARAMETER
;
80 /* get interface stats from /proc/net/dev, no error if can't
81 no inUnknownProtos, outNUcastPkts, outQLen */
82 fp
= fopen("/proc/net/dev", "r");
84 char buf
[512] = { 0 }, *ptr
;
85 int nameLen
= strlen(name
), nameFound
= 0;
88 ptr
= fgets(buf
, sizeof(buf
), fp
);
89 while (ptr
&& !nameFound
) {
90 while (*ptr
&& isspace(*ptr
))
92 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
95 ptr
= fgets(buf
, sizeof(buf
), fp
);
102 entry
->dwInOctets
= strtoul(ptr
, &endPtr
, 10);
106 entry
->dwInUcastPkts
= strtoul(ptr
, &endPtr
, 10);
110 entry
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
114 entry
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
118 strtoul(ptr
, &endPtr
, 10); /* skip */
122 strtoul(ptr
, &endPtr
, 10); /* skip */
126 strtoul(ptr
, &endPtr
, 10); /* skip */
130 entry
->dwInNUcastPkts
= strtoul(ptr
, &endPtr
, 10);
134 entry
->dwOutOctets
= strtoul(ptr
, &endPtr
, 10);
138 entry
->dwOutUcastPkts
= strtoul(ptr
, &endPtr
, 10);
142 entry
->dwOutErrors
= strtoul(ptr
, &endPtr
, 10);
146 entry
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
155 DWORD
getICMPStats(MIB_ICMP
*stats
)
160 return ERROR_INVALID_PARAMETER
;
162 memset(stats
, 0, sizeof(MIB_ICMP
));
163 /* get most of these stats from /proc/net/snmp, no error if can't */
164 fp
= fopen("/proc/net/snmp", "r");
166 static const char hdr
[] = "Icmp:";
167 char buf
[512] = { 0 }, *ptr
;
170 ptr
= fgets(buf
, sizeof(buf
), fp
);
171 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
173 /* last line was a header, get another */
174 ptr
= fgets(buf
, sizeof(buf
), fp
);
175 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
180 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
184 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
188 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
192 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
196 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
200 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
204 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
208 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
212 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
216 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
220 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
224 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
228 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
232 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
236 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
240 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
244 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
248 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
252 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
256 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
260 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
264 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
268 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
272 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
282 DWORD
getIPStats(PMIB_IPSTATS stats
)
287 return ERROR_INVALID_PARAMETER
;
289 memset(stats
, 0, sizeof(MIB_IPSTATS
));
290 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
291 stats
->dwNumRoutes
= getNumRoutes();
293 /* get most of these stats from /proc/net/snmp, no error if can't */
294 fp
= fopen("/proc/net/snmp", "r");
296 static const char hdr
[] = "Ip:";
297 char buf
[512] = { 0 }, *ptr
;
300 ptr
= fgets(buf
, sizeof(buf
), fp
);
301 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
303 /* last line was a header, get another */
304 ptr
= fgets(buf
, sizeof(buf
), fp
);
305 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
310 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
314 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
318 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
322 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
326 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
330 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
334 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
338 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
342 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
346 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
350 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
354 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
358 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
362 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
366 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
370 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
374 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
378 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
382 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
385 /* hmm, no routingDiscards */
393 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
398 return ERROR_INVALID_PARAMETER
;
400 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
402 /* get from /proc/net/snmp, no error if can't */
403 fp
= fopen("/proc/net/snmp", "r");
405 static const char hdr
[] = "Tcp:";
406 char buf
[512] = { 0 }, *ptr
;
410 ptr
= fgets(buf
, sizeof(buf
), fp
);
411 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
413 /* last line was a header, get another */
414 ptr
= fgets(buf
, sizeof(buf
), fp
);
415 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
420 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
424 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
428 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
432 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
436 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
440 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
444 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
448 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
452 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
456 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
460 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
464 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
468 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
472 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
475 stats
->dwNumConns
= getNumTcpEntries();
483 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
488 return ERROR_INVALID_PARAMETER
;
490 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
492 /* get from /proc/net/snmp, no error if can't */
493 fp
= fopen("/proc/net/snmp", "r");
495 static const char hdr
[] = "Udp:";
496 char buf
[512] = { 0 }, *ptr
;
500 ptr
= fgets(buf
, sizeof(buf
), fp
);
501 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
503 /* last line was a header, get another */
504 ptr
= fgets(buf
, sizeof(buf
), fp
);
505 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
510 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
514 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
518 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
522 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
526 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
536 static DWORD
getNumWithOneHeader(const char *filename
)
541 fp
= fopen(filename
, "r");
543 char buf
[512] = { 0 }, *ptr
;
546 ptr
= fgets(buf
, sizeof(buf
), fp
);
549 ptr
= fgets(buf
, sizeof(buf
), fp
);
559 DWORD
getNumRoutes(void)
561 return getNumWithOneHeader("/proc/net/route");
564 RouteTable
*getRouteTable(void)
566 DWORD numRoutes
= getNumRoutes();
569 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
570 sizeof(RouteTable
) + (numRoutes
- 1) * sizeof(RouteEntry
));
574 /* get from /proc/net/route, no error if can't */
575 fp
= fopen("/proc/net/route", "r");
577 char buf
[512] = { 0 }, *ptr
;
579 /* skip header line */
580 ptr
= fgets(buf
, sizeof(buf
), fp
);
581 while (ptr
&& ret
->numRoutes
< numRoutes
) {
582 ptr
= fgets(buf
, sizeof(buf
), fp
);
586 while (!isspace(*ptr
))
590 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
593 ret
->routes
[ret
->numRoutes
].ifIndex
= index
;
595 ret
->routes
[ret
->numRoutes
].dest
= strtoul(ptr
, &endPtr
, 16);
599 ret
->routes
[ret
->numRoutes
].gateway
= strtoul(ptr
, &endPtr
, 16);
603 strtoul(ptr
, &endPtr
, 16); /* flags, skip */
607 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
611 strtoul(ptr
, &endPtr
, 16); /* use, skip */
615 ret
->routes
[ret
->numRoutes
].metric
= strtoul(ptr
, &endPtr
, 16);
619 ret
->routes
[ret
->numRoutes
].mask
= strtoul(ptr
, &endPtr
, 16);
632 DWORD
getNumArpEntries(void)
634 return getNumWithOneHeader("/proc/net/arp");
637 PMIB_IPNETTABLE
getArpTable(void)
639 DWORD numEntries
= getNumArpEntries();
642 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
643 sizeof(MIB_IPNETTABLE
) + (numEntries
- 1) * sizeof(MIB_IPNETROW
));
647 /* get from /proc/net/arp, no error if can't */
648 fp
= fopen("/proc/net/arp", "r");
650 char buf
[512] = { 0 }, *ptr
;
652 /* skip header line */
653 ptr
= fgets(buf
, sizeof(buf
), fp
);
654 while (ptr
&& ret
->dwNumEntries
< numEntries
) {
655 ptr
= fgets(buf
, sizeof(buf
), fp
);
659 ret
->table
[ret
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
660 while (ptr
&& *ptr
&& !isspace(*ptr
))
664 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
668 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
672 ret
->table
[ret
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_DYNAMIC
;
676 if (flags
& ATF_PERM
)
677 ret
->table
[ret
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_STATIC
;
680 ret
->table
[ret
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
684 while (ptr
&& *ptr
&& isspace(*ptr
))
686 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
687 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
689 if (endPtr
&& *endPtr
) {
691 ret
->table
[ret
->dwNumEntries
].bPhysAddr
[
692 ret
->table
[ret
->dwNumEntries
].dwPhysAddrLen
++] = byte
& 0x0ff;
697 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
700 getInterfaceIndexByName(ptr
, &ret
->table
[ret
->dwNumEntries
].dwIndex
);
710 DWORD
getNumUdpEntries(void)
712 return getNumWithOneHeader("/proc/net/udp");
715 PMIB_UDPTABLE
getUdpTable(void)
717 DWORD numEntries
= getNumUdpEntries();
720 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
721 sizeof(MIB_UDPTABLE
) + (numEntries
- 1) * sizeof(MIB_UDPROW
));
725 /* get from /proc/net/udp, no error if can't */
726 fp
= fopen("/proc/net/udp", "r");
728 char buf
[512] = { 0 }, *ptr
;
730 /* skip header line */
731 ptr
= fgets(buf
, sizeof(buf
), fp
);
732 while (ptr
&& ret
->dwNumEntries
< numEntries
) {
733 ptr
= fgets(buf
, sizeof(buf
), fp
);
738 strtoul(ptr
, &endPtr
, 16); /* skip */
743 ret
->table
[ret
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
, &endPtr
,
749 ret
->table
[ret
->dwNumEntries
].dwLocalPort
= strtoul(ptr
, &endPtr
,
762 DWORD
getNumTcpEntries(void)
764 return getNumWithOneHeader("/proc/net/tcp");
767 PMIB_TCPTABLE
getTcpTable(void)
769 DWORD numEntries
= getNumTcpEntries();
772 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
773 sizeof(MIB_TCPTABLE
) + (numEntries
- 1) * sizeof(MIB_TCPROW
));
777 /* get from /proc/net/tcp, no error if can't */
778 fp
= fopen("/proc/net/tcp", "r");
780 char buf
[512] = { 0 }, *ptr
;
782 /* skip header line */
783 ptr
= fgets(buf
, sizeof(buf
), fp
);
784 while (ptr
&& ret
->dwNumEntries
< numEntries
) {
785 ptr
= fgets(buf
, sizeof(buf
), fp
);
789 while (ptr
&& *ptr
&& *ptr
!= ':')
794 ret
->table
[ret
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
, &endPtr
,
800 ret
->table
[ret
->dwNumEntries
].dwLocalPort
= strtoul(ptr
, &endPtr
,
805 ret
->table
[ret
->dwNumEntries
].dwRemoteAddr
= strtoul(ptr
, &endPtr
,
811 ret
->table
[ret
->dwNumEntries
].dwRemotePort
= strtoul(ptr
, &endPtr
,
816 DWORD state
= strtoul(ptr
, &endPtr
, 16);
820 case TCPS_ESTABLISHED
:
821 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_ESTAB
;
824 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_SYN_SENT
;
826 case TCPS_SYN_RECEIVED
:
827 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_SYN_RCVD
;
829 case TCPS_FIN_WAIT_1
:
830 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_FIN_WAIT1
;
832 case TCPS_FIN_WAIT_2
:
833 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_FIN_WAIT2
;
836 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_TIME_WAIT
;
839 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_CLOSED
;
841 case TCPS_CLOSE_WAIT
:
842 ret
->table
[ret
->dwNumEntries
].dwState
=
843 MIB_TCP_STATE_CLOSE_WAIT
;
846 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_LAST_ACK
;
849 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_LISTEN
;
852 ret
->table
[ret
->dwNumEntries
].dwState
= MIB_TCP_STATE_CLOSING
;