1 /* Copyright (C) 2003,2006 Juan Lang
2 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * This file implements statistics getting using the /proc filesystem exported
19 * by Linux, and maybe other OSes.
23 #include "wine/port.h"
24 #include "wine/debug.h"
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
46 #ifdef HAVE_NET_IF_TYPES_H
47 #include <net/if_types.h>
49 #ifdef HAVE_NET_ROUTE_H
50 #include <net/route.h>
52 #ifdef HAVE_NET_IF_ARP_H
53 #include <net/if_arp.h>
55 #ifdef HAVE_NETINET_TCP_H
56 #include <netinet/tcp.h>
58 #ifdef HAVE_NETINET_TCP_FSM_H
59 #include <netinet/tcp_fsm.h>
62 #ifdef HAVE_NETINET_IN_PCB_H
63 #include <netinet/in_pcb.h>
65 #ifdef HAVE_NETINET_TCP_VAR_H
66 #include <netinet/tcp_var.h>
68 #ifdef HAVE_NETINET_IP_VAR_H
69 #include <netinet/ip_var.h>
72 #ifdef HAVE_SYS_SYSCTL_H
73 #include <sys/sysctl.h>
78 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
81 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
90 #ifndef HAVE_NETINET_TCP_FSM_H
91 #define TCPS_ESTABLISHED 1
92 #define TCPS_SYN_SENT 2
93 #define TCPS_SYN_RECEIVED 3
94 #define TCPS_FIN_WAIT_1 4
95 #define TCPS_FIN_WAIT_2 5
96 #define TCPS_TIME_WAIT 6
98 #define TCPS_CLOSE_WAIT 8
99 #define TCPS_LAST_ACK 9
100 #define TCPS_LISTEN 10
101 #define TCPS_CLOSING 11
104 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
106 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
108 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
109 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
110 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
114 struct if_msghdr
*ifm
;
115 struct if_data ifdata
;
117 return ERROR_INVALID_PARAMETER
;
119 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
121 ERR ("failed to get size of iflist\n");
122 return ERROR_NOT_SUPPORTED
;
124 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
125 if (!buf
) return ERROR_NOT_SUPPORTED
;
126 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
128 ERR ("failed to get iflist\n");
129 HeapFree (GetProcessHeap (), 0, buf
);
130 return ERROR_NOT_SUPPORTED
;
133 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
135 ifm
= (struct if_msghdr
*) buf
;
136 if(ifm
->ifm_type
== RTM_IFINFO
&& ifm
->ifm_data
.ifi_type
== IFT_ETHER
)
138 ifdata
= ifm
->ifm_data
;
139 entry
->dwMtu
= ifdata
.ifi_mtu
;
140 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
141 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
142 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
143 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
144 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
145 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
146 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
147 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
148 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
149 HeapFree (GetProcessHeap (), 0, buf
);
153 HeapFree (GetProcessHeap (), 0, buf
);
154 return ERROR_NOT_SUPPORTED
;
156 /* get interface stats from /proc/net/dev, no error if can't
157 no inUnknownProtos, outNUcastPkts, outQLen */
161 return ERROR_INVALID_PARAMETER
;
162 fp
= fopen("/proc/net/dev", "r");
164 char buf
[512] = { 0 }, *ptr
;
165 int nameLen
= strlen(name
), nameFound
= 0;
168 ptr
= fgets(buf
, sizeof(buf
), fp
);
169 while (ptr
&& !nameFound
) {
170 while (*ptr
&& isspace(*ptr
))
172 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
175 ptr
= fgets(buf
, sizeof(buf
), fp
);
182 entry
->dwInOctets
= strtoul(ptr
, &endPtr
, 10);
186 entry
->dwInUcastPkts
= strtoul(ptr
, &endPtr
, 10);
190 entry
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
194 entry
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
198 strtoul(ptr
, &endPtr
, 10); /* skip */
202 strtoul(ptr
, &endPtr
, 10); /* skip */
206 strtoul(ptr
, &endPtr
, 10); /* skip */
210 entry
->dwInNUcastPkts
= strtoul(ptr
, &endPtr
, 10);
214 entry
->dwOutOctets
= strtoul(ptr
, &endPtr
, 10);
218 entry
->dwOutUcastPkts
= strtoul(ptr
, &endPtr
, 10);
222 entry
->dwOutErrors
= strtoul(ptr
, &endPtr
, 10);
226 entry
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
234 ERR ("unimplemented!\n");
235 return ERROR_NOT_SUPPORTED
;
242 DWORD
getICMPStats(MIB_ICMP
*stats
)
247 return ERROR_INVALID_PARAMETER
;
249 memset(stats
, 0, sizeof(MIB_ICMP
));
250 /* get most of these stats from /proc/net/snmp, no error if can't */
251 fp
= fopen("/proc/net/snmp", "r");
253 static const char hdr
[] = "Icmp:";
254 char buf
[512] = { 0 }, *ptr
;
257 ptr
= fgets(buf
, sizeof(buf
), fp
);
258 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
260 /* last line was a header, get another */
261 ptr
= fgets(buf
, sizeof(buf
), fp
);
262 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
267 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
271 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
275 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
279 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
283 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
287 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
291 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
295 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
299 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
303 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
307 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
311 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
315 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
319 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
323 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
327 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
331 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
335 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
339 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
343 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
347 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
351 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
355 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
359 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
368 ERR ("unimplemented!\n");
369 return ERROR_NOT_SUPPORTED
;
375 DWORD
getIPStats(PMIB_IPSTATS stats
)
380 return ERROR_INVALID_PARAMETER
;
382 memset(stats
, 0, sizeof(MIB_IPSTATS
));
383 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
384 stats
->dwNumRoutes
= getNumRoutes();
386 /* get most of these stats from /proc/net/snmp, no error if can't */
387 fp
= fopen("/proc/net/snmp", "r");
389 static const char hdr
[] = "Ip:";
390 char buf
[512] = { 0 }, *ptr
;
393 ptr
= fgets(buf
, sizeof(buf
), fp
);
394 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
396 /* last line was a header, get another */
397 ptr
= fgets(buf
, sizeof(buf
), fp
);
398 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
403 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
407 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
411 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
415 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
419 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
423 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
427 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
431 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
435 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
439 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
443 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
447 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
451 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
455 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
459 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
463 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
467 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
471 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
475 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
478 /* hmm, no routingDiscards */
485 ERR ("unimplemented!\n");
486 return ERROR_NOT_SUPPORTED
;
492 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
497 return ERROR_INVALID_PARAMETER
;
499 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
501 /* get from /proc/net/snmp, no error if can't */
502 fp
= fopen("/proc/net/snmp", "r");
504 static const char hdr
[] = "Tcp:";
505 char buf
[512] = { 0 }, *ptr
;
509 ptr
= fgets(buf
, sizeof(buf
), fp
);
510 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
512 /* last line was a header, get another */
513 ptr
= fgets(buf
, sizeof(buf
), fp
);
514 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
519 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
523 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
527 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
531 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
535 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
539 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
543 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
547 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
551 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
555 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
559 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
563 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
567 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
571 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
574 stats
->dwNumConns
= getNumTcpEntries();
581 ERR ("unimplemented!\n");
582 return ERROR_NOT_SUPPORTED
;
588 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
593 return ERROR_INVALID_PARAMETER
;
595 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
597 /* get from /proc/net/snmp, no error if can't */
598 fp
= fopen("/proc/net/snmp", "r");
600 static const char hdr
[] = "Udp:";
601 char buf
[512] = { 0 }, *ptr
;
605 ptr
= fgets(buf
, sizeof(buf
), fp
);
606 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
608 /* last line was a header, get another */
609 ptr
= fgets(buf
, sizeof(buf
), fp
);
610 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
615 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
619 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
623 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
627 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
631 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
640 ERR ("unimplemented!\n");
641 return ERROR_NOT_SUPPORTED
;
647 static DWORD
getNumWithOneHeader(const char *filename
)
649 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
652 struct xinpgen
*pXIG
, *pOrigXIG
;
654 DWORD NumEntries
= 0;
656 if (!strcmp (filename
, "net.inet.tcp.pcblist"))
657 Protocol
= IPPROTO_TCP
;
658 else if (!strcmp (filename
, "net.inet.udp.pcblist"))
659 Protocol
= IPPROTO_UDP
;
662 ERR ("Unsupported mib '%s', needs protocol mapping\n",
667 if (sysctlbyname (filename
, NULL
, &Len
, NULL
, 0) < 0)
669 WARN ("Unable to read '%s' via sysctlbyname\n", filename
);
673 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
676 ERR ("Out of memory!\n");
680 if (sysctlbyname (filename
, Buf
, &Len
, NULL
, 0) < 0)
682 ERR ("Failure to read '%s' via sysctlbyname!\n", filename
);
683 HeapFree (GetProcessHeap (), 0, Buf
);
687 /* Might be nothing here; first entry is just a header it seems */
688 if (Len
<= sizeof (struct xinpgen
))
690 HeapFree (GetProcessHeap (), 0, Buf
);
694 pOrigXIG
= (struct xinpgen
*)Buf
;
697 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
698 pXIG
->xig_len
> sizeof (struct xinpgen
);
699 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
701 struct tcpcb
*pTCPData
= NULL
;
702 struct inpcb
*pINData
;
703 struct xsocket
*pSockData
;
705 if (Protocol
== IPPROTO_TCP
)
707 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
708 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
709 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
713 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
714 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
717 /* Ignore sockets for other protocols */
718 if (pSockData
->xso_protocol
!= Protocol
)
721 /* Ignore PCBs that were freed while generating the data */
722 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
725 /* we're only interested in IPv4 addresses */
726 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
727 (pINData
->inp_vflag
& INP_IPV6
))
730 /* If all 0's, skip it */
731 if (!pINData
->inp_laddr
.s_addr
&&
732 !pINData
->inp_lport
&&
733 !pINData
->inp_faddr
.s_addr
&&
740 HeapFree (GetProcessHeap (), 0, Buf
);
746 fp
= fopen(filename
, "r");
748 char buf
[512] = { 0 }, *ptr
;
751 ptr
= fgets(buf
, sizeof(buf
), fp
);
754 ptr
= fgets(buf
, sizeof(buf
), fp
);
762 ERR ("Unable to open '%s' to count entries!\n", filename
);
768 DWORD
getNumRoutes(void)
770 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
771 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
773 char *buf
, *lim
, *next
;
774 struct rt_msghdr
*rtm
;
775 DWORD RouteCount
= 0;
777 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
779 ERR ("sysctl 1 failed!\n");
783 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
786 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
788 ERR ("sysctl 2 failed!\n");
789 HeapFree (GetProcessHeap (), 0, buf
);
794 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
796 rtm
= (struct rt_msghdr
*)next
;
798 if (rtm
->rtm_type
!= RTM_GET
)
800 WARN ("Got unexpected message type 0x%x!\n",
805 /* Ignore all entries except for gateway routes which aren't
807 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) || (rtm
->rtm_flags
& RTF_MULTICAST
))
813 HeapFree (GetProcessHeap (), 0, buf
);
816 return getNumWithOneHeader("/proc/net/route");
820 DWORD
getRouteTable(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, HANDLE heap
,
825 if (!ppIpForwardTable
)
826 ret
= ERROR_INVALID_PARAMETER
;
828 DWORD numRoutes
= getNumRoutes();
829 DWORD size
= sizeof(MIB_IPFORWARDTABLE
);
830 PMIB_IPFORWARDTABLE table
;
833 size
+= (numRoutes
- 1) * sizeof(MIB_IPFORWARDROW
);
834 table
= HeapAlloc(heap
, flags
, size
);
836 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
837 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
839 char *buf
, *lim
, *next
, *addrPtr
;
840 struct rt_msghdr
*rtm
;
842 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
844 ERR ("sysctl 1 failed!\n");
845 HeapFree (GetProcessHeap (), 0, table
);
849 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
852 HeapFree (GetProcessHeap (), 0, table
);
853 return ERROR_OUTOFMEMORY
;
856 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
858 ERR ("sysctl 2 failed!\n");
859 HeapFree (GetProcessHeap (), 0, table
);
860 HeapFree (GetProcessHeap (), 0, buf
);
864 *ppIpForwardTable
= table
;
865 table
->dwNumEntries
= 0;
868 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
872 rtm
= (struct rt_msghdr
*)next
;
874 if (rtm
->rtm_type
!= RTM_GET
)
876 WARN ("Got unexpected message type 0x%x!\n",
881 /* Ignore all entries except for gateway routes which aren't
883 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
884 (rtm
->rtm_flags
& RTF_MULTICAST
))
887 memset (&table
->table
[table
->dwNumEntries
], 0,
888 sizeof (MIB_IPFORWARDROW
));
889 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= rtm
->rtm_index
;
890 table
->table
[table
->dwNumEntries
].dwForwardType
=
891 MIB_IPROUTE_TYPE_INDIRECT
;
892 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
893 rtm
->rtm_rmx
.rmx_hopcount
;
894 table
->table
[table
->dwNumEntries
].dwForwardProto
=
897 addrPtr
= (char *)(rtm
+ 1);
899 for (i
= 1; i
; i
<<= 1)
904 if (!(i
& rtm
->rtm_addrs
))
907 sa
= (struct sockaddr
*)addrPtr
;
908 ADVANCE (addrPtr
, sa
);
910 /* default routes are encoded by length-zero sockaddr */
913 else if (sa
->sa_family
!= AF_INET
)
915 ERR ("Received unsupported sockaddr family 0x%x\n",
921 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
923 addr
= sin
->sin_addr
.s_addr
;
929 table
->table
[table
->dwNumEntries
].dwForwardDest
= addr
;
933 table
->table
[table
->dwNumEntries
].dwForwardNextHop
= addr
;
937 table
->table
[table
->dwNumEntries
].dwForwardMask
= addr
;
941 ERR ("Unexpected address type 0x%x\n", i
);
945 table
->dwNumEntries
++;
948 HeapFree (GetProcessHeap (), 0, buf
);
954 *ppIpForwardTable
= table
;
955 table
->dwNumEntries
= 0;
956 /* get from /proc/net/route, no error if can't */
957 fp
= fopen("/proc/net/route", "r");
959 char buf
[512] = { 0 }, *ptr
;
961 /* skip header line */
962 ptr
= fgets(buf
, sizeof(buf
), fp
);
963 while (ptr
&& table
->dwNumEntries
< numRoutes
) {
964 memset(&table
->table
[table
->dwNumEntries
], 0,
965 sizeof(MIB_IPFORWARDROW
));
966 ptr
= fgets(buf
, sizeof(buf
), fp
);
970 while (!isspace(*ptr
))
974 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
977 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= index
;
979 table
->table
[table
->dwNumEntries
].dwForwardDest
=
980 strtoul(ptr
, &endPtr
, 16);
984 table
->table
[table
->dwNumEntries
].dwForwardNextHop
=
985 strtoul(ptr
, &endPtr
, 16);
989 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
991 if (!(flags
& RTF_UP
))
992 table
->table
[table
->dwNumEntries
].dwForwardType
=
993 MIB_IPROUTE_TYPE_INVALID
;
994 else if (flags
& RTF_GATEWAY
)
995 table
->table
[table
->dwNumEntries
].dwForwardType
=
996 MIB_IPROUTE_TYPE_INDIRECT
;
998 table
->table
[table
->dwNumEntries
].dwForwardType
=
999 MIB_IPROUTE_TYPE_DIRECT
;
1003 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
1007 strtoul(ptr
, &endPtr
, 16); /* use, skip */
1011 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1012 strtoul(ptr
, &endPtr
, 16);
1016 table
->table
[table
->dwNumEntries
].dwForwardMask
=
1017 strtoul(ptr
, &endPtr
, 16);
1020 /* FIXME: other protos might be appropriate, e.g. the default
1021 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1022 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1024 table
->dwNumEntries
++;
1032 ERR ("unimplemented!\n");
1033 return ERROR_NOT_SUPPORTED
;
1038 ret
= ERROR_OUTOFMEMORY
;
1043 DWORD
getNumArpEntries(void)
1045 return getNumWithOneHeader("/proc/net/arp");
1048 DWORD
getArpTable(PMIB_IPNETTABLE
*ppIpNetTable
, HANDLE heap
, DWORD flags
)
1052 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1053 ERR ("unimplemented!\n");
1054 return ERROR_NOT_SUPPORTED
;
1058 ret
= ERROR_INVALID_PARAMETER
;
1060 DWORD numEntries
= getNumArpEntries();
1061 DWORD size
= sizeof(MIB_IPNETTABLE
);
1062 PMIB_IPNETTABLE table
;
1065 size
+= (numEntries
- 1) * sizeof(MIB_IPNETROW
);
1066 table
= HeapAlloc(heap
, flags
, size
);
1071 *ppIpNetTable
= table
;
1072 table
->dwNumEntries
= 0;
1073 /* get from /proc/net/arp, no error if can't */
1074 fp
= fopen("/proc/net/arp", "r");
1076 char buf
[512] = { 0 }, *ptr
;
1078 /* skip header line */
1079 ptr
= fgets(buf
, sizeof(buf
), fp
);
1080 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1081 ptr
= fgets(buf
, sizeof(buf
), fp
);
1085 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1086 table
->table
[table
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
1087 while (ptr
&& *ptr
&& !isspace(*ptr
))
1091 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
1095 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1098 if (flags
& ATF_COM
)
1099 table
->table
[table
->dwNumEntries
].dwType
=
1100 MIB_IPNET_TYPE_DYNAMIC
;
1104 if (flags
& ATF_PERM
)
1105 table
->table
[table
->dwNumEntries
].dwType
=
1106 MIB_IPNET_TYPE_STATIC
;
1109 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1113 while (ptr
&& *ptr
&& isspace(*ptr
))
1115 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
1116 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
1118 if (endPtr
&& *endPtr
) {
1120 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1121 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1127 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
1130 getInterfaceIndexByName(ptr
,
1131 &table
->table
[table
->dwNumEntries
].dwIndex
);
1132 table
->dwNumEntries
++;
1138 ret
= ERROR_NOT_SUPPORTED
;
1141 ret
= ERROR_OUTOFMEMORY
;
1146 DWORD
getNumUdpEntries(void)
1148 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1149 return getNumWithOneHeader ("net.inet.udp.pcblist");
1151 return getNumWithOneHeader("/proc/net/udp");
1155 DWORD
getUdpTable(PMIB_UDPTABLE
*ppUdpTable
, HANDLE heap
, DWORD flags
)
1159 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1160 ERR ("unimplemented!\n");
1161 return ERROR_NOT_SUPPORTED
;
1165 ret
= ERROR_INVALID_PARAMETER
;
1167 DWORD numEntries
= getNumUdpEntries();
1168 DWORD size
= sizeof(MIB_UDPTABLE
);
1169 PMIB_UDPTABLE table
;
1172 size
+= (numEntries
- 1) * sizeof(MIB_UDPROW
);
1173 table
= HeapAlloc(heap
, flags
, size
);
1178 *ppUdpTable
= table
;
1179 table
->dwNumEntries
= 0;
1180 /* get from /proc/net/udp, no error if can't */
1181 fp
= fopen("/proc/net/udp", "r");
1183 char buf
[512] = { 0 }, *ptr
;
1185 /* skip header line */
1186 ptr
= fgets(buf
, sizeof(buf
), fp
);
1187 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1188 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_UDPROW
));
1189 ptr
= fgets(buf
, sizeof(buf
), fp
);
1194 strtoul(ptr
, &endPtr
, 16); /* skip */
1199 table
->table
[table
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
,
1205 table
->table
[table
->dwNumEntries
].dwLocalPort
= strtoul(ptr
,
1209 table
->dwNumEntries
++;
1215 ret
= ERROR_NOT_SUPPORTED
;
1218 ret
= ERROR_OUTOFMEMORY
;
1224 DWORD
getNumTcpEntries(void)
1226 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1227 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1229 return getNumWithOneHeader ("/proc/net/tcp");
1234 /* Why not a lookup table? Because the TCPS_* constants are different
1235 on different platforms */
1236 static DWORD
TCPStateToMIBState (int state
)
1240 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1241 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1242 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1243 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1244 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1245 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1246 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1247 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1248 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1249 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1251 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1256 DWORD
getTcpTable(PMIB_TCPTABLE
*ppTcpTable
, DWORD maxEntries
, HANDLE heap
,
1260 PMIB_TCPTABLE table
;
1261 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1264 struct xinpgen
*pXIG
, *pOrigXIG
;
1267 char buf
[512] = { 0 }, *ptr
;
1271 return ERROR_INVALID_PARAMETER
;
1273 numEntries
= getNumTcpEntries ();
1277 DWORD size
= sizeof(MIB_TCPTABLE
);
1280 size
+= (numEntries
- 1) * sizeof (MIB_TCPROW
);
1281 *ppTcpTable
= HeapAlloc (heap
, flags
, size
);
1284 ERR ("Out of memory!\n");
1285 return ERROR_OUTOFMEMORY
;
1287 maxEntries
= numEntries
;
1290 table
= *ppTcpTable
;
1291 table
->dwNumEntries
= 0;
1295 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1297 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1299 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1300 return ERROR_OUTOFMEMORY
;
1303 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1306 ERR ("Out of memory!\n");
1307 return ERROR_OUTOFMEMORY
;
1310 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1312 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1313 HeapFree (GetProcessHeap (), 0, Buf
);
1314 return ERROR_OUTOFMEMORY
;
1317 /* Might be nothing here; first entry is just a header it seems */
1318 if (Len
<= sizeof (struct xinpgen
))
1320 HeapFree (GetProcessHeap (), 0, Buf
);
1324 pOrigXIG
= (struct xinpgen
*)Buf
;
1327 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1328 (pXIG
->xig_len
> sizeof (struct xinpgen
)) &&
1329 (table
->dwNumEntries
< maxEntries
);
1330 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1332 struct tcpcb
*pTCPData
= NULL
;
1333 struct inpcb
*pINData
;
1334 struct xsocket
*pSockData
;
1336 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1337 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1338 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1340 /* Ignore sockets for other protocols */
1341 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1344 /* Ignore PCBs that were freed while generating the data */
1345 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1348 /* we're only interested in IPv4 addresses */
1349 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1350 (pINData
->inp_vflag
& INP_IPV6
))
1353 /* If all 0's, skip it */
1354 if (!pINData
->inp_laddr
.s_addr
&&
1355 !pINData
->inp_lport
&&
1356 !pINData
->inp_faddr
.s_addr
&&
1357 !pINData
->inp_fport
)
1360 /* Fill in structure details */
1361 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1362 pINData
->inp_laddr
.s_addr
;
1363 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1365 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1366 pINData
->inp_faddr
.s_addr
;
1367 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1369 table
->table
[table
->dwNumEntries
].dwState
=
1370 TCPStateToMIBState (pTCPData
->t_state
);
1372 table
->dwNumEntries
++;
1375 HeapFree (GetProcessHeap (), 0, Buf
);
1377 /* get from /proc/net/tcp, no error if can't */
1378 fp
= fopen("/proc/net/tcp", "r");
1380 return ERROR_NOT_SUPPORTED
;
1382 /* skip header line */
1383 ptr
= fgets(buf
, sizeof(buf
), fp
);
1384 while (ptr
&& table
->dwNumEntries
< maxEntries
) {
1385 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_TCPROW
));
1386 ptr
= fgets(buf
, sizeof(buf
), fp
);
1390 while (ptr
&& *ptr
&& *ptr
!= ':')
1395 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1396 strtoul(ptr
, &endPtr
, 16);
1401 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1402 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1406 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1407 strtoul(ptr
, &endPtr
, 16);
1412 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1413 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1417 DWORD state
= strtoul(ptr
, &endPtr
, 16);
1419 table
->table
[table
->dwNumEntries
].dwState
=
1420 TCPStateToMIBState (state
);
1423 table
->dwNumEntries
++;