iphlpapi: Simplify parsing of IP stats. Only try to open /proc on Linux.
[wine/multimedia.git] / dlls / iphlpapi / ipstats.c
blob6e210fa063bb1c764bea8a22cb4683e449802726
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #ifdef HAVE_ALIAS_H
30 #include <alias.h>
31 #endif
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
35 #ifdef HAVE_SYS_SOCKETVAR_H
36 #include <sys/socketvar.h>
37 #endif
38 #ifdef HAVE_SYS_TIMEOUT_H
39 #include <sys/timeout.h>
40 #endif
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
46 #endif
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
50 #ifdef HAVE_NET_IF_H
51 #include <net/if.h>
52 #endif
53 #ifdef HAVE_NET_IF_DL_H
54 #include <net/if_dl.h>
55 #endif
56 #ifdef HAVE_NET_IF_TYPES_H
57 #include <net/if_types.h>
58 #endif
59 #ifdef HAVE_NET_ROUTE_H
60 #include <net/route.h>
61 #endif
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
64 #endif
65 #ifdef HAVE_NETINET_IF_ETHER_H
66 #include <netinet/if_ether.h>
67 #endif
68 #ifdef HAVE_NETINET_IF_INARP_H
69 #include <netinet/if_inarp.h>
70 #endif
71 #ifdef HAVE_NETINET_IP_H
72 #include <netinet/ip.h>
73 #endif
74 #ifdef HAVE_NETINET_TCP_H
75 #include <netinet/tcp.h>
76 #endif
77 #ifdef HAVE_NETINET_IP_VAR_H
78 #include <netinet/ip_var.h>
79 #endif
80 #ifdef HAVE_NETINET_TCP_FSM_H
81 #include <netinet/tcp_fsm.h>
82 #endif
83 #ifdef HAVE_NETINET_IN_PCB_H
84 #include <netinet/in_pcb.h>
85 #endif
86 #ifdef HAVE_NETINET_TCP_TIMER_H
87 #include <netinet/tcp_timer.h>
88 #endif
89 #ifdef HAVE_NETINET_TCP_VAR_H
90 #include <netinet/tcp_var.h>
91 #endif
92 #ifdef HAVE_NETINET_IP_ICMP_H
93 #include <netinet/ip_icmp.h>
94 #endif
95 #ifdef HAVE_NETINET_ICMP_VAR_H
96 #include <netinet/icmp_var.h>
97 #endif
98 #ifdef HAVE_NETINET_UDP_H
99 #include <netinet/udp.h>
100 #endif
101 #ifdef HAVE_NETINET_UDP_VAR_H
102 #include <netinet/udp_var.h>
103 #endif
104 #ifdef HAVE_SYS_PROTOSW_H
105 #include <sys/protosw.h>
106 #endif
107 #ifdef HAVE_SYS_SYSCTL_H
108 #include <sys/sysctl.h>
109 #endif
111 #ifndef ROUNDUP
112 #define ROUNDUP(a) \
113 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
114 #endif
115 #ifndef ADVANCE
116 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
117 #endif
119 #include "windef.h"
120 #include "winbase.h"
121 #include "iprtrmib.h"
122 #include "ifenum.h"
123 #include "ipstats.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
139 #endif
141 #ifndef RTF_MULTICAST
142 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
143 #endif
145 #ifndef RTF_LLINFO
146 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
147 #endif
149 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
151 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
153 DWORD ret = ERROR_NOT_SUPPORTED;
155 if (!name || !entry) return ERROR_INVALID_PARAMETER;
157 #ifdef __linux__
159 FILE *fp;
161 if ((fp = fopen("/proc/net/dev", "r")))
163 DWORD skip;
164 char buf[512], *ptr;
165 int nameLen = strlen(name);
167 while ((ptr = fgets(buf, sizeof(buf), fp)))
169 while (*ptr && isspace(*ptr)) ptr++;
170 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
172 ptr += nameLen + 1;
173 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
174 &entry->dwInOctets, &entry->dwInUcastPkts,
175 &entry->dwInErrors, &entry->dwInDiscards,
176 &skip, &skip, &skip,
177 &entry->dwInNUcastPkts, &entry->dwOutOctets,
178 &entry->dwOutUcastPkts, &entry->dwOutErrors,
179 &entry->dwOutDiscards );
180 break;
183 fclose(fp);
184 ret = NO_ERROR;
187 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
189 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
190 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
192 size_t needed;
193 char *buf = NULL, *end;
194 struct if_msghdr *ifm;
195 struct if_data ifdata;
197 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
199 ERR ("failed to get size of iflist\n");
200 goto done;
202 buf = HeapAlloc (GetProcessHeap (), 0, needed);
203 if (!buf)
205 ret = ERROR_OUTOFMEMORY;
206 goto done;
208 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
210 ERR ("failed to get iflist\n");
211 goto done;
213 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
215 ifm = (struct if_msghdr *) buf;
216 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
218 ifdata = ifm->ifm_data;
219 entry->dwMtu = ifdata.ifi_mtu;
220 entry->dwSpeed = ifdata.ifi_baudrate;
221 entry->dwInOctets = ifdata.ifi_ibytes;
222 entry->dwInErrors = ifdata.ifi_ierrors;
223 entry->dwInDiscards = ifdata.ifi_iqdrops;
224 entry->dwInUcastPkts = ifdata.ifi_ipackets;
225 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
226 entry->dwOutOctets = ifdata.ifi_obytes;
227 entry->dwOutUcastPkts = ifdata.ifi_opackets;
228 entry->dwOutErrors = ifdata.ifi_oerrors;
229 ret = NO_ERROR;
230 break;
233 done:
234 HeapFree (GetProcessHeap (), 0, buf);
236 #else
237 FIXME( "unimplemented\n" );
238 #endif
239 return ret;
243 /******************************************************************
244 * GetIcmpStatistics (IPHLPAPI.@)
246 * Get the ICMP statistics for the local computer.
248 * PARAMS
249 * stats [Out] buffer for ICMP statistics
251 * RETURNS
252 * Success: NO_ERROR
253 * Failure: error code from winerror.h
255 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
257 DWORD ret = ERROR_NOT_SUPPORTED;
259 if (!stats) return ERROR_INVALID_PARAMETER;
260 memset( stats, 0, sizeof(MIB_ICMP) );
262 #ifdef __linux__
264 FILE *fp;
266 if ((fp = fopen("/proc/net/snmp", "r")))
268 static const char hdr[] = "Icmp:";
269 char buf[512], *ptr;
271 while ((ptr = fgets(buf, sizeof(buf), fp)))
273 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
274 /* last line was a header, get another */
275 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
276 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
278 ptr += sizeof(hdr);
279 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
280 &stats->stats.icmpInStats.dwMsgs,
281 &stats->stats.icmpInStats.dwErrors,
282 &stats->stats.icmpInStats.dwDestUnreachs,
283 &stats->stats.icmpInStats.dwTimeExcds,
284 &stats->stats.icmpInStats.dwParmProbs,
285 &stats->stats.icmpInStats.dwSrcQuenchs,
286 &stats->stats.icmpInStats.dwRedirects,
287 &stats->stats.icmpInStats.dwEchoReps,
288 &stats->stats.icmpInStats.dwTimestamps,
289 &stats->stats.icmpInStats.dwTimestampReps,
290 &stats->stats.icmpInStats.dwAddrMasks,
291 &stats->stats.icmpInStats.dwAddrMaskReps,
292 &stats->stats.icmpOutStats.dwMsgs,
293 &stats->stats.icmpOutStats.dwErrors,
294 &stats->stats.icmpOutStats.dwDestUnreachs,
295 &stats->stats.icmpOutStats.dwTimeExcds,
296 &stats->stats.icmpOutStats.dwParmProbs,
297 &stats->stats.icmpOutStats.dwSrcQuenchs,
298 &stats->stats.icmpOutStats.dwRedirects,
299 &stats->stats.icmpOutStats.dwEchoReps,
300 &stats->stats.icmpOutStats.dwTimestamps,
301 &stats->stats.icmpOutStats.dwTimestampReps,
302 &stats->stats.icmpOutStats.dwAddrMasks,
303 &stats->stats.icmpOutStats.dwAddrMaskReps );
304 break;
307 fclose(fp);
308 ret = NO_ERROR;
311 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
313 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
314 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
315 struct icmpstat icmp_stat;
316 size_t needed = sizeof(icmp_stat);
317 int i;
319 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
321 /*in stats */
322 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
323 for(i = 0; i <= ICMP_MAXTYPE; i++)
324 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
326 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
328 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
329 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
330 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
331 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
332 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
333 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
334 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
335 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
336 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
337 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
338 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
340 #ifdef HAVE_ICPS_OUTHIST
341 /* out stats */
342 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
343 for(i = 0; i <= ICMP_MAXTYPE; i++)
344 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
346 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
348 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
349 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
350 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
351 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
352 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
353 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
354 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
355 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
356 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
357 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
358 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
359 #endif /* ICPS_OUTHIST */
360 ret = NO_ERROR;
363 #else /* ICMPCTL_STATS */
364 FIXME( "unimplemented\n" );
365 #endif
366 return ret;
370 /******************************************************************
371 * GetIpStatistics (IPHLPAPI.@)
373 * Get the IP statistics for the local computer.
375 * PARAMS
376 * stats [Out] buffer for IP statistics
378 * RETURNS
379 * Success: NO_ERROR
380 * Failure: error code from winerror.h
382 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
384 DWORD ret = ERROR_NOT_SUPPORTED;
385 MIB_IPFORWARDTABLE *fwd_table;
387 if (!stats) return ERROR_INVALID_PARAMETER;
388 memset( stats, 0, sizeof(*stats) );
390 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
391 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
393 stats->dwNumRoutes = fwd_table->dwNumEntries;
394 HeapFree( GetProcessHeap(), 0, fwd_table );
397 #ifdef __linux__
399 FILE *fp;
401 if ((fp = fopen("/proc/net/snmp", "r")))
403 static const char hdr[] = "Ip:";
404 char buf[512], *ptr;
406 while ((ptr = fgets(buf, sizeof(buf), fp)))
408 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
409 /* last line was a header, get another */
410 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
411 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
413 ptr += sizeof(hdr);
414 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
415 &stats->dwForwarding,
416 &stats->dwDefaultTTL,
417 &stats->dwInReceives,
418 &stats->dwInHdrErrors,
419 &stats->dwInAddrErrors,
420 &stats->dwForwDatagrams,
421 &stats->dwInUnknownProtos,
422 &stats->dwInDiscards,
423 &stats->dwInDelivers,
424 &stats->dwOutRequests,
425 &stats->dwOutDiscards,
426 &stats->dwOutNoRoutes,
427 &stats->dwReasmTimeout,
428 &stats->dwReasmReqds,
429 &stats->dwReasmOks,
430 &stats->dwReasmFails,
431 &stats->dwFragOks,
432 &stats->dwFragFails,
433 &stats->dwFragCreates );
434 /* hmm, no routingDiscards */
435 break;
438 fclose(fp);
439 ret = NO_ERROR;
442 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
444 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
445 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
446 int ip_ttl, ip_forwarding;
447 struct ipstat ip_stat;
448 size_t needed;
450 needed = sizeof(ip_stat);
451 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
453 ERR ("failed to get ipstat\n");
454 return ERROR_NOT_SUPPORTED;
457 needed = sizeof(ip_ttl);
458 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
460 ERR ("failed to get ip Default TTL\n");
461 return ERROR_NOT_SUPPORTED;
464 needed = sizeof(ip_forwarding);
465 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
467 ERR ("failed to get ip forwarding\n");
468 return ERROR_NOT_SUPPORTED;
471 stats->dwForwarding = ip_forwarding;
472 stats->dwDefaultTTL = ip_ttl;
473 stats->dwInDelivers = ip_stat.ips_delivered;
474 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
475 stats->dwInAddrErrors = ip_stat.ips_cantforward;
476 stats->dwInReceives = ip_stat.ips_total;
477 stats->dwForwDatagrams = ip_stat.ips_forward;
478 stats->dwInUnknownProtos = ip_stat.ips_noproto;
479 stats->dwInDiscards = ip_stat.ips_fragdropped;
480 stats->dwOutDiscards = ip_stat.ips_odropped;
481 stats->dwReasmOks = ip_stat.ips_reassembled;
482 stats->dwFragOks = ip_stat.ips_fragmented;
483 stats->dwFragFails = ip_stat.ips_cantfrag;
484 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
485 stats->dwOutNoRoutes = ip_stat.ips_noroute;
486 stats->dwOutRequests = ip_stat.ips_localout;
487 stats->dwReasmReqds = ip_stat.ips_fragments;
488 ret = NO_ERROR;
490 #else
491 FIXME( "unimplemented\n" );
492 #endif
493 return ret;
497 /******************************************************************
498 * GetTcpStatistics (IPHLPAPI.@)
500 * Get the TCP statistics for the local computer.
502 * PARAMS
503 * stats [Out] buffer for TCP statistics
505 * RETURNS
506 * Success: NO_ERROR
507 * Failure: error code from winerror.h
509 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
511 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
512 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
513 #define TCPTV_MIN 2
514 #define TCPTV_REXMTMAX 128
515 #endif
516 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
517 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
518 #define hz 1000
519 struct tcpstat tcp_stat;
520 size_t needed;
522 if (!stats)
523 return ERROR_INVALID_PARAMETER;
524 needed = sizeof(tcp_stat);
526 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
528 ERR ("failed to get tcpstat\n");
529 return ERROR_NOT_SUPPORTED;
532 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
533 stats->dwRtoMin = TCPTV_MIN;
534 stats->dwRtoMax = TCPTV_REXMTMAX;
535 stats->dwMaxConn = -1;
536 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
537 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
538 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
539 stats->dwEstabResets = tcp_stat.tcps_drops;
540 stats->dwCurrEstab = 0;
541 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
542 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
543 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
544 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
545 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
546 stats->dwNumConns = tcp_stat.tcps_connects;
548 return NO_ERROR;
550 #else
551 FILE *fp;
552 MIB_TCPTABLE *tcp_table;
554 if (!stats)
555 return ERROR_INVALID_PARAMETER;
557 memset(stats, 0, sizeof(MIB_TCPSTATS));
559 /* get from /proc/net/snmp, no error if can't */
560 fp = fopen("/proc/net/snmp", "r");
561 if (fp) {
562 static const char hdr[] = "Tcp:";
563 char buf[512] = { 0 }, *ptr;
566 do {
567 ptr = fgets(buf, sizeof(buf), fp);
568 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
569 if (ptr) {
570 /* last line was a header, get another */
571 ptr = fgets(buf, sizeof(buf), fp);
572 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
573 char *endPtr;
575 ptr += sizeof(hdr);
576 if (ptr && *ptr) {
577 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
578 ptr = endPtr;
580 if (ptr && *ptr) {
581 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
582 ptr = endPtr;
584 if (ptr && *ptr) {
585 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
586 ptr = endPtr;
588 if (ptr && *ptr) {
589 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
590 ptr = endPtr;
592 if (ptr && *ptr) {
593 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
594 ptr = endPtr;
596 if (ptr && *ptr) {
597 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
598 ptr = endPtr;
600 if (ptr && *ptr) {
601 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
602 ptr = endPtr;
604 if (ptr && *ptr) {
605 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
606 ptr = endPtr;
608 if (ptr && *ptr) {
609 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
610 ptr = endPtr;
612 if (ptr && *ptr) {
613 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
614 ptr = endPtr;
616 if (ptr && *ptr) {
617 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
618 ptr = endPtr;
620 if (ptr && *ptr) {
621 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
622 ptr = endPtr;
624 if (ptr && *ptr) {
625 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
626 ptr = endPtr;
628 if (ptr && *ptr) {
629 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
630 ptr = endPtr;
632 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
634 stats->dwNumConns = tcp_table->dwNumEntries;
635 HeapFree( GetProcessHeap(), 0, tcp_table );
639 fclose(fp);
641 else
643 ERR ("unimplemented!\n");
644 return ERROR_NOT_SUPPORTED;
647 return NO_ERROR;
648 #endif
652 /******************************************************************
653 * GetUdpStatistics (IPHLPAPI.@)
655 * Get the UDP statistics for the local computer.
657 * PARAMS
658 * stats [Out] buffer for UDP statistics
660 * RETURNS
661 * Success: NO_ERROR
662 * Failure: error code from winerror.h
664 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
666 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
667 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
668 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
669 struct udpstat udp_stat;
670 MIB_UDPTABLE *udp_table;
671 size_t needed;
672 if (!stats)
673 return ERROR_INVALID_PARAMETER;
675 needed = sizeof(udp_stat);
677 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
679 ERR ("failed to get udpstat\n");
680 return ERROR_NOT_SUPPORTED;
683 stats->dwInDatagrams = udp_stat.udps_ipackets;
684 stats->dwOutDatagrams = udp_stat.udps_opackets;
685 stats->dwNoPorts = udp_stat.udps_noport;
686 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
687 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
689 stats->dwNumAddrs = udp_table->dwNumEntries;
690 HeapFree( GetProcessHeap(), 0, udp_table );
692 else stats->dwNumAddrs = 0;
694 return NO_ERROR;
695 #else
696 FILE *fp;
698 if (!stats)
699 return ERROR_INVALID_PARAMETER;
701 memset(stats, 0, sizeof(MIB_UDPSTATS));
703 /* get from /proc/net/snmp, no error if can't */
704 fp = fopen("/proc/net/snmp", "r");
705 if (fp) {
706 static const char hdr[] = "Udp:";
707 char buf[512] = { 0 }, *ptr;
710 do {
711 ptr = fgets(buf, sizeof(buf), fp);
712 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
713 if (ptr) {
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) {
717 char *endPtr;
719 ptr += sizeof(hdr);
720 if (ptr && *ptr) {
721 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
722 ptr = endPtr;
724 if (ptr && *ptr) {
725 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
726 ptr = endPtr;
728 if (ptr && *ptr) {
729 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
730 ptr = endPtr;
732 if (ptr && *ptr) {
733 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
734 ptr = endPtr;
736 if (ptr && *ptr) {
737 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
738 ptr = endPtr;
742 fclose(fp);
744 else
746 ERR ("unimplemented!\n");
747 return ERROR_NOT_SUPPORTED;
750 return NO_ERROR;
751 #endif
755 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
756 DWORD *count, const MIB_IPFORWARDROW *row )
758 if (table->dwNumEntries >= *count)
760 MIB_IPFORWARDTABLE *new_table;
761 DWORD new_count = table->dwNumEntries * 2;
763 if (!(new_table = HeapReAlloc( heap, flags, table,
764 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
766 HeapFree( heap, 0, table );
767 return NULL;
769 *count = new_count;
770 table = new_table;
772 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
773 return table;
776 static int compare_ipforward_rows(const void *a, const void *b)
778 const MIB_IPFORWARDROW *rowA = a;
779 const MIB_IPFORWARDROW *rowB = b;
780 int ret;
782 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
783 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
784 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
785 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
788 /******************************************************************
789 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
791 * Get the route table.
792 * Like GetIpForwardTable(), but allocate the returned table from heap.
794 * PARAMS
795 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
796 * allocated and returned.
797 * bOrder [In] whether to sort the table
798 * heap [In] heap from which the table is allocated
799 * flags [In] flags to HeapAlloc
801 * RETURNS
802 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
803 * on failure, NO_ERROR on success.
805 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
806 HANDLE heap, DWORD flags)
808 MIB_IPFORWARDTABLE *table;
809 MIB_IPFORWARDROW row;
810 DWORD ret = NO_ERROR, count = 16;
812 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
814 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
816 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
817 return ERROR_OUTOFMEMORY;
819 table->dwNumEntries = 0;
821 #ifdef __linux__
823 FILE *fp;
825 if ((fp = fopen("/proc/net/route", "r")))
827 char buf[512], *ptr;
828 DWORD flags;
830 /* skip header line */
831 ptr = fgets(buf, sizeof(buf), fp);
832 while ((ptr = fgets(buf, sizeof(buf), fp)))
834 memset( &row, 0, sizeof(row) );
836 while (!isspace(*ptr)) ptr++;
837 *ptr++ = 0;
838 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
839 continue;
841 row.dwForwardDest = strtoul(ptr, &ptr, 16);
842 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
843 flags = strtoul(ptr + 1, &ptr, 16);
845 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
846 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
847 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
849 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
850 strtoul(ptr + 1, &ptr, 16); /* use, skip */
851 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
852 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
853 /* FIXME: other protos might be appropriate, e.g. the default
854 * route is typically set with MIB_IPPROTO_NETMGMT instead */
855 row.dwForwardProto = MIB_IPPROTO_LOCAL;
857 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
858 break;
860 fclose(fp);
862 else ret = ERROR_NOT_SUPPORTED;
864 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
866 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
867 size_t needed;
868 char *buf = NULL, *lim, *next, *addrPtr;
869 struct rt_msghdr *rtm;
871 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
873 ERR ("sysctl 1 failed!\n");
874 ret = ERROR_NOT_SUPPORTED;
875 goto done;
878 buf = HeapAlloc (GetProcessHeap (), 0, needed);
879 if (!buf)
881 ret = ERROR_OUTOFMEMORY;
882 goto done;
885 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
887 ret = ERROR_NOT_SUPPORTED;
888 goto done;
891 lim = buf + needed;
892 for (next = buf; next < lim; next += rtm->rtm_msglen)
894 int i;
896 rtm = (struct rt_msghdr *)next;
898 if (rtm->rtm_type != RTM_GET)
900 WARN ("Got unexpected message type 0x%x!\n",
901 rtm->rtm_type);
902 continue;
905 /* Ignore all entries except for gateway routes which aren't
906 multicast */
907 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
908 (rtm->rtm_flags & RTF_MULTICAST))
909 continue;
911 memset( &row, 0, sizeof(row) );
912 row.dwForwardIfIndex = rtm->rtm_index;
913 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
914 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
915 row.dwForwardProto = MIB_IPPROTO_LOCAL;
917 addrPtr = (char *)(rtm + 1);
919 for (i = 1; i; i <<= 1)
921 struct sockaddr *sa;
922 DWORD addr;
924 if (!(i & rtm->rtm_addrs))
925 continue;
927 sa = (struct sockaddr *)addrPtr;
928 ADVANCE (addrPtr, sa);
930 /* default routes are encoded by length-zero sockaddr */
931 if (sa->sa_len == 0)
932 addr = 0;
933 else if (sa->sa_family != AF_INET)
935 WARN ("Received unsupported sockaddr family 0x%x\n",
936 sa->sa_family);
937 addr = 0;
939 else
941 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
943 addr = sin->sin_addr.s_addr;
946 switch (i)
948 case RTA_DST: row.dwForwardDest = addr; break;
949 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
950 case RTA_NETMASK: row.dwForwardMask = addr; break;
951 default:
952 WARN ("Unexpected address type 0x%x\n", i);
956 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
957 break;
959 done:
960 HeapFree( GetProcessHeap (), 0, buf );
962 #else
963 FIXME( "not implemented\n" );
964 ret = ERROR_NOT_SUPPORTED;
965 #endif
967 if (!table) return ERROR_OUTOFMEMORY;
968 if (!ret)
970 if (bOrder && table->dwNumEntries)
971 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
972 *ppIpForwardTable = table;
974 else HeapFree( heap, flags, table );
975 TRACE( "returning ret %u table %p\n", ret, table );
976 return ret;
979 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
980 DWORD *count, const MIB_IPNETROW *row )
982 if (table->dwNumEntries >= *count)
984 MIB_IPNETTABLE *new_table;
985 DWORD new_count = table->dwNumEntries * 2;
987 if (!(new_table = HeapReAlloc( heap, flags, table,
988 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
990 HeapFree( heap, 0, table );
991 return NULL;
993 *count = new_count;
994 table = new_table;
996 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
997 return table;
1000 static int compare_ipnet_rows(const void *a, const void *b)
1002 const MIB_IPNETROW *rowA = a;
1003 const MIB_IPNETROW *rowB = b;
1005 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1009 /******************************************************************
1010 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1012 * Get the IP-to-physical address mapping table.
1013 * Like GetIpNetTable(), but allocate the returned table from heap.
1015 * PARAMS
1016 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1017 * allocated and returned.
1018 * bOrder [In] whether to sort the table
1019 * heap [In] heap from which the table is allocated
1020 * flags [In] flags to HeapAlloc
1022 * RETURNS
1023 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1024 * on failure, NO_ERROR on success.
1026 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1027 HANDLE heap, DWORD flags)
1029 MIB_IPNETTABLE *table;
1030 MIB_IPNETROW row;
1031 DWORD ret = NO_ERROR, count = 16;
1033 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1035 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1037 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1038 return ERROR_OUTOFMEMORY;
1040 table->dwNumEntries = 0;
1042 #ifdef __linux__
1044 FILE *fp;
1046 if ((fp = fopen("/proc/net/arp", "r")))
1048 char buf[512], *ptr;
1049 DWORD flags;
1051 /* skip header line */
1052 ptr = fgets(buf, sizeof(buf), fp);
1053 while ((ptr = fgets(buf, sizeof(buf), fp)))
1055 memset( &row, 0, sizeof(row) );
1057 row.dwAddr = inet_addr(ptr);
1058 while (*ptr && !isspace(*ptr)) ptr++;
1059 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1060 flags = strtoul(ptr + 1, &ptr, 16);
1062 #ifdef ATF_COM
1063 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1064 else
1065 #endif
1066 #ifdef ATF_PERM
1067 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1068 else
1069 #endif
1070 row.dwType = MIB_IPNET_TYPE_OTHER;
1072 while (*ptr && isspace(*ptr)) ptr++;
1073 while (*ptr && !isspace(*ptr))
1075 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1076 if (*ptr) ptr++;
1078 while (*ptr && isspace(*ptr)) ptr++;
1079 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1080 while (*ptr && isspace(*ptr)) ptr++;
1081 getInterfaceIndexByName(ptr, &row.dwIndex);
1083 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1084 break;
1086 fclose(fp);
1088 else ret = ERROR_NOT_SUPPORTED;
1090 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1092 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1093 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1094 size_t needed;
1095 char *buf = NULL, *lim, *next;
1096 struct rt_msghdr *rtm;
1097 struct sockaddr_inarp *sinarp;
1098 struct sockaddr_dl *sdl;
1100 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1102 ERR ("failed to get arp table\n");
1103 ret = ERROR_NOT_SUPPORTED;
1104 goto done;
1107 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1108 if (!buf)
1110 ret = ERROR_OUTOFMEMORY;
1111 goto done;
1114 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1116 ret = ERROR_NOT_SUPPORTED;
1117 goto done;
1120 lim = buf + needed;
1121 next = buf;
1122 while(next < lim)
1124 rtm = (struct rt_msghdr *)next;
1125 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1126 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1127 if(sdl->sdl_alen) /* arp entry */
1129 memset( &row, 0, sizeof(row) );
1130 row.dwAddr = sinarp->sin_addr.s_addr;
1131 row.dwIndex = sdl->sdl_index;
1132 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1133 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1134 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1135 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1136 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1137 else row.dwType = MIB_IPNET_TYPE_INVALID;
1139 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1140 break;
1142 next += rtm->rtm_msglen;
1144 done:
1145 HeapFree( GetProcessHeap (), 0, buf );
1147 #else
1148 FIXME( "not implemented\n" );
1149 ret = ERROR_NOT_SUPPORTED;
1150 #endif
1152 if (!table) return ERROR_OUTOFMEMORY;
1153 if (!ret)
1155 if (bOrder && table->dwNumEntries)
1156 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1157 *ppIpNetTable = table;
1159 else HeapFree( heap, flags, table );
1160 TRACE( "returning ret %u table %p\n", ret, table );
1161 return ret;
1165 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1166 DWORD *count, const MIB_UDPROW *row )
1168 if (table->dwNumEntries >= *count)
1170 MIB_UDPTABLE *new_table;
1171 DWORD new_count = table->dwNumEntries * 2;
1173 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1175 HeapFree( heap, 0, table );
1176 return NULL;
1178 *count = new_count;
1179 table = new_table;
1181 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1182 return table;
1185 static int compare_udp_rows(const void *a, const void *b)
1187 const MIB_UDPROW *rowA = a;
1188 const MIB_UDPROW *rowB = b;
1189 int ret;
1191 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1192 return rowA->dwLocalPort - rowB->dwLocalPort;
1196 /******************************************************************
1197 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1199 * Get the UDP listener table.
1200 * Like GetUdpTable(), but allocate the returned table from heap.
1202 * PARAMS
1203 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1204 * allocated and returned.
1205 * bOrder [In] whether to sort the table
1206 * heap [In] heap from which the table is allocated
1207 * flags [In] flags to HeapAlloc
1209 * RETURNS
1210 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1211 * returns otherwise.
1213 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1214 HANDLE heap, DWORD flags)
1216 MIB_UDPTABLE *table;
1217 MIB_UDPROW row;
1218 DWORD ret = NO_ERROR, count = 16;
1220 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1222 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1224 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1225 return ERROR_OUTOFMEMORY;
1227 table->dwNumEntries = 0;
1229 #ifdef __linux__
1231 FILE *fp;
1233 if ((fp = fopen("/proc/net/udp", "r")))
1235 char buf[512], *ptr;
1236 DWORD dummy;
1238 /* skip header line */
1239 ptr = fgets(buf, sizeof(buf), fp);
1240 while ((ptr = fgets(buf, sizeof(buf), fp)))
1242 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1243 continue;
1244 row.dwLocalPort = htons( row.dwLocalPort );
1245 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1246 break;
1248 fclose(fp);
1250 else ret = ERROR_NOT_SUPPORTED;
1252 #else
1253 FIXME( "not implemented\n" );
1254 ret = ERROR_NOT_SUPPORTED;
1255 #endif
1257 if (!table) return ERROR_OUTOFMEMORY;
1258 if (!ret)
1260 if (bOrder && table->dwNumEntries)
1261 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1262 *ppUdpTable = table;
1264 else HeapFree( heap, flags, table );
1265 TRACE( "returning ret %u table %p\n", ret, table );
1266 return ret;
1270 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1271 DWORD *count, const MIB_TCPROW *row )
1273 if (table->dwNumEntries >= *count)
1275 MIB_TCPTABLE *new_table;
1276 DWORD new_count = table->dwNumEntries * 2;
1278 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1280 HeapFree( heap, 0, table );
1281 return NULL;
1283 *count = new_count;
1284 table = new_table;
1286 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1287 return table;
1291 /* Why not a lookup table? Because the TCPS_* constants are different
1292 on different platforms */
1293 static DWORD TCPStateToMIBState (int state)
1295 switch (state)
1297 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1298 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1299 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1300 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1301 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1302 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1303 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1304 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1305 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1306 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1307 default:
1308 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1313 static int compare_tcp_rows(const void *a, const void *b)
1315 const MIB_TCPROW *rowA = a;
1316 const MIB_TCPROW *rowB = b;
1317 int ret;
1319 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1320 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1321 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1322 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1323 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1327 /******************************************************************
1328 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1330 * Get the TCP connection table.
1331 * Like GetTcpTable(), but allocate the returned table from heap.
1333 * PARAMS
1334 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1335 * allocated and returned.
1336 * bOrder [In] whether to sort the table
1337 * heap [In] heap from which the table is allocated
1338 * flags [In] flags to HeapAlloc
1340 * RETURNS
1341 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1342 * returns otherwise.
1344 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1345 HANDLE heap, DWORD flags)
1347 MIB_TCPTABLE *table;
1348 MIB_TCPROW row;
1349 DWORD ret = NO_ERROR, count = 16;
1351 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1353 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1355 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1356 return ERROR_OUTOFMEMORY;
1358 table->dwNumEntries = 0;
1360 #ifdef __linux__
1362 FILE *fp;
1364 if ((fp = fopen("/proc/net/tcp", "r")))
1366 char buf[512], *ptr;
1367 DWORD dummy;
1369 /* skip header line */
1370 ptr = fgets(buf, sizeof(buf), fp);
1371 while ((ptr = fgets(buf, sizeof(buf), fp)))
1373 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1374 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1375 continue;
1376 row.dwLocalPort = htons( row.dwLocalPort );
1377 row.dwRemotePort = htons( row.dwRemotePort );
1378 row.dwState = TCPStateToMIBState( row.dwState );
1379 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1380 break;
1382 fclose( fp );
1384 else ret = ERROR_NOT_SUPPORTED;
1386 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1388 size_t Len = 0;
1389 char *Buf = NULL;
1390 struct xinpgen *pXIG, *pOrigXIG;
1392 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1394 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1395 ret = ERROR_NOT_SUPPORTED;
1396 goto done;
1399 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1400 if (!Buf)
1402 ret = ERROR_OUTOFMEMORY;
1403 goto done;
1406 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1408 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1409 ret = ERROR_NOT_SUPPORTED;
1410 goto done;
1413 /* Might be nothing here; first entry is just a header it seems */
1414 if (Len <= sizeof (struct xinpgen)) goto done;
1416 pOrigXIG = (struct xinpgen *)Buf;
1417 pXIG = pOrigXIG;
1419 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1420 pXIG->xig_len > sizeof (struct xinpgen);
1421 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1423 struct tcpcb *pTCPData = NULL;
1424 struct inpcb *pINData;
1425 struct xsocket *pSockData;
1427 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1428 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1429 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1431 /* Ignore sockets for other protocols */
1432 if (pSockData->xso_protocol != IPPROTO_TCP)
1433 continue;
1435 /* Ignore PCBs that were freed while generating the data */
1436 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1437 continue;
1439 /* we're only interested in IPv4 addresses */
1440 if (!(pINData->inp_vflag & INP_IPV4) ||
1441 (pINData->inp_vflag & INP_IPV6))
1442 continue;
1444 /* If all 0's, skip it */
1445 if (!pINData->inp_laddr.s_addr &&
1446 !pINData->inp_lport &&
1447 !pINData->inp_faddr.s_addr &&
1448 !pINData->inp_fport)
1449 continue;
1451 /* Fill in structure details */
1452 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1453 row.dwLocalPort = pINData->inp_lport;
1454 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1455 row.dwRemotePort = pINData->inp_fport;
1456 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1457 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1460 done:
1461 HeapFree (GetProcessHeap (), 0, Buf);
1463 #else
1464 FIXME( "not implemented\n" );
1465 ret = ERROR_NOT_SUPPORTED;
1466 #endif
1468 if (!table) return ERROR_OUTOFMEMORY;
1469 if (!ret)
1471 if (bOrder && table->dwNumEntries)
1472 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1473 *ppTcpTable = table;
1475 else HeapFree( heap, flags, table );
1476 TRACE( "returning ret %u table %p\n", ret, table );
1477 return ret;