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_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
49 #ifdef HAVE_NET_IF_DL_H
50 #include <net/if_dl.h>
52 #ifdef HAVE_NET_IF_TYPES_H
53 #include <net/if_types.h>
55 #ifdef HAVE_NET_ROUTE_H
56 #include <net/route.h>
58 #ifdef HAVE_NET_IF_ARP_H
59 #include <net/if_arp.h>
61 #ifdef HAVE_NETINET_IF_ETHER_H
62 #include <netinet/if_ether.h>
64 #ifdef HAVE_NETINET_IP_H
65 #include <netinet/ip.h>
67 #ifdef HAVE_NETINET_TCP_H
68 #include <netinet/tcp.h>
70 #ifdef HAVE_NETINET_TCP_FSM_H
71 #include <netinet/tcp_fsm.h>
73 #ifdef HAVE_NETINET_IN_PCB_H
74 #include <netinet/in_pcb.h>
76 #ifdef HAVE_NETINET_TCP_TIMER_H
77 #include <netinet/tcp_timer.h>
79 #ifdef HAVE_NETINET_TCP_VAR_H
80 #include <netinet/tcp_var.h>
82 #ifdef HAVE_NETINET_IN_SYSTM_H
83 #include <netinet/in_systm.h>
85 #ifdef HAVE_NETINET_IP_ICMP_H
86 #include <netinet/ip_icmp.h>
88 #ifdef HAVE_NETINET_ICMP_VAR_H
89 #include <netinet/icmp_var.h>
91 #ifdef HAVE_NETINET_IP_VAR_H
92 #include <netinet/ip_var.h>
94 #ifdef HAVE_NETINET_UDP_H
95 #include <netinet/udp.h>
97 #ifdef HAVE_NETINET_UDP_VAR_H
98 #include <netinet/udp_var.h>
100 #ifdef HAVE_SYS_PROTOSW_H
101 #include <sys/protosw.h>
103 #ifdef HAVE_SYS_SYSCTL_H
104 #include <sys/sysctl.h>
109 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
112 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
117 #include "iprtrmib.h"
121 #ifndef HAVE_NETINET_TCP_FSM_H
122 #define TCPS_ESTABLISHED 1
123 #define TCPS_SYN_SENT 2
124 #define TCPS_SYN_RECEIVED 3
125 #define TCPS_FIN_WAIT_1 4
126 #define TCPS_FIN_WAIT_2 5
127 #define TCPS_TIME_WAIT 6
128 #define TCPS_CLOSED 7
129 #define TCPS_CLOSE_WAIT 8
130 #define TCPS_LAST_ACK 9
131 #define TCPS_LISTEN 10
132 #define TCPS_CLOSING 11
135 #ifndef RTF_MULTICAST
136 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
139 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
141 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
143 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
144 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
145 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
149 struct if_msghdr *ifm;
150 struct if_data ifdata;
152 return ERROR_INVALID_PARAMETER;
154 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
156 ERR ("failed to get size of iflist\n");
157 return ERROR_NOT_SUPPORTED;
159 buf = HeapAlloc (GetProcessHeap (), 0, needed);
160 if (!buf) return ERROR_NOT_SUPPORTED;
161 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
163 ERR ("failed to get iflist\n");
164 HeapFree (GetProcessHeap (), 0, buf);
165 return ERROR_NOT_SUPPORTED;
168 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
170 ifm = (struct if_msghdr *) buf;
171 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
173 ifdata = ifm->ifm_data;
174 entry->dwMtu = ifdata.ifi_mtu;
175 entry->dwSpeed = ifdata.ifi_baudrate;
176 entry->dwInOctets = ifdata.ifi_ibytes;
177 entry->dwInErrors = ifdata.ifi_ierrors;
178 entry->dwInDiscards = ifdata.ifi_iqdrops;
179 entry->dwInUcastPkts = ifdata.ifi_ipackets;
180 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
181 entry->dwOutOctets = ifdata.ifi_obytes;
182 entry->dwOutUcastPkts = ifdata.ifi_opackets;
183 entry->dwOutErrors = ifdata.ifi_oerrors;
184 HeapFree (GetProcessHeap (), 0, buf);
188 HeapFree (GetProcessHeap (), 0, buf);
189 return ERROR_NOT_SUPPORTED;
191 /* get interface stats from /proc/net/dev, no error if can't
192 no inUnknownProtos, outNUcastPkts, outQLen */
196 return ERROR_INVALID_PARAMETER;
197 fp = fopen("/proc/net/dev", "r");
199 char buf[512] = { 0 }, *ptr;
200 int nameLen = strlen(name), nameFound = 0;
203 ptr = fgets(buf, sizeof(buf), fp);
204 while (ptr && !nameFound) {
205 while (*ptr && isspace(*ptr))
207 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
210 ptr = fgets(buf, sizeof(buf), fp);
217 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
221 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
225 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
229 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
233 strtoul(ptr, &endPtr, 10); /* skip */
237 strtoul(ptr, &endPtr, 10); /* skip */
241 strtoul(ptr, &endPtr, 10); /* skip */
245 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
249 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
253 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
257 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
261 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
269 ERR ("unimplemented!\n");
270 return ERROR_NOT_SUPPORTED;
277 DWORD getICMPStats(MIB_ICMP *stats)
279 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
280 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
281 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
283 struct icmpstat icmp_stat;
287 return ERROR_INVALID_PARAMETER;
289 needed = sizeof(icmp_stat);
290 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
292 ERR ("failed to get icmpstat\n");
293 return ERROR_NOT_SUPPORTED;
298 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
299 for(i = 0; i <= ICMP_MAXTYPE; i++)
300 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
302 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
304 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
305 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
306 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
307 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
308 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
309 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
310 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
311 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
312 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
313 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
314 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
318 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
319 for(i = 0; i <= ICMP_MAXTYPE; i++)
320 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
322 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
324 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
325 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
326 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
327 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
328 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
329 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
330 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
331 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
332 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
333 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
334 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
341 return ERROR_INVALID_PARAMETER;
343 memset(stats, 0, sizeof(MIB_ICMP));
344 /* get most of these stats from /proc/net/snmp, no error if can't */
345 fp = fopen("/proc/net/snmp", "r");
347 static const char hdr[] = "Icmp:";
348 char buf[512] = { 0 }, *ptr;
351 ptr = fgets(buf, sizeof(buf), fp);
352 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
354 /* last line was a header, get another */
355 ptr = fgets(buf, sizeof(buf), fp);
356 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
361 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
365 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
369 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
373 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
377 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
381 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
385 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
389 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
393 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
397 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
401 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
405 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
409 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
413 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
417 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
421 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
425 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
429 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
433 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
437 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
441 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
445 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
449 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
453 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
462 ERR ("unimplemented!\n");
463 return ERROR_NOT_SUPPORTED;
470 DWORD getIPStats(PMIB_IPSTATS stats)
472 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
473 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
474 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
475 int ip_ttl, ip_forwarding;
476 struct ipstat ip_stat;
480 return ERROR_INVALID_PARAMETER;
482 needed = sizeof(ip_stat);
483 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
485 ERR ("failed to get ipstat\n");
486 return ERROR_NOT_SUPPORTED;
489 needed = sizeof(ip_ttl);
490 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
492 ERR ("failed to get ip Default TTL\n");
493 return ERROR_NOT_SUPPORTED;
496 needed = sizeof(ip_forwarding);
497 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
499 ERR ("failed to get ip forwarding\n");
500 return ERROR_NOT_SUPPORTED;
503 stats->dwForwarding = ip_forwarding;
504 stats->dwDefaultTTL = ip_ttl;
505 stats->dwInDelivers = ip_stat.ips_delivered;
506 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
507 stats->dwInAddrErrors = ip_stat.ips_cantforward;
508 stats->dwInReceives = ip_stat.ips_total;
509 stats->dwForwDatagrams = ip_stat.ips_forward;
510 stats->dwInUnknownProtos = ip_stat.ips_noproto;
511 stats->dwInDiscards = ip_stat.ips_fragdropped;
512 stats->dwOutDiscards = ip_stat.ips_odropped;
513 stats->dwReasmOks = ip_stat.ips_reassembled;
514 stats->dwFragOks = ip_stat.ips_fragmented;
515 stats->dwFragFails = ip_stat.ips_cantfrag;
516 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
517 stats->dwOutNoRoutes = ip_stat.ips_noroute;
518 stats->dwOutRequests = ip_stat.ips_localout;
519 stats->dwReasmReqds = ip_stat.ips_fragments;
526 return ERROR_INVALID_PARAMETER;
528 memset(stats, 0, sizeof(MIB_IPSTATS));
529 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
530 stats->dwNumRoutes = getNumRoutes();
532 /* get most of these stats from /proc/net/snmp, no error if can't */
533 fp = fopen("/proc/net/snmp", "r");
535 static const char hdr[] = "Ip:";
536 char buf[512] = { 0 }, *ptr;
539 ptr = fgets(buf, sizeof(buf), fp);
540 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
542 /* last line was a header, get another */
543 ptr = fgets(buf, sizeof(buf), fp);
544 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
549 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
553 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
557 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
561 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
565 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
569 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
573 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
577 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
581 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
585 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
589 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
593 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
597 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
601 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
605 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
609 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
613 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
617 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
621 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
624 /* hmm, no routingDiscards */
631 ERR ("unimplemented!\n");
632 return ERROR_NOT_SUPPORTED;
639 DWORD getTCPStats(MIB_TCPSTATS *stats)
641 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
642 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
644 #define TCPTV_REXMTMAX 128
646 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
647 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
649 struct tcpstat tcp_stat;
653 return ERROR_INVALID_PARAMETER;
654 needed = sizeof(tcp_stat);
656 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
658 ERR ("failed to get tcpstat\n");
659 return ERROR_NOT_SUPPORTED;
662 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
663 stats->dwRtoMin = TCPTV_MIN;
664 stats->dwRtoMax = TCPTV_REXMTMAX;
665 stats->dwMaxConn = -1;
666 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
667 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
668 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
669 stats->dwEstabResets = tcp_stat.tcps_drops;
670 stats->dwCurrEstab = 0;
671 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
672 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
673 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
674 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
675 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
676 stats->dwNumConns = tcp_stat.tcps_connects;
684 return ERROR_INVALID_PARAMETER;
686 memset(stats, 0, sizeof(MIB_TCPSTATS));
688 /* get from /proc/net/snmp, no error if can't */
689 fp = fopen("/proc/net/snmp", "r");
691 static const char hdr[] = "Tcp:";
692 char buf[512] = { 0 }, *ptr;
696 ptr = fgets(buf, sizeof(buf), fp);
697 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
699 /* last line was a header, get another */
700 ptr = fgets(buf, sizeof(buf), fp);
701 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
706 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
710 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
714 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
718 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
722 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
726 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
730 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
734 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
738 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
742 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
746 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
750 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
754 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
758 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
761 stats->dwNumConns = getNumTcpEntries();
768 ERR ("unimplemented!\n");
769 return ERROR_NOT_SUPPORTED;
776 DWORD getUDPStats(MIB_UDPSTATS *stats)
778 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
779 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
780 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
781 struct udpstat udp_stat;
784 return ERROR_INVALID_PARAMETER;
786 needed = sizeof(udp_stat);
788 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
790 ERR ("failed to get udpstat\n");
791 return ERROR_NOT_SUPPORTED;
794 stats->dwInDatagrams = udp_stat.udps_ipackets;
795 stats->dwOutDatagrams = udp_stat.udps_opackets;
796 stats->dwNoPorts = udp_stat.udps_noport;
797 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
798 stats->dwNumAddrs = getNumUdpEntries();
805 return ERROR_INVALID_PARAMETER;
807 memset(stats, 0, sizeof(MIB_UDPSTATS));
809 /* get from /proc/net/snmp, no error if can't */
810 fp = fopen("/proc/net/snmp", "r");
812 static const char hdr[] = "Udp:";
813 char buf[512] = { 0 }, *ptr;
817 ptr = fgets(buf, sizeof(buf), fp);
818 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
820 /* last line was a header, get another */
821 ptr = fgets(buf, sizeof(buf), fp);
822 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
827 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
831 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
835 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
839 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
843 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
852 ERR ("unimplemented!\n");
853 return ERROR_NOT_SUPPORTED;
860 static DWORD getNumWithOneHeader(const char *filename)
862 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
865 struct xinpgen *pXIG, *pOrigXIG;
867 DWORD NumEntries = 0;
869 if (!strcmp (filename, "net.inet.tcp.pcblist"))
870 Protocol = IPPROTO_TCP;
871 else if (!strcmp (filename, "net.inet.udp.pcblist"))
872 Protocol = IPPROTO_UDP;
875 ERR ("Unsupported mib '%s', needs protocol mapping\n",
880 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
882 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
886 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
889 ERR ("Out of memory!\n");
893 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
895 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
896 HeapFree (GetProcessHeap (), 0, Buf);
900 /* Might be nothing here; first entry is just a header it seems */
901 if (Len <= sizeof (struct xinpgen))
903 HeapFree (GetProcessHeap (), 0, Buf);
907 pOrigXIG = (struct xinpgen *)Buf;
910 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
911 pXIG->xig_len > sizeof (struct xinpgen);
912 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
914 struct tcpcb *pTCPData = NULL;
915 struct inpcb *pINData;
916 struct xsocket *pSockData;
918 if (Protocol == IPPROTO_TCP)
920 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
921 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
922 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
926 pINData = &((struct xinpcb *)pXIG)->xi_inp;
927 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
930 /* Ignore sockets for other protocols */
931 if (pSockData->xso_protocol != Protocol)
934 /* Ignore PCBs that were freed while generating the data */
935 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
938 /* we're only interested in IPv4 addresses */
939 if (!(pINData->inp_vflag & INP_IPV4) ||
940 (pINData->inp_vflag & INP_IPV6))
943 /* If all 0's, skip it */
944 if (!pINData->inp_laddr.s_addr &&
945 !pINData->inp_lport &&
946 !pINData->inp_faddr.s_addr &&
953 HeapFree (GetProcessHeap (), 0, Buf);
959 fp = fopen(filename, "r");
961 char buf[512] = { 0 }, *ptr;
964 ptr = fgets(buf, sizeof(buf), fp);
967 ptr = fgets(buf, sizeof(buf), fp);
975 ERR ("Unable to open '%s' to count entries!\n", filename);
981 DWORD getNumRoutes(void)
983 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
984 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
986 char *buf, *lim, *next;
987 struct rt_msghdr *rtm;
988 DWORD RouteCount = 0;
990 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
992 ERR ("sysctl 1 failed!\n");
996 buf = HeapAlloc (GetProcessHeap (), 0, needed);
999 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1001 ERR ("sysctl 2 failed!\n");
1002 HeapFree (GetProcessHeap (), 0, buf);
1007 for (next = buf; next < lim; next += rtm->rtm_msglen)
1009 rtm = (struct rt_msghdr *)next;
1011 if (rtm->rtm_type != RTM_GET)
1013 WARN ("Got unexpected message type 0x%x!\n",
1018 /* Ignore all entries except for gateway routes which aren't
1020 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1026 HeapFree (GetProcessHeap (), 0, buf);
1029 return getNumWithOneHeader("/proc/net/route");
1033 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1038 if (!ppIpForwardTable)
1039 ret = ERROR_INVALID_PARAMETER;
1041 DWORD numRoutes = getNumRoutes();
1042 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1043 PMIB_IPFORWARDTABLE table;
1046 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1047 table = HeapAlloc(heap, flags, size);
1049 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1050 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1052 char *buf, *lim, *next, *addrPtr;
1053 struct rt_msghdr *rtm;
1055 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1057 ERR ("sysctl 1 failed!\n");
1058 HeapFree (GetProcessHeap (), 0, table);
1062 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1065 HeapFree (GetProcessHeap (), 0, table);
1066 return ERROR_OUTOFMEMORY;
1069 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1071 ERR ("sysctl 2 failed!\n");
1072 HeapFree (GetProcessHeap (), 0, table);
1073 HeapFree (GetProcessHeap (), 0, buf);
1077 *ppIpForwardTable = table;
1078 table->dwNumEntries = 0;
1081 for (next = buf; next < lim; next += rtm->rtm_msglen)
1085 rtm = (struct rt_msghdr *)next;
1087 if (rtm->rtm_type != RTM_GET)
1089 WARN ("Got unexpected message type 0x%x!\n",
1094 /* Ignore all entries except for gateway routes which aren't
1096 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1097 (rtm->rtm_flags & RTF_MULTICAST))
1100 memset (&table->table[table->dwNumEntries], 0,
1101 sizeof (MIB_IPFORWARDROW));
1102 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1103 table->table[table->dwNumEntries].dwForwardType =
1104 MIB_IPROUTE_TYPE_INDIRECT;
1105 table->table[table->dwNumEntries].dwForwardMetric1 =
1106 rtm->rtm_rmx.rmx_hopcount;
1107 table->table[table->dwNumEntries].dwForwardProto =
1110 addrPtr = (char *)(rtm + 1);
1112 for (i = 1; i; i <<= 1)
1114 struct sockaddr *sa;
1117 if (!(i & rtm->rtm_addrs))
1120 sa = (struct sockaddr *)addrPtr;
1121 ADVANCE (addrPtr, sa);
1123 /* default routes are encoded by length-zero sockaddr */
1124 if (sa->sa_len == 0)
1126 else if (sa->sa_family != AF_INET)
1128 WARN ("Received unsupported sockaddr family 0x%x\n",
1134 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1136 addr = sin->sin_addr.s_addr;
1142 table->table[table->dwNumEntries].dwForwardDest = addr;
1146 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1150 table->table[table->dwNumEntries].dwForwardMask = addr;
1154 WARN ("Unexpected address type 0x%x\n", i);
1158 table->dwNumEntries++;
1161 HeapFree (GetProcessHeap (), 0, buf);
1167 *ppIpForwardTable = table;
1168 table->dwNumEntries = 0;
1169 /* get from /proc/net/route, no error if can't */
1170 fp = fopen("/proc/net/route", "r");
1172 char buf[512] = { 0 }, *ptr;
1174 /* skip header line */
1175 ptr = fgets(buf, sizeof(buf), fp);
1176 while (ptr && table->dwNumEntries < numRoutes) {
1177 memset(&table->table[table->dwNumEntries], 0,
1178 sizeof(MIB_IPFORWARDROW));
1179 ptr = fgets(buf, sizeof(buf), fp);
1183 while (!isspace(*ptr))
1187 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1190 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1192 table->table[table->dwNumEntries].dwForwardDest =
1193 strtoul(ptr, &endPtr, 16);
1197 table->table[table->dwNumEntries].dwForwardNextHop =
1198 strtoul(ptr, &endPtr, 16);
1202 DWORD flags = strtoul(ptr, &endPtr, 16);
1204 if (!(flags & RTF_UP))
1205 table->table[table->dwNumEntries].dwForwardType =
1206 MIB_IPROUTE_TYPE_INVALID;
1207 else if (flags & RTF_GATEWAY)
1208 table->table[table->dwNumEntries].dwForwardType =
1209 MIB_IPROUTE_TYPE_INDIRECT;
1211 table->table[table->dwNumEntries].dwForwardType =
1212 MIB_IPROUTE_TYPE_DIRECT;
1216 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1220 strtoul(ptr, &endPtr, 16); /* use, skip */
1224 table->table[table->dwNumEntries].dwForwardMetric1 =
1225 strtoul(ptr, &endPtr, 16);
1229 table->table[table->dwNumEntries].dwForwardMask =
1230 strtoul(ptr, &endPtr, 16);
1233 /* FIXME: other protos might be appropriate, e.g. the default
1234 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1235 table->table[table->dwNumEntries].dwForwardProto =
1237 table->dwNumEntries++;
1245 ERR ("unimplemented!\n");
1246 return ERROR_NOT_SUPPORTED;
1251 ret = ERROR_OUTOFMEMORY;
1256 DWORD getNumArpEntries(void)
1258 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1259 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1260 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1261 DWORD arpEntries = 0;
1263 char *buf, *lim, *next;
1264 struct rt_msghdr *rtm;
1265 struct sockaddr_inarp *sinarp;
1266 struct sockaddr_dl *sdl;
1268 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1270 ERR ("failed to get size of arp table\n");
1274 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1277 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1279 ERR ("failed to get arp table\n");
1280 HeapFree (GetProcessHeap (), 0, buf);
1288 rtm = (struct rt_msghdr *)next;
1289 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1290 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1291 if(sdl->sdl_alen) /* arp entry */
1293 next += rtm->rtm_msglen;
1295 HeapFree (GetProcessHeap (), 0, buf);
1298 return getNumWithOneHeader("/proc/net/arp");
1301 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1303 DWORD ret = NO_ERROR;
1305 ret = ERROR_INVALID_PARAMETER;
1307 DWORD numEntries = getNumArpEntries();
1308 DWORD size = sizeof(MIB_IPNETTABLE);
1309 PMIB_IPNETTABLE table;
1312 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1313 table = HeapAlloc(heap, flags, size);
1314 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1317 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1318 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1320 char *buf, *lim, *next;
1321 struct rt_msghdr *rtm;
1322 struct sockaddr_inarp *sinarp;
1323 struct sockaddr_dl *sdl;
1325 *ppIpNetTable = table;
1326 table->dwNumEntries = 0;
1328 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1330 ERR ("failed to get size of arp table\n");
1331 return ERROR_NOT_SUPPORTED;
1334 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1335 if (!buf) return ERROR_OUTOFMEMORY;
1337 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1339 ERR ("failed to get arp table\n");
1340 HeapFree (GetProcessHeap (), 0, buf);
1341 return ERROR_NOT_SUPPORTED;
1348 rtm = (struct rt_msghdr *)next;
1349 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1350 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1351 if(sdl->sdl_alen) /* arp entry */
1353 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1354 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1355 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1356 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1357 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1359 table->table[table->dwNumEntries].bPhysAddr[
1360 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1362 if(rtm->rtm_rmx.rmx_expire == 0)
1363 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1364 else if(sinarp->sin_other & SIN_PROXY)
1365 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1366 else if(rtm->rtm_rmx.rmx_expire != 0)
1367 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1369 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1371 table->dwNumEntries++;
1373 next += rtm->rtm_msglen;
1375 HeapFree (GetProcessHeap (), 0, buf);
1378 ret = ERROR_OUTOFMEMORY;
1384 *ppIpNetTable = table;
1385 table->dwNumEntries = 0;
1386 /* get from /proc/net/arp, no error if can't */
1387 fp = fopen("/proc/net/arp", "r");
1389 char buf[512] = { 0 }, *ptr;
1391 /* skip header line */
1392 ptr = fgets(buf, sizeof(buf), fp);
1393 while (ptr && table->dwNumEntries < numEntries) {
1394 ptr = fgets(buf, sizeof(buf), fp);
1398 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1399 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1400 while (ptr && *ptr && !isspace(*ptr))
1404 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1408 DWORD flags = strtoul(ptr, &endPtr, 16);
1411 if (flags & ATF_COM)
1412 table->table[table->dwNumEntries].dwType =
1413 MIB_IPNET_TYPE_DYNAMIC;
1417 if (flags & ATF_PERM)
1418 table->table[table->dwNumEntries].dwType =
1419 MIB_IPNET_TYPE_STATIC;
1422 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1426 while (ptr && *ptr && isspace(*ptr))
1428 while (ptr && *ptr && !isspace(*ptr)) {
1429 DWORD byte = strtoul(ptr, &endPtr, 16);
1431 if (endPtr && *endPtr) {
1433 table->table[table->dwNumEntries].bPhysAddr[
1434 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1440 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1443 getInterfaceIndexByName(ptr,
1444 &table->table[table->dwNumEntries].dwIndex);
1445 table->dwNumEntries++;
1451 ret = ERROR_NOT_SUPPORTED;
1454 ret = ERROR_OUTOFMEMORY;
1459 DWORD getNumUdpEntries(void)
1461 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1462 return getNumWithOneHeader ("net.inet.udp.pcblist");
1464 return getNumWithOneHeader("/proc/net/udp");
1468 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1472 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1473 ERR ("unimplemented!\n");
1474 return ERROR_NOT_SUPPORTED;
1478 ret = ERROR_INVALID_PARAMETER;
1480 DWORD numEntries = getNumUdpEntries();
1481 DWORD size = sizeof(MIB_UDPTABLE);
1482 PMIB_UDPTABLE table;
1485 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1486 table = HeapAlloc(heap, flags, size);
1491 *ppUdpTable = table;
1492 table->dwNumEntries = 0;
1493 /* get from /proc/net/udp, no error if can't */
1494 fp = fopen("/proc/net/udp", "r");
1496 char buf[512] = { 0 }, *ptr;
1498 /* skip header line */
1499 ptr = fgets(buf, sizeof(buf), fp);
1500 while (ptr && table->dwNumEntries < numEntries) {
1501 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1502 ptr = fgets(buf, sizeof(buf), fp);
1507 strtoul(ptr, &endPtr, 16); /* skip */
1512 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1518 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1522 table->dwNumEntries++;
1528 ret = ERROR_NOT_SUPPORTED;
1531 ret = ERROR_OUTOFMEMORY;
1537 DWORD getNumTcpEntries(void)
1539 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1540 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1542 return getNumWithOneHeader ("/proc/net/tcp");
1547 /* Why not a lookup table? Because the TCPS_* constants are different
1548 on different platforms */
1549 static DWORD TCPStateToMIBState (int state)
1553 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1554 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1555 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1556 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1557 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1558 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1559 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1560 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1561 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1562 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1564 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1569 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1573 PMIB_TCPTABLE table;
1574 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1577 struct xinpgen *pXIG, *pOrigXIG;
1580 char buf[512] = { 0 }, *ptr;
1584 return ERROR_INVALID_PARAMETER;
1586 numEntries = getNumTcpEntries ();
1590 DWORD size = sizeof(MIB_TCPTABLE);
1593 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1594 *ppTcpTable = HeapAlloc (heap, flags, size);
1597 ERR ("Out of memory!\n");
1598 return ERROR_OUTOFMEMORY;
1600 maxEntries = numEntries;
1603 table = *ppTcpTable;
1604 table->dwNumEntries = 0;
1608 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1610 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1612 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1613 return ERROR_OUTOFMEMORY;
1616 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1619 ERR ("Out of memory!\n");
1620 return ERROR_OUTOFMEMORY;
1623 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1625 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1626 HeapFree (GetProcessHeap (), 0, Buf);
1627 return ERROR_OUTOFMEMORY;
1630 /* Might be nothing here; first entry is just a header it seems */
1631 if (Len <= sizeof (struct xinpgen))
1633 HeapFree (GetProcessHeap (), 0, Buf);
1637 pOrigXIG = (struct xinpgen *)Buf;
1640 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1641 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1642 (table->dwNumEntries < maxEntries);
1643 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1645 struct tcpcb *pTCPData = NULL;
1646 struct inpcb *pINData;
1647 struct xsocket *pSockData;
1649 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1650 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1651 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1653 /* Ignore sockets for other protocols */
1654 if (pSockData->xso_protocol != IPPROTO_TCP)
1657 /* Ignore PCBs that were freed while generating the data */
1658 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1661 /* we're only interested in IPv4 addresses */
1662 if (!(pINData->inp_vflag & INP_IPV4) ||
1663 (pINData->inp_vflag & INP_IPV6))
1666 /* If all 0's, skip it */
1667 if (!pINData->inp_laddr.s_addr &&
1668 !pINData->inp_lport &&
1669 !pINData->inp_faddr.s_addr &&
1670 !pINData->inp_fport)
1673 /* Fill in structure details */
1674 table->table[table->dwNumEntries].dwLocalAddr =
1675 pINData->inp_laddr.s_addr;
1676 table->table[table->dwNumEntries].dwLocalPort =
1678 table->table[table->dwNumEntries].dwRemoteAddr =
1679 pINData->inp_faddr.s_addr;
1680 table->table[table->dwNumEntries].dwRemotePort =
1682 table->table[table->dwNumEntries].dwState =
1683 TCPStateToMIBState (pTCPData->t_state);
1685 table->dwNumEntries++;
1688 HeapFree (GetProcessHeap (), 0, Buf);
1690 /* get from /proc/net/tcp, no error if can't */
1691 fp = fopen("/proc/net/tcp", "r");
1693 return ERROR_NOT_SUPPORTED;
1695 /* skip header line */
1696 ptr = fgets(buf, sizeof(buf), fp);
1697 while (ptr && table->dwNumEntries < maxEntries) {
1698 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1699 ptr = fgets(buf, sizeof(buf), fp);
1703 while (ptr && *ptr && *ptr != ':')
1708 table->table[table->dwNumEntries].dwLocalAddr =
1709 strtoul(ptr, &endPtr, 16);
1714 table->table[table->dwNumEntries].dwLocalPort =
1715 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1719 table->table[table->dwNumEntries].dwRemoteAddr =
1720 strtoul(ptr, &endPtr, 16);
1725 table->table[table->dwNumEntries].dwRemotePort =
1726 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1730 DWORD state = strtoul(ptr, &endPtr, 16);
1732 table->table[table->dwNumEntries].dwState =
1733 TCPStateToMIBState (state);
1736 table->dwNumEntries++;