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;
288 /******************************************************************
289 * GetIcmpStatistics (IPHLPAPI.@)
291 * Get the ICMP statistics for the local computer.
294 * stats [Out] buffer for ICMP statistics
298 * Failure: error code from winerror.h
300 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
302 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
303 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
304 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
306 struct icmpstat icmp_stat;
310 return ERROR_INVALID_PARAMETER;
312 needed = sizeof(icmp_stat);
313 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
315 ERR ("failed to get icmpstat\n");
316 return ERROR_NOT_SUPPORTED;
321 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
322 for(i = 0; i <= ICMP_MAXTYPE; i++)
323 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
325 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
327 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
328 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
329 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
330 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
331 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
332 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
333 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
334 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
335 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
336 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
337 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
339 #ifdef HAVE_ICPS_OUTHIST
341 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
342 for(i = 0; i <= ICMP_MAXTYPE; i++)
343 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
345 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
347 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
348 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
349 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
350 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
351 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
352 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
353 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
354 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
355 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
356 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
357 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
358 #else /* ICPS_OUTHIST */
359 memset( &stats->stats.icmpOutStats, 0, sizeof(stats->stats.icmpOutStats) );
360 #endif /* ICPS_OUTHIST */
364 #else /* ICMPCTL_STATS */
368 return ERROR_INVALID_PARAMETER;
370 memset(stats, 0, sizeof(MIB_ICMP));
371 /* get most of these stats from /proc/net/snmp, no error if can't */
372 fp = fopen("/proc/net/snmp", "r");
374 static const char hdr[] = "Icmp:";
375 char buf[512] = { 0 }, *ptr;
378 ptr = fgets(buf, sizeof(buf), fp);
379 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
381 /* last line was a header, get another */
382 ptr = fgets(buf, sizeof(buf), fp);
383 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
388 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
392 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
396 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
400 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
404 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
408 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
412 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
416 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
420 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
424 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
428 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
432 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
436 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
440 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
444 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
448 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
452 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
456 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
460 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
464 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
468 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
472 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
476 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
480 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
489 ERR ("unimplemented!\n");
490 return ERROR_NOT_SUPPORTED;
498 /******************************************************************
499 * GetIpStatistics (IPHLPAPI.@)
501 * Get the IP statistics for the local computer.
504 * stats [Out] buffer for IP statistics
508 * Failure: error code from winerror.h
510 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
512 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
513 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
514 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
515 int ip_ttl, ip_forwarding;
516 struct ipstat ip_stat;
520 return ERROR_INVALID_PARAMETER;
522 needed = sizeof(ip_stat);
523 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
525 ERR ("failed to get ipstat\n");
526 return ERROR_NOT_SUPPORTED;
529 needed = sizeof(ip_ttl);
530 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
532 ERR ("failed to get ip Default TTL\n");
533 return ERROR_NOT_SUPPORTED;
536 needed = sizeof(ip_forwarding);
537 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
539 ERR ("failed to get ip forwarding\n");
540 return ERROR_NOT_SUPPORTED;
543 stats->dwForwarding = ip_forwarding;
544 stats->dwDefaultTTL = ip_ttl;
545 stats->dwInDelivers = ip_stat.ips_delivered;
546 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
547 stats->dwInAddrErrors = ip_stat.ips_cantforward;
548 stats->dwInReceives = ip_stat.ips_total;
549 stats->dwForwDatagrams = ip_stat.ips_forward;
550 stats->dwInUnknownProtos = ip_stat.ips_noproto;
551 stats->dwInDiscards = ip_stat.ips_fragdropped;
552 stats->dwOutDiscards = ip_stat.ips_odropped;
553 stats->dwReasmOks = ip_stat.ips_reassembled;
554 stats->dwFragOks = ip_stat.ips_fragmented;
555 stats->dwFragFails = ip_stat.ips_cantfrag;
556 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
557 stats->dwOutNoRoutes = ip_stat.ips_noroute;
558 stats->dwOutRequests = ip_stat.ips_localout;
559 stats->dwReasmReqds = ip_stat.ips_fragments;
564 MIB_IPFORWARDTABLE *fwd_table;
567 return ERROR_INVALID_PARAMETER;
569 memset(stats, 0, sizeof(MIB_IPSTATS));
570 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
571 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
573 stats->dwNumRoutes = fwd_table->dwNumEntries;
574 HeapFree( GetProcessHeap(), 0, fwd_table );
577 /* get most of these stats from /proc/net/snmp, no error if can't */
578 fp = fopen("/proc/net/snmp", "r");
580 static const char hdr[] = "Ip:";
581 char buf[512] = { 0 }, *ptr;
584 ptr = fgets(buf, sizeof(buf), fp);
585 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
587 /* last line was a header, get another */
588 ptr = fgets(buf, sizeof(buf), fp);
589 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
594 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
598 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
602 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
606 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
610 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
614 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
618 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
622 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
626 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
630 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
634 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
638 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
642 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
646 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
650 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
654 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
658 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
662 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
666 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
669 /* hmm, no routingDiscards */
676 ERR ("unimplemented!\n");
677 return ERROR_NOT_SUPPORTED;
685 /******************************************************************
686 * GetTcpStatistics (IPHLPAPI.@)
688 * Get the TCP statistics for the local computer.
691 * stats [Out] buffer for TCP statistics
695 * Failure: error code from winerror.h
697 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
699 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
700 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
702 #define TCPTV_REXMTMAX 128
704 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
705 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
707 struct tcpstat tcp_stat;
711 return ERROR_INVALID_PARAMETER;
712 needed = sizeof(tcp_stat);
714 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
716 ERR ("failed to get tcpstat\n");
717 return ERROR_NOT_SUPPORTED;
720 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
721 stats->dwRtoMin = TCPTV_MIN;
722 stats->dwRtoMax = TCPTV_REXMTMAX;
723 stats->dwMaxConn = -1;
724 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
725 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
726 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
727 stats->dwEstabResets = tcp_stat.tcps_drops;
728 stats->dwCurrEstab = 0;
729 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
730 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
731 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
732 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
733 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
734 stats->dwNumConns = tcp_stat.tcps_connects;
740 MIB_TCPTABLE *tcp_table;
743 return ERROR_INVALID_PARAMETER;
745 memset(stats, 0, sizeof(MIB_TCPSTATS));
747 /* get from /proc/net/snmp, no error if can't */
748 fp = fopen("/proc/net/snmp", "r");
750 static const char hdr[] = "Tcp:";
751 char buf[512] = { 0 }, *ptr;
755 ptr = fgets(buf, sizeof(buf), fp);
756 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
758 /* last line was a header, get another */
759 ptr = fgets(buf, sizeof(buf), fp);
760 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
765 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
769 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
773 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
777 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
781 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
785 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
789 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
793 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
797 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
801 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
805 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
809 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
813 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
817 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
820 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
822 stats->dwNumConns = tcp_table->dwNumEntries;
823 HeapFree( GetProcessHeap(), 0, tcp_table );
831 ERR ("unimplemented!\n");
832 return ERROR_NOT_SUPPORTED;
840 /******************************************************************
841 * GetUdpStatistics (IPHLPAPI.@)
843 * Get the UDP statistics for the local computer.
846 * stats [Out] buffer for UDP statistics
850 * Failure: error code from winerror.h
852 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
854 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
855 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
856 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
857 struct udpstat udp_stat;
858 MIB_UDPTABLE *udp_table;
861 return ERROR_INVALID_PARAMETER;
863 needed = sizeof(udp_stat);
865 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
867 ERR ("failed to get udpstat\n");
868 return ERROR_NOT_SUPPORTED;
871 stats->dwInDatagrams = udp_stat.udps_ipackets;
872 stats->dwOutDatagrams = udp_stat.udps_opackets;
873 stats->dwNoPorts = udp_stat.udps_noport;
874 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
875 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
877 stats->dwNumAddrs = udp_table->dwNumEntries;
878 HeapFree( GetProcessHeap(), 0, udp_table );
880 else stats->dwNumAddrs = 0;
887 return ERROR_INVALID_PARAMETER;
889 memset(stats, 0, sizeof(MIB_UDPSTATS));
891 /* get from /proc/net/snmp, no error if can't */
892 fp = fopen("/proc/net/snmp", "r");
894 static const char hdr[] = "Udp:";
895 char buf[512] = { 0 }, *ptr;
899 ptr = fgets(buf, sizeof(buf), fp);
900 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
902 /* last line was a header, get another */
903 ptr = fgets(buf, sizeof(buf), fp);
904 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
909 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
913 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
917 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
921 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
925 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
934 ERR ("unimplemented!\n");
935 return ERROR_NOT_SUPPORTED;
943 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
944 DWORD *count, const MIB_IPFORWARDROW *row )
946 if (table->dwNumEntries >= *count)
948 MIB_IPFORWARDTABLE *new_table;
949 DWORD new_count = table->dwNumEntries * 2;
951 if (!(new_table = HeapReAlloc( heap, flags, table,
952 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
954 HeapFree( heap, 0, table );
960 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
964 static int compare_ipforward_rows(const void *a, const void *b)
966 const MIB_IPFORWARDROW *rowA = a;
967 const MIB_IPFORWARDROW *rowB = b;
970 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
971 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
972 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
973 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
976 /******************************************************************
977 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
979 * Get the route table.
980 * Like GetIpForwardTable(), but allocate the returned table from heap.
983 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
984 * allocated and returned.
985 * bOrder [In] whether to sort the table
986 * heap [In] heap from which the table is allocated
987 * flags [In] flags to HeapAlloc
990 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
991 * on failure, NO_ERROR on success.
993 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
994 HANDLE heap, DWORD flags)
996 MIB_IPFORWARDTABLE *table;
997 MIB_IPFORWARDROW row;
998 DWORD ret = NO_ERROR, count = 16;
1000 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1002 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1004 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1005 return ERROR_OUTOFMEMORY;
1007 table->dwNumEntries = 0;
1013 if ((fp = fopen("/proc/net/route", "r")))
1015 char buf[512], *ptr;
1018 /* skip header line */
1019 ptr = fgets(buf, sizeof(buf), fp);
1020 while ((ptr = fgets(buf, sizeof(buf), fp)))
1022 memset( &row, 0, sizeof(row) );
1024 while (!isspace(*ptr)) ptr++;
1026 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1029 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1030 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1031 flags = strtoul(ptr + 1, &ptr, 16);
1033 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
1034 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1035 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1037 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1038 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1039 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1040 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1041 /* FIXME: other protos might be appropriate, e.g. the default
1042 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1043 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1045 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1050 else ret = ERROR_NOT_SUPPORTED;
1052 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1054 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1056 char *buf = NULL, *lim, *next, *addrPtr;
1057 struct rt_msghdr *rtm;
1059 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1061 ERR ("sysctl 1 failed!\n");
1062 ret = ERROR_NOT_SUPPORTED;
1066 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1069 ret = ERROR_OUTOFMEMORY;
1073 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1075 ret = ERROR_NOT_SUPPORTED;
1080 for (next = buf; next < lim; next += rtm->rtm_msglen)
1084 rtm = (struct rt_msghdr *)next;
1086 if (rtm->rtm_type != RTM_GET)
1088 WARN ("Got unexpected message type 0x%x!\n",
1093 /* Ignore all entries except for gateway routes which aren't
1095 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1096 (rtm->rtm_flags & RTF_MULTICAST))
1099 memset( &row, 0, sizeof(row) );
1100 row.dwForwardIfIndex = rtm->rtm_index;
1101 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1102 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1103 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1105 addrPtr = (char *)(rtm + 1);
1107 for (i = 1; i; i <<= 1)
1109 struct sockaddr *sa;
1112 if (!(i & rtm->rtm_addrs))
1115 sa = (struct sockaddr *)addrPtr;
1116 ADVANCE (addrPtr, sa);
1118 /* default routes are encoded by length-zero sockaddr */
1119 if (sa->sa_len == 0)
1121 else if (sa->sa_family != AF_INET)
1123 WARN ("Received unsupported sockaddr family 0x%x\n",
1129 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1131 addr = sin->sin_addr.s_addr;
1136 case RTA_DST: row.dwForwardDest = addr; break;
1137 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1138 case RTA_NETMASK: row.dwForwardMask = addr; break;
1140 WARN ("Unexpected address type 0x%x\n", i);
1144 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1148 HeapFree( GetProcessHeap (), 0, buf );
1151 FIXME( "not implemented\n" );
1152 ret = ERROR_NOT_SUPPORTED;
1155 if (!table) return ERROR_OUTOFMEMORY;
1158 if (bOrder && table->dwNumEntries)
1159 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1160 *ppIpForwardTable = table;
1162 else HeapFree( heap, flags, table );
1163 TRACE( "returning ret %u table %p\n", ret, table );
1167 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1168 DWORD *count, const MIB_IPNETROW *row )
1170 if (table->dwNumEntries >= *count)
1172 MIB_IPNETTABLE *new_table;
1173 DWORD new_count = table->dwNumEntries * 2;
1175 if (!(new_table = HeapReAlloc( heap, flags, table,
1176 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1178 HeapFree( heap, 0, table );
1184 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1188 static int compare_ipnet_rows(const void *a, const void *b)
1190 const MIB_IPNETROW *rowA = a;
1191 const MIB_IPNETROW *rowB = b;
1193 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1197 /******************************************************************
1198 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1200 * Get the IP-to-physical address mapping table.
1201 * Like GetIpNetTable(), but allocate the returned table from heap.
1204 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1205 * allocated and returned.
1206 * bOrder [In] whether to sort the table
1207 * heap [In] heap from which the table is allocated
1208 * flags [In] flags to HeapAlloc
1211 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1212 * on failure, NO_ERROR on success.
1214 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1215 HANDLE heap, DWORD flags)
1217 MIB_IPNETTABLE *table;
1219 DWORD ret = NO_ERROR, count = 16;
1221 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1223 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1225 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1226 return ERROR_OUTOFMEMORY;
1228 table->dwNumEntries = 0;
1234 if ((fp = fopen("/proc/net/arp", "r")))
1236 char buf[512], *ptr;
1239 /* skip header line */
1240 ptr = fgets(buf, sizeof(buf), fp);
1241 while ((ptr = fgets(buf, sizeof(buf), fp)))
1243 memset( &row, 0, sizeof(row) );
1245 row.dwAddr = inet_addr(ptr);
1246 while (*ptr && !isspace(*ptr)) ptr++;
1247 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1248 flags = strtoul(ptr + 1, &ptr, 16);
1251 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1255 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1258 row.dwType = MIB_IPNET_TYPE_OTHER;
1260 while (*ptr && isspace(*ptr)) ptr++;
1261 while (*ptr && !isspace(*ptr))
1263 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1266 while (*ptr && isspace(*ptr)) ptr++;
1267 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1268 while (*ptr && isspace(*ptr)) ptr++;
1269 getInterfaceIndexByName(ptr, &row.dwIndex);
1271 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1276 else ret = ERROR_NOT_SUPPORTED;
1278 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1280 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1281 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1283 char *buf = NULL, *lim, *next;
1284 struct rt_msghdr *rtm;
1285 struct sockaddr_inarp *sinarp;
1286 struct sockaddr_dl *sdl;
1288 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1290 ERR ("failed to get arp table\n");
1291 ret = ERROR_NOT_SUPPORTED;
1295 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1298 ret = ERROR_OUTOFMEMORY;
1302 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1304 ret = ERROR_NOT_SUPPORTED;
1312 rtm = (struct rt_msghdr *)next;
1313 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1314 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1315 if(sdl->sdl_alen) /* arp entry */
1317 memset( &row, 0, sizeof(row) );
1318 row.dwAddr = sinarp->sin_addr.s_addr;
1319 row.dwIndex = sdl->sdl_index;
1320 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1321 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1322 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1323 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1324 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1325 else row.dwType = MIB_IPNET_TYPE_INVALID;
1327 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1330 next += rtm->rtm_msglen;
1333 HeapFree( GetProcessHeap (), 0, buf );
1336 FIXME( "not implemented\n" );
1337 ret = ERROR_NOT_SUPPORTED;
1340 if (!table) return ERROR_OUTOFMEMORY;
1343 if (bOrder && table->dwNumEntries)
1344 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1345 *ppIpNetTable = table;
1347 else HeapFree( heap, flags, table );
1348 TRACE( "returning ret %u table %p\n", ret, table );
1353 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1354 DWORD *count, const MIB_UDPROW *row )
1356 if (table->dwNumEntries >= *count)
1358 MIB_UDPTABLE *new_table;
1359 DWORD new_count = table->dwNumEntries * 2;
1361 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1363 HeapFree( heap, 0, table );
1369 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1373 static int compare_udp_rows(const void *a, const void *b)
1375 const MIB_UDPROW *rowA = a;
1376 const MIB_UDPROW *rowB = b;
1379 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1380 return rowA->dwLocalPort - rowB->dwLocalPort;
1384 /******************************************************************
1385 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1387 * Get the UDP listener table.
1388 * Like GetUdpTable(), but allocate the returned table from heap.
1391 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1392 * allocated and returned.
1393 * bOrder [In] whether to sort the table
1394 * heap [In] heap from which the table is allocated
1395 * flags [In] flags to HeapAlloc
1398 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1399 * returns otherwise.
1401 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1402 HANDLE heap, DWORD flags)
1404 MIB_UDPTABLE *table;
1406 DWORD ret = NO_ERROR, count = 16;
1408 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1410 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1412 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1413 return ERROR_OUTOFMEMORY;
1415 table->dwNumEntries = 0;
1421 if ((fp = fopen("/proc/net/udp", "r")))
1423 char buf[512], *ptr;
1426 /* skip header line */
1427 ptr = fgets(buf, sizeof(buf), fp);
1428 while ((ptr = fgets(buf, sizeof(buf), fp)))
1430 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1432 row.dwLocalPort = htons( row.dwLocalPort );
1433 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1438 else ret = ERROR_NOT_SUPPORTED;
1441 FIXME( "not implemented\n" );
1442 ret = ERROR_NOT_SUPPORTED;
1445 if (!table) return ERROR_OUTOFMEMORY;
1448 if (bOrder && table->dwNumEntries)
1449 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1450 *ppUdpTable = table;
1452 else HeapFree( heap, flags, table );
1453 TRACE( "returning ret %u table %p\n", ret, table );
1458 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1459 DWORD *count, const MIB_TCPROW *row )
1461 if (table->dwNumEntries >= *count)
1463 MIB_TCPTABLE *new_table;
1464 DWORD new_count = table->dwNumEntries * 2;
1466 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1468 HeapFree( heap, 0, table );
1474 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1479 /* Why not a lookup table? Because the TCPS_* constants are different
1480 on different platforms */
1481 static DWORD TCPStateToMIBState (int state)
1485 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1486 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1487 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1488 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1489 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1490 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1491 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1492 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1493 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1494 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1496 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1501 static int compare_tcp_rows(const void *a, const void *b)
1503 const MIB_TCPROW *rowA = a;
1504 const MIB_TCPROW *rowB = b;
1507 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1508 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1509 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1510 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1511 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1515 /******************************************************************
1516 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1518 * Get the TCP connection table.
1519 * Like GetTcpTable(), but allocate the returned table from heap.
1522 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1523 * allocated and returned.
1524 * bOrder [In] whether to sort the table
1525 * heap [In] heap from which the table is allocated
1526 * flags [In] flags to HeapAlloc
1529 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1530 * returns otherwise.
1532 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1533 HANDLE heap, DWORD flags)
1535 MIB_TCPTABLE *table;
1537 DWORD ret = NO_ERROR, count = 16;
1539 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1541 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1543 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1544 return ERROR_OUTOFMEMORY;
1546 table->dwNumEntries = 0;
1552 if ((fp = fopen("/proc/net/tcp", "r")))
1554 char buf[512], *ptr;
1557 /* skip header line */
1558 ptr = fgets(buf, sizeof(buf), fp);
1559 while ((ptr = fgets(buf, sizeof(buf), fp)))
1561 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1562 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1564 row.dwLocalPort = htons( row.dwLocalPort );
1565 row.dwRemotePort = htons( row.dwRemotePort );
1566 row.dwState = TCPStateToMIBState( row.dwState );
1567 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1572 else ret = ERROR_NOT_SUPPORTED;
1574 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1578 struct xinpgen *pXIG, *pOrigXIG;
1580 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1582 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1583 ret = ERROR_NOT_SUPPORTED;
1587 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1590 ret = ERROR_OUTOFMEMORY;
1594 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1596 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1597 ret = ERROR_NOT_SUPPORTED;
1601 /* Might be nothing here; first entry is just a header it seems */
1602 if (Len <= sizeof (struct xinpgen)) goto done;
1604 pOrigXIG = (struct xinpgen *)Buf;
1607 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1608 pXIG->xig_len > sizeof (struct xinpgen);
1609 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1611 struct tcpcb *pTCPData = NULL;
1612 struct inpcb *pINData;
1613 struct xsocket *pSockData;
1615 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1616 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1617 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1619 /* Ignore sockets for other protocols */
1620 if (pSockData->xso_protocol != IPPROTO_TCP)
1623 /* Ignore PCBs that were freed while generating the data */
1624 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1627 /* we're only interested in IPv4 addresses */
1628 if (!(pINData->inp_vflag & INP_IPV4) ||
1629 (pINData->inp_vflag & INP_IPV6))
1632 /* If all 0's, skip it */
1633 if (!pINData->inp_laddr.s_addr &&
1634 !pINData->inp_lport &&
1635 !pINData->inp_faddr.s_addr &&
1636 !pINData->inp_fport)
1639 /* Fill in structure details */
1640 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1641 row.dwLocalPort = pINData->inp_lport;
1642 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1643 row.dwRemotePort = pINData->inp_fport;
1644 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1645 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1649 HeapFree (GetProcessHeap (), 0, Buf);
1652 FIXME( "not implemented\n" );
1653 ret = ERROR_NOT_SUPPORTED;
1656 if (!table) return ERROR_OUTOFMEMORY;
1659 if (bOrder && table->dwNumEntries)
1660 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1661 *ppTcpTable = table;
1663 else HeapFree( heap, flags, table );
1664 TRACE( "returning ret %u table %p\n", ret, table );