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_IP_H
68 #include <netinet/ip.h>
70 #ifdef HAVE_NETINET_TCP_H
71 #include <netinet/tcp.h>
73 #ifdef HAVE_NETINET_IP_VAR_H
74 #include <netinet/ip_var.h>
76 #ifdef HAVE_NETINET_TCP_FSM_H
77 #include <netinet/tcp_fsm.h>
79 #ifdef HAVE_NETINET_IN_PCB_H
80 #include <netinet/in_pcb.h>
82 #ifdef HAVE_NETINET_TCP_TIMER_H
83 #include <netinet/tcp_timer.h>
85 #ifdef HAVE_NETINET_TCP_VAR_H
86 #include <netinet/tcp_var.h>
88 #ifdef HAVE_NETINET_IN_SYSTM_H
89 #include <netinet/in_systm.h>
91 #ifdef HAVE_NETINET_IP_ICMP_H
92 #include <netinet/ip_icmp.h>
94 #ifdef HAVE_NETINET_ICMP_VAR_H
95 #include <netinet/icmp_var.h>
97 #ifdef HAVE_NETINET_UDP_H
98 #include <netinet/udp.h>
100 #ifdef HAVE_NETINET_UDP_VAR_H
101 #include <netinet/udp_var.h>
103 #ifdef HAVE_SYS_PROTOSW_H
104 #include <sys/protosw.h>
106 #ifdef HAVE_SYS_SYSCTL_H
107 #include <sys/sysctl.h>
112 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
115 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
120 #include "iprtrmib.h"
124 #ifndef HAVE_NETINET_TCP_FSM_H
125 #define TCPS_ESTABLISHED 1
126 #define TCPS_SYN_SENT 2
127 #define TCPS_SYN_RECEIVED 3
128 #define TCPS_FIN_WAIT_1 4
129 #define TCPS_FIN_WAIT_2 5
130 #define TCPS_TIME_WAIT 6
131 #define TCPS_CLOSED 7
132 #define TCPS_CLOSE_WAIT 8
133 #define TCPS_LAST_ACK 9
134 #define TCPS_LISTEN 10
135 #define TCPS_CLOSING 11
138 #ifndef RTF_MULTICAST
139 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
142 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
144 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
146 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
147 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
148 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
152 struct if_msghdr *ifm;
153 struct if_data ifdata;
155 return ERROR_INVALID_PARAMETER;
157 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
159 ERR ("failed to get size of iflist\n");
160 return ERROR_NOT_SUPPORTED;
162 buf = HeapAlloc (GetProcessHeap (), 0, needed);
163 if (!buf) return ERROR_NOT_SUPPORTED;
164 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
166 ERR ("failed to get iflist\n");
167 HeapFree (GetProcessHeap (), 0, buf);
168 return ERROR_NOT_SUPPORTED;
171 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
173 ifm = (struct if_msghdr *) buf;
174 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
176 ifdata = ifm->ifm_data;
177 entry->dwMtu = ifdata.ifi_mtu;
178 entry->dwSpeed = ifdata.ifi_baudrate;
179 entry->dwInOctets = ifdata.ifi_ibytes;
180 entry->dwInErrors = ifdata.ifi_ierrors;
181 entry->dwInDiscards = ifdata.ifi_iqdrops;
182 entry->dwInUcastPkts = ifdata.ifi_ipackets;
183 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
184 entry->dwOutOctets = ifdata.ifi_obytes;
185 entry->dwOutUcastPkts = ifdata.ifi_opackets;
186 entry->dwOutErrors = ifdata.ifi_oerrors;
187 HeapFree (GetProcessHeap (), 0, buf);
191 HeapFree (GetProcessHeap (), 0, buf);
192 return ERROR_NOT_SUPPORTED;
194 /* get interface stats from /proc/net/dev, no error if can't
195 no inUnknownProtos, outNUcastPkts, outQLen */
199 return ERROR_INVALID_PARAMETER;
200 fp = fopen("/proc/net/dev", "r");
202 char buf[512] = { 0 }, *ptr;
203 int nameLen = strlen(name), nameFound = 0;
206 ptr = fgets(buf, sizeof(buf), fp);
207 while (ptr && !nameFound) {
208 while (*ptr && isspace(*ptr))
210 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
213 ptr = fgets(buf, sizeof(buf), fp);
220 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
224 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
228 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
232 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
236 strtoul(ptr, &endPtr, 10); /* skip */
240 strtoul(ptr, &endPtr, 10); /* skip */
244 strtoul(ptr, &endPtr, 10); /* skip */
248 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
252 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
256 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
260 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
264 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
272 ERR ("unimplemented!\n");
273 return ERROR_NOT_SUPPORTED;
280 DWORD getICMPStats(MIB_ICMP *stats)
282 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
283 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
284 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
286 struct icmpstat icmp_stat;
290 return ERROR_INVALID_PARAMETER;
292 needed = sizeof(icmp_stat);
293 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
295 ERR ("failed to get icmpstat\n");
296 return ERROR_NOT_SUPPORTED;
301 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
302 for(i = 0; i <= ICMP_MAXTYPE; i++)
303 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
305 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
307 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
308 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
309 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
310 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
311 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
312 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
313 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
314 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
315 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
316 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
317 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
321 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
322 for(i = 0; i <= ICMP_MAXTYPE; i++)
323 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
325 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
327 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
328 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
329 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
330 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
331 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
332 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
333 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
334 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
335 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
336 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
337 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
344 return ERROR_INVALID_PARAMETER;
346 memset(stats, 0, sizeof(MIB_ICMP));
347 /* get most of these stats from /proc/net/snmp, no error if can't */
348 fp = fopen("/proc/net/snmp", "r");
350 static const char hdr[] = "Icmp:";
351 char buf[512] = { 0 }, *ptr;
354 ptr = fgets(buf, sizeof(buf), fp);
355 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
357 /* last line was a header, get another */
358 ptr = fgets(buf, sizeof(buf), fp);
359 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
364 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
368 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
372 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
376 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
380 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
384 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
388 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
392 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
396 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
400 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
404 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
408 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
412 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
416 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
420 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
424 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
428 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
432 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
436 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
440 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
444 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
448 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
452 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
456 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
465 ERR ("unimplemented!\n");
466 return ERROR_NOT_SUPPORTED;
473 DWORD getIPStats(PMIB_IPSTATS stats)
475 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
476 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
477 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
478 int ip_ttl, ip_forwarding;
479 struct ipstat ip_stat;
483 return ERROR_INVALID_PARAMETER;
485 needed = sizeof(ip_stat);
486 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
488 ERR ("failed to get ipstat\n");
489 return ERROR_NOT_SUPPORTED;
492 needed = sizeof(ip_ttl);
493 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
495 ERR ("failed to get ip Default TTL\n");
496 return ERROR_NOT_SUPPORTED;
499 needed = sizeof(ip_forwarding);
500 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
502 ERR ("failed to get ip forwarding\n");
503 return ERROR_NOT_SUPPORTED;
506 stats->dwForwarding = ip_forwarding;
507 stats->dwDefaultTTL = ip_ttl;
508 stats->dwInDelivers = ip_stat.ips_delivered;
509 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
510 stats->dwInAddrErrors = ip_stat.ips_cantforward;
511 stats->dwInReceives = ip_stat.ips_total;
512 stats->dwForwDatagrams = ip_stat.ips_forward;
513 stats->dwInUnknownProtos = ip_stat.ips_noproto;
514 stats->dwInDiscards = ip_stat.ips_fragdropped;
515 stats->dwOutDiscards = ip_stat.ips_odropped;
516 stats->dwReasmOks = ip_stat.ips_reassembled;
517 stats->dwFragOks = ip_stat.ips_fragmented;
518 stats->dwFragFails = ip_stat.ips_cantfrag;
519 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
520 stats->dwOutNoRoutes = ip_stat.ips_noroute;
521 stats->dwOutRequests = ip_stat.ips_localout;
522 stats->dwReasmReqds = ip_stat.ips_fragments;
529 return ERROR_INVALID_PARAMETER;
531 memset(stats, 0, sizeof(MIB_IPSTATS));
532 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
533 stats->dwNumRoutes = getNumRoutes();
535 /* get most of these stats from /proc/net/snmp, no error if can't */
536 fp = fopen("/proc/net/snmp", "r");
538 static const char hdr[] = "Ip:";
539 char buf[512] = { 0 }, *ptr;
542 ptr = fgets(buf, sizeof(buf), fp);
543 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
545 /* last line was a header, get another */
546 ptr = fgets(buf, sizeof(buf), fp);
547 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
552 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
556 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
560 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
564 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
568 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
572 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
576 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
580 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
584 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
588 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
592 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
596 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
600 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
604 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
608 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
612 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
616 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
620 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
624 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
627 /* hmm, no routingDiscards */
634 ERR ("unimplemented!\n");
635 return ERROR_NOT_SUPPORTED;
642 DWORD getTCPStats(MIB_TCPSTATS *stats)
644 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
645 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
647 #define TCPTV_REXMTMAX 128
649 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
650 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
652 struct tcpstat tcp_stat;
656 return ERROR_INVALID_PARAMETER;
657 needed = sizeof(tcp_stat);
659 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
661 ERR ("failed to get tcpstat\n");
662 return ERROR_NOT_SUPPORTED;
665 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
666 stats->dwRtoMin = TCPTV_MIN;
667 stats->dwRtoMax = TCPTV_REXMTMAX;
668 stats->dwMaxConn = -1;
669 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
670 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
671 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
672 stats->dwEstabResets = tcp_stat.tcps_drops;
673 stats->dwCurrEstab = 0;
674 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
675 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
676 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
677 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
678 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
679 stats->dwNumConns = tcp_stat.tcps_connects;
687 return ERROR_INVALID_PARAMETER;
689 memset(stats, 0, sizeof(MIB_TCPSTATS));
691 /* get from /proc/net/snmp, no error if can't */
692 fp = fopen("/proc/net/snmp", "r");
694 static const char hdr[] = "Tcp:";
695 char buf[512] = { 0 }, *ptr;
699 ptr = fgets(buf, sizeof(buf), fp);
700 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
702 /* last line was a header, get another */
703 ptr = fgets(buf, sizeof(buf), fp);
704 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
709 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
713 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
717 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
721 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
725 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
729 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
733 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
737 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
741 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
745 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
749 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
753 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
757 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
761 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
764 stats->dwNumConns = getNumTcpEntries();
771 ERR ("unimplemented!\n");
772 return ERROR_NOT_SUPPORTED;
779 DWORD getUDPStats(MIB_UDPSTATS *stats)
781 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
782 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
783 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
784 struct udpstat udp_stat;
787 return ERROR_INVALID_PARAMETER;
789 needed = sizeof(udp_stat);
791 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
793 ERR ("failed to get udpstat\n");
794 return ERROR_NOT_SUPPORTED;
797 stats->dwInDatagrams = udp_stat.udps_ipackets;
798 stats->dwOutDatagrams = udp_stat.udps_opackets;
799 stats->dwNoPorts = udp_stat.udps_noport;
800 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
801 stats->dwNumAddrs = getNumUdpEntries();
808 return ERROR_INVALID_PARAMETER;
810 memset(stats, 0, sizeof(MIB_UDPSTATS));
812 /* get from /proc/net/snmp, no error if can't */
813 fp = fopen("/proc/net/snmp", "r");
815 static const char hdr[] = "Udp:";
816 char buf[512] = { 0 }, *ptr;
820 ptr = fgets(buf, sizeof(buf), fp);
821 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
823 /* last line was a header, get another */
824 ptr = fgets(buf, sizeof(buf), fp);
825 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
830 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
834 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
838 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
842 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
846 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
855 ERR ("unimplemented!\n");
856 return ERROR_NOT_SUPPORTED;
863 static DWORD getNumWithOneHeader(const char *filename)
865 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
868 struct xinpgen *pXIG, *pOrigXIG;
870 DWORD NumEntries = 0;
872 if (!strcmp (filename, "net.inet.tcp.pcblist"))
873 Protocol = IPPROTO_TCP;
874 else if (!strcmp (filename, "net.inet.udp.pcblist"))
875 Protocol = IPPROTO_UDP;
878 ERR ("Unsupported mib '%s', needs protocol mapping\n",
883 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
885 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
889 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
892 ERR ("Out of memory!\n");
896 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
898 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
899 HeapFree (GetProcessHeap (), 0, Buf);
903 /* Might be nothing here; first entry is just a header it seems */
904 if (Len <= sizeof (struct xinpgen))
906 HeapFree (GetProcessHeap (), 0, Buf);
910 pOrigXIG = (struct xinpgen *)Buf;
913 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
914 pXIG->xig_len > sizeof (struct xinpgen);
915 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
917 struct tcpcb *pTCPData = NULL;
918 struct inpcb *pINData;
919 struct xsocket *pSockData;
921 if (Protocol == IPPROTO_TCP)
923 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
924 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
925 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
929 pINData = &((struct xinpcb *)pXIG)->xi_inp;
930 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
933 /* Ignore sockets for other protocols */
934 if (pSockData->xso_protocol != Protocol)
937 /* Ignore PCBs that were freed while generating the data */
938 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
941 /* we're only interested in IPv4 addresses */
942 if (!(pINData->inp_vflag & INP_IPV4) ||
943 (pINData->inp_vflag & INP_IPV6))
946 /* If all 0's, skip it */
947 if (!pINData->inp_laddr.s_addr &&
948 !pINData->inp_lport &&
949 !pINData->inp_faddr.s_addr &&
956 HeapFree (GetProcessHeap (), 0, Buf);
962 fp = fopen(filename, "r");
964 char buf[512] = { 0 }, *ptr;
967 ptr = fgets(buf, sizeof(buf), fp);
970 ptr = fgets(buf, sizeof(buf), fp);
978 ERR ("Unable to open '%s' to count entries!\n", filename);
984 DWORD getNumRoutes(void)
986 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
987 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
989 char *buf, *lim, *next;
990 struct rt_msghdr *rtm;
991 DWORD RouteCount = 0;
993 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
995 ERR ("sysctl 1 failed!\n");
999 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1002 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1004 ERR ("sysctl 2 failed!\n");
1005 HeapFree (GetProcessHeap (), 0, buf);
1010 for (next = buf; next < lim; next += rtm->rtm_msglen)
1012 rtm = (struct rt_msghdr *)next;
1014 if (rtm->rtm_type != RTM_GET)
1016 WARN ("Got unexpected message type 0x%x!\n",
1021 /* Ignore all entries except for gateway routes which aren't
1023 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1029 HeapFree (GetProcessHeap (), 0, buf);
1032 return getNumWithOneHeader("/proc/net/route");
1036 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1041 if (!ppIpForwardTable)
1042 ret = ERROR_INVALID_PARAMETER;
1044 DWORD numRoutes = getNumRoutes();
1045 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1046 PMIB_IPFORWARDTABLE table;
1049 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1050 table = HeapAlloc(heap, flags, size);
1052 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1053 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1055 char *buf, *lim, *next, *addrPtr;
1056 struct rt_msghdr *rtm;
1058 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1060 ERR ("sysctl 1 failed!\n");
1061 HeapFree (GetProcessHeap (), 0, table);
1065 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1068 HeapFree (GetProcessHeap (), 0, table);
1069 return ERROR_OUTOFMEMORY;
1072 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1074 ERR ("sysctl 2 failed!\n");
1075 HeapFree (GetProcessHeap (), 0, table);
1076 HeapFree (GetProcessHeap (), 0, buf);
1080 *ppIpForwardTable = table;
1081 table->dwNumEntries = 0;
1084 for (next = buf; next < lim; next += rtm->rtm_msglen)
1088 rtm = (struct rt_msghdr *)next;
1090 if (rtm->rtm_type != RTM_GET)
1092 WARN ("Got unexpected message type 0x%x!\n",
1097 /* Ignore all entries except for gateway routes which aren't
1099 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1100 (rtm->rtm_flags & RTF_MULTICAST))
1103 memset (&table->table[table->dwNumEntries], 0,
1104 sizeof (MIB_IPFORWARDROW));
1105 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1106 table->table[table->dwNumEntries].dwForwardType =
1107 MIB_IPROUTE_TYPE_INDIRECT;
1108 table->table[table->dwNumEntries].dwForwardMetric1 =
1109 rtm->rtm_rmx.rmx_hopcount;
1110 table->table[table->dwNumEntries].dwForwardProto =
1113 addrPtr = (char *)(rtm + 1);
1115 for (i = 1; i; i <<= 1)
1117 struct sockaddr *sa;
1120 if (!(i & rtm->rtm_addrs))
1123 sa = (struct sockaddr *)addrPtr;
1124 ADVANCE (addrPtr, sa);
1126 /* default routes are encoded by length-zero sockaddr */
1127 if (sa->sa_len == 0)
1129 else if (sa->sa_family != AF_INET)
1131 WARN ("Received unsupported sockaddr family 0x%x\n",
1137 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1139 addr = sin->sin_addr.s_addr;
1145 table->table[table->dwNumEntries].dwForwardDest = addr;
1149 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1153 table->table[table->dwNumEntries].dwForwardMask = addr;
1157 WARN ("Unexpected address type 0x%x\n", i);
1161 table->dwNumEntries++;
1164 HeapFree (GetProcessHeap (), 0, buf);
1170 *ppIpForwardTable = table;
1171 table->dwNumEntries = 0;
1172 /* get from /proc/net/route, no error if can't */
1173 fp = fopen("/proc/net/route", "r");
1175 char buf[512] = { 0 }, *ptr;
1177 /* skip header line */
1178 ptr = fgets(buf, sizeof(buf), fp);
1179 while (ptr && table->dwNumEntries < numRoutes) {
1180 memset(&table->table[table->dwNumEntries], 0,
1181 sizeof(MIB_IPFORWARDROW));
1182 ptr = fgets(buf, sizeof(buf), fp);
1186 while (!isspace(*ptr))
1190 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1193 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1195 table->table[table->dwNumEntries].dwForwardDest =
1196 strtoul(ptr, &endPtr, 16);
1200 table->table[table->dwNumEntries].dwForwardNextHop =
1201 strtoul(ptr, &endPtr, 16);
1205 DWORD flags = strtoul(ptr, &endPtr, 16);
1207 if (!(flags & RTF_UP))
1208 table->table[table->dwNumEntries].dwForwardType =
1209 MIB_IPROUTE_TYPE_INVALID;
1210 else if (flags & RTF_GATEWAY)
1211 table->table[table->dwNumEntries].dwForwardType =
1212 MIB_IPROUTE_TYPE_INDIRECT;
1214 table->table[table->dwNumEntries].dwForwardType =
1215 MIB_IPROUTE_TYPE_DIRECT;
1219 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1223 strtoul(ptr, &endPtr, 16); /* use, skip */
1227 table->table[table->dwNumEntries].dwForwardMetric1 =
1228 strtoul(ptr, &endPtr, 16);
1232 table->table[table->dwNumEntries].dwForwardMask =
1233 strtoul(ptr, &endPtr, 16);
1236 /* FIXME: other protos might be appropriate, e.g. the default
1237 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1238 table->table[table->dwNumEntries].dwForwardProto =
1240 table->dwNumEntries++;
1248 ERR ("unimplemented!\n");
1249 return ERROR_NOT_SUPPORTED;
1254 ret = ERROR_OUTOFMEMORY;
1259 DWORD getNumArpEntries(void)
1261 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1262 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1263 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1264 DWORD arpEntries = 0;
1266 char *buf, *lim, *next;
1267 struct rt_msghdr *rtm;
1268 struct sockaddr_inarp *sinarp;
1269 struct sockaddr_dl *sdl;
1271 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1273 ERR ("failed to get size of arp table\n");
1277 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1280 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1282 ERR ("failed to get arp table\n");
1283 HeapFree (GetProcessHeap (), 0, buf);
1291 rtm = (struct rt_msghdr *)next;
1292 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1293 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1294 if(sdl->sdl_alen) /* arp entry */
1296 next += rtm->rtm_msglen;
1298 HeapFree (GetProcessHeap (), 0, buf);
1301 return getNumWithOneHeader("/proc/net/arp");
1304 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1306 DWORD ret = NO_ERROR;
1308 ret = ERROR_INVALID_PARAMETER;
1310 DWORD numEntries = getNumArpEntries();
1311 DWORD size = sizeof(MIB_IPNETTABLE);
1312 PMIB_IPNETTABLE table;
1315 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1316 table = HeapAlloc(heap, flags, size);
1317 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1320 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1321 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1323 char *buf, *lim, *next;
1324 struct rt_msghdr *rtm;
1325 struct sockaddr_inarp *sinarp;
1326 struct sockaddr_dl *sdl;
1328 *ppIpNetTable = table;
1329 table->dwNumEntries = 0;
1331 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1333 ERR ("failed to get size of arp table\n");
1334 return ERROR_NOT_SUPPORTED;
1337 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1338 if (!buf) return ERROR_OUTOFMEMORY;
1340 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1342 ERR ("failed to get arp table\n");
1343 HeapFree (GetProcessHeap (), 0, buf);
1344 return ERROR_NOT_SUPPORTED;
1351 rtm = (struct rt_msghdr *)next;
1352 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1353 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1354 if(sdl->sdl_alen) /* arp entry */
1356 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1357 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1358 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1359 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1360 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1362 table->table[table->dwNumEntries].bPhysAddr[
1363 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1365 if(rtm->rtm_rmx.rmx_expire == 0)
1366 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1367 else if(sinarp->sin_other & SIN_PROXY)
1368 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1369 else if(rtm->rtm_rmx.rmx_expire != 0)
1370 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1372 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1374 table->dwNumEntries++;
1376 next += rtm->rtm_msglen;
1378 HeapFree (GetProcessHeap (), 0, buf);
1381 ret = ERROR_OUTOFMEMORY;
1387 *ppIpNetTable = table;
1388 table->dwNumEntries = 0;
1389 /* get from /proc/net/arp, no error if can't */
1390 fp = fopen("/proc/net/arp", "r");
1392 char buf[512] = { 0 }, *ptr;
1394 /* skip header line */
1395 ptr = fgets(buf, sizeof(buf), fp);
1396 while (ptr && table->dwNumEntries < numEntries) {
1397 ptr = fgets(buf, sizeof(buf), fp);
1401 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1402 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1403 while (ptr && *ptr && !isspace(*ptr))
1407 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1411 DWORD flags = strtoul(ptr, &endPtr, 16);
1414 if (flags & ATF_COM)
1415 table->table[table->dwNumEntries].dwType =
1416 MIB_IPNET_TYPE_DYNAMIC;
1420 if (flags & ATF_PERM)
1421 table->table[table->dwNumEntries].dwType =
1422 MIB_IPNET_TYPE_STATIC;
1425 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1429 while (ptr && *ptr && isspace(*ptr))
1431 while (ptr && *ptr && !isspace(*ptr)) {
1432 DWORD byte = strtoul(ptr, &endPtr, 16);
1434 if (endPtr && *endPtr) {
1436 table->table[table->dwNumEntries].bPhysAddr[
1437 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1443 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1446 getInterfaceIndexByName(ptr,
1447 &table->table[table->dwNumEntries].dwIndex);
1448 table->dwNumEntries++;
1454 ret = ERROR_NOT_SUPPORTED;
1457 ret = ERROR_OUTOFMEMORY;
1462 DWORD getNumUdpEntries(void)
1464 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1465 return getNumWithOneHeader ("net.inet.udp.pcblist");
1467 return getNumWithOneHeader("/proc/net/udp");
1471 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1475 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1476 ERR ("unimplemented!\n");
1477 return ERROR_NOT_SUPPORTED;
1481 ret = ERROR_INVALID_PARAMETER;
1483 DWORD numEntries = getNumUdpEntries();
1484 DWORD size = sizeof(MIB_UDPTABLE);
1485 PMIB_UDPTABLE table;
1488 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1489 table = HeapAlloc(heap, flags, size);
1494 *ppUdpTable = table;
1495 table->dwNumEntries = 0;
1496 /* get from /proc/net/udp, no error if can't */
1497 fp = fopen("/proc/net/udp", "r");
1499 char buf[512] = { 0 }, *ptr;
1501 /* skip header line */
1502 ptr = fgets(buf, sizeof(buf), fp);
1503 while (ptr && table->dwNumEntries < numEntries) {
1504 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1505 ptr = fgets(buf, sizeof(buf), fp);
1510 strtoul(ptr, &endPtr, 16); /* skip */
1515 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1521 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1525 table->dwNumEntries++;
1531 ret = ERROR_NOT_SUPPORTED;
1534 ret = ERROR_OUTOFMEMORY;
1540 DWORD getNumTcpEntries(void)
1542 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1543 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1545 return getNumWithOneHeader ("/proc/net/tcp");
1550 /* Why not a lookup table? Because the TCPS_* constants are different
1551 on different platforms */
1552 static DWORD TCPStateToMIBState (int state)
1556 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1557 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1558 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1559 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1560 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1561 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1562 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1563 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1564 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1565 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1567 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1572 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1576 PMIB_TCPTABLE table;
1577 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1580 struct xinpgen *pXIG, *pOrigXIG;
1583 char buf[512] = { 0 }, *ptr;
1587 return ERROR_INVALID_PARAMETER;
1589 numEntries = getNumTcpEntries ();
1593 DWORD size = sizeof(MIB_TCPTABLE);
1596 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1597 *ppTcpTable = HeapAlloc (heap, flags, size);
1600 ERR ("Out of memory!\n");
1601 return ERROR_OUTOFMEMORY;
1603 maxEntries = numEntries;
1606 table = *ppTcpTable;
1607 table->dwNumEntries = 0;
1611 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1613 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1615 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1616 return ERROR_OUTOFMEMORY;
1619 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1622 ERR ("Out of memory!\n");
1623 return ERROR_OUTOFMEMORY;
1626 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1628 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1629 HeapFree (GetProcessHeap (), 0, Buf);
1630 return ERROR_OUTOFMEMORY;
1633 /* Might be nothing here; first entry is just a header it seems */
1634 if (Len <= sizeof (struct xinpgen))
1636 HeapFree (GetProcessHeap (), 0, Buf);
1640 pOrigXIG = (struct xinpgen *)Buf;
1643 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1644 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1645 (table->dwNumEntries < maxEntries);
1646 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1648 struct tcpcb *pTCPData = NULL;
1649 struct inpcb *pINData;
1650 struct xsocket *pSockData;
1652 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1653 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1654 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1656 /* Ignore sockets for other protocols */
1657 if (pSockData->xso_protocol != IPPROTO_TCP)
1660 /* Ignore PCBs that were freed while generating the data */
1661 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1664 /* we're only interested in IPv4 addresses */
1665 if (!(pINData->inp_vflag & INP_IPV4) ||
1666 (pINData->inp_vflag & INP_IPV6))
1669 /* If all 0's, skip it */
1670 if (!pINData->inp_laddr.s_addr &&
1671 !pINData->inp_lport &&
1672 !pINData->inp_faddr.s_addr &&
1673 !pINData->inp_fport)
1676 /* Fill in structure details */
1677 table->table[table->dwNumEntries].dwLocalAddr =
1678 pINData->inp_laddr.s_addr;
1679 table->table[table->dwNumEntries].dwLocalPort =
1681 table->table[table->dwNumEntries].dwRemoteAddr =
1682 pINData->inp_faddr.s_addr;
1683 table->table[table->dwNumEntries].dwRemotePort =
1685 table->table[table->dwNumEntries].dwState =
1686 TCPStateToMIBState (pTCPData->t_state);
1688 table->dwNumEntries++;
1691 HeapFree (GetProcessHeap (), 0, Buf);
1693 /* get from /proc/net/tcp, no error if can't */
1694 fp = fopen("/proc/net/tcp", "r");
1696 return ERROR_NOT_SUPPORTED;
1698 /* skip header line */
1699 ptr = fgets(buf, sizeof(buf), fp);
1700 while (ptr && table->dwNumEntries < maxEntries) {
1701 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1702 ptr = fgets(buf, sizeof(buf), fp);
1706 while (ptr && *ptr && *ptr != ':')
1711 table->table[table->dwNumEntries].dwLocalAddr =
1712 strtoul(ptr, &endPtr, 16);
1717 table->table[table->dwNumEntries].dwLocalPort =
1718 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1722 table->table[table->dwNumEntries].dwRemoteAddr =
1723 strtoul(ptr, &endPtr, 16);
1728 table->table[table->dwNumEntries].dwRemotePort =
1729 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1733 DWORD state = strtoul(ptr, &endPtr, 16);
1735 table->table[table->dwNumEntries].dwState =
1736 TCPStateToMIBState (state);
1739 table->dwNumEntries++;