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_ROUTE_H
47 #include <net/route.h>
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/tcp.h>
55 #ifdef HAVE_NETINET_TCP_FSM_H
56 #include <netinet/tcp_fsm.h>
59 #ifdef HAVE_NETINET_IN_PCB_H
60 #include <netinet/in_pcb.h>
62 #ifdef HAVE_NETINET_TCP_VAR_H
63 #include <netinet/tcp_var.h>
65 #ifdef HAVE_NETINET_IP_VAR_H
66 #include <netinet/ip_var.h>
69 #ifdef HAVE_SYS_SYSCTL_H
70 #include <sys/sysctl.h>
75 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
78 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
87 #ifndef HAVE_NETINET_TCP_FSM_H
88 #define TCPS_ESTABLISHED 1
89 #define TCPS_SYN_SENT 2
90 #define TCPS_SYN_RECEIVED 3
91 #define TCPS_FIN_WAIT_1 4
92 #define TCPS_FIN_WAIT_2 5
93 #define TCPS_TIME_WAIT 6
95 #define TCPS_CLOSE_WAIT 8
96 #define TCPS_LAST_ACK 9
97 #define TCPS_LISTEN 10
98 #define TCPS_CLOSING 11
101 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
103 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
108 return ERROR_INVALID_PARAMETER
;
110 return ERROR_INVALID_PARAMETER
;
112 /* get interface stats from /proc/net/dev, no error if can't
113 no inUnknownProtos, outNUcastPkts, outQLen */
114 fp
= fopen("/proc/net/dev", "r");
116 char buf
[512] = { 0 }, *ptr
;
117 int nameLen
= strlen(name
), nameFound
= 0;
120 ptr
= fgets(buf
, sizeof(buf
), fp
);
121 while (ptr
&& !nameFound
) {
122 while (*ptr
&& isspace(*ptr
))
124 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
127 ptr
= fgets(buf
, sizeof(buf
), fp
);
134 entry
->dwInOctets
= strtoul(ptr
, &endPtr
, 10);
138 entry
->dwInUcastPkts
= strtoul(ptr
, &endPtr
, 10);
142 entry
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
146 entry
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
150 strtoul(ptr
, &endPtr
, 10); /* skip */
154 strtoul(ptr
, &endPtr
, 10); /* skip */
158 strtoul(ptr
, &endPtr
, 10); /* skip */
162 entry
->dwInNUcastPkts
= strtoul(ptr
, &endPtr
, 10);
166 entry
->dwOutOctets
= strtoul(ptr
, &endPtr
, 10);
170 entry
->dwOutUcastPkts
= strtoul(ptr
, &endPtr
, 10);
174 entry
->dwOutErrors
= strtoul(ptr
, &endPtr
, 10);
178 entry
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
185 ERR ("unimplemented!\n");
190 DWORD
getICMPStats(MIB_ICMP
*stats
)
195 return ERROR_INVALID_PARAMETER
;
197 memset(stats
, 0, sizeof(MIB_ICMP
));
198 /* get most of these stats from /proc/net/snmp, no error if can't */
199 fp
= fopen("/proc/net/snmp", "r");
201 static const char hdr
[] = "Icmp:";
202 char buf
[512] = { 0 }, *ptr
;
205 ptr
= fgets(buf
, sizeof(buf
), fp
);
206 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
208 /* last line was a header, get another */
209 ptr
= fgets(buf
, sizeof(buf
), fp
);
210 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
215 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
219 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
223 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
227 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
231 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
235 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
239 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
243 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
247 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
251 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
255 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
259 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
263 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
267 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
271 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
275 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
279 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
283 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
287 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
291 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
295 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
299 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
303 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
307 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
315 ERR ("unimplemented!\n");
320 DWORD
getIPStats(PMIB_IPSTATS stats
)
325 return ERROR_INVALID_PARAMETER
;
327 memset(stats
, 0, sizeof(MIB_IPSTATS
));
328 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
329 stats
->dwNumRoutes
= getNumRoutes();
331 /* get most of these stats from /proc/net/snmp, no error if can't */
332 fp
= fopen("/proc/net/snmp", "r");
334 static const char hdr
[] = "Ip:";
335 char buf
[512] = { 0 }, *ptr
;
338 ptr
= fgets(buf
, sizeof(buf
), fp
);
339 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
341 /* last line was a header, get another */
342 ptr
= fgets(buf
, sizeof(buf
), fp
);
343 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
348 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
352 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
356 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
360 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
364 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
368 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
372 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
376 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
380 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
384 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
388 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
392 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
396 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
400 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
404 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
408 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
412 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
416 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
420 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
423 /* hmm, no routingDiscards */
429 ERR ("unimplemented!\n");
434 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
439 return ERROR_INVALID_PARAMETER
;
441 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
443 /* get from /proc/net/snmp, no error if can't */
444 fp
= fopen("/proc/net/snmp", "r");
446 static const char hdr
[] = "Tcp:";
447 char buf
[512] = { 0 }, *ptr
;
451 ptr
= fgets(buf
, sizeof(buf
), fp
);
452 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
454 /* last line was a header, get another */
455 ptr
= fgets(buf
, sizeof(buf
), fp
);
456 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
461 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
465 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
469 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
473 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
477 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
481 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
485 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
489 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
493 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
497 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
501 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
505 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
509 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
513 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
516 stats
->dwNumConns
= getNumTcpEntries();
522 ERR ("unimplemented!\n");
527 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
532 return ERROR_INVALID_PARAMETER
;
534 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
536 /* get from /proc/net/snmp, no error if can't */
537 fp
= fopen("/proc/net/snmp", "r");
539 static const char hdr
[] = "Udp:";
540 char buf
[512] = { 0 }, *ptr
;
544 ptr
= fgets(buf
, sizeof(buf
), fp
);
545 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
547 /* last line was a header, get another */
548 ptr
= fgets(buf
, sizeof(buf
), fp
);
549 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
554 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
558 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
562 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
566 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
570 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
578 ERR ("unimplemented!\n");
583 static DWORD
getNumWithOneHeader(const char *filename
)
585 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
588 struct xinpgen
*pXIG
, *pOrigXIG
;
590 DWORD NumEntries
= 0;
592 if (!strcmp (filename
, "net.inet.tcp.pcblist"))
593 Protocol
= IPPROTO_TCP
;
594 else if (!strcmp (filename
, "net.inet.udp.pcblist"))
595 Protocol
= IPPROTO_UDP
;
598 ERR ("Unsupported mib '%s', needs protocol mapping\n",
603 if (sysctlbyname (filename
, NULL
, &Len
, NULL
, 0) < 0)
605 WARN ("Unable to read '%s' via sysctlbyname\n", filename
);
609 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
612 ERR ("Out of memory!\n");
616 if (sysctlbyname (filename
, Buf
, &Len
, NULL
, 0) < 0)
618 ERR ("Failure to read '%s' via sysctlbyname!\n", filename
);
619 HeapFree (GetProcessHeap (), 0, Buf
);
623 /* Might be nothing here; first entry is just a header it seems */
624 if (Len
<= sizeof (struct xinpgen
))
626 HeapFree (GetProcessHeap (), 0, Buf
);
630 pOrigXIG
= (struct xinpgen
*)Buf
;
633 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
634 pXIG
->xig_len
> sizeof (struct xinpgen
);
635 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
637 struct tcpcb
*pTCPData
= NULL
;
638 struct inpcb
*pINData
;
639 struct xsocket
*pSockData
;
641 if (Protocol
== IPPROTO_TCP
)
643 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
644 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
645 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
649 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
650 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
653 /* Ignore sockets for other protocols */
654 if (pSockData
->xso_protocol
!= Protocol
)
657 /* Ignore PCBs that were freed while generating the data */
658 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
661 /* we're only interested in IPv4 addresses */
662 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
663 (pINData
->inp_vflag
& INP_IPV6
))
666 /* If all 0's, skip it */
667 if (!pINData
->inp_laddr
.s_addr
&&
668 !pINData
->inp_lport
&&
669 !pINData
->inp_faddr
.s_addr
&&
676 HeapFree (GetProcessHeap (), 0, Buf
);
682 fp
= fopen(filename
, "r");
684 char buf
[512] = { 0 }, *ptr
;
687 ptr
= fgets(buf
, sizeof(buf
), fp
);
690 ptr
= fgets(buf
, sizeof(buf
), fp
);
698 ERR ("Unable to open '%s' to count entries!\n", filename
);
704 DWORD
getNumRoutes(void)
706 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
707 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
709 char *buf
, *lim
, *next
;
710 struct rt_msghdr
*rtm
;
711 DWORD RouteCount
= 0;
713 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
715 ERR ("sysctl 1 failed!\n");
719 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
722 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
724 ERR ("sysctl 2 failed!\n");
725 HeapFree (GetProcessHeap (), 0, buf
);
730 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
732 rtm
= (struct rt_msghdr
*)next
;
734 if (rtm
->rtm_type
!= RTM_GET
)
736 WARN ("Got unexpected message type 0x%x!\n",
741 /* Ignore all entries except for gateway routes which aren't
743 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) || (rtm
->rtm_flags
& RTF_MULTICAST
))
749 HeapFree (GetProcessHeap (), 0, buf
);
752 return getNumWithOneHeader("/proc/net/route");
756 DWORD
getRouteTable(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, HANDLE heap
,
761 if (!ppIpForwardTable
)
762 ret
= ERROR_INVALID_PARAMETER
;
764 DWORD numRoutes
= getNumRoutes();
765 PMIB_IPFORWARDTABLE table
= HeapAlloc(heap
, flags
,
766 sizeof(MIB_IPFORWARDTABLE
) + (numRoutes
- 1) * sizeof(MIB_IPFORWARDROW
));
769 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
770 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
772 char *buf
, *lim
, *next
, *addrPtr
;
773 struct rt_msghdr
*rtm
;
775 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
777 ERR ("sysctl 1 failed!\n");
778 HeapFree (GetProcessHeap (), 0, table
);
782 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
785 HeapFree (GetProcessHeap (), 0, table
);
786 return ERROR_OUTOFMEMORY
;
789 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
791 ERR ("sysctl 2 failed!\n");
792 HeapFree (GetProcessHeap (), 0, table
);
793 HeapFree (GetProcessHeap (), 0, buf
);
797 *ppIpForwardTable
= table
;
798 table
->dwNumEntries
= 0;
801 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
805 rtm
= (struct rt_msghdr
*)next
;
807 if (rtm
->rtm_type
!= RTM_GET
)
809 WARN ("Got unexpected message type 0x%x!\n",
814 /* Ignore all entries except for gateway routes which aren't
816 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
817 (rtm
->rtm_flags
& RTF_MULTICAST
))
820 memset (&table
->table
[table
->dwNumEntries
], 0,
821 sizeof (MIB_IPFORWARDROW
));
822 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= rtm
->rtm_index
;
823 table
->table
[table
->dwNumEntries
].dwForwardType
=
824 MIB_IPROUTE_TYPE_INDIRECT
;
825 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
826 rtm
->rtm_rmx
.rmx_hopcount
;
827 table
->table
[table
->dwNumEntries
].dwForwardProto
=
830 addrPtr
= (char *)(rtm
+ 1);
832 for (i
= 1; i
; i
<<= 1)
837 if (!(i
& rtm
->rtm_addrs
))
840 sa
= (struct sockaddr
*)addrPtr
;
841 ADVANCE (addrPtr
, sa
);
843 /* default routes are encoded by length-zero sockaddr */
846 else if (sa
->sa_family
!= AF_INET
)
848 ERR ("Received unsupported sockaddr family 0x%x\n",
854 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
856 addr
= sin
->sin_addr
.s_addr
;
862 table
->table
[table
->dwNumEntries
].dwForwardDest
= addr
;
866 table
->table
[table
->dwNumEntries
].dwForwardNextHop
= addr
;
870 table
->table
[table
->dwNumEntries
].dwForwardMask
= addr
;
874 ERR ("Unexpected address type 0x%x\n", i
);
878 table
->dwNumEntries
++;
881 HeapFree (GetProcessHeap (), 0, buf
);
887 *ppIpForwardTable
= table
;
888 table
->dwNumEntries
= 0;
889 /* get from /proc/net/route, no error if can't */
890 fp
= fopen("/proc/net/route", "r");
892 char buf
[512] = { 0 }, *ptr
;
894 /* skip header line */
895 ptr
= fgets(buf
, sizeof(buf
), fp
);
896 while (ptr
&& table
->dwNumEntries
< numRoutes
) {
897 memset(&table
->table
[table
->dwNumEntries
], 0,
898 sizeof(MIB_IPFORWARDROW
));
899 ptr
= fgets(buf
, sizeof(buf
), fp
);
903 while (!isspace(*ptr
))
907 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
910 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= index
;
912 table
->table
[table
->dwNumEntries
].dwForwardDest
=
913 strtoul(ptr
, &endPtr
, 16);
917 table
->table
[table
->dwNumEntries
].dwForwardNextHop
=
918 strtoul(ptr
, &endPtr
, 16);
922 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
924 if (!(flags
& RTF_UP
))
925 table
->table
[table
->dwNumEntries
].dwForwardType
=
926 MIB_IPROUTE_TYPE_INVALID
;
927 else if (flags
& RTF_GATEWAY
)
928 table
->table
[table
->dwNumEntries
].dwForwardType
=
929 MIB_IPROUTE_TYPE_INDIRECT
;
931 table
->table
[table
->dwNumEntries
].dwForwardType
=
932 MIB_IPROUTE_TYPE_DIRECT
;
936 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
940 strtoul(ptr
, &endPtr
, 16); /* use, skip */
944 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
945 strtoul(ptr
, &endPtr
, 16);
949 table
->table
[table
->dwNumEntries
].dwForwardMask
=
950 strtoul(ptr
, &endPtr
, 16);
953 /* FIXME: other protos might be appropriate, e.g. the default
954 * route is typically set with MIB_IPPROTO_NETMGMT instead */
955 table
->table
[table
->dwNumEntries
].dwForwardProto
=
957 table
->dwNumEntries
++;
965 ERR ("unimplemented!\n");
966 return ERROR_INVALID_PARAMETER
;
971 ret
= ERROR_OUTOFMEMORY
;
976 DWORD
getNumArpEntries(void)
978 return getNumWithOneHeader("/proc/net/arp");
981 DWORD
getArpTable(PMIB_IPNETTABLE
*ppIpNetTable
, HANDLE heap
, DWORD flags
)
985 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
986 ERR ("unimplemented!\n");
987 return ERROR_INVALID_PARAMETER
;
991 ret
= ERROR_INVALID_PARAMETER
;
993 DWORD numEntries
= getNumArpEntries();
994 PMIB_IPNETTABLE table
= HeapAlloc(heap
, flags
,
995 sizeof(MIB_IPNETTABLE
) + (numEntries
- 1) * sizeof(MIB_IPNETROW
));
1001 *ppIpNetTable
= table
;
1002 table
->dwNumEntries
= 0;
1003 /* get from /proc/net/arp, no error if can't */
1004 fp
= fopen("/proc/net/arp", "r");
1006 char buf
[512] = { 0 }, *ptr
;
1008 /* skip header line */
1009 ptr
= fgets(buf
, sizeof(buf
), fp
);
1010 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1011 ptr
= fgets(buf
, sizeof(buf
), fp
);
1015 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1016 table
->table
[table
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
1017 while (ptr
&& *ptr
&& !isspace(*ptr
))
1021 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
1025 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1028 if (flags
& ATF_COM
)
1029 table
->table
[table
->dwNumEntries
].dwType
=
1030 MIB_IPNET_TYPE_DYNAMIC
;
1034 if (flags
& ATF_PERM
)
1035 table
->table
[table
->dwNumEntries
].dwType
=
1036 MIB_IPNET_TYPE_STATIC
;
1039 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1043 while (ptr
&& *ptr
&& isspace(*ptr
))
1045 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
1046 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
1048 if (endPtr
&& *endPtr
) {
1050 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1051 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1057 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
1060 getInterfaceIndexByName(ptr
,
1061 &table
->table
[table
->dwNumEntries
].dwIndex
);
1062 table
->dwNumEntries
++;
1069 ret
= ERROR_OUTOFMEMORY
;
1074 DWORD
getNumUdpEntries(void)
1076 return getNumWithOneHeader("/proc/net/udp");
1079 DWORD
getUdpTable(PMIB_UDPTABLE
*ppUdpTable
, HANDLE heap
, DWORD flags
)
1083 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1084 ERR ("unimplemented!\n");
1085 return ERROR_INVALID_PARAMETER
;
1089 ret
= ERROR_INVALID_PARAMETER
;
1091 DWORD numEntries
= getNumUdpEntries();
1092 PMIB_UDPTABLE table
= HeapAlloc(heap
, flags
,
1093 sizeof(MIB_UDPTABLE
) + (numEntries
- 1) * sizeof(MIB_UDPROW
));
1099 *ppUdpTable
= table
;
1100 table
->dwNumEntries
= 0;
1101 /* get from /proc/net/udp, no error if can't */
1102 fp
= fopen("/proc/net/udp", "r");
1104 char buf
[512] = { 0 }, *ptr
;
1106 /* skip header line */
1107 ptr
= fgets(buf
, sizeof(buf
), fp
);
1108 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1109 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_UDPROW
));
1110 ptr
= fgets(buf
, sizeof(buf
), fp
);
1115 strtoul(ptr
, &endPtr
, 16); /* skip */
1120 table
->table
[table
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
,
1126 table
->table
[table
->dwNumEntries
].dwLocalPort
= strtoul(ptr
,
1130 table
->dwNumEntries
++;
1137 ret
= ERROR_OUTOFMEMORY
;
1143 DWORD
getNumTcpEntries(void)
1145 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1146 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1148 return getNumWithOneHeader ("/proc/net/tcp");
1153 /* Why not a lookup table? Because the TCPS_* constants are different
1154 on different platforms */
1155 static DWORD
TCPStateToMIBState (int state
)
1159 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1160 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1161 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1162 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1163 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1164 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1165 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1166 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1167 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1168 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1170 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1175 DWORD
getTcpTable(PMIB_TCPTABLE
*ppTcpTable
, DWORD maxEntries
, HANDLE heap
,
1179 PMIB_TCPTABLE table
;
1180 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1183 struct xinpgen
*pXIG
, *pOrigXIG
;
1186 char buf
[512] = { 0 }, *ptr
;
1190 return ERROR_INVALID_PARAMETER
;
1192 numEntries
= getNumTcpEntries ();
1196 *ppTcpTable
= HeapAlloc (heap
, flags
,
1197 sizeof (MIB_TCPTABLE
) +
1198 (numEntries
- 1) * sizeof (MIB_TCPROW
));
1201 ERR ("Out of memory!\n");
1202 return ERROR_OUTOFMEMORY
;
1204 maxEntries
= numEntries
;
1207 table
= *ppTcpTable
;
1208 table
->dwNumEntries
= 0;
1212 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1214 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1216 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1217 return ERROR_OUTOFMEMORY
;
1220 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1223 ERR ("Out of memory!\n");
1224 return ERROR_OUTOFMEMORY
;
1227 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1229 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1230 HeapFree (GetProcessHeap (), 0, Buf
);
1231 return ERROR_OUTOFMEMORY
;
1234 /* Might be nothing here; first entry is just a header it seems */
1235 if (Len
<= sizeof (struct xinpgen
))
1237 HeapFree (GetProcessHeap (), 0, Buf
);
1241 pOrigXIG
= (struct xinpgen
*)Buf
;
1244 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1245 (pXIG
->xig_len
> sizeof (struct xinpgen
)) &&
1246 (table
->dwNumEntries
< maxEntries
);
1247 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1249 struct tcpcb
*pTCPData
= NULL
;
1250 struct inpcb
*pINData
;
1251 struct xsocket
*pSockData
;
1253 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1254 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1255 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1257 /* Ignore sockets for other protocols */
1258 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1261 /* Ignore PCBs that were freed while generating the data */
1262 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1265 /* we're only interested in IPv4 addresses */
1266 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1267 (pINData
->inp_vflag
& INP_IPV6
))
1270 /* If all 0's, skip it */
1271 if (!pINData
->inp_laddr
.s_addr
&&
1272 !pINData
->inp_lport
&&
1273 !pINData
->inp_faddr
.s_addr
&&
1274 !pINData
->inp_fport
)
1277 /* Fill in structure details */
1278 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1279 pINData
->inp_laddr
.s_addr
;
1280 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1282 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1283 pINData
->inp_faddr
.s_addr
;
1284 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1286 table
->table
[table
->dwNumEntries
].dwState
=
1287 TCPStateToMIBState (pTCPData
->t_state
);
1289 table
->dwNumEntries
++;
1292 HeapFree (GetProcessHeap (), 0, Buf
);
1294 /* get from /proc/net/tcp, no error if can't */
1295 fp
= fopen("/proc/net/tcp", "r");
1299 /* skip header line */
1300 ptr
= fgets(buf
, sizeof(buf
), fp
);
1301 while (ptr
&& table
->dwNumEntries
< maxEntries
) {
1302 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_TCPROW
));
1303 ptr
= fgets(buf
, sizeof(buf
), fp
);
1307 while (ptr
&& *ptr
&& *ptr
!= ':')
1312 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1313 strtoul(ptr
, &endPtr
, 16);
1318 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1319 strtoul(ptr
, &endPtr
, 16);
1323 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1324 strtoul(ptr
, &endPtr
, 16);
1329 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1330 strtoul(ptr
, &endPtr
, 16);
1334 DWORD state
= strtoul(ptr
, &endPtr
, 16);
1336 table
->table
[table
->dwNumEntries
].dwState
=
1337 TCPStateToMIBState (state
);
1340 table
->dwNumEntries
++;