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>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
37 #ifdef HAVE_SYS_SOCKETVAR_H
38 #include <sys/socketvar.h>
40 #ifdef HAVE_SYS_TIMEOUT_H
41 #include <sys/timeout.h>
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
46 #ifdef HAVE_ARPA_INET_H
47 #include <arpa/inet.h>
52 #ifdef HAVE_NET_IF_DL_H
53 #include <net/if_dl.h>
55 #ifdef HAVE_NET_IF_TYPES_H
56 #include <net/if_types.h>
58 #ifdef HAVE_NET_ROUTE_H
59 #include <net/route.h>
61 #ifdef HAVE_NET_IF_ARP_H
62 #include <net/if_arp.h>
64 #ifdef HAVE_NETINET_IF_ETHER_H
65 #include <netinet/if_ether.h>
67 #ifdef HAVE_NETINET_IF_INARP_H
68 #include <netinet/if_inarp.h>
70 #ifdef HAVE_NETINET_IP_H
71 #include <netinet/ip.h>
73 #ifdef HAVE_NETINET_TCP_H
74 #include <netinet/tcp.h>
76 #ifdef HAVE_NETINET_IP_VAR_H
77 #include <netinet/ip_var.h>
79 #ifdef HAVE_NETINET_TCP_FSM_H
80 #include <netinet/tcp_fsm.h>
82 #ifdef HAVE_NETINET_IN_PCB_H
83 #include <netinet/in_pcb.h>
85 #ifdef HAVE_NETINET_TCP_TIMER_H
86 #include <netinet/tcp_timer.h>
88 #ifdef HAVE_NETINET_TCP_VAR_H
89 #include <netinet/tcp_var.h>
91 #ifdef HAVE_NETINET_IN_SYSTM_H
92 #include <netinet/in_systm.h>
94 #ifdef HAVE_NETINET_IP_ICMP_H
95 #include <netinet/ip_icmp.h>
97 #ifdef HAVE_NETINET_ICMP_VAR_H
98 #include <netinet/icmp_var.h>
100 #ifdef HAVE_NETINET_UDP_H
101 #include <netinet/udp.h>
103 #ifdef HAVE_NETINET_UDP_VAR_H
104 #include <netinet/udp_var.h>
106 #ifdef HAVE_SYS_PROTOSW_H
107 #include <sys/protosw.h>
109 #ifdef HAVE_SYS_SYSCTL_H
110 #include <sys/sysctl.h>
115 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
118 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
123 #include "iprtrmib.h"
127 #ifndef HAVE_NETINET_TCP_FSM_H
128 #define TCPS_ESTABLISHED 1
129 #define TCPS_SYN_SENT 2
130 #define TCPS_SYN_RECEIVED 3
131 #define TCPS_FIN_WAIT_1 4
132 #define TCPS_FIN_WAIT_2 5
133 #define TCPS_TIME_WAIT 6
134 #define TCPS_CLOSED 7
135 #define TCPS_CLOSE_WAIT 8
136 #define TCPS_LAST_ACK 9
137 #define TCPS_LISTEN 10
138 #define TCPS_CLOSING 11
141 #ifndef RTF_MULTICAST
142 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
145 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
147 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
149 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
150 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
151 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
155 struct if_msghdr *ifm;
156 struct if_data ifdata;
158 return ERROR_INVALID_PARAMETER;
160 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
162 ERR ("failed to get size of iflist\n");
163 return ERROR_NOT_SUPPORTED;
165 buf = HeapAlloc (GetProcessHeap (), 0, needed);
166 if (!buf) return ERROR_NOT_SUPPORTED;
167 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
169 ERR ("failed to get iflist\n");
170 HeapFree (GetProcessHeap (), 0, buf);
171 return ERROR_NOT_SUPPORTED;
174 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
176 ifm = (struct if_msghdr *) buf;
177 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
179 ifdata = ifm->ifm_data;
180 entry->dwMtu = ifdata.ifi_mtu;
181 entry->dwSpeed = ifdata.ifi_baudrate;
182 entry->dwInOctets = ifdata.ifi_ibytes;
183 entry->dwInErrors = ifdata.ifi_ierrors;
184 entry->dwInDiscards = ifdata.ifi_iqdrops;
185 entry->dwInUcastPkts = ifdata.ifi_ipackets;
186 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
187 entry->dwOutOctets = ifdata.ifi_obytes;
188 entry->dwOutUcastPkts = ifdata.ifi_opackets;
189 entry->dwOutErrors = ifdata.ifi_oerrors;
190 HeapFree (GetProcessHeap (), 0, buf);
194 HeapFree (GetProcessHeap (), 0, buf);
195 return ERROR_NOT_SUPPORTED;
197 /* get interface stats from /proc/net/dev, no error if can't
198 no inUnknownProtos, outNUcastPkts, outQLen */
202 return ERROR_INVALID_PARAMETER;
203 fp = fopen("/proc/net/dev", "r");
205 char buf[512] = { 0 }, *ptr;
206 int nameLen = strlen(name), nameFound = 0;
209 ptr = fgets(buf, sizeof(buf), fp);
210 while (ptr && !nameFound) {
211 while (*ptr && isspace(*ptr))
213 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
216 ptr = fgets(buf, sizeof(buf), fp);
223 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
227 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
231 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
235 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
239 strtoul(ptr, &endPtr, 10); /* skip */
243 strtoul(ptr, &endPtr, 10); /* skip */
247 strtoul(ptr, &endPtr, 10); /* skip */
251 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
255 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
259 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
263 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
267 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
275 ERR ("unimplemented!\n");
276 return ERROR_NOT_SUPPORTED;
283 DWORD getICMPStats(MIB_ICMP *stats)
285 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
286 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
287 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
289 struct icmpstat icmp_stat;
293 return ERROR_INVALID_PARAMETER;
295 needed = sizeof(icmp_stat);
296 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
298 ERR ("failed to get icmpstat\n");
299 return ERROR_NOT_SUPPORTED;
304 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
305 for(i = 0; i <= ICMP_MAXTYPE; i++)
306 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
308 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
310 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
311 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
312 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
313 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
314 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
315 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
316 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
317 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
318 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
319 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
320 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
324 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
325 for(i = 0; i <= ICMP_MAXTYPE; i++)
326 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
328 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
330 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
331 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
332 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
333 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
334 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
335 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
336 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
337 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
338 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
339 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
340 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
347 return ERROR_INVALID_PARAMETER;
349 memset(stats, 0, sizeof(MIB_ICMP));
350 /* get most of these stats from /proc/net/snmp, no error if can't */
351 fp = fopen("/proc/net/snmp", "r");
353 static const char hdr[] = "Icmp:";
354 char buf[512] = { 0 }, *ptr;
357 ptr = fgets(buf, sizeof(buf), fp);
358 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
360 /* last line was a header, get another */
361 ptr = fgets(buf, sizeof(buf), fp);
362 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
367 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
371 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
375 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
379 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
383 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
387 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
391 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
395 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
399 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
403 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
407 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
411 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
415 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
419 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
423 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
427 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
431 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
435 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
439 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
443 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
447 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
451 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
455 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
459 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
468 ERR ("unimplemented!\n");
469 return ERROR_NOT_SUPPORTED;
476 DWORD getIPStats(PMIB_IPSTATS stats)
478 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
479 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
480 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
481 int ip_ttl, ip_forwarding;
482 struct ipstat ip_stat;
486 return ERROR_INVALID_PARAMETER;
488 needed = sizeof(ip_stat);
489 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
491 ERR ("failed to get ipstat\n");
492 return ERROR_NOT_SUPPORTED;
495 needed = sizeof(ip_ttl);
496 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
498 ERR ("failed to get ip Default TTL\n");
499 return ERROR_NOT_SUPPORTED;
502 needed = sizeof(ip_forwarding);
503 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
505 ERR ("failed to get ip forwarding\n");
506 return ERROR_NOT_SUPPORTED;
509 stats->dwForwarding = ip_forwarding;
510 stats->dwDefaultTTL = ip_ttl;
511 stats->dwInDelivers = ip_stat.ips_delivered;
512 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
513 stats->dwInAddrErrors = ip_stat.ips_cantforward;
514 stats->dwInReceives = ip_stat.ips_total;
515 stats->dwForwDatagrams = ip_stat.ips_forward;
516 stats->dwInUnknownProtos = ip_stat.ips_noproto;
517 stats->dwInDiscards = ip_stat.ips_fragdropped;
518 stats->dwOutDiscards = ip_stat.ips_odropped;
519 stats->dwReasmOks = ip_stat.ips_reassembled;
520 stats->dwFragOks = ip_stat.ips_fragmented;
521 stats->dwFragFails = ip_stat.ips_cantfrag;
522 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
523 stats->dwOutNoRoutes = ip_stat.ips_noroute;
524 stats->dwOutRequests = ip_stat.ips_localout;
525 stats->dwReasmReqds = ip_stat.ips_fragments;
532 return ERROR_INVALID_PARAMETER;
534 memset(stats, 0, sizeof(MIB_IPSTATS));
535 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
536 stats->dwNumRoutes = getNumRoutes();
538 /* get most of these stats from /proc/net/snmp, no error if can't */
539 fp = fopen("/proc/net/snmp", "r");
541 static const char hdr[] = "Ip:";
542 char buf[512] = { 0 }, *ptr;
545 ptr = fgets(buf, sizeof(buf), fp);
546 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
548 /* last line was a header, get another */
549 ptr = fgets(buf, sizeof(buf), fp);
550 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
555 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
559 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
563 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
567 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
571 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
575 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
579 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
583 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
587 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
591 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
595 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
599 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
603 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
607 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
611 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
615 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
619 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
623 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
627 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
630 /* hmm, no routingDiscards */
637 ERR ("unimplemented!\n");
638 return ERROR_NOT_SUPPORTED;
645 DWORD getTCPStats(MIB_TCPSTATS *stats)
647 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
648 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
650 #define TCPTV_REXMTMAX 128
652 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
653 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
655 struct tcpstat tcp_stat;
659 return ERROR_INVALID_PARAMETER;
660 needed = sizeof(tcp_stat);
662 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
664 ERR ("failed to get tcpstat\n");
665 return ERROR_NOT_SUPPORTED;
668 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
669 stats->dwRtoMin = TCPTV_MIN;
670 stats->dwRtoMax = TCPTV_REXMTMAX;
671 stats->dwMaxConn = -1;
672 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
673 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
674 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
675 stats->dwEstabResets = tcp_stat.tcps_drops;
676 stats->dwCurrEstab = 0;
677 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
678 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
679 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
680 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
681 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
682 stats->dwNumConns = tcp_stat.tcps_connects;
690 return ERROR_INVALID_PARAMETER;
692 memset(stats, 0, sizeof(MIB_TCPSTATS));
694 /* get from /proc/net/snmp, no error if can't */
695 fp = fopen("/proc/net/snmp", "r");
697 static const char hdr[] = "Tcp:";
698 char buf[512] = { 0 }, *ptr;
702 ptr = fgets(buf, sizeof(buf), fp);
703 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
705 /* last line was a header, get another */
706 ptr = fgets(buf, sizeof(buf), fp);
707 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
712 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
716 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
720 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
724 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
728 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
732 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
736 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
740 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
744 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
748 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
752 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
756 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
760 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
764 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
767 stats->dwNumConns = getNumTcpEntries();
774 ERR ("unimplemented!\n");
775 return ERROR_NOT_SUPPORTED;
782 DWORD getUDPStats(MIB_UDPSTATS *stats)
784 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
785 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
786 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
787 struct udpstat udp_stat;
790 return ERROR_INVALID_PARAMETER;
792 needed = sizeof(udp_stat);
794 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
796 ERR ("failed to get udpstat\n");
797 return ERROR_NOT_SUPPORTED;
800 stats->dwInDatagrams = udp_stat.udps_ipackets;
801 stats->dwOutDatagrams = udp_stat.udps_opackets;
802 stats->dwNoPorts = udp_stat.udps_noport;
803 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
804 stats->dwNumAddrs = getNumUdpEntries();
811 return ERROR_INVALID_PARAMETER;
813 memset(stats, 0, sizeof(MIB_UDPSTATS));
815 /* get from /proc/net/snmp, no error if can't */
816 fp = fopen("/proc/net/snmp", "r");
818 static const char hdr[] = "Udp:";
819 char buf[512] = { 0 }, *ptr;
823 ptr = fgets(buf, sizeof(buf), fp);
824 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
826 /* last line was a header, get another */
827 ptr = fgets(buf, sizeof(buf), fp);
828 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
833 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
837 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
841 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
845 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
849 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
858 ERR ("unimplemented!\n");
859 return ERROR_NOT_SUPPORTED;
866 static DWORD getNumWithOneHeader(const char *filename)
868 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
871 struct xinpgen *pXIG, *pOrigXIG;
873 DWORD NumEntries = 0;
875 if (!strcmp (filename, "net.inet.tcp.pcblist"))
876 Protocol = IPPROTO_TCP;
877 else if (!strcmp (filename, "net.inet.udp.pcblist"))
878 Protocol = IPPROTO_UDP;
881 ERR ("Unsupported mib '%s', needs protocol mapping\n",
886 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
888 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
892 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
895 ERR ("Out of memory!\n");
899 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
901 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
902 HeapFree (GetProcessHeap (), 0, Buf);
906 /* Might be nothing here; first entry is just a header it seems */
907 if (Len <= sizeof (struct xinpgen))
909 HeapFree (GetProcessHeap (), 0, Buf);
913 pOrigXIG = (struct xinpgen *)Buf;
916 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
917 pXIG->xig_len > sizeof (struct xinpgen);
918 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
920 struct tcpcb *pTCPData = NULL;
921 struct inpcb *pINData;
922 struct xsocket *pSockData;
924 if (Protocol == IPPROTO_TCP)
926 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
927 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
928 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
932 pINData = &((struct xinpcb *)pXIG)->xi_inp;
933 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
936 /* Ignore sockets for other protocols */
937 if (pSockData->xso_protocol != Protocol)
940 /* Ignore PCBs that were freed while generating the data */
941 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
944 /* we're only interested in IPv4 addresses */
945 if (!(pINData->inp_vflag & INP_IPV4) ||
946 (pINData->inp_vflag & INP_IPV6))
949 /* If all 0's, skip it */
950 if (!pINData->inp_laddr.s_addr &&
951 !pINData->inp_lport &&
952 !pINData->inp_faddr.s_addr &&
959 HeapFree (GetProcessHeap (), 0, Buf);
965 fp = fopen(filename, "r");
967 char buf[512] = { 0 }, *ptr;
970 ptr = fgets(buf, sizeof(buf), fp);
973 ptr = fgets(buf, sizeof(buf), fp);
981 ERR ("Unable to open '%s' to count entries!\n", filename);
987 DWORD getNumRoutes(void)
989 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
990 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
992 char *buf, *lim, *next;
993 struct rt_msghdr *rtm;
994 DWORD RouteCount = 0;
996 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
998 ERR ("sysctl 1 failed!\n");
1002 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1005 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1007 ERR ("sysctl 2 failed!\n");
1008 HeapFree (GetProcessHeap (), 0, buf);
1013 for (next = buf; next < lim; next += rtm->rtm_msglen)
1015 rtm = (struct rt_msghdr *)next;
1017 if (rtm->rtm_type != RTM_GET)
1019 WARN ("Got unexpected message type 0x%x!\n",
1024 /* Ignore all entries except for gateway routes which aren't
1026 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1032 HeapFree (GetProcessHeap (), 0, buf);
1035 return getNumWithOneHeader("/proc/net/route");
1039 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1044 if (!ppIpForwardTable)
1045 ret = ERROR_INVALID_PARAMETER;
1047 DWORD numRoutes = getNumRoutes();
1048 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1049 PMIB_IPFORWARDTABLE table;
1052 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1053 table = HeapAlloc(heap, flags, size);
1055 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1056 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1058 char *buf, *lim, *next, *addrPtr;
1059 struct rt_msghdr *rtm;
1061 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1063 ERR ("sysctl 1 failed!\n");
1064 HeapFree (GetProcessHeap (), 0, table);
1068 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1071 HeapFree (GetProcessHeap (), 0, table);
1072 return ERROR_OUTOFMEMORY;
1075 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1077 ERR ("sysctl 2 failed!\n");
1078 HeapFree (GetProcessHeap (), 0, table);
1079 HeapFree (GetProcessHeap (), 0, buf);
1083 *ppIpForwardTable = table;
1084 table->dwNumEntries = 0;
1087 for (next = buf; next < lim; next += rtm->rtm_msglen)
1091 rtm = (struct rt_msghdr *)next;
1093 if (rtm->rtm_type != RTM_GET)
1095 WARN ("Got unexpected message type 0x%x!\n",
1100 /* Ignore all entries except for gateway routes which aren't
1102 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1103 (rtm->rtm_flags & RTF_MULTICAST))
1106 memset (&table->table[table->dwNumEntries], 0,
1107 sizeof (MIB_IPFORWARDROW));
1108 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1109 table->table[table->dwNumEntries].dwForwardType =
1110 MIB_IPROUTE_TYPE_INDIRECT;
1111 table->table[table->dwNumEntries].dwForwardMetric1 =
1112 rtm->rtm_rmx.rmx_hopcount;
1113 table->table[table->dwNumEntries].dwForwardProto =
1116 addrPtr = (char *)(rtm + 1);
1118 for (i = 1; i; i <<= 1)
1120 struct sockaddr *sa;
1123 if (!(i & rtm->rtm_addrs))
1126 sa = (struct sockaddr *)addrPtr;
1127 ADVANCE (addrPtr, sa);
1129 /* default routes are encoded by length-zero sockaddr */
1130 if (sa->sa_len == 0)
1132 else if (sa->sa_family != AF_INET)
1134 WARN ("Received unsupported sockaddr family 0x%x\n",
1140 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1142 addr = sin->sin_addr.s_addr;
1148 table->table[table->dwNumEntries].dwForwardDest = addr;
1152 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1156 table->table[table->dwNumEntries].dwForwardMask = addr;
1160 WARN ("Unexpected address type 0x%x\n", i);
1164 table->dwNumEntries++;
1167 HeapFree (GetProcessHeap (), 0, buf);
1173 *ppIpForwardTable = table;
1174 table->dwNumEntries = 0;
1175 /* get from /proc/net/route, no error if can't */
1176 fp = fopen("/proc/net/route", "r");
1178 char buf[512] = { 0 }, *ptr;
1180 /* skip header line */
1181 ptr = fgets(buf, sizeof(buf), fp);
1182 while (ptr && table->dwNumEntries < numRoutes) {
1183 memset(&table->table[table->dwNumEntries], 0,
1184 sizeof(MIB_IPFORWARDROW));
1185 ptr = fgets(buf, sizeof(buf), fp);
1189 while (!isspace(*ptr))
1193 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1196 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1198 table->table[table->dwNumEntries].dwForwardDest =
1199 strtoul(ptr, &endPtr, 16);
1203 table->table[table->dwNumEntries].dwForwardNextHop =
1204 strtoul(ptr, &endPtr, 16);
1208 DWORD flags = strtoul(ptr, &endPtr, 16);
1210 if (!(flags & RTF_UP))
1211 table->table[table->dwNumEntries].dwForwardType =
1212 MIB_IPROUTE_TYPE_INVALID;
1213 else if (flags & RTF_GATEWAY)
1214 table->table[table->dwNumEntries].dwForwardType =
1215 MIB_IPROUTE_TYPE_INDIRECT;
1217 table->table[table->dwNumEntries].dwForwardType =
1218 MIB_IPROUTE_TYPE_DIRECT;
1222 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1226 strtoul(ptr, &endPtr, 16); /* use, skip */
1230 table->table[table->dwNumEntries].dwForwardMetric1 =
1231 strtoul(ptr, &endPtr, 16);
1235 table->table[table->dwNumEntries].dwForwardMask =
1236 strtoul(ptr, &endPtr, 16);
1239 /* FIXME: other protos might be appropriate, e.g. the default
1240 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1241 table->table[table->dwNumEntries].dwForwardProto =
1243 table->dwNumEntries++;
1251 ERR ("unimplemented!\n");
1252 return ERROR_NOT_SUPPORTED;
1257 ret = ERROR_OUTOFMEMORY;
1262 DWORD getNumArpEntries(void)
1264 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1265 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1266 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1267 DWORD arpEntries = 0;
1269 char *buf, *lim, *next;
1270 struct rt_msghdr *rtm;
1271 struct sockaddr_inarp *sinarp;
1272 struct sockaddr_dl *sdl;
1274 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1276 ERR ("failed to get size of arp table\n");
1280 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1283 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1285 ERR ("failed to get arp table\n");
1286 HeapFree (GetProcessHeap (), 0, buf);
1294 rtm = (struct rt_msghdr *)next;
1295 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1296 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1297 if(sdl->sdl_alen) /* arp entry */
1299 next += rtm->rtm_msglen;
1301 HeapFree (GetProcessHeap (), 0, buf);
1304 return getNumWithOneHeader("/proc/net/arp");
1307 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1309 DWORD ret = NO_ERROR;
1311 ret = ERROR_INVALID_PARAMETER;
1313 DWORD numEntries = getNumArpEntries();
1314 DWORD size = sizeof(MIB_IPNETTABLE);
1315 PMIB_IPNETTABLE table;
1318 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1319 table = HeapAlloc(heap, flags, size);
1320 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1323 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1324 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1326 char *buf, *lim, *next;
1327 struct rt_msghdr *rtm;
1328 struct sockaddr_inarp *sinarp;
1329 struct sockaddr_dl *sdl;
1331 *ppIpNetTable = table;
1332 table->dwNumEntries = 0;
1334 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1336 ERR ("failed to get size of arp table\n");
1337 return ERROR_NOT_SUPPORTED;
1340 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1341 if (!buf) return ERROR_OUTOFMEMORY;
1343 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1345 ERR ("failed to get arp table\n");
1346 HeapFree (GetProcessHeap (), 0, buf);
1347 return ERROR_NOT_SUPPORTED;
1354 rtm = (struct rt_msghdr *)next;
1355 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1356 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1357 if(sdl->sdl_alen) /* arp entry */
1359 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1360 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1361 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1362 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1363 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1365 table->table[table->dwNumEntries].bPhysAddr[
1366 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1368 if(rtm->rtm_rmx.rmx_expire == 0)
1369 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1370 else if(sinarp->sin_other & SIN_PROXY)
1371 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1372 else if(rtm->rtm_rmx.rmx_expire != 0)
1373 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1375 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1377 table->dwNumEntries++;
1379 next += rtm->rtm_msglen;
1381 HeapFree (GetProcessHeap (), 0, buf);
1384 ret = ERROR_OUTOFMEMORY;
1390 *ppIpNetTable = table;
1391 table->dwNumEntries = 0;
1392 /* get from /proc/net/arp, no error if can't */
1393 fp = fopen("/proc/net/arp", "r");
1395 char buf[512] = { 0 }, *ptr;
1397 /* skip header line */
1398 ptr = fgets(buf, sizeof(buf), fp);
1399 while (ptr && table->dwNumEntries < numEntries) {
1400 ptr = fgets(buf, sizeof(buf), fp);
1404 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1405 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1406 while (ptr && *ptr && !isspace(*ptr))
1410 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1414 DWORD flags = strtoul(ptr, &endPtr, 16);
1417 if (flags & ATF_COM)
1418 table->table[table->dwNumEntries].dwType =
1419 MIB_IPNET_TYPE_DYNAMIC;
1423 if (flags & ATF_PERM)
1424 table->table[table->dwNumEntries].dwType =
1425 MIB_IPNET_TYPE_STATIC;
1428 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1432 while (ptr && *ptr && isspace(*ptr))
1434 while (ptr && *ptr && !isspace(*ptr)) {
1435 DWORD byte = strtoul(ptr, &endPtr, 16);
1437 if (endPtr && *endPtr) {
1439 table->table[table->dwNumEntries].bPhysAddr[
1440 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1446 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1449 getInterfaceIndexByName(ptr,
1450 &table->table[table->dwNumEntries].dwIndex);
1451 table->dwNumEntries++;
1457 ret = ERROR_NOT_SUPPORTED;
1460 ret = ERROR_OUTOFMEMORY;
1465 DWORD getNumUdpEntries(void)
1467 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1468 return getNumWithOneHeader ("net.inet.udp.pcblist");
1470 return getNumWithOneHeader("/proc/net/udp");
1474 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1478 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1479 ERR ("unimplemented!\n");
1480 return ERROR_NOT_SUPPORTED;
1484 ret = ERROR_INVALID_PARAMETER;
1486 DWORD numEntries = getNumUdpEntries();
1487 DWORD size = sizeof(MIB_UDPTABLE);
1488 PMIB_UDPTABLE table;
1491 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1492 table = HeapAlloc(heap, flags, size);
1497 *ppUdpTable = table;
1498 table->dwNumEntries = 0;
1499 /* get from /proc/net/udp, no error if can't */
1500 fp = fopen("/proc/net/udp", "r");
1502 char buf[512] = { 0 }, *ptr;
1504 /* skip header line */
1505 ptr = fgets(buf, sizeof(buf), fp);
1506 while (ptr && table->dwNumEntries < numEntries) {
1507 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1508 ptr = fgets(buf, sizeof(buf), fp);
1513 strtoul(ptr, &endPtr, 16); /* skip */
1518 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1524 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1528 table->dwNumEntries++;
1534 ret = ERROR_NOT_SUPPORTED;
1537 ret = ERROR_OUTOFMEMORY;
1543 DWORD getNumTcpEntries(void)
1545 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1546 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1548 return getNumWithOneHeader ("/proc/net/tcp");
1553 /* Why not a lookup table? Because the TCPS_* constants are different
1554 on different platforms */
1555 static DWORD TCPStateToMIBState (int state)
1559 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1560 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1561 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1562 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1563 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1564 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1565 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1566 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1567 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1568 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1570 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1575 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1579 PMIB_TCPTABLE table;
1580 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1583 struct xinpgen *pXIG, *pOrigXIG;
1586 char buf[512] = { 0 }, *ptr;
1590 return ERROR_INVALID_PARAMETER;
1592 numEntries = getNumTcpEntries ();
1596 DWORD size = sizeof(MIB_TCPTABLE);
1599 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1600 *ppTcpTable = HeapAlloc (heap, flags, size);
1603 ERR ("Out of memory!\n");
1604 return ERROR_OUTOFMEMORY;
1606 maxEntries = numEntries;
1609 table = *ppTcpTable;
1610 table->dwNumEntries = 0;
1614 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1616 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1618 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1619 return ERROR_OUTOFMEMORY;
1622 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1625 ERR ("Out of memory!\n");
1626 return ERROR_OUTOFMEMORY;
1629 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1631 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1632 HeapFree (GetProcessHeap (), 0, Buf);
1633 return ERROR_OUTOFMEMORY;
1636 /* Might be nothing here; first entry is just a header it seems */
1637 if (Len <= sizeof (struct xinpgen))
1639 HeapFree (GetProcessHeap (), 0, Buf);
1643 pOrigXIG = (struct xinpgen *)Buf;
1646 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1647 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1648 (table->dwNumEntries < maxEntries);
1649 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1651 struct tcpcb *pTCPData = NULL;
1652 struct inpcb *pINData;
1653 struct xsocket *pSockData;
1655 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1656 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1657 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1659 /* Ignore sockets for other protocols */
1660 if (pSockData->xso_protocol != IPPROTO_TCP)
1663 /* Ignore PCBs that were freed while generating the data */
1664 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1667 /* we're only interested in IPv4 addresses */
1668 if (!(pINData->inp_vflag & INP_IPV4) ||
1669 (pINData->inp_vflag & INP_IPV6))
1672 /* If all 0's, skip it */
1673 if (!pINData->inp_laddr.s_addr &&
1674 !pINData->inp_lport &&
1675 !pINData->inp_faddr.s_addr &&
1676 !pINData->inp_fport)
1679 /* Fill in structure details */
1680 table->table[table->dwNumEntries].dwLocalAddr =
1681 pINData->inp_laddr.s_addr;
1682 table->table[table->dwNumEntries].dwLocalPort =
1684 table->table[table->dwNumEntries].dwRemoteAddr =
1685 pINData->inp_faddr.s_addr;
1686 table->table[table->dwNumEntries].dwRemotePort =
1688 table->table[table->dwNumEntries].dwState =
1689 TCPStateToMIBState (pTCPData->t_state);
1691 table->dwNumEntries++;
1694 HeapFree (GetProcessHeap (), 0, Buf);
1696 /* get from /proc/net/tcp, no error if can't */
1697 fp = fopen("/proc/net/tcp", "r");
1699 return ERROR_NOT_SUPPORTED;
1701 /* skip header line */
1702 ptr = fgets(buf, sizeof(buf), fp);
1703 while (ptr && table->dwNumEntries < maxEntries) {
1704 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1705 ptr = fgets(buf, sizeof(buf), fp);
1709 while (ptr && *ptr && *ptr != ':')
1714 table->table[table->dwNumEntries].dwLocalAddr =
1715 strtoul(ptr, &endPtr, 16);
1720 table->table[table->dwNumEntries].dwLocalPort =
1721 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1725 table->table[table->dwNumEntries].dwRemoteAddr =
1726 strtoul(ptr, &endPtr, 16);
1731 table->table[table->dwNumEntries].dwRemotePort =
1732 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1736 DWORD state = strtoul(ptr, &endPtr, 16);
1738 table->table[table->dwNumEntries].dwState =
1739 TCPStateToMIBState (state);
1742 table->dwNumEntries++;