2 * Copyright (C) 2003,2006 Juan Lang
3 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * Copyright (C) 2009 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
28 #include <sys/types.h>
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
35 #ifdef HAVE_SYS_SOCKETVAR_H
36 #include <sys/socketvar.h>
38 #ifdef HAVE_SYS_TIMEOUT_H
39 #include <sys/timeout.h>
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
53 #ifdef HAVE_NET_IF_DL_H
54 #include <net/if_dl.h>
56 #ifdef HAVE_NET_IF_TYPES_H
57 #include <net/if_types.h>
59 #ifdef HAVE_NET_ROUTE_H
60 #include <net/route.h>
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
65 #ifdef HAVE_NETINET_IF_ETHER_H
66 #include <netinet/if_ether.h>
68 #ifdef HAVE_NETINET_IF_INARP_H
69 #include <netinet/if_inarp.h>
71 #ifdef HAVE_NETINET_IP_H
72 #include <netinet/ip.h>
74 #ifdef HAVE_NETINET_TCP_H
75 #include <netinet/tcp.h>
77 #ifdef HAVE_NETINET_IP_VAR_H
78 #include <netinet/ip_var.h>
80 #ifdef HAVE_NETINET_TCP_FSM_H
81 #include <netinet/tcp_fsm.h>
83 #ifdef HAVE_NETINET_IN_PCB_H
84 #include <netinet/in_pcb.h>
86 #ifdef HAVE_NETINET_TCP_TIMER_H
87 #include <netinet/tcp_timer.h>
89 #ifdef HAVE_NETINET_TCP_VAR_H
90 #include <netinet/tcp_var.h>
92 #ifdef HAVE_NETINET_IP_ICMP_H
93 #include <netinet/ip_icmp.h>
95 #ifdef HAVE_NETINET_ICMP_VAR_H
96 #include <netinet/icmp_var.h>
98 #ifdef HAVE_NETINET_UDP_H
99 #include <netinet/udp.h>
101 #ifdef HAVE_NETINET_UDP_VAR_H
102 #include <netinet/udp_var.h>
104 #ifdef HAVE_SYS_PROTOSW_H
105 #include <sys/protosw.h>
107 #ifdef HAVE_SYS_SYSCTL_H
108 #include <sys/sysctl.h>
113 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
116 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
121 #include "iprtrmib.h"
125 #include "wine/debug.h"
127 #ifndef HAVE_NETINET_TCP_FSM_H
128 #define TCPS_ESTABLISHED 1
129 #define TCPS_SYN_SENT 2
130 #define TCPS_SYN_RECEIVED 3
131 #define TCPS_FIN_WAIT_1 4
132 #define TCPS_FIN_WAIT_2 5
133 #define TCPS_TIME_WAIT 6
134 #define TCPS_CLOSED 7
135 #define TCPS_CLOSE_WAIT 8
136 #define TCPS_LAST_ACK 9
137 #define TCPS_LISTEN 10
138 #define TCPS_CLOSING 11
141 #ifndef RTF_MULTICAST
142 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
146 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
149 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
151 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
153 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
154 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
155 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
159 struct if_msghdr *ifm;
160 struct if_data ifdata;
162 return ERROR_INVALID_PARAMETER;
164 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
166 ERR ("failed to get size of iflist\n");
167 return ERROR_NOT_SUPPORTED;
169 buf = HeapAlloc (GetProcessHeap (), 0, needed);
170 if (!buf) return ERROR_NOT_SUPPORTED;
171 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
173 ERR ("failed to get iflist\n");
174 HeapFree (GetProcessHeap (), 0, buf);
175 return ERROR_NOT_SUPPORTED;
178 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
180 ifm = (struct if_msghdr *) buf;
181 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
183 ifdata = ifm->ifm_data;
184 entry->dwMtu = ifdata.ifi_mtu;
185 entry->dwSpeed = ifdata.ifi_baudrate;
186 entry->dwInOctets = ifdata.ifi_ibytes;
187 entry->dwInErrors = ifdata.ifi_ierrors;
188 entry->dwInDiscards = ifdata.ifi_iqdrops;
189 entry->dwInUcastPkts = ifdata.ifi_ipackets;
190 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
191 entry->dwOutOctets = ifdata.ifi_obytes;
192 entry->dwOutUcastPkts = ifdata.ifi_opackets;
193 entry->dwOutErrors = ifdata.ifi_oerrors;
194 HeapFree (GetProcessHeap (), 0, buf);
198 HeapFree (GetProcessHeap (), 0, buf);
199 return ERROR_NOT_SUPPORTED;
201 /* get interface stats from /proc/net/dev, no error if can't
202 no inUnknownProtos, outNUcastPkts, outQLen */
206 return ERROR_INVALID_PARAMETER;
207 fp = fopen("/proc/net/dev", "r");
209 char buf[512] = { 0 }, *ptr;
210 int nameLen = strlen(name), nameFound = 0;
213 ptr = fgets(buf, sizeof(buf), fp);
214 while (ptr && !nameFound) {
215 while (*ptr && isspace(*ptr))
217 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
220 ptr = fgets(buf, sizeof(buf), fp);
227 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
231 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
235 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
239 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
243 strtoul(ptr, &endPtr, 10); /* skip */
247 strtoul(ptr, &endPtr, 10); /* skip */
251 strtoul(ptr, &endPtr, 10); /* skip */
255 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
259 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
263 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
267 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
271 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
279 ERR ("unimplemented!\n");
280 return ERROR_NOT_SUPPORTED;
287 DWORD getICMPStats(MIB_ICMP *stats)
289 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
290 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
291 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
293 struct icmpstat icmp_stat;
297 return ERROR_INVALID_PARAMETER;
299 needed = sizeof(icmp_stat);
300 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
302 ERR ("failed to get icmpstat\n");
303 return ERROR_NOT_SUPPORTED;
308 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
309 for(i = 0; i <= ICMP_MAXTYPE; i++)
310 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
312 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
314 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
315 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
316 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
317 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
318 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
319 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
320 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
321 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
322 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
323 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
324 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
326 #ifdef HAVE_ICPS_OUTHIST
328 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
329 for(i = 0; i <= ICMP_MAXTYPE; i++)
330 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
332 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
334 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
335 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
336 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
337 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
338 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
339 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
340 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
341 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
342 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
343 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
344 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
345 #else /* ICPS_OUTHIST */
346 memset( &stats->stats.icmpOutStats, 0, sizeof(stats->stats.icmpOutStats) );
347 #endif /* ICPS_OUTHIST */
351 #else /* ICMPCTL_STATS */
355 return ERROR_INVALID_PARAMETER;
357 memset(stats, 0, sizeof(MIB_ICMP));
358 /* get most of these stats from /proc/net/snmp, no error if can't */
359 fp = fopen("/proc/net/snmp", "r");
361 static const char hdr[] = "Icmp:";
362 char buf[512] = { 0 }, *ptr;
365 ptr = fgets(buf, sizeof(buf), fp);
366 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
368 /* last line was a header, get another */
369 ptr = fgets(buf, sizeof(buf), fp);
370 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
375 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
379 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
383 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
387 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
391 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
395 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
399 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
403 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
407 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
411 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
415 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
419 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
423 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
427 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
431 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
435 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
439 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
443 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
447 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
451 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
455 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
459 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
463 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
467 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
476 ERR ("unimplemented!\n");
477 return ERROR_NOT_SUPPORTED;
484 DWORD getIPStats(PMIB_IPSTATS stats)
486 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
487 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
488 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
489 int ip_ttl, ip_forwarding;
490 struct ipstat ip_stat;
494 return ERROR_INVALID_PARAMETER;
496 needed = sizeof(ip_stat);
497 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
499 ERR ("failed to get ipstat\n");
500 return ERROR_NOT_SUPPORTED;
503 needed = sizeof(ip_ttl);
504 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
506 ERR ("failed to get ip Default TTL\n");
507 return ERROR_NOT_SUPPORTED;
510 needed = sizeof(ip_forwarding);
511 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
513 ERR ("failed to get ip forwarding\n");
514 return ERROR_NOT_SUPPORTED;
517 stats->dwForwarding = ip_forwarding;
518 stats->dwDefaultTTL = ip_ttl;
519 stats->dwInDelivers = ip_stat.ips_delivered;
520 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
521 stats->dwInAddrErrors = ip_stat.ips_cantforward;
522 stats->dwInReceives = ip_stat.ips_total;
523 stats->dwForwDatagrams = ip_stat.ips_forward;
524 stats->dwInUnknownProtos = ip_stat.ips_noproto;
525 stats->dwInDiscards = ip_stat.ips_fragdropped;
526 stats->dwOutDiscards = ip_stat.ips_odropped;
527 stats->dwReasmOks = ip_stat.ips_reassembled;
528 stats->dwFragOks = ip_stat.ips_fragmented;
529 stats->dwFragFails = ip_stat.ips_cantfrag;
530 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
531 stats->dwOutNoRoutes = ip_stat.ips_noroute;
532 stats->dwOutRequests = ip_stat.ips_localout;
533 stats->dwReasmReqds = ip_stat.ips_fragments;
540 return ERROR_INVALID_PARAMETER;
542 memset(stats, 0, sizeof(MIB_IPSTATS));
543 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
544 stats->dwNumRoutes = getNumRoutes();
546 /* get most of these stats from /proc/net/snmp, no error if can't */
547 fp = fopen("/proc/net/snmp", "r");
549 static const char hdr[] = "Ip:";
550 char buf[512] = { 0 }, *ptr;
553 ptr = fgets(buf, sizeof(buf), fp);
554 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
556 /* last line was a header, get another */
557 ptr = fgets(buf, sizeof(buf), fp);
558 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
563 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
567 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
571 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
575 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
579 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
583 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
587 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
591 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
595 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
599 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
603 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
607 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
611 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
615 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
619 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
623 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
627 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
631 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
635 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
638 /* hmm, no routingDiscards */
645 ERR ("unimplemented!\n");
646 return ERROR_NOT_SUPPORTED;
653 DWORD getTCPStats(MIB_TCPSTATS *stats)
655 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
656 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
658 #define TCPTV_REXMTMAX 128
660 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
661 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
663 struct tcpstat tcp_stat;
667 return ERROR_INVALID_PARAMETER;
668 needed = sizeof(tcp_stat);
670 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
672 ERR ("failed to get tcpstat\n");
673 return ERROR_NOT_SUPPORTED;
676 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
677 stats->dwRtoMin = TCPTV_MIN;
678 stats->dwRtoMax = TCPTV_REXMTMAX;
679 stats->dwMaxConn = -1;
680 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
681 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
682 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
683 stats->dwEstabResets = tcp_stat.tcps_drops;
684 stats->dwCurrEstab = 0;
685 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
686 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
687 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
688 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
689 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
690 stats->dwNumConns = tcp_stat.tcps_connects;
696 MIB_TCPTABLE *tcp_table;
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 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
778 stats->dwNumConns = tcp_table->dwNumEntries;
779 HeapFree( GetProcessHeap(), 0, tcp_table );
787 ERR ("unimplemented!\n");
788 return ERROR_NOT_SUPPORTED;
795 DWORD getUDPStats(MIB_UDPSTATS *stats)
797 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
798 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
799 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
800 struct udpstat udp_stat;
801 MIB_UDPTABLE *udp_table;
804 return ERROR_INVALID_PARAMETER;
806 needed = sizeof(udp_stat);
808 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
810 ERR ("failed to get udpstat\n");
811 return ERROR_NOT_SUPPORTED;
814 stats->dwInDatagrams = udp_stat.udps_ipackets;
815 stats->dwOutDatagrams = udp_stat.udps_opackets;
816 stats->dwNoPorts = udp_stat.udps_noport;
817 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
818 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
820 stats->dwNumAddrs = udp_table->dwNumEntries;
821 HeapFree( GetProcessHeap(), 0, udp_table );
823 else stats->dwNumAddrs = 0;
830 return ERROR_INVALID_PARAMETER;
832 memset(stats, 0, sizeof(MIB_UDPSTATS));
834 /* get from /proc/net/snmp, no error if can't */
835 fp = fopen("/proc/net/snmp", "r");
837 static const char hdr[] = "Udp:";
838 char buf[512] = { 0 }, *ptr;
842 ptr = fgets(buf, sizeof(buf), fp);
843 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
845 /* last line was a header, get another */
846 ptr = fgets(buf, sizeof(buf), fp);
847 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
852 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
856 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
860 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
864 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
868 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
877 ERR ("unimplemented!\n");
878 return ERROR_NOT_SUPPORTED;
885 static DWORD getNumWithOneHeader(const char *filename)
887 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
890 struct xinpgen *pXIG, *pOrigXIG;
892 DWORD NumEntries = 0;
894 if (!strcmp (filename, "net.inet.tcp.pcblist"))
895 Protocol = IPPROTO_TCP;
896 else if (!strcmp (filename, "net.inet.udp.pcblist"))
897 Protocol = IPPROTO_UDP;
900 ERR ("Unsupported mib '%s', needs protocol mapping\n",
905 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
907 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
911 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
914 ERR ("Out of memory!\n");
918 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
920 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
921 HeapFree (GetProcessHeap (), 0, Buf);
925 /* Might be nothing here; first entry is just a header it seems */
926 if (Len <= sizeof (struct xinpgen))
928 HeapFree (GetProcessHeap (), 0, Buf);
932 pOrigXIG = (struct xinpgen *)Buf;
935 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
936 pXIG->xig_len > sizeof (struct xinpgen);
937 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
939 struct tcpcb *pTCPData = NULL;
940 struct inpcb *pINData;
941 struct xsocket *pSockData;
943 if (Protocol == IPPROTO_TCP)
945 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
946 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
947 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
951 pINData = &((struct xinpcb *)pXIG)->xi_inp;
952 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
955 /* Ignore sockets for other protocols */
956 if (pSockData->xso_protocol != Protocol)
959 /* Ignore PCBs that were freed while generating the data */
960 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
963 /* we're only interested in IPv4 addresses */
964 if (!(pINData->inp_vflag & INP_IPV4) ||
965 (pINData->inp_vflag & INP_IPV6))
968 /* If all 0's, skip it */
969 if (!pINData->inp_laddr.s_addr &&
970 !pINData->inp_lport &&
971 !pINData->inp_faddr.s_addr &&
978 HeapFree (GetProcessHeap (), 0, Buf);
984 fp = fopen(filename, "r");
986 char buf[512] = { 0 }, *ptr;
989 ptr = fgets(buf, sizeof(buf), fp);
992 ptr = fgets(buf, sizeof(buf), fp);
1000 ERR ("Unable to open '%s' to count entries!\n", filename);
1006 DWORD getNumRoutes(void)
1008 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1009 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1011 char *buf, *lim, *next;
1012 struct rt_msghdr *rtm;
1013 DWORD RouteCount = 0;
1015 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1017 ERR ("sysctl 1 failed!\n");
1021 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1024 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1026 ERR ("sysctl 2 failed!\n");
1027 HeapFree (GetProcessHeap (), 0, buf);
1032 for (next = buf; next < lim; next += rtm->rtm_msglen)
1034 rtm = (struct rt_msghdr *)next;
1036 if (rtm->rtm_type != RTM_GET)
1038 WARN ("Got unexpected message type 0x%x!\n",
1043 /* Ignore all entries except for gateway routes which aren't
1045 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1051 HeapFree (GetProcessHeap (), 0, buf);
1054 return getNumWithOneHeader("/proc/net/route");
1058 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
1059 DWORD *count, const MIB_IPFORWARDROW *row )
1061 if (table->dwNumEntries >= *count)
1063 MIB_IPFORWARDTABLE *new_table;
1064 DWORD new_count = table->dwNumEntries * 2;
1066 if (!(new_table = HeapReAlloc( heap, flags, table,
1067 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
1069 HeapFree( heap, 0, table );
1075 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1079 static int compare_ipforward_rows(const void *a, const void *b)
1081 const MIB_IPFORWARDROW *rowA = a;
1082 const MIB_IPFORWARDROW *rowB = b;
1085 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
1086 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
1087 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
1088 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1091 /******************************************************************
1092 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1094 * Get the route table.
1095 * Like GetIpForwardTable(), but allocate the returned table from heap.
1098 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1099 * allocated and returned.
1100 * bOrder [In] whether to sort the table
1101 * heap [In] heap from which the table is allocated
1102 * flags [In] flags to HeapAlloc
1105 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1106 * on failure, NO_ERROR on success.
1108 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
1109 HANDLE heap, DWORD flags)
1111 MIB_IPFORWARDTABLE *table;
1112 MIB_IPFORWARDROW row;
1113 DWORD ret = NO_ERROR, count = 16;
1115 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1117 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1119 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1120 return ERROR_OUTOFMEMORY;
1122 table->dwNumEntries = 0;
1128 if ((fp = fopen("/proc/net/route", "r")))
1130 char buf[512], *ptr;
1133 /* skip header line */
1134 ptr = fgets(buf, sizeof(buf), fp);
1135 while ((ptr = fgets(buf, sizeof(buf), fp)))
1137 memset( &row, 0, sizeof(row) );
1139 while (!isspace(*ptr)) ptr++;
1141 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1144 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1145 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1146 flags = strtoul(ptr + 1, &ptr, 16);
1148 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
1149 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1150 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1152 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1153 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1154 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1155 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1156 /* FIXME: other protos might be appropriate, e.g. the default
1157 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1158 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1160 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1165 else ret = ERROR_NOT_SUPPORTED;
1167 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1169 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1171 char *buf = NULL, *lim, *next, *addrPtr;
1172 struct rt_msghdr *rtm;
1174 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1176 ERR ("sysctl 1 failed!\n");
1177 ret = ERROR_NOT_SUPPORTED;
1181 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1184 ret = ERROR_OUTOFMEMORY;
1188 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1190 ret = ERROR_NOT_SUPPORTED;
1195 for (next = buf; next < lim; next += rtm->rtm_msglen)
1199 rtm = (struct rt_msghdr *)next;
1201 if (rtm->rtm_type != RTM_GET)
1203 WARN ("Got unexpected message type 0x%x!\n",
1208 /* Ignore all entries except for gateway routes which aren't
1210 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1211 (rtm->rtm_flags & RTF_MULTICAST))
1214 memset( &row, 0, sizeof(row) );
1215 row.dwForwardIfIndex = rtm->rtm_index;
1216 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1217 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1218 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1220 addrPtr = (char *)(rtm + 1);
1222 for (i = 1; i; i <<= 1)
1224 struct sockaddr *sa;
1227 if (!(i & rtm->rtm_addrs))
1230 sa = (struct sockaddr *)addrPtr;
1231 ADVANCE (addrPtr, sa);
1233 /* default routes are encoded by length-zero sockaddr */
1234 if (sa->sa_len == 0)
1236 else if (sa->sa_family != AF_INET)
1238 WARN ("Received unsupported sockaddr family 0x%x\n",
1244 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1246 addr = sin->sin_addr.s_addr;
1251 case RTA_DST: row.dwForwardDest = addr; break;
1252 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1253 case RTA_NETMASK: row.dwForwardMask = addr; break;
1255 WARN ("Unexpected address type 0x%x\n", i);
1259 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1263 HeapFree( GetProcessHeap (), 0, buf );
1266 FIXME( "not implemented\n" );
1267 ret = ERROR_NOT_SUPPORTED;
1270 if (!table) return ERROR_OUTOFMEMORY;
1273 if (bOrder && table->dwNumEntries)
1274 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1275 *ppIpForwardTable = table;
1277 else HeapFree( heap, flags, table );
1278 TRACE( "returning ret %u table %p\n", ret, table );
1282 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1283 DWORD *count, const MIB_IPNETROW *row )
1285 if (table->dwNumEntries >= *count)
1287 MIB_IPNETTABLE *new_table;
1288 DWORD new_count = table->dwNumEntries * 2;
1290 if (!(new_table = HeapReAlloc( heap, flags, table,
1291 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1293 HeapFree( heap, 0, table );
1299 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1303 static int compare_ipnet_rows(const void *a, const void *b)
1305 const MIB_IPNETROW *rowA = a;
1306 const MIB_IPNETROW *rowB = b;
1308 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1312 /******************************************************************
1313 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1315 * Get the IP-to-physical address mapping table.
1316 * Like GetIpNetTable(), but allocate the returned table from heap.
1319 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1320 * allocated and returned.
1321 * bOrder [In] whether to sort the table
1322 * heap [In] heap from which the table is allocated
1323 * flags [In] flags to HeapAlloc
1326 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1327 * on failure, NO_ERROR on success.
1329 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1330 HANDLE heap, DWORD flags)
1332 MIB_IPNETTABLE *table;
1334 DWORD ret = NO_ERROR, count = 16;
1336 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1338 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1340 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1341 return ERROR_OUTOFMEMORY;
1343 table->dwNumEntries = 0;
1349 if ((fp = fopen("/proc/net/arp", "r")))
1351 char buf[512], *ptr;
1354 /* skip header line */
1355 ptr = fgets(buf, sizeof(buf), fp);
1356 while ((ptr = fgets(buf, sizeof(buf), fp)))
1358 memset( &row, 0, sizeof(row) );
1360 row.dwAddr = inet_addr(ptr);
1361 while (*ptr && !isspace(*ptr)) ptr++;
1362 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1363 flags = strtoul(ptr + 1, &ptr, 16);
1366 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1370 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1373 row.dwType = MIB_IPNET_TYPE_OTHER;
1375 while (*ptr && isspace(*ptr)) ptr++;
1376 while (*ptr && !isspace(*ptr))
1378 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1381 while (*ptr && isspace(*ptr)) ptr++;
1382 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1383 while (*ptr && isspace(*ptr)) ptr++;
1384 getInterfaceIndexByName(ptr, &row.dwIndex);
1386 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1391 else ret = ERROR_NOT_SUPPORTED;
1393 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1395 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1396 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1398 char *buf = NULL, *lim, *next;
1399 struct rt_msghdr *rtm;
1400 struct sockaddr_inarp *sinarp;
1401 struct sockaddr_dl *sdl;
1403 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1405 ERR ("failed to get arp table\n");
1406 ret = ERROR_NOT_SUPPORTED;
1410 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1413 ret = ERROR_OUTOFMEMORY;
1417 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1419 ret = ERROR_NOT_SUPPORTED;
1427 rtm = (struct rt_msghdr *)next;
1428 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1429 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1430 if(sdl->sdl_alen) /* arp entry */
1432 memset( &row, 0, sizeof(row) );
1433 row.dwAddr = sinarp->sin_addr.s_addr;
1434 row.dwIndex = sdl->sdl_index;
1435 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1436 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1437 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1438 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1439 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1440 else row.dwType = MIB_IPNET_TYPE_INVALID;
1442 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1445 next += rtm->rtm_msglen;
1448 HeapFree( GetProcessHeap (), 0, buf );
1451 FIXME( "not implemented\n" );
1452 ret = ERROR_NOT_SUPPORTED;
1455 if (!table) return ERROR_OUTOFMEMORY;
1458 if (bOrder && table->dwNumEntries)
1459 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1460 *ppIpNetTable = table;
1462 else HeapFree( heap, flags, table );
1463 TRACE( "returning ret %u table %p\n", ret, table );
1468 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1469 DWORD *count, const MIB_UDPROW *row )
1471 if (table->dwNumEntries >= *count)
1473 MIB_UDPTABLE *new_table;
1474 DWORD new_count = table->dwNumEntries * 2;
1476 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1478 HeapFree( heap, 0, table );
1484 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1488 static int compare_udp_rows(const void *a, const void *b)
1490 const MIB_UDPROW *rowA = a;
1491 const MIB_UDPROW *rowB = b;
1494 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1495 return rowA->dwLocalPort - rowB->dwLocalPort;
1499 /******************************************************************
1500 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1502 * Get the UDP listener table.
1503 * Like GetUdpTable(), but allocate the returned table from heap.
1506 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1507 * allocated and returned.
1508 * bOrder [In] whether to sort the table
1509 * heap [In] heap from which the table is allocated
1510 * flags [In] flags to HeapAlloc
1513 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1514 * returns otherwise.
1516 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1517 HANDLE heap, DWORD flags)
1519 MIB_UDPTABLE *table;
1521 DWORD ret = NO_ERROR, count = 16;
1523 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1525 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1527 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1528 return ERROR_OUTOFMEMORY;
1530 table->dwNumEntries = 0;
1536 if ((fp = fopen("/proc/net/udp", "r")))
1538 char buf[512], *ptr;
1541 /* skip header line */
1542 ptr = fgets(buf, sizeof(buf), fp);
1543 while ((ptr = fgets(buf, sizeof(buf), fp)))
1545 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1547 row.dwLocalPort = htons( row.dwLocalPort );
1548 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1553 else ret = ERROR_NOT_SUPPORTED;
1556 FIXME( "not implemented\n" );
1557 ret = ERROR_NOT_SUPPORTED;
1560 if (!table) return ERROR_OUTOFMEMORY;
1563 if (bOrder && table->dwNumEntries)
1564 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1565 *ppUdpTable = table;
1567 else HeapFree( heap, flags, table );
1568 TRACE( "returning ret %u table %p\n", ret, table );
1573 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1574 DWORD *count, const MIB_TCPROW *row )
1576 if (table->dwNumEntries >= *count)
1578 MIB_TCPTABLE *new_table;
1579 DWORD new_count = table->dwNumEntries * 2;
1581 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1583 HeapFree( heap, 0, table );
1589 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1594 /* Why not a lookup table? Because the TCPS_* constants are different
1595 on different platforms */
1596 static DWORD TCPStateToMIBState (int state)
1600 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1601 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1602 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1603 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1604 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1605 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1606 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1607 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1608 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1609 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1611 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1616 static int compare_tcp_rows(const void *a, const void *b)
1618 const MIB_TCPROW *rowA = a;
1619 const MIB_TCPROW *rowB = b;
1622 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1623 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1624 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1625 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1626 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1630 /******************************************************************
1631 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1633 * Get the TCP connection table.
1634 * Like GetTcpTable(), but allocate the returned table from heap.
1637 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1638 * allocated and returned.
1639 * bOrder [In] whether to sort the table
1640 * heap [In] heap from which the table is allocated
1641 * flags [In] flags to HeapAlloc
1644 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1645 * returns otherwise.
1647 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1648 HANDLE heap, DWORD flags)
1650 MIB_TCPTABLE *table;
1652 DWORD ret = NO_ERROR, count = 16;
1654 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1656 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1658 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1659 return ERROR_OUTOFMEMORY;
1661 table->dwNumEntries = 0;
1667 if ((fp = fopen("/proc/net/tcp", "r")))
1669 char buf[512], *ptr;
1672 /* skip header line */
1673 ptr = fgets(buf, sizeof(buf), fp);
1674 while ((ptr = fgets(buf, sizeof(buf), fp)))
1676 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1677 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1679 row.dwLocalPort = htons( row.dwLocalPort );
1680 row.dwRemotePort = htons( row.dwRemotePort );
1681 row.dwState = TCPStateToMIBState( row.dwState );
1682 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1687 else ret = ERROR_NOT_SUPPORTED;
1689 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1693 struct xinpgen *pXIG, *pOrigXIG;
1695 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1697 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1698 ret = ERROR_NOT_SUPPORTED;
1702 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1705 ret = ERROR_OUTOFMEMORY;
1709 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1711 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1712 ret = ERROR_NOT_SUPPORTED;
1716 /* Might be nothing here; first entry is just a header it seems */
1717 if (Len <= sizeof (struct xinpgen)) goto done;
1719 pOrigXIG = (struct xinpgen *)Buf;
1722 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1723 pXIG->xig_len > sizeof (struct xinpgen);
1724 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1726 struct tcpcb *pTCPData = NULL;
1727 struct inpcb *pINData;
1728 struct xsocket *pSockData;
1730 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1731 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1732 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1734 /* Ignore sockets for other protocols */
1735 if (pSockData->xso_protocol != IPPROTO_TCP)
1738 /* Ignore PCBs that were freed while generating the data */
1739 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1742 /* we're only interested in IPv4 addresses */
1743 if (!(pINData->inp_vflag & INP_IPV4) ||
1744 (pINData->inp_vflag & INP_IPV6))
1747 /* If all 0's, skip it */
1748 if (!pINData->inp_laddr.s_addr &&
1749 !pINData->inp_lport &&
1750 !pINData->inp_faddr.s_addr &&
1751 !pINData->inp_fport)
1754 /* Fill in structure details */
1755 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1756 row.dwLocalPort = pINData->inp_lport;
1757 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1758 row.dwRemotePort = pINData->inp_fport;
1759 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1760 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1764 HeapFree (GetProcessHeap (), 0, Buf);
1767 FIXME( "not implemented\n" );
1768 ret = ERROR_NOT_SUPPORTED;
1771 if (!table) return ERROR_OUTOFMEMORY;
1774 if (bOrder && table->dwNumEntries)
1775 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1776 *ppTcpTable = table;
1778 else HeapFree( heap, flags, table );
1779 TRACE( "returning ret %u table %p\n", ret, table );