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"
29 #include <sys/types.h>
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
36 #ifdef HAVE_SYS_SOCKETVAR_H
37 #include <sys/socketvar.h>
39 #ifdef HAVE_SYS_TIMEOUT_H
40 #include <sys/timeout.h>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #ifdef HAVE_NETINET_IN_SYSTM_H
46 #include <netinet/in_systm.h>
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
54 #ifdef HAVE_NET_IF_DL_H
55 #include <net/if_dl.h>
57 #ifdef HAVE_NET_IF_TYPES_H
58 #include <net/if_types.h>
60 #ifdef HAVE_NET_ROUTE_H
61 #include <net/route.h>
63 #ifdef HAVE_NET_IF_ARP_H
64 #include <net/if_arp.h>
66 #ifdef HAVE_NETINET_IF_ETHER_H
67 #include <netinet/if_ether.h>
69 #ifdef HAVE_NETINET_IF_INARP_H
70 #include <netinet/if_inarp.h>
72 #ifdef HAVE_NETINET_IP_H
73 #include <netinet/ip.h>
75 #ifdef HAVE_NETINET_TCP_H
76 #include <netinet/tcp.h>
78 #ifdef HAVE_NETINET_IP_VAR_H
79 #include <netinet/ip_var.h>
81 #ifdef HAVE_NETINET_TCP_FSM_H
82 #include <netinet/tcp_fsm.h>
84 #ifdef HAVE_NETINET_IN_PCB_H
85 #include <netinet/in_pcb.h>
87 #ifdef HAVE_NETINET_TCP_TIMER_H
88 #include <netinet/tcp_timer.h>
90 #ifdef HAVE_NETINET_TCP_VAR_H
91 #include <netinet/tcp_var.h>
93 #ifdef HAVE_NETINET_IP_ICMP_H
94 #include <netinet/ip_icmp.h>
96 #ifdef HAVE_NETINET_ICMP_VAR_H
97 #include <netinet/icmp_var.h>
99 #ifdef HAVE_NETINET_UDP_H
100 #include <netinet/udp.h>
102 #ifdef HAVE_NETINET_UDP_VAR_H
103 #include <netinet/udp_var.h>
105 #ifdef HAVE_SYS_PROTOSW_H
106 #include <sys/protosw.h>
108 #ifdef HAVE_SYS_SYSCTL_H
109 #include <sys/sysctl.h>
114 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
117 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
122 #include "iprtrmib.h"
126 #include "wine/debug.h"
128 #ifndef HAVE_NETINET_TCP_FSM_H
129 #define TCPS_ESTABLISHED 1
130 #define TCPS_SYN_SENT 2
131 #define TCPS_SYN_RECEIVED 3
132 #define TCPS_FIN_WAIT_1 4
133 #define TCPS_FIN_WAIT_2 5
134 #define TCPS_TIME_WAIT 6
135 #define TCPS_CLOSED 7
136 #define TCPS_CLOSE_WAIT 8
137 #define TCPS_LAST_ACK 9
138 #define TCPS_LISTEN 10
139 #define TCPS_CLOSING 11
142 #ifndef RTF_MULTICAST
143 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
147 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
150 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
152 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
154 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
155 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
156 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
160 struct if_msghdr *ifm;
161 struct if_data ifdata;
163 return ERROR_INVALID_PARAMETER;
165 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
167 ERR ("failed to get size of iflist\n");
168 return ERROR_NOT_SUPPORTED;
170 buf = HeapAlloc (GetProcessHeap (), 0, needed);
171 if (!buf) return ERROR_NOT_SUPPORTED;
172 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
174 ERR ("failed to get iflist\n");
175 HeapFree (GetProcessHeap (), 0, buf);
176 return ERROR_NOT_SUPPORTED;
179 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
181 ifm = (struct if_msghdr *) buf;
182 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
184 ifdata = ifm->ifm_data;
185 entry->dwMtu = ifdata.ifi_mtu;
186 entry->dwSpeed = ifdata.ifi_baudrate;
187 entry->dwInOctets = ifdata.ifi_ibytes;
188 entry->dwInErrors = ifdata.ifi_ierrors;
189 entry->dwInDiscards = ifdata.ifi_iqdrops;
190 entry->dwInUcastPkts = ifdata.ifi_ipackets;
191 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
192 entry->dwOutOctets = ifdata.ifi_obytes;
193 entry->dwOutUcastPkts = ifdata.ifi_opackets;
194 entry->dwOutErrors = ifdata.ifi_oerrors;
195 HeapFree (GetProcessHeap (), 0, buf);
199 HeapFree (GetProcessHeap (), 0, buf);
200 return ERROR_NOT_SUPPORTED;
202 /* get interface stats from /proc/net/dev, no error if can't
203 no inUnknownProtos, outNUcastPkts, outQLen */
207 return ERROR_INVALID_PARAMETER;
208 fp = fopen("/proc/net/dev", "r");
210 char buf[512] = { 0 }, *ptr;
211 int nameLen = strlen(name), nameFound = 0;
214 ptr = fgets(buf, sizeof(buf), fp);
215 while (ptr && !nameFound) {
216 while (*ptr && isspace(*ptr))
218 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
221 ptr = fgets(buf, sizeof(buf), fp);
228 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
232 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
236 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
240 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
244 strtoul(ptr, &endPtr, 10); /* skip */
248 strtoul(ptr, &endPtr, 10); /* skip */
252 strtoul(ptr, &endPtr, 10); /* skip */
256 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
260 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
264 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
268 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
272 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
280 ERR ("unimplemented!\n");
281 return ERROR_NOT_SUPPORTED;
288 DWORD getICMPStats(MIB_ICMP *stats)
290 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
291 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
292 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
294 struct icmpstat icmp_stat;
298 return ERROR_INVALID_PARAMETER;
300 needed = sizeof(icmp_stat);
301 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
303 ERR ("failed to get icmpstat\n");
304 return ERROR_NOT_SUPPORTED;
309 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
310 for(i = 0; i <= ICMP_MAXTYPE; i++)
311 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
313 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
315 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
316 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
317 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
318 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
319 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
320 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
321 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
322 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
323 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
324 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
325 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
327 #ifdef HAVE_ICPS_OUTHIST
329 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
330 for(i = 0; i <= ICMP_MAXTYPE; i++)
331 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
333 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
335 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
336 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
337 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
338 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
339 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
340 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
341 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
342 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
343 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
344 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
345 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
346 #else /* ICPS_OUTHIST */
347 memset( &stats->stats.icmpOutStats, 0, sizeof(stats->stats.icmpOutStats) );
348 #endif /* ICPS_OUTHIST */
352 #else /* ICMPCTL_STATS */
356 return ERROR_INVALID_PARAMETER;
358 memset(stats, 0, sizeof(MIB_ICMP));
359 /* get most of these stats from /proc/net/snmp, no error if can't */
360 fp = fopen("/proc/net/snmp", "r");
362 static const char hdr[] = "Icmp:";
363 char buf[512] = { 0 }, *ptr;
366 ptr = fgets(buf, sizeof(buf), fp);
367 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
369 /* last line was a header, get another */
370 ptr = fgets(buf, sizeof(buf), fp);
371 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
376 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
380 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
384 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
388 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
392 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
396 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
400 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
404 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
408 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
412 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
416 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
420 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
424 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
428 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
432 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
436 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
440 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
444 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
448 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
452 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
456 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
460 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
464 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
468 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
477 ERR ("unimplemented!\n");
478 return ERROR_NOT_SUPPORTED;
485 DWORD getIPStats(PMIB_IPSTATS stats)
487 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
488 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
489 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
490 int ip_ttl, ip_forwarding;
491 struct ipstat ip_stat;
495 return ERROR_INVALID_PARAMETER;
497 needed = sizeof(ip_stat);
498 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
500 ERR ("failed to get ipstat\n");
501 return ERROR_NOT_SUPPORTED;
504 needed = sizeof(ip_ttl);
505 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
507 ERR ("failed to get ip Default TTL\n");
508 return ERROR_NOT_SUPPORTED;
511 needed = sizeof(ip_forwarding);
512 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
514 ERR ("failed to get ip forwarding\n");
515 return ERROR_NOT_SUPPORTED;
518 stats->dwForwarding = ip_forwarding;
519 stats->dwDefaultTTL = ip_ttl;
520 stats->dwInDelivers = ip_stat.ips_delivered;
521 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
522 stats->dwInAddrErrors = ip_stat.ips_cantforward;
523 stats->dwInReceives = ip_stat.ips_total;
524 stats->dwForwDatagrams = ip_stat.ips_forward;
525 stats->dwInUnknownProtos = ip_stat.ips_noproto;
526 stats->dwInDiscards = ip_stat.ips_fragdropped;
527 stats->dwOutDiscards = ip_stat.ips_odropped;
528 stats->dwReasmOks = ip_stat.ips_reassembled;
529 stats->dwFragOks = ip_stat.ips_fragmented;
530 stats->dwFragFails = ip_stat.ips_cantfrag;
531 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
532 stats->dwOutNoRoutes = ip_stat.ips_noroute;
533 stats->dwOutRequests = ip_stat.ips_localout;
534 stats->dwReasmReqds = ip_stat.ips_fragments;
541 return ERROR_INVALID_PARAMETER;
543 memset(stats, 0, sizeof(MIB_IPSTATS));
544 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
545 stats->dwNumRoutes = getNumRoutes();
547 /* get most of these stats from /proc/net/snmp, no error if can't */
548 fp = fopen("/proc/net/snmp", "r");
550 static const char hdr[] = "Ip:";
551 char buf[512] = { 0 }, *ptr;
554 ptr = fgets(buf, sizeof(buf), fp);
555 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
557 /* last line was a header, get another */
558 ptr = fgets(buf, sizeof(buf), fp);
559 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
564 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
568 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
572 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
576 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
580 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
584 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
588 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
592 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
596 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
600 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
604 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
608 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
612 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
616 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
620 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
624 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
628 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
632 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
636 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
639 /* hmm, no routingDiscards */
646 ERR ("unimplemented!\n");
647 return ERROR_NOT_SUPPORTED;
654 DWORD getTCPStats(MIB_TCPSTATS *stats)
656 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
657 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
659 #define TCPTV_REXMTMAX 128
661 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
662 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
664 struct tcpstat tcp_stat;
668 return ERROR_INVALID_PARAMETER;
669 needed = sizeof(tcp_stat);
671 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
673 ERR ("failed to get tcpstat\n");
674 return ERROR_NOT_SUPPORTED;
677 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
678 stats->dwRtoMin = TCPTV_MIN;
679 stats->dwRtoMax = TCPTV_REXMTMAX;
680 stats->dwMaxConn = -1;
681 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
682 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
683 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
684 stats->dwEstabResets = tcp_stat.tcps_drops;
685 stats->dwCurrEstab = 0;
686 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
687 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
688 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
689 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
690 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
691 stats->dwNumConns = tcp_stat.tcps_connects;
699 return ERROR_INVALID_PARAMETER;
701 memset(stats, 0, sizeof(MIB_TCPSTATS));
703 /* get from /proc/net/snmp, no error if can't */
704 fp = fopen("/proc/net/snmp", "r");
706 static const char hdr[] = "Tcp:";
707 char buf[512] = { 0 }, *ptr;
711 ptr = fgets(buf, sizeof(buf), fp);
712 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
714 /* last line was a header, get another */
715 ptr = fgets(buf, sizeof(buf), fp);
716 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
721 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
725 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
729 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
733 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
737 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
741 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
745 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
749 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
753 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
757 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
761 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
765 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
769 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
773 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
776 stats->dwNumConns = getNumTcpEntries();
783 ERR ("unimplemented!\n");
784 return ERROR_NOT_SUPPORTED;
791 DWORD getUDPStats(MIB_UDPSTATS *stats)
793 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
794 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
795 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
796 struct udpstat udp_stat;
799 return ERROR_INVALID_PARAMETER;
801 needed = sizeof(udp_stat);
803 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
805 ERR ("failed to get udpstat\n");
806 return ERROR_NOT_SUPPORTED;
809 stats->dwInDatagrams = udp_stat.udps_ipackets;
810 stats->dwOutDatagrams = udp_stat.udps_opackets;
811 stats->dwNoPorts = udp_stat.udps_noport;
812 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
813 stats->dwNumAddrs = getNumUdpEntries();
820 return ERROR_INVALID_PARAMETER;
822 memset(stats, 0, sizeof(MIB_UDPSTATS));
824 /* get from /proc/net/snmp, no error if can't */
825 fp = fopen("/proc/net/snmp", "r");
827 static const char hdr[] = "Udp:";
828 char buf[512] = { 0 }, *ptr;
832 ptr = fgets(buf, sizeof(buf), fp);
833 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
835 /* last line was a header, get another */
836 ptr = fgets(buf, sizeof(buf), fp);
837 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
842 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
846 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
850 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
854 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
858 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
867 ERR ("unimplemented!\n");
868 return ERROR_NOT_SUPPORTED;
875 static DWORD getNumWithOneHeader(const char *filename)
877 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
880 struct xinpgen *pXIG, *pOrigXIG;
882 DWORD NumEntries = 0;
884 if (!strcmp (filename, "net.inet.tcp.pcblist"))
885 Protocol = IPPROTO_TCP;
886 else if (!strcmp (filename, "net.inet.udp.pcblist"))
887 Protocol = IPPROTO_UDP;
890 ERR ("Unsupported mib '%s', needs protocol mapping\n",
895 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
897 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
901 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
904 ERR ("Out of memory!\n");
908 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
910 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
911 HeapFree (GetProcessHeap (), 0, Buf);
915 /* Might be nothing here; first entry is just a header it seems */
916 if (Len <= sizeof (struct xinpgen))
918 HeapFree (GetProcessHeap (), 0, Buf);
922 pOrigXIG = (struct xinpgen *)Buf;
925 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
926 pXIG->xig_len > sizeof (struct xinpgen);
927 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
929 struct tcpcb *pTCPData = NULL;
930 struct inpcb *pINData;
931 struct xsocket *pSockData;
933 if (Protocol == IPPROTO_TCP)
935 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
936 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
937 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
941 pINData = &((struct xinpcb *)pXIG)->xi_inp;
942 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
945 /* Ignore sockets for other protocols */
946 if (pSockData->xso_protocol != Protocol)
949 /* Ignore PCBs that were freed while generating the data */
950 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
953 /* we're only interested in IPv4 addresses */
954 if (!(pINData->inp_vflag & INP_IPV4) ||
955 (pINData->inp_vflag & INP_IPV6))
958 /* If all 0's, skip it */
959 if (!pINData->inp_laddr.s_addr &&
960 !pINData->inp_lport &&
961 !pINData->inp_faddr.s_addr &&
968 HeapFree (GetProcessHeap (), 0, Buf);
974 fp = fopen(filename, "r");
976 char buf[512] = { 0 }, *ptr;
979 ptr = fgets(buf, sizeof(buf), fp);
982 ptr = fgets(buf, sizeof(buf), fp);
990 ERR ("Unable to open '%s' to count entries!\n", filename);
996 DWORD getNumRoutes(void)
998 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
999 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1001 char *buf, *lim, *next;
1002 struct rt_msghdr *rtm;
1003 DWORD RouteCount = 0;
1005 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1007 ERR ("sysctl 1 failed!\n");
1011 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1014 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1016 ERR ("sysctl 2 failed!\n");
1017 HeapFree (GetProcessHeap (), 0, buf);
1022 for (next = buf; next < lim; next += rtm->rtm_msglen)
1024 rtm = (struct rt_msghdr *)next;
1026 if (rtm->rtm_type != RTM_GET)
1028 WARN ("Got unexpected message type 0x%x!\n",
1033 /* Ignore all entries except for gateway routes which aren't
1035 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1041 HeapFree (GetProcessHeap (), 0, buf);
1044 return getNumWithOneHeader("/proc/net/route");
1048 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1053 if (!ppIpForwardTable)
1054 ret = ERROR_INVALID_PARAMETER;
1056 DWORD numRoutes = getNumRoutes();
1057 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1058 PMIB_IPFORWARDTABLE table;
1061 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1062 table = HeapAlloc(heap, flags, size);
1064 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1065 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1067 char *buf, *lim, *next, *addrPtr;
1068 struct rt_msghdr *rtm;
1070 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1072 ERR ("sysctl 1 failed!\n");
1073 HeapFree (GetProcessHeap (), 0, table);
1077 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1080 HeapFree (GetProcessHeap (), 0, table);
1081 return ERROR_OUTOFMEMORY;
1084 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1086 ERR ("sysctl 2 failed!\n");
1087 HeapFree (GetProcessHeap (), 0, table);
1088 HeapFree (GetProcessHeap (), 0, buf);
1092 *ppIpForwardTable = table;
1093 table->dwNumEntries = 0;
1096 for (next = buf; next < lim; next += rtm->rtm_msglen)
1100 rtm = (struct rt_msghdr *)next;
1102 if (rtm->rtm_type != RTM_GET)
1104 WARN ("Got unexpected message type 0x%x!\n",
1109 /* Ignore all entries except for gateway routes which aren't
1111 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1112 (rtm->rtm_flags & RTF_MULTICAST))
1115 memset (&table->table[table->dwNumEntries], 0,
1116 sizeof (MIB_IPFORWARDROW));
1117 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1118 table->table[table->dwNumEntries].dwForwardType =
1119 MIB_IPROUTE_TYPE_INDIRECT;
1120 table->table[table->dwNumEntries].dwForwardMetric1 =
1121 rtm->rtm_rmx.rmx_hopcount;
1122 table->table[table->dwNumEntries].dwForwardProto =
1125 addrPtr = (char *)(rtm + 1);
1127 for (i = 1; i; i <<= 1)
1129 struct sockaddr *sa;
1132 if (!(i & rtm->rtm_addrs))
1135 sa = (struct sockaddr *)addrPtr;
1136 ADVANCE (addrPtr, sa);
1138 /* default routes are encoded by length-zero sockaddr */
1139 if (sa->sa_len == 0)
1141 else if (sa->sa_family != AF_INET)
1143 WARN ("Received unsupported sockaddr family 0x%x\n",
1149 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1151 addr = sin->sin_addr.s_addr;
1157 table->table[table->dwNumEntries].dwForwardDest = addr;
1161 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1165 table->table[table->dwNumEntries].dwForwardMask = addr;
1169 WARN ("Unexpected address type 0x%x\n", i);
1173 table->dwNumEntries++;
1176 HeapFree (GetProcessHeap (), 0, buf);
1182 *ppIpForwardTable = table;
1183 table->dwNumEntries = 0;
1184 /* get from /proc/net/route, no error if can't */
1185 fp = fopen("/proc/net/route", "r");
1187 char buf[512] = { 0 }, *ptr;
1189 /* skip header line */
1190 ptr = fgets(buf, sizeof(buf), fp);
1191 while (ptr && table->dwNumEntries < numRoutes) {
1192 memset(&table->table[table->dwNumEntries], 0,
1193 sizeof(MIB_IPFORWARDROW));
1194 ptr = fgets(buf, sizeof(buf), fp);
1198 while (!isspace(*ptr))
1202 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1205 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1207 table->table[table->dwNumEntries].dwForwardDest =
1208 strtoul(ptr, &endPtr, 16);
1212 table->table[table->dwNumEntries].dwForwardNextHop =
1213 strtoul(ptr, &endPtr, 16);
1217 DWORD flags = strtoul(ptr, &endPtr, 16);
1219 if (!(flags & RTF_UP))
1220 table->table[table->dwNumEntries].dwForwardType =
1221 MIB_IPROUTE_TYPE_INVALID;
1222 else if (flags & RTF_GATEWAY)
1223 table->table[table->dwNumEntries].dwForwardType =
1224 MIB_IPROUTE_TYPE_INDIRECT;
1226 table->table[table->dwNumEntries].dwForwardType =
1227 MIB_IPROUTE_TYPE_DIRECT;
1231 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1235 strtoul(ptr, &endPtr, 16); /* use, skip */
1239 table->table[table->dwNumEntries].dwForwardMetric1 =
1240 strtoul(ptr, &endPtr, 16);
1244 table->table[table->dwNumEntries].dwForwardMask =
1245 strtoul(ptr, &endPtr, 16);
1248 /* FIXME: other protos might be appropriate, e.g. the default
1249 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1250 table->table[table->dwNumEntries].dwForwardProto =
1252 table->dwNumEntries++;
1260 ERR ("unimplemented!\n");
1261 return ERROR_NOT_SUPPORTED;
1266 ret = ERROR_OUTOFMEMORY;
1271 DWORD getNumArpEntries(void)
1273 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1274 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1275 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1276 DWORD arpEntries = 0;
1278 char *buf, *lim, *next;
1279 struct rt_msghdr *rtm;
1280 struct sockaddr_inarp *sinarp;
1281 struct sockaddr_dl *sdl;
1283 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1285 ERR ("failed to get size of arp table\n");
1289 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1292 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1294 ERR ("failed to get arp table\n");
1295 HeapFree (GetProcessHeap (), 0, buf);
1303 rtm = (struct rt_msghdr *)next;
1304 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1305 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1306 if(sdl->sdl_alen) /* arp entry */
1308 next += rtm->rtm_msglen;
1310 HeapFree (GetProcessHeap (), 0, buf);
1313 return getNumWithOneHeader("/proc/net/arp");
1316 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1318 DWORD ret = NO_ERROR;
1320 ret = ERROR_INVALID_PARAMETER;
1322 DWORD numEntries = getNumArpEntries();
1323 DWORD size = sizeof(MIB_IPNETTABLE);
1324 PMIB_IPNETTABLE table;
1327 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1328 table = HeapAlloc(heap, flags, size);
1329 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1332 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1333 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1335 char *buf, *lim, *next;
1336 struct rt_msghdr *rtm;
1337 struct sockaddr_inarp *sinarp;
1338 struct sockaddr_dl *sdl;
1340 *ppIpNetTable = table;
1341 table->dwNumEntries = 0;
1343 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1345 ERR ("failed to get size of arp table\n");
1346 return ERROR_NOT_SUPPORTED;
1349 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1350 if (!buf) return ERROR_OUTOFMEMORY;
1352 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1354 ERR ("failed to get arp table\n");
1355 HeapFree (GetProcessHeap (), 0, buf);
1356 return ERROR_NOT_SUPPORTED;
1363 rtm = (struct rt_msghdr *)next;
1364 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1365 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1366 if(sdl->sdl_alen) /* arp entry */
1368 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1369 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1370 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1371 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1372 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1374 table->table[table->dwNumEntries].bPhysAddr[
1375 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1377 if(rtm->rtm_rmx.rmx_expire == 0)
1378 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1379 else if(sinarp->sin_other & SIN_PROXY)
1380 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1381 else if(rtm->rtm_rmx.rmx_expire != 0)
1382 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1384 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1386 table->dwNumEntries++;
1388 next += rtm->rtm_msglen;
1390 HeapFree (GetProcessHeap (), 0, buf);
1393 ret = ERROR_OUTOFMEMORY;
1399 *ppIpNetTable = table;
1400 table->dwNumEntries = 0;
1401 /* get from /proc/net/arp, no error if can't */
1402 fp = fopen("/proc/net/arp", "r");
1404 char buf[512] = { 0 }, *ptr;
1406 /* skip header line */
1407 ptr = fgets(buf, sizeof(buf), fp);
1408 while (ptr && table->dwNumEntries < numEntries) {
1409 ptr = fgets(buf, sizeof(buf), fp);
1413 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1414 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1415 while (ptr && *ptr && !isspace(*ptr))
1419 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1423 DWORD flags = strtoul(ptr, &endPtr, 16);
1426 if (flags & ATF_COM)
1427 table->table[table->dwNumEntries].dwType =
1428 MIB_IPNET_TYPE_DYNAMIC;
1432 if (flags & ATF_PERM)
1433 table->table[table->dwNumEntries].dwType =
1434 MIB_IPNET_TYPE_STATIC;
1437 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1441 while (ptr && *ptr && isspace(*ptr))
1443 while (ptr && *ptr && !isspace(*ptr)) {
1444 DWORD byte = strtoul(ptr, &endPtr, 16);
1446 if (endPtr && *endPtr) {
1448 table->table[table->dwNumEntries].bPhysAddr[
1449 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1455 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1458 getInterfaceIndexByName(ptr,
1459 &table->table[table->dwNumEntries].dwIndex);
1460 table->dwNumEntries++;
1466 ret = ERROR_NOT_SUPPORTED;
1469 ret = ERROR_OUTOFMEMORY;
1474 DWORD getNumUdpEntries(void)
1476 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1477 return getNumWithOneHeader ("net.inet.udp.pcblist");
1479 return getNumWithOneHeader("/proc/net/udp");
1483 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1487 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1488 ERR ("unimplemented!\n");
1489 return ERROR_NOT_SUPPORTED;
1493 ret = ERROR_INVALID_PARAMETER;
1495 DWORD numEntries = getNumUdpEntries();
1496 DWORD size = sizeof(MIB_UDPTABLE);
1497 PMIB_UDPTABLE table;
1500 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1501 table = HeapAlloc(heap, flags, size);
1506 *ppUdpTable = table;
1507 table->dwNumEntries = 0;
1508 /* get from /proc/net/udp, no error if can't */
1509 fp = fopen("/proc/net/udp", "r");
1511 char buf[512] = { 0 }, *ptr;
1513 /* skip header line */
1514 ptr = fgets(buf, sizeof(buf), fp);
1515 while (ptr && table->dwNumEntries < numEntries) {
1516 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1517 ptr = fgets(buf, sizeof(buf), fp);
1522 strtoul(ptr, &endPtr, 16); /* skip */
1527 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1533 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1537 table->dwNumEntries++;
1543 ret = ERROR_NOT_SUPPORTED;
1546 ret = ERROR_OUTOFMEMORY;
1552 DWORD getNumTcpEntries(void)
1554 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1555 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1557 return getNumWithOneHeader ("/proc/net/tcp");
1562 /* Why not a lookup table? Because the TCPS_* constants are different
1563 on different platforms */
1564 static DWORD TCPStateToMIBState (int state)
1568 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1569 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1570 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1571 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1572 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1573 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1574 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1575 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1576 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1577 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1579 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1584 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1588 PMIB_TCPTABLE table;
1589 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1592 struct xinpgen *pXIG, *pOrigXIG;
1595 char buf[512] = { 0 }, *ptr;
1599 return ERROR_INVALID_PARAMETER;
1601 numEntries = getNumTcpEntries ();
1605 DWORD size = sizeof(MIB_TCPTABLE);
1608 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1609 *ppTcpTable = HeapAlloc (heap, flags, size);
1612 ERR ("Out of memory!\n");
1613 return ERROR_OUTOFMEMORY;
1615 maxEntries = numEntries;
1618 table = *ppTcpTable;
1619 table->dwNumEntries = 0;
1623 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1625 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1627 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1628 return ERROR_OUTOFMEMORY;
1631 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1634 ERR ("Out of memory!\n");
1635 return ERROR_OUTOFMEMORY;
1638 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1640 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1641 HeapFree (GetProcessHeap (), 0, Buf);
1642 return ERROR_OUTOFMEMORY;
1645 /* Might be nothing here; first entry is just a header it seems */
1646 if (Len <= sizeof (struct xinpgen))
1648 HeapFree (GetProcessHeap (), 0, Buf);
1652 pOrigXIG = (struct xinpgen *)Buf;
1655 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1656 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1657 (table->dwNumEntries < maxEntries);
1658 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1660 struct tcpcb *pTCPData = NULL;
1661 struct inpcb *pINData;
1662 struct xsocket *pSockData;
1664 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1665 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1666 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1668 /* Ignore sockets for other protocols */
1669 if (pSockData->xso_protocol != IPPROTO_TCP)
1672 /* Ignore PCBs that were freed while generating the data */
1673 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1676 /* we're only interested in IPv4 addresses */
1677 if (!(pINData->inp_vflag & INP_IPV4) ||
1678 (pINData->inp_vflag & INP_IPV6))
1681 /* If all 0's, skip it */
1682 if (!pINData->inp_laddr.s_addr &&
1683 !pINData->inp_lport &&
1684 !pINData->inp_faddr.s_addr &&
1685 !pINData->inp_fport)
1688 /* Fill in structure details */
1689 table->table[table->dwNumEntries].dwLocalAddr =
1690 pINData->inp_laddr.s_addr;
1691 table->table[table->dwNumEntries].dwLocalPort =
1693 table->table[table->dwNumEntries].dwRemoteAddr =
1694 pINData->inp_faddr.s_addr;
1695 table->table[table->dwNumEntries].dwRemotePort =
1697 table->table[table->dwNumEntries].dwState =
1698 TCPStateToMIBState (pTCPData->t_state);
1700 table->dwNumEntries++;
1703 HeapFree (GetProcessHeap (), 0, Buf);
1705 /* get from /proc/net/tcp, no error if can't */
1706 fp = fopen("/proc/net/tcp", "r");
1708 return ERROR_NOT_SUPPORTED;
1710 /* skip header line */
1711 ptr = fgets(buf, sizeof(buf), fp);
1712 while (ptr && table->dwNumEntries < maxEntries) {
1713 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1714 ptr = fgets(buf, sizeof(buf), fp);
1718 while (ptr && *ptr && *ptr != ':')
1723 table->table[table->dwNumEntries].dwLocalAddr =
1724 strtoul(ptr, &endPtr, 16);
1729 table->table[table->dwNumEntries].dwLocalPort =
1730 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1734 table->table[table->dwNumEntries].dwRemoteAddr =
1735 strtoul(ptr, &endPtr, 16);
1740 table->table[table->dwNumEntries].dwRemotePort =
1741 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1745 DWORD state = strtoul(ptr, &endPtr, 16);
1747 table->table[table->dwNumEntries].dwState =
1748 TCPStateToMIBState (state);
1751 table->dwNumEntries++;