server: Use create_request_async for write requests.
[wine.git] / dlls / iphlpapi / ipstats.c
blob47df7ebfde52b76a79d843d105186924ed077c8f
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 <errno.h>
29 #include <sys/types.h>
30 #ifdef HAVE_DIRENT_H
31 #include <dirent.h>
32 #endif
33 #ifdef HAVE_ALIAS_H
34 #include <alias.h>
35 #endif
36 #ifdef HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
38 #endif
39 #ifdef HAVE_SYS_SOCKETVAR_H
40 #include <sys/socketvar.h>
41 #endif
42 #ifdef HAVE_SYS_TIMEOUT_H
43 #include <sys/timeout.h>
44 #endif
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 #ifdef HAVE_NETINET_IN_SYSTM_H
49 #include <netinet/in_systm.h>
50 #endif
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
53 #endif
54 #ifdef HAVE_NET_IF_H
55 #include <net/if.h>
56 #endif
57 #ifdef HAVE_NET_IF_DL_H
58 #include <net/if_dl.h>
59 #endif
60 #ifdef HAVE_NET_IF_TYPES_H
61 #include <net/if_types.h>
62 #endif
63 #ifdef HAVE_NET_ROUTE_H
64 #include <net/route.h>
65 #endif
66 #ifdef HAVE_NET_IF_ARP_H
67 #include <net/if_arp.h>
68 #endif
69 #ifdef HAVE_NETINET_IF_ETHER_H
70 #include <netinet/if_ether.h>
71 #endif
72 #ifdef HAVE_NETINET_IF_INARP_H
73 #include <netinet/if_inarp.h>
74 #endif
75 #ifdef HAVE_NETINET_IP_H
76 #include <netinet/ip.h>
77 #endif
78 #ifdef HAVE_NETINET_TCP_H
79 #include <netinet/tcp.h>
80 #endif
81 #ifdef HAVE_NETINET_IP_VAR_H
82 #include <netinet/ip_var.h>
83 #endif
84 #ifdef HAVE_NETINET_TCP_FSM_H
85 #include <netinet/tcp_fsm.h>
86 #endif
87 #ifdef HAVE_NETINET_IN_PCB_H
88 #include <netinet/in_pcb.h>
89 #endif
90 #ifdef HAVE_NETINET_TCP_TIMER_H
91 #include <netinet/tcp_timer.h>
92 #endif
93 #ifdef HAVE_NETINET_TCP_VAR_H
94 #include <netinet/tcp_var.h>
95 #endif
96 #ifdef HAVE_NETINET_IP_ICMP_H
97 #include <netinet/ip_icmp.h>
98 #endif
99 #ifdef HAVE_NETINET_ICMP_VAR_H
100 #include <netinet/icmp_var.h>
101 #endif
102 #ifdef HAVE_NETINET_UDP_H
103 #include <netinet/udp.h>
104 #endif
105 #ifdef HAVE_NETINET_UDP_VAR_H
106 #include <netinet/udp_var.h>
107 #endif
108 #ifdef HAVE_SYS_PROTOSW_H
109 #include <sys/protosw.h>
110 #endif
111 #ifdef HAVE_SYS_SYSCTL_H
112 #include <sys/sysctl.h>
113 #endif
114 #ifdef HAVE_KSTAT_H
115 #include <kstat.h>
116 #endif
117 #ifdef HAVE_INET_MIB2_H
118 #include <inet/mib2.h>
119 #endif
120 #ifdef HAVE_STROPTS_H
121 #include <stropts.h>
122 #endif
123 #ifdef HAVE_SYS_TIHDR_H
124 #include <sys/tihdr.h>
125 #endif
126 #ifdef HAVE_SYS_PARAM_H
127 #include <sys/param.h>
128 #endif
129 #ifdef HAVE_SYS_QUEUE_H
130 #include <sys/queue.h>
131 #endif
132 #ifdef HAVE_SYS_USER_H
133 /* Make sure the definitions of struct kinfo_proc are the same. */
134 #include <sys/user.h>
135 #endif
136 #ifdef HAVE_LIBPROCSTAT_H
137 #include <libprocstat.h>
138 #endif
139 #ifdef HAVE_LIBPROC_H
140 #include <libproc.h>
141 #endif
143 #ifndef ROUNDUP
144 #define ROUNDUP(a) \
145 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
146 #endif
147 #ifndef ADVANCE
148 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
149 #endif
151 #include "ntstatus.h"
152 #define WIN32_NO_STATUS
153 #define NONAMELESSUNION
154 #include "ifenum.h"
155 #include "ipstats.h"
157 #include "wine/debug.h"
158 #include "wine/server.h"
159 #include "wine/unicode.h"
161 #ifndef HAVE_NETINET_TCP_FSM_H
162 #define TCPS_ESTABLISHED 1
163 #define TCPS_SYN_SENT 2
164 #define TCPS_SYN_RECEIVED 3
165 #define TCPS_FIN_WAIT_1 4
166 #define TCPS_FIN_WAIT_2 5
167 #define TCPS_TIME_WAIT 6
168 #define TCPS_CLOSED 7
169 #define TCPS_CLOSE_WAIT 8
170 #define TCPS_LAST_ACK 9
171 #define TCPS_LISTEN 10
172 #define TCPS_CLOSING 11
173 #endif
175 #ifndef RTF_MULTICAST
176 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
177 #endif
179 #ifndef RTF_LLINFO
180 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
181 #endif
183 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
185 #ifdef HAVE_LIBKSTAT
186 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
188 unsigned int i;
189 kstat_named_t *data = ksp->ks_data;
191 for (i = 0; i < ksp->ks_ndata; i++)
192 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
193 return 0;
196 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
198 unsigned int i;
199 kstat_named_t *data = ksp->ks_data;
201 for (i = 0; i < ksp->ks_ndata; i++)
202 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
203 return 0;
205 #endif
207 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
208 static int open_streams_mib( const char *proto )
210 int fd;
211 struct strbuf buf;
212 struct request
214 struct T_optmgmt_req req_header;
215 struct opthdr opt_header;
216 } request;
218 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
220 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
221 return -1;
223 if (proto) ioctl( fd, I_PUSH, proto );
225 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
226 request.req_header.OPT_length = sizeof(request.opt_header);
227 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
228 request.req_header.MGMT_flags = T_CURRENT;
229 request.opt_header.level = MIB2_IP;
230 request.opt_header.name = 0;
231 request.opt_header.len = 0;
233 buf.len = sizeof(request);
234 buf.buf = (caddr_t)&request;
235 if (putmsg( fd, &buf, NULL, 0 ) == -1)
237 WARN( "putmsg: %s\n", strerror(errno) );
238 close( fd );
239 fd = -1;
241 return fd;
244 static void *read_mib_entry( int fd, int level, int name, int *len )
246 struct strbuf buf;
247 void *data;
248 int ret, flags = 0;
250 struct reply
252 struct T_optmgmt_ack ack_header;
253 struct opthdr opt_header;
254 } reply;
256 for (;;)
258 buf.maxlen = sizeof(reply);
259 buf.buf = (caddr_t)&reply;
260 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
261 if (!(ret & MOREDATA)) return NULL;
262 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
263 if (buf.len < sizeof(reply.ack_header)) return NULL;
264 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
266 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
267 buf.maxlen = reply.opt_header.len;
268 buf.buf = (caddr_t)data;
269 flags = 0;
270 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
271 reply.opt_header.level == level &&
272 reply.opt_header.name == name)
274 *len = buf.len;
275 return data;
277 HeapFree( GetProcessHeap(), 0, data );
280 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
282 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
284 DWORD ret = ERROR_NOT_SUPPORTED;
286 if (!name || !entry) return ERROR_INVALID_PARAMETER;
288 #ifdef __linux__
290 FILE *fp;
292 if ((fp = fopen("/proc/net/dev", "r")))
294 DWORD skip;
295 char buf[512], *ptr;
296 int nameLen = strlen(name);
298 while ((ptr = fgets(buf, sizeof(buf), fp)))
300 while (*ptr && isspace(*ptr)) ptr++;
301 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
303 ptr += nameLen + 1;
304 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
305 &entry->dwInOctets, &entry->dwInUcastPkts,
306 &entry->dwInErrors, &entry->dwInDiscards,
307 &skip, &skip, &skip,
308 &entry->dwInNUcastPkts, &entry->dwOutOctets,
309 &entry->dwOutUcastPkts, &entry->dwOutErrors,
310 &entry->dwOutDiscards );
311 break;
314 fclose(fp);
315 ret = NO_ERROR;
318 #elif defined(HAVE_LIBKSTAT)
320 kstat_ctl_t *kc;
321 kstat_t *ksp;
323 if ((kc = kstat_open()) &&
324 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
325 kstat_read( kc, ksp, NULL ) != -1 &&
326 ksp->ks_type == KSTAT_TYPE_NAMED)
328 entry->dwMtu = 1500; /* FIXME */
329 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
330 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
331 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
332 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
333 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
334 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
335 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
336 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
337 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
338 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
339 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
340 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
341 entry->dwOutDiscards = 0; /* FIXME */
342 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
343 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
344 ret = NO_ERROR;
346 if (kc) kstat_close( kc );
348 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
350 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
351 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
353 size_t needed;
354 char *buf = NULL, *end;
355 struct if_msghdr *ifm;
356 struct if_data ifdata;
358 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
360 ERR ("failed to get size of iflist\n");
361 goto done;
363 buf = HeapAlloc (GetProcessHeap (), 0, needed);
364 if (!buf)
366 ret = ERROR_OUTOFMEMORY;
367 goto done;
369 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
371 ERR ("failed to get iflist\n");
372 goto done;
374 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
376 ifm = (struct if_msghdr *) buf;
377 if(ifm->ifm_type == RTM_IFINFO)
379 ifdata = ifm->ifm_data;
380 entry->dwMtu = ifdata.ifi_mtu;
381 entry->dwSpeed = ifdata.ifi_baudrate;
382 entry->dwInOctets = ifdata.ifi_ibytes;
383 entry->dwInErrors = ifdata.ifi_ierrors;
384 entry->dwInDiscards = ifdata.ifi_iqdrops;
385 entry->dwInUcastPkts = ifdata.ifi_ipackets;
386 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
387 entry->dwOutOctets = ifdata.ifi_obytes;
388 entry->dwOutUcastPkts = ifdata.ifi_opackets;
389 entry->dwOutErrors = ifdata.ifi_oerrors;
390 ret = NO_ERROR;
391 break;
394 done:
395 HeapFree (GetProcessHeap (), 0, buf);
397 #else
398 FIXME( "unimplemented\n" );
399 #endif
400 return ret;
404 /******************************************************************
405 * GetIcmpStatistics (IPHLPAPI.@)
407 * Get the ICMP statistics for the local computer.
409 * PARAMS
410 * stats [Out] buffer for ICMP statistics
412 * RETURNS
413 * Success: NO_ERROR
414 * Failure: error code from winerror.h
416 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
418 DWORD ret = ERROR_NOT_SUPPORTED;
420 if (!stats) return ERROR_INVALID_PARAMETER;
421 memset( stats, 0, sizeof(MIB_ICMP) );
423 #ifdef __linux__
425 FILE *fp;
427 if ((fp = fopen("/proc/net/snmp", "r")))
429 static const char hdr[] = "Icmp:";
430 char buf[512], *ptr;
432 while ((ptr = fgets(buf, sizeof(buf), fp)))
434 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
435 /* last line was a header, get another */
436 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
437 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
439 ptr += sizeof(hdr);
440 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",
441 &stats->stats.icmpInStats.dwMsgs,
442 &stats->stats.icmpInStats.dwErrors,
443 &stats->stats.icmpInStats.dwDestUnreachs,
444 &stats->stats.icmpInStats.dwTimeExcds,
445 &stats->stats.icmpInStats.dwParmProbs,
446 &stats->stats.icmpInStats.dwSrcQuenchs,
447 &stats->stats.icmpInStats.dwRedirects,
448 &stats->stats.icmpInStats.dwEchoReps,
449 &stats->stats.icmpInStats.dwTimestamps,
450 &stats->stats.icmpInStats.dwTimestampReps,
451 &stats->stats.icmpInStats.dwAddrMasks,
452 &stats->stats.icmpInStats.dwAddrMaskReps,
453 &stats->stats.icmpOutStats.dwMsgs,
454 &stats->stats.icmpOutStats.dwErrors,
455 &stats->stats.icmpOutStats.dwDestUnreachs,
456 &stats->stats.icmpOutStats.dwTimeExcds,
457 &stats->stats.icmpOutStats.dwParmProbs,
458 &stats->stats.icmpOutStats.dwSrcQuenchs,
459 &stats->stats.icmpOutStats.dwRedirects,
460 &stats->stats.icmpOutStats.dwEchoReps,
461 &stats->stats.icmpOutStats.dwTimestamps,
462 &stats->stats.icmpOutStats.dwTimestampReps,
463 &stats->stats.icmpOutStats.dwAddrMasks,
464 &stats->stats.icmpOutStats.dwAddrMaskReps );
465 break;
468 fclose(fp);
469 ret = NO_ERROR;
472 #elif defined(HAVE_LIBKSTAT)
474 static char ip[] = "ip", icmp[] = "icmp";
475 kstat_ctl_t *kc;
476 kstat_t *ksp;
478 if ((kc = kstat_open()) &&
479 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
480 kstat_read( kc, ksp, NULL ) != -1 &&
481 ksp->ks_type == KSTAT_TYPE_NAMED)
483 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
484 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
485 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
486 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
487 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
488 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
489 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
490 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
491 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
492 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
493 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
494 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
495 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
496 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
497 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
498 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
499 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
500 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
501 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
502 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
503 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
504 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
505 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
506 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
507 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
508 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
509 ret = NO_ERROR;
511 if (kc) kstat_close( kc );
513 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && (defined(HAVE_STRUCT_ICMPSTAT_ICPS_INHIST) || defined(HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST))
515 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
516 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
517 struct icmpstat icmp_stat;
518 size_t needed = sizeof(icmp_stat);
519 int i;
521 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
523 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_INHIST
524 /*in stats */
525 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
526 for(i = 0; i <= ICMP_MAXTYPE; i++)
527 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
529 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
531 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
532 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
533 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
534 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
535 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
536 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
537 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
538 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
539 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
540 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
541 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
542 #endif
544 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST
545 /* out stats */
546 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
547 for(i = 0; i <= ICMP_MAXTYPE; i++)
548 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
550 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
552 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
553 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
554 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
555 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
556 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
557 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
558 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
559 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
560 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
561 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
562 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
563 #endif /* HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST */
564 ret = NO_ERROR;
567 #else /* ICMPCTL_STATS */
568 FIXME( "unimplemented\n" );
569 #endif
570 return ret;
573 /******************************************************************
574 * GetIcmpStatisticsEx (IPHLPAPI.@)
576 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
578 * PARAMS
579 * stats [Out] buffer for ICMP statistics
580 * family [In] specifies whether IPv4 or IPv6 statistics are returned
582 * RETURNS
583 * Success: NO_ERROR
584 * Failure: error code from winerror.h
586 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX stats, DWORD family)
588 DWORD ret = ERROR_NOT_SUPPORTED;
589 MIB_ICMP ipv4stats;
591 if (!stats) return ERROR_INVALID_PARAMETER;
592 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
593 memset( stats, 0, sizeof(MIB_ICMP_EX) );
595 if (family == WS_AF_INET6)
597 #ifdef __linux__
599 FILE *fp;
601 if ((fp = fopen("/proc/net/snmp6", "r")))
603 struct icmpstatstruct{
604 const char *name;
605 DWORD pos;
607 static const struct icmpstatstruct icmpinstatlist[] = {
608 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
609 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
610 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
611 { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
612 { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
613 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
614 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
615 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
616 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
617 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
618 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
619 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
620 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
621 { "Icmp6InRedirects", ND_REDIRECT },
622 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
624 static const struct icmpstatstruct icmpoutstatlist[] = {
625 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
626 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
627 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
628 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
629 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
630 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
631 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
632 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
633 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
634 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
635 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
636 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
637 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
638 { "Icmp6OutRedirects", ND_REDIRECT },
639 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
641 char buf[512], *ptr, *value;
642 DWORD res, i;
644 while ((ptr = fgets(buf, sizeof(buf), fp)))
646 if (!(value = strchr(buf, ' ')))
647 continue;
649 /* terminate the valuename */
650 ptr = value - 1;
651 *(ptr + 1) = '\0';
653 /* and strip leading spaces from value */
654 value += 1;
655 while (*value==' ') value++;
656 if ((ptr = strchr(value, '\n')))
657 *ptr='\0';
659 if (!strcasecmp(buf, "Icmp6InMsgs"))
661 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwMsgs = res;
662 continue;
665 if (!strcasecmp(buf, "Icmp6InErrors"))
667 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwErrors = res;
668 continue;
671 for (i = 0; i < sizeof(icmpinstatlist)/sizeof(icmpinstatlist[0]); i++)
673 if (!strcasecmp(buf, icmpinstatlist[i].name))
675 if (sscanf(value, "%d", &res))
676 stats->icmpInStats.rgdwTypeCount[icmpinstatlist[i].pos] = res;
677 break;
681 if (!strcasecmp(buf, "Icmp6OutMsgs"))
683 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwMsgs = res;
684 continue;
687 if (!strcasecmp(buf, "Icmp6OutErrors"))
689 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwErrors = res;
690 continue;
693 for (i = 0; i < sizeof(icmpoutstatlist)/sizeof(icmpoutstatlist[0]); i++)
695 if (!strcasecmp(buf, icmpoutstatlist[i].name))
697 if (sscanf(value, "%d", &res))
698 stats->icmpOutStats.rgdwTypeCount[icmpoutstatlist[i].pos] = res;
699 break;
704 fclose(fp);
705 ret = NO_ERROR;
708 #else
709 FIXME( "unimplemented for IPv6\n" );
710 #endif
711 return ret;
714 ret = GetIcmpStatistics(&ipv4stats);
715 if (!ret)
717 stats->icmpInStats.dwMsgs = ipv4stats.stats.icmpInStats.dwMsgs;
718 stats->icmpInStats.dwErrors = ipv4stats.stats.icmpInStats.dwErrors;
719 stats->icmpInStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpInStats.dwDestUnreachs;
720 stats->icmpInStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpInStats.dwSrcQuenchs;
721 stats->icmpInStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpInStats.dwRedirects;
722 stats->icmpInStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpInStats.dwEchos;
723 stats->icmpInStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpInStats.dwTimeExcds;
724 stats->icmpInStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpInStats.dwParmProbs;
725 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpInStats.dwTimestamps;
726 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpInStats.dwTimestampReps;
727 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpInStats.dwAddrMasks;
728 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpInStats.dwAddrMaskReps;
730 stats->icmpOutStats.dwMsgs = ipv4stats.stats.icmpOutStats.dwMsgs;
731 stats->icmpOutStats.dwErrors = ipv4stats.stats.icmpOutStats.dwErrors;
732 stats->icmpOutStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpOutStats.dwDestUnreachs;
733 stats->icmpOutStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpOutStats.dwSrcQuenchs;
734 stats->icmpOutStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpOutStats.dwRedirects;
735 stats->icmpOutStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpOutStats.dwEchos;
736 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpOutStats.dwTimeExcds;
737 stats->icmpOutStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpOutStats.dwParmProbs;
738 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpOutStats.dwTimestamps;
739 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpOutStats.dwTimestampReps;
740 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpOutStats.dwAddrMasks;
741 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpOutStats.dwAddrMaskReps;
743 return ret;
746 /******************************************************************
747 * GetIpStatisticsEx (IPHLPAPI.@)
749 * Get the IPv4 and IPv6 statistics for the local computer.
751 * PARAMS
752 * stats [Out] buffer for IP statistics
753 * family [In] specifies whether IPv4 or IPv6 statistics are returned
755 * RETURNS
756 * Success: NO_ERROR
757 * Failure: error code from winerror.h
759 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS stats, DWORD family)
761 DWORD ret = ERROR_NOT_SUPPORTED;
762 MIB_IPFORWARDTABLE *fwd_table;
764 if (!stats) return ERROR_INVALID_PARAMETER;
765 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
766 memset( stats, 0, sizeof(*stats) );
768 stats->dwNumIf = stats->dwNumAddr = get_interface_indices( FALSE, NULL );
769 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
771 stats->dwNumRoutes = fwd_table->dwNumEntries;
772 HeapFree( GetProcessHeap(), 0, fwd_table );
775 if (family == WS_AF_INET6)
777 #ifdef __linux__
779 FILE *fp;
781 if ((fp = fopen("/proc/net/snmp6", "r")))
783 struct {
784 const char *name;
785 DWORD *elem;
786 } ipstatlist[] = {
787 { "Ip6InReceives", &stats->dwInReceives },
788 { "Ip6InHdrErrors", &stats->dwInHdrErrors },
789 { "Ip6InAddrErrors", &stats->dwInAddrErrors },
790 { "Ip6OutForwDatagrams", &stats->dwForwDatagrams },
791 { "Ip6InUnknownProtos", &stats->dwInUnknownProtos },
792 { "Ip6InDiscards", &stats->dwInDiscards },
793 { "Ip6InDelivers", &stats->dwInDelivers },
794 { "Ip6OutRequests", &stats->dwOutRequests },
795 { "Ip6OutDiscards", &stats->dwOutDiscards },
796 { "Ip6OutNoRoutes", &stats->dwOutNoRoutes },
797 { "Ip6ReasmTimeout", &stats->dwReasmTimeout },
798 { "Ip6ReasmReqds", &stats->dwReasmReqds },
799 { "Ip6ReasmOKs", &stats->dwReasmOks },
800 { "Ip6ReasmFails", &stats->dwReasmFails },
801 { "Ip6FragOKs", &stats->dwFragOks },
802 { "Ip6FragFails", &stats->dwFragFails },
803 { "Ip6FragCreates", &stats->dwFragCreates },
804 /* hmm, no routingDiscards, defaultTTL and forwarding? */
806 char buf[512], *ptr, *value;
807 DWORD res, i;
809 while ((ptr = fgets(buf, sizeof(buf), fp)))
811 if (!(value = strchr(buf, ' ')))
812 continue;
814 /* terminate the valuename */
815 ptr = value - 1;
816 *(ptr + 1) = '\0';
818 /* and strip leading spaces from value */
819 value += 1;
820 while (*value==' ') value++;
821 if ((ptr = strchr(value, '\n')))
822 *ptr='\0';
824 for (i = 0; i < sizeof(ipstatlist)/sizeof(ipstatlist[0]); i++)
825 if (!strcasecmp(buf, ipstatlist[i].name))
827 if (sscanf(value, "%d", &res)) *ipstatlist[i].elem = res;
828 continue;
831 fclose(fp);
832 ret = NO_ERROR;
835 #else
836 FIXME( "unimplemented for IPv6\n" );
837 #endif
838 return ret;
841 #ifdef __linux__
843 FILE *fp;
845 if ((fp = fopen("/proc/net/snmp", "r")))
847 static const char hdr[] = "Ip:";
848 char buf[512], *ptr;
850 while ((ptr = fgets(buf, sizeof(buf), fp)))
852 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
853 /* last line was a header, get another */
854 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
855 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
857 ptr += sizeof(hdr);
858 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
859 &stats->u.dwForwarding,
860 &stats->dwDefaultTTL,
861 &stats->dwInReceives,
862 &stats->dwInHdrErrors,
863 &stats->dwInAddrErrors,
864 &stats->dwForwDatagrams,
865 &stats->dwInUnknownProtos,
866 &stats->dwInDiscards,
867 &stats->dwInDelivers,
868 &stats->dwOutRequests,
869 &stats->dwOutDiscards,
870 &stats->dwOutNoRoutes,
871 &stats->dwReasmTimeout,
872 &stats->dwReasmReqds,
873 &stats->dwReasmOks,
874 &stats->dwReasmFails,
875 &stats->dwFragOks,
876 &stats->dwFragFails,
877 &stats->dwFragCreates );
878 /* hmm, no routingDiscards */
879 break;
882 fclose(fp);
883 ret = NO_ERROR;
886 #elif defined(HAVE_LIBKSTAT)
888 static char ip[] = "ip";
889 kstat_ctl_t *kc;
890 kstat_t *ksp;
892 if ((kc = kstat_open()) &&
893 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
894 kstat_read( kc, ksp, NULL ) != -1 &&
895 ksp->ks_type == KSTAT_TYPE_NAMED)
897 stats->u.dwForwarding = kstat_get_ui32( ksp, "forwarding" );
898 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
899 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
900 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
901 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
902 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
903 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
904 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
905 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
906 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
907 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
908 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
909 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
910 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
911 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
912 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
913 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
914 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
915 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
916 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
917 ret = NO_ERROR;
919 if (kc) kstat_close( kc );
921 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
923 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
924 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
925 int ip_ttl, ip_forwarding;
926 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
927 struct ipstat ip_stat;
928 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
929 struct ip_stats ip_stat;
930 #endif
931 size_t needed;
933 needed = sizeof(ip_stat);
934 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
936 ERR ("failed to get ipstat\n");
937 return ERROR_NOT_SUPPORTED;
940 needed = sizeof(ip_ttl);
941 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
943 ERR ("failed to get ip Default TTL\n");
944 return ERROR_NOT_SUPPORTED;
947 needed = sizeof(ip_forwarding);
948 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
950 ERR ("failed to get ip forwarding\n");
951 return ERROR_NOT_SUPPORTED;
954 stats->u.dwForwarding = ip_forwarding;
955 stats->dwDefaultTTL = ip_ttl;
956 stats->dwInDelivers = ip_stat.ips_delivered;
957 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
958 stats->dwInAddrErrors = ip_stat.ips_cantforward;
959 stats->dwInReceives = ip_stat.ips_total;
960 stats->dwForwDatagrams = ip_stat.ips_forward;
961 stats->dwInUnknownProtos = ip_stat.ips_noproto;
962 stats->dwInDiscards = ip_stat.ips_fragdropped;
963 stats->dwOutDiscards = ip_stat.ips_odropped;
964 stats->dwReasmOks = ip_stat.ips_reassembled;
965 stats->dwFragOks = ip_stat.ips_fragmented;
966 stats->dwFragFails = ip_stat.ips_cantfrag;
967 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
968 stats->dwOutNoRoutes = ip_stat.ips_noroute;
969 stats->dwOutRequests = ip_stat.ips_localout;
970 stats->dwReasmReqds = ip_stat.ips_fragments;
971 ret = NO_ERROR;
973 #else
974 FIXME( "unimplemented for IPv4\n" );
975 #endif
976 return ret;
979 /******************************************************************
980 * GetIpStatistics (IPHLPAPI.@)
982 * Get the IP statistics for the local computer.
984 * PARAMS
985 * stats [Out] buffer for IP statistics
987 * RETURNS
988 * Success: NO_ERROR
989 * Failure: error code from winerror.h
991 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
993 return GetIpStatisticsEx(stats, WS_AF_INET);
996 /******************************************************************
997 * GetTcpStatisticsEx (IPHLPAPI.@)
999 * Get the IPv4 and IPv6 TCP statistics for the local computer.
1001 * PARAMS
1002 * stats [Out] buffer for TCP statistics
1003 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1005 * RETURNS
1006 * Success: NO_ERROR
1007 * Failure: error code from winerror.h
1009 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS stats, DWORD family)
1011 DWORD ret = ERROR_NOT_SUPPORTED;
1013 if (!stats) return ERROR_INVALID_PARAMETER;
1014 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1015 memset( stats, 0, sizeof(*stats) );
1017 if (family == WS_AF_INET6)
1019 FIXME( "unimplemented for IPv6\n" );
1020 return ret;
1023 #ifdef __linux__
1025 FILE *fp;
1027 if ((fp = fopen("/proc/net/snmp", "r")))
1029 static const char hdr[] = "Tcp:";
1030 MIB_TCPTABLE *tcp_table;
1031 char buf[512], *ptr;
1033 while ((ptr = fgets(buf, sizeof(buf), fp)))
1035 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
1036 /* last line was a header, get another */
1037 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1038 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
1040 ptr += sizeof(hdr);
1041 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
1042 &stats->u.dwRtoAlgorithm,
1043 &stats->dwRtoMin,
1044 &stats->dwRtoMax,
1045 &stats->dwMaxConn,
1046 &stats->dwActiveOpens,
1047 &stats->dwPassiveOpens,
1048 &stats->dwAttemptFails,
1049 &stats->dwEstabResets,
1050 &stats->dwCurrEstab,
1051 &stats->dwInSegs,
1052 &stats->dwOutSegs,
1053 &stats->dwRetransSegs,
1054 &stats->dwInErrs,
1055 &stats->dwOutRsts );
1056 break;
1059 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
1061 stats->dwNumConns = tcp_table->dwNumEntries;
1062 HeapFree( GetProcessHeap(), 0, tcp_table );
1064 fclose(fp);
1065 ret = NO_ERROR;
1068 #elif defined(HAVE_LIBKSTAT)
1070 static char tcp[] = "tcp";
1071 kstat_ctl_t *kc;
1072 kstat_t *ksp;
1074 if ((kc = kstat_open()) &&
1075 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
1076 kstat_read( kc, ksp, NULL ) != -1 &&
1077 ksp->ks_type == KSTAT_TYPE_NAMED)
1079 stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
1080 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
1081 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
1082 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
1083 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
1084 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
1085 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
1086 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
1087 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
1088 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
1089 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
1090 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
1091 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
1092 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
1093 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
1094 ret = NO_ERROR;
1096 if (kc) kstat_close( kc );
1098 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
1100 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
1101 #define TCPTV_MIN 2
1102 #define TCPTV_REXMTMAX 128
1103 #endif
1104 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
1105 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1106 #define hz 1000
1107 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
1108 struct tcpstat tcp_stat;
1109 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
1110 struct tcp_stats tcp_stat;
1111 #endif
1112 size_t needed = sizeof(tcp_stat);
1114 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
1116 stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
1117 stats->dwRtoMin = TCPTV_MIN;
1118 stats->dwRtoMax = TCPTV_REXMTMAX;
1119 stats->dwMaxConn = -1;
1120 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
1121 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
1122 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
1123 stats->dwEstabResets = tcp_stat.tcps_drops;
1124 stats->dwCurrEstab = 0;
1125 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
1126 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
1127 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
1128 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
1129 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
1130 stats->dwNumConns = tcp_stat.tcps_connects;
1131 ret = NO_ERROR;
1133 else ERR ("failed to get tcpstat\n");
1135 #else
1136 FIXME( "unimplemented\n" );
1137 #endif
1138 return ret;
1141 /******************************************************************
1142 * GetTcpStatistics (IPHLPAPI.@)
1144 * Get the TCP statistics for the local computer.
1146 * PARAMS
1147 * stats [Out] buffer for TCP statistics
1149 * RETURNS
1150 * Success: NO_ERROR
1151 * Failure: error code from winerror.h
1153 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
1155 return GetTcpStatisticsEx(stats, WS_AF_INET);
1158 /******************************************************************
1159 * GetUdpStatistics (IPHLPAPI.@)
1161 * Get the IPv4 and IPv6 UDP statistics for the local computer.
1163 * PARAMS
1164 * stats [Out] buffer for UDP statistics
1165 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1167 * RETURNS
1168 * Success: NO_ERROR
1169 * Failure: error code from winerror.h
1171 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS stats, DWORD family)
1173 DWORD ret = ERROR_NOT_SUPPORTED;
1175 if (!stats) return ERROR_INVALID_PARAMETER;
1176 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1177 memset( stats, 0, sizeof(*stats) );
1179 stats->dwNumAddrs = get_interface_indices( FALSE, NULL );
1181 if (family == WS_AF_INET6)
1183 #ifdef __linux__
1185 FILE *fp;
1187 if ((fp = fopen("/proc/net/snmp6", "r")))
1189 struct {
1190 const char *name;
1191 DWORD *elem;
1192 } udpstatlist[] = {
1193 { "Udp6InDatagrams", &stats->dwInDatagrams },
1194 { "Udp6NoPorts", &stats->dwNoPorts },
1195 { "Udp6InErrors", &stats->dwInErrors },
1196 { "Udp6OutDatagrams", &stats->dwOutDatagrams },
1198 char buf[512], *ptr, *value;
1199 DWORD res, i;
1201 while ((ptr = fgets(buf, sizeof(buf), fp)))
1203 if (!(value = strchr(buf, ' ')))
1204 continue;
1206 /* terminate the valuename */
1207 ptr = value - 1;
1208 *(ptr + 1) = '\0';
1210 /* and strip leading spaces from value */
1211 value += 1;
1212 while (*value==' ') value++;
1213 if ((ptr = strchr(value, '\n')))
1214 *ptr='\0';
1216 for (i = 0; i < sizeof(udpstatlist)/sizeof(udpstatlist[0]); i++)
1217 if (!strcasecmp(buf, udpstatlist[i].name))
1219 if (sscanf(value, "%d", &res)) *udpstatlist[i].elem = res;
1220 continue;
1223 fclose(fp);
1224 ret = NO_ERROR;
1227 #else
1228 FIXME( "unimplemented for IPv6\n" );
1229 #endif
1230 return ret;
1233 #ifdef __linux__
1235 FILE *fp;
1237 if ((fp = fopen("/proc/net/snmp", "r")))
1239 static const char hdr[] = "Udp:";
1240 char buf[512], *ptr;
1242 while ((ptr = fgets(buf, sizeof(buf), fp)))
1244 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
1245 /* last line was a header, get another */
1246 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1247 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
1249 ptr += sizeof(hdr);
1250 sscanf( ptr, "%u %u %u %u %u",
1251 &stats->dwInDatagrams, &stats->dwNoPorts,
1252 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
1253 break;
1256 fclose(fp);
1257 ret = NO_ERROR;
1260 #elif defined(HAVE_LIBKSTAT)
1262 static char udp[] = "udp";
1263 kstat_ctl_t *kc;
1264 kstat_t *ksp;
1265 MIB_UDPTABLE *udp_table;
1267 if ((kc = kstat_open()) &&
1268 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
1269 kstat_read( kc, ksp, NULL ) != -1 &&
1270 ksp->ks_type == KSTAT_TYPE_NAMED)
1272 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
1273 stats->dwNoPorts = 0; /* FIXME */
1274 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
1275 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
1276 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1278 stats->dwNumAddrs = udp_table->dwNumEntries;
1279 HeapFree( GetProcessHeap(), 0, udp_table );
1281 ret = NO_ERROR;
1283 if (kc) kstat_close( kc );
1285 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
1287 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
1288 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1289 struct udpstat udp_stat;
1290 MIB_UDPTABLE *udp_table;
1291 size_t needed = sizeof(udp_stat);
1293 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
1295 stats->dwInDatagrams = udp_stat.udps_ipackets;
1296 stats->dwOutDatagrams = udp_stat.udps_opackets;
1297 stats->dwNoPorts = udp_stat.udps_noport;
1298 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
1299 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1301 stats->dwNumAddrs = udp_table->dwNumEntries;
1302 HeapFree( GetProcessHeap(), 0, udp_table );
1304 ret = NO_ERROR;
1306 else ERR ("failed to get udpstat\n");
1308 #else
1309 FIXME( "unimplemented for IPv4\n" );
1310 #endif
1311 return ret;
1314 /******************************************************************
1315 * GetUdpStatistics (IPHLPAPI.@)
1317 * Get the UDP statistics for the local computer.
1319 * PARAMS
1320 * stats [Out] buffer for UDP statistics
1322 * RETURNS
1323 * Success: NO_ERROR
1324 * Failure: error code from winerror.h
1326 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
1328 return GetUdpStatisticsEx(stats, WS_AF_INET);
1331 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
1332 DWORD *count, const MIB_IPFORWARDROW *row )
1334 if (table->dwNumEntries >= *count)
1336 MIB_IPFORWARDTABLE *new_table;
1337 DWORD new_count = table->dwNumEntries * 2;
1339 if (!(new_table = HeapReAlloc( heap, flags, table,
1340 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
1342 HeapFree( heap, 0, table );
1343 return NULL;
1345 *count = new_count;
1346 table = new_table;
1348 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1349 return table;
1352 static int compare_ipforward_rows(const void *a, const void *b)
1354 const MIB_IPFORWARDROW *rowA = a;
1355 const MIB_IPFORWARDROW *rowB = b;
1356 int ret;
1358 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
1359 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
1360 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
1361 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1364 /******************************************************************
1365 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1367 * Get the route table.
1368 * Like GetIpForwardTable(), but allocate the returned table from heap.
1370 * PARAMS
1371 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1372 * allocated and returned.
1373 * bOrder [In] whether to sort the table
1374 * heap [In] heap from which the table is allocated
1375 * flags [In] flags to HeapAlloc
1377 * RETURNS
1378 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1379 * on failure, NO_ERROR on success.
1381 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
1382 HANDLE heap, DWORD flags)
1384 MIB_IPFORWARDTABLE *table;
1385 MIB_IPFORWARDROW row;
1386 DWORD ret = NO_ERROR, count = 16;
1388 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1390 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1392 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1393 return ERROR_OUTOFMEMORY;
1395 table->dwNumEntries = 0;
1397 #ifdef __linux__
1399 FILE *fp;
1401 if ((fp = fopen("/proc/net/route", "r")))
1403 char buf[512], *ptr;
1404 DWORD flags;
1406 /* skip header line */
1407 ptr = fgets(buf, sizeof(buf), fp);
1408 while ((ptr = fgets(buf, sizeof(buf), fp)))
1410 memset( &row, 0, sizeof(row) );
1412 while (!isspace(*ptr)) ptr++;
1413 *ptr++ = 0;
1414 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1415 continue;
1417 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1418 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1419 flags = strtoul(ptr + 1, &ptr, 16);
1421 if (!(flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID;
1422 else if (flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1423 else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT;
1425 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1426 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1427 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1428 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1429 /* FIXME: other protos might be appropriate, e.g. the default
1430 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1431 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1433 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1434 break;
1436 fclose(fp);
1438 else ret = ERROR_NOT_SUPPORTED;
1440 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1442 void *data;
1443 int fd, len, namelen;
1444 mib2_ipRouteEntry_t *entry;
1445 char name[64];
1447 if ((fd = open_streams_mib( NULL )) != -1)
1449 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1451 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1453 row.dwForwardDest = entry->ipRouteDest;
1454 row.dwForwardMask = entry->ipRouteMask;
1455 row.dwForwardPolicy = 0;
1456 row.dwForwardNextHop = entry->ipRouteNextHop;
1457 row.u1.dwForwardType = entry->ipRouteType;
1458 row.u2.dwForwardProto = entry->ipRouteProto;
1459 row.dwForwardAge = entry->ipRouteAge;
1460 row.dwForwardNextHopAS = 0;
1461 row.dwForwardMetric1 = entry->ipRouteMetric1;
1462 row.dwForwardMetric2 = entry->ipRouteMetric2;
1463 row.dwForwardMetric3 = entry->ipRouteMetric3;
1464 row.dwForwardMetric4 = entry->ipRouteMetric4;
1465 row.dwForwardMetric5 = entry->ipRouteMetric5;
1466 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1467 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1468 name[namelen] = 0;
1469 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1470 if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1472 HeapFree( GetProcessHeap(), 0, data );
1474 close( fd );
1476 else ret = ERROR_NOT_SUPPORTED;
1478 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1480 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1481 size_t needed;
1482 char *buf = NULL, *lim, *next, *addrPtr;
1483 struct rt_msghdr *rtm;
1485 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1487 ERR ("sysctl 1 failed!\n");
1488 ret = ERROR_NOT_SUPPORTED;
1489 goto done;
1492 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1493 if (!buf)
1495 ret = ERROR_OUTOFMEMORY;
1496 goto done;
1499 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1501 ret = ERROR_NOT_SUPPORTED;
1502 goto done;
1505 lim = buf + needed;
1506 for (next = buf; next < lim; next += rtm->rtm_msglen)
1508 int i;
1510 rtm = (struct rt_msghdr *)next;
1512 if (rtm->rtm_type != RTM_GET)
1514 WARN ("Got unexpected message type 0x%x!\n",
1515 rtm->rtm_type);
1516 continue;
1519 /* Ignore gateway routes which are multicast */
1520 if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST))
1521 continue;
1523 memset( &row, 0, sizeof(row) );
1524 row.dwForwardIfIndex = rtm->rtm_index;
1525 row.u1.ForwardType = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
1526 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1527 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1529 addrPtr = (char *)(rtm + 1);
1531 for (i = 1; i; i <<= 1)
1533 struct sockaddr *sa;
1534 DWORD addr;
1536 if (!(i & rtm->rtm_addrs))
1537 continue;
1539 sa = (struct sockaddr *)addrPtr;
1540 ADVANCE (addrPtr, sa);
1542 /* default routes are encoded by length-zero sockaddr */
1543 if (sa->sa_len == 0) {
1544 addr = 0;
1545 }else {
1546 switch(sa->sa_family) {
1547 case AF_INET: {
1548 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1549 addr = sin->sin_addr.s_addr;
1550 break;
1552 #ifdef AF_LINK
1553 case AF_LINK:
1554 if(i == RTA_GATEWAY && row.u1.ForwardType == MIB_IPROUTE_TYPE_DIRECT) {
1555 /* For direct route we may simply use dest addr as next hop */
1556 C_ASSERT(RTA_DST < RTA_GATEWAY);
1557 addr = row.dwForwardDest;
1558 break;
1560 /* fallthrough */
1561 #endif
1562 default:
1563 WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family);
1564 addr = 0;
1568 switch (i)
1570 case RTA_DST: row.dwForwardDest = addr; break;
1571 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1572 case RTA_NETMASK: row.dwForwardMask = addr; break;
1573 default:
1574 WARN ("Unexpected address type 0x%x\n", i);
1578 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1579 break;
1581 done:
1582 HeapFree( GetProcessHeap (), 0, buf );
1584 #else
1585 FIXME( "not implemented\n" );
1586 ret = ERROR_NOT_SUPPORTED;
1587 #endif
1589 if (!table) return ERROR_OUTOFMEMORY;
1590 if (!ret)
1592 if (bOrder && table->dwNumEntries)
1593 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1594 *ppIpForwardTable = table;
1596 else HeapFree( heap, flags, table );
1597 TRACE( "returning ret %u table %p\n", ret, table );
1598 return ret;
1601 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1602 DWORD *count, const MIB_IPNETROW *row )
1604 if (table->dwNumEntries >= *count)
1606 MIB_IPNETTABLE *new_table;
1607 DWORD new_count = table->dwNumEntries * 2;
1609 if (!(new_table = HeapReAlloc( heap, flags, table,
1610 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1612 HeapFree( heap, 0, table );
1613 return NULL;
1615 *count = new_count;
1616 table = new_table;
1618 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1619 return table;
1622 static int compare_ipnet_rows(const void *a, const void *b)
1624 const MIB_IPNETROW *rowA = a;
1625 const MIB_IPNETROW *rowB = b;
1627 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1631 /******************************************************************
1632 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1634 * Get the IP-to-physical address mapping table.
1635 * Like GetIpNetTable(), but allocate the returned table from heap.
1637 * PARAMS
1638 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1639 * allocated and returned.
1640 * bOrder [In] whether to sort the table
1641 * heap [In] heap from which the table is allocated
1642 * flags [In] flags to HeapAlloc
1644 * RETURNS
1645 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1646 * on failure, NO_ERROR on success.
1648 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1649 HANDLE heap, DWORD flags)
1651 MIB_IPNETTABLE *table;
1652 MIB_IPNETROW row;
1653 DWORD ret = NO_ERROR, count = 16;
1655 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1657 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1659 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1660 return ERROR_OUTOFMEMORY;
1662 table->dwNumEntries = 0;
1664 #ifdef __linux__
1666 FILE *fp;
1668 if ((fp = fopen("/proc/net/arp", "r")))
1670 char buf[512], *ptr;
1671 DWORD flags;
1673 /* skip header line */
1674 ptr = fgets(buf, sizeof(buf), fp);
1675 while ((ptr = fgets(buf, sizeof(buf), fp)))
1677 memset( &row, 0, sizeof(row) );
1679 row.dwAddr = inet_addr(ptr);
1680 while (*ptr && !isspace(*ptr)) ptr++;
1681 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1682 flags = strtoul(ptr + 1, &ptr, 16);
1684 #ifdef ATF_COM
1685 if (flags & ATF_COM) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1686 else
1687 #endif
1688 #ifdef ATF_PERM
1689 if (flags & ATF_PERM) row.u.Type = MIB_IPNET_TYPE_STATIC;
1690 else
1691 #endif
1692 row.u.Type = MIB_IPNET_TYPE_OTHER;
1694 while (*ptr && isspace(*ptr)) ptr++;
1695 while (*ptr && !isspace(*ptr))
1697 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1698 if (*ptr) ptr++;
1700 while (*ptr && isspace(*ptr)) ptr++;
1701 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1702 while (*ptr && isspace(*ptr)) ptr++;
1703 getInterfaceIndexByName(ptr, &row.dwIndex);
1705 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1706 break;
1708 fclose(fp);
1710 else ret = ERROR_NOT_SUPPORTED;
1712 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1714 void *data;
1715 int fd, len, namelen;
1716 mib2_ipNetToMediaEntry_t *entry;
1717 char name[64];
1719 if ((fd = open_streams_mib( NULL )) != -1)
1721 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1723 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1725 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1726 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1727 row.dwAddr = entry->ipNetToMediaNetAddress;
1728 row.u.Type = entry->ipNetToMediaType;
1729 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1730 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1731 name[namelen] = 0;
1732 getInterfaceIndexByName( name, &row.dwIndex );
1733 if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1735 HeapFree( GetProcessHeap(), 0, data );
1737 close( fd );
1739 else ret = ERROR_NOT_SUPPORTED;
1741 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1743 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1744 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1745 size_t needed;
1746 char *buf = NULL, *lim, *next;
1747 struct rt_msghdr *rtm;
1748 struct sockaddr_inarp *sinarp;
1749 struct sockaddr_dl *sdl;
1751 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1753 ERR ("failed to get arp table\n");
1754 ret = ERROR_NOT_SUPPORTED;
1755 goto done;
1758 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1759 if (!buf)
1761 ret = ERROR_OUTOFMEMORY;
1762 goto done;
1765 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1767 ret = ERROR_NOT_SUPPORTED;
1768 goto done;
1771 lim = buf + needed;
1772 next = buf;
1773 while(next < lim)
1775 rtm = (struct rt_msghdr *)next;
1776 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1777 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1778 if(sdl->sdl_alen) /* arp entry */
1780 memset( &row, 0, sizeof(row) );
1781 row.dwAddr = sinarp->sin_addr.s_addr;
1782 row.dwIndex = sdl->sdl_index;
1783 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1784 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1785 if(rtm->rtm_rmx.rmx_expire == 0) row.u.Type = MIB_IPNET_TYPE_STATIC;
1786 else if(sinarp->sin_other & SIN_PROXY) row.u.Type = MIB_IPNET_TYPE_OTHER;
1787 else if(rtm->rtm_rmx.rmx_expire != 0) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1788 else row.u.Type = MIB_IPNET_TYPE_INVALID;
1790 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1791 break;
1793 next += rtm->rtm_msglen;
1795 done:
1796 HeapFree( GetProcessHeap (), 0, buf );
1798 #else
1799 FIXME( "not implemented\n" );
1800 ret = ERROR_NOT_SUPPORTED;
1801 #endif
1803 if (!table) return ERROR_OUTOFMEMORY;
1804 if (!ret)
1806 if (bOrder && table->dwNumEntries)
1807 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1808 *ppIpNetTable = table;
1810 else HeapFree( heap, flags, table );
1811 TRACE( "returning ret %u table %p\n", ret, table );
1812 return ret;
1815 static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
1817 DWORD table_size;
1819 switch (class)
1821 case TCP_TABLE_BASIC_LISTENER:
1822 case TCP_TABLE_BASIC_CONNECTIONS:
1823 case TCP_TABLE_BASIC_ALL:
1825 table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
1826 if (row_size) *row_size = sizeof(MIB_TCPROW);
1827 break;
1829 case TCP_TABLE_OWNER_PID_LISTENER:
1830 case TCP_TABLE_OWNER_PID_CONNECTIONS:
1831 case TCP_TABLE_OWNER_PID_ALL:
1833 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
1834 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
1835 break;
1837 case TCP_TABLE_OWNER_MODULE_LISTENER:
1838 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1839 case TCP_TABLE_OWNER_MODULE_ALL:
1841 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]);
1842 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_MODULE);
1843 break;
1845 default:
1846 ERR("unhandled class %u\n", class);
1847 return 0;
1849 return table_size;
1852 static MIB_TCPTABLE *append_tcp_row( TCP_TABLE_CLASS class, HANDLE heap, DWORD flags,
1853 MIB_TCPTABLE *table, DWORD *count,
1854 const MIB_TCPROW_OWNER_MODULE *row, DWORD row_size )
1856 if (table->dwNumEntries >= *count)
1858 MIB_TCPTABLE *new_table;
1859 DWORD new_count = table->dwNumEntries * 2, new_table_size;
1861 new_table_size = get_tcp_table_sizes( class, new_count, NULL );
1862 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
1864 HeapFree( heap, 0, table );
1865 return NULL;
1867 *count = new_count;
1868 table = new_table;
1870 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
1871 table->dwNumEntries++;
1872 return table;
1876 /* Why not a lookup table? Because the TCPS_* constants are different
1877 on different platforms */
1878 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1880 switch (state)
1882 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1883 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1884 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1885 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1886 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1887 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1888 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1889 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1890 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1891 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1892 default:
1893 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1897 static int compare_tcp_rows(const void *a, const void *b)
1899 const MIB_TCPROW *rowA = a;
1900 const MIB_TCPROW *rowB = b;
1901 int ret;
1903 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1904 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1905 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1906 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1907 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1910 struct pid_map
1912 unsigned int pid;
1913 unsigned int unix_pid;
1916 static struct pid_map *get_pid_map( unsigned int *num_entries )
1918 HANDLE snapshot = NULL;
1919 struct pid_map *map;
1920 unsigned int i = 0, count = 16, size = count * sizeof(*map);
1921 NTSTATUS ret;
1923 if (!(map = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
1925 SERVER_START_REQ( create_snapshot )
1927 req->flags = SNAP_PROCESS;
1928 req->attributes = 0;
1929 if (!(ret = wine_server_call( req )))
1930 snapshot = wine_server_ptr_handle( reply->handle );
1932 SERVER_END_REQ;
1934 *num_entries = 0;
1935 while (ret == STATUS_SUCCESS)
1937 SERVER_START_REQ( next_process )
1939 req->handle = wine_server_obj_handle( snapshot );
1940 req->reset = (i == 0);
1941 if (!(ret = wine_server_call( req )))
1943 if (i >= count)
1945 struct pid_map *new_map;
1946 count *= 2;
1947 size = count * sizeof(*new_map);
1949 if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, size )))
1951 HeapFree( GetProcessHeap(), 0, map );
1952 map = NULL;
1953 goto done;
1955 map = new_map;
1957 map[i].pid = reply->pid;
1958 map[i].unix_pid = reply->unix_pid;
1959 (*num_entries)++;
1960 i++;
1963 SERVER_END_REQ;
1966 done:
1967 NtClose( snapshot );
1968 return map;
1971 static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, UINT_PTR inode )
1973 #ifdef __linux__
1974 unsigned int i, len_socket;
1975 char socket[32];
1977 sprintf( socket, "socket:[%lu]", inode );
1978 len_socket = strlen( socket );
1979 for (i = 0; i < num_entries; i++)
1981 char dir[32];
1982 struct dirent *dirent;
1983 DIR *dirfd;
1985 sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
1986 if ((dirfd = opendir( dir )))
1988 while ((dirent = readdir( dirfd )))
1990 char link[sizeof(dirent->d_name) + 32], name[32];
1991 int len;
1993 sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
1994 if ((len = readlink( link, name, sizeof(name) - 1 )) > 0) name[len] = 0;
1995 if (len == len_socket && !strcmp( socket, name ))
1997 closedir( dirfd );
1998 return map[i].pid;
2001 closedir( dirfd );
2004 return 0;
2005 #elif defined(HAVE_LIBPROCSTAT)
2006 struct procstat *pstat;
2007 struct kinfo_proc *proc;
2008 struct filestat_list *fds;
2009 struct filestat *fd;
2010 struct sockstat sock;
2011 unsigned int i, proc_count;
2013 pstat = procstat_open_sysctl();
2014 if (!pstat) return 0;
2016 for (i = 0; i < num_entries; i++)
2018 proc = procstat_getprocs( pstat, KERN_PROC_PID, map[i].unix_pid, &proc_count );
2019 if (!proc || proc_count < 1) continue;
2021 fds = procstat_getfiles( pstat, proc, 0 );
2022 if (!fds)
2024 procstat_freeprocs( pstat, proc );
2025 continue;
2028 STAILQ_FOREACH( fd, fds, next )
2030 char errbuf[_POSIX2_LINE_MAX];
2032 if (fd->fs_type != PS_FST_TYPE_SOCKET) continue;
2034 procstat_get_socket_info( pstat, fd, &sock, errbuf );
2036 if (sock.so_pcb == inode)
2038 procstat_freefiles( pstat, fds );
2039 procstat_freeprocs( pstat, proc );
2040 procstat_close( pstat );
2041 return map[i].pid;
2045 procstat_freefiles( pstat, fds );
2046 procstat_freeprocs( pstat, proc );
2049 procstat_close( pstat );
2050 return 0;
2051 #elif defined(HAVE_PROC_PIDINFO)
2052 struct proc_fdinfo *fds;
2053 struct socket_fdinfo sock;
2054 unsigned int i, j, n, fd_len;
2056 for (i = 0; i < num_entries; i++)
2058 fd_len = proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, NULL, 0 );
2059 if (fd_len <= 0) continue;
2061 fds = HeapAlloc( GetProcessHeap(), 0, fd_len );
2062 if (!fds) continue;
2064 proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, fds, fd_len );
2065 n = fd_len / sizeof(struct proc_fdinfo);
2066 for (j = 0; j < n; j++)
2068 if (fds[j].proc_fdtype != PROX_FDTYPE_SOCKET) continue;
2070 proc_pidfdinfo( map[i].unix_pid, fds[j].proc_fd, PROC_PIDFDSOCKETINFO, &sock, sizeof(sock) );
2071 if (sock.psi.soi_pcb == inode)
2073 HeapFree( GetProcessHeap(), 0, fds );
2074 return map[i].pid;
2078 HeapFree( GetProcessHeap(), 0, fds );
2080 return 0;
2081 #else
2082 FIXME( "not implemented\n" );
2083 return 0;
2084 #endif
2087 static BOOL match_class( TCP_TABLE_CLASS class, MIB_TCP_STATE state )
2089 switch (class)
2091 case TCP_TABLE_BASIC_ALL:
2092 case TCP_TABLE_OWNER_PID_ALL:
2093 case TCP_TABLE_OWNER_MODULE_ALL:
2094 return TRUE;
2096 case TCP_TABLE_BASIC_LISTENER:
2097 case TCP_TABLE_OWNER_PID_LISTENER:
2098 case TCP_TABLE_OWNER_MODULE_LISTENER:
2099 if (state == MIB_TCP_STATE_LISTEN) return TRUE;
2100 return FALSE;
2102 case TCP_TABLE_BASIC_CONNECTIONS:
2103 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2104 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2105 if (state == MIB_TCP_STATE_ESTAB) return TRUE;
2106 return FALSE;
2108 default:
2109 ERR( "unhandled class %u\n", class );
2110 return FALSE;
2114 DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2115 DWORD *size )
2117 MIB_TCPTABLE *table;
2118 MIB_TCPROW_OWNER_MODULE row;
2119 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2121 if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
2122 return ERROR_INVALID_PARAMETER;
2124 if (!(table = HeapAlloc( heap, flags, table_size )))
2125 return ERROR_OUTOFMEMORY;
2127 table->dwNumEntries = 0;
2129 #ifdef __linux__
2131 FILE *fp;
2133 if ((fp = fopen("/proc/net/tcp", "r")))
2135 char buf[512], *ptr;
2136 struct pid_map *map = NULL;
2137 unsigned int dummy, num_entries = 0;
2138 int inode;
2140 if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
2142 /* skip header line */
2143 ptr = fgets(buf, sizeof(buf), fp);
2144 while ((ptr = fgets(buf, sizeof(buf), fp)))
2146 if (sscanf( ptr, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy,
2147 &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
2148 &row.dwRemotePort, &row.dwState, &inode ) != 7)
2149 continue;
2150 row.dwLocalPort = htons( row.dwLocalPort );
2151 row.dwRemotePort = htons( row.dwRemotePort );
2152 row.dwState = TCPStateToMIBState( row.dwState );
2153 if (!match_class( class, row.dwState )) continue;
2155 if (class >= TCP_TABLE_OWNER_PID_LISTENER)
2156 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2157 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2159 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2160 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2162 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2163 break;
2165 HeapFree( GetProcessHeap(), 0, map );
2166 fclose( fp );
2168 else ret = ERROR_NOT_SUPPORTED;
2170 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2172 void *data;
2173 int fd, len;
2174 mib2_tcpConnEntry_t *entry;
2176 if ((fd = open_streams_mib( "tcp" )) != -1)
2178 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
2180 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2182 row.dwLocalAddr = entry->tcpConnLocalAddress;
2183 row.dwLocalPort = htons( entry->tcpConnLocalPort );
2184 row.dwRemoteAddr = entry->tcpConnRemAddress;
2185 row.dwRemotePort = htons( entry->tcpConnRemPort );
2186 row.dwState = entry->tcpConnState;
2187 if (!match_class( class, row.dwState )) continue;
2188 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2189 break;
2191 HeapFree( GetProcessHeap(), 0, data );
2193 close( fd );
2195 else ret = ERROR_NOT_SUPPORTED;
2197 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2199 size_t Len = 0;
2200 char *Buf = NULL;
2201 struct xinpgen *pXIG, *pOrigXIG;
2202 struct pid_map *pMap = NULL;
2203 unsigned NumEntries;
2205 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
2207 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2208 ret = ERROR_NOT_SUPPORTED;
2209 goto done;
2212 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2213 if (!Buf)
2215 ret = ERROR_OUTOFMEMORY;
2216 goto done;
2219 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
2221 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2222 ret = ERROR_NOT_SUPPORTED;
2223 goto done;
2226 if (class >= TCP_TABLE_OWNER_PID_LISTENER) pMap = get_pid_map( &NumEntries );
2228 /* Might be nothing here; first entry is just a header it seems */
2229 if (Len <= sizeof (struct xinpgen)) goto done;
2231 pOrigXIG = (struct xinpgen *)Buf;
2232 pXIG = pOrigXIG;
2234 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2235 pXIG->xig_len > sizeof (struct xinpgen);
2236 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2238 struct tcpcb *pTCPData = NULL;
2239 struct inpcb *pINData;
2240 struct xsocket *pSockData;
2242 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
2243 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
2244 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
2246 /* Ignore sockets for other protocols */
2247 if (pSockData->xso_protocol != IPPROTO_TCP)
2248 continue;
2250 /* Ignore PCBs that were freed while generating the data */
2251 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2252 continue;
2254 /* we're only interested in IPv4 addresses */
2255 if (!(pINData->inp_vflag & INP_IPV4) ||
2256 (pINData->inp_vflag & INP_IPV6))
2257 continue;
2259 /* If all 0's, skip it */
2260 if (!pINData->inp_laddr.s_addr &&
2261 !pINData->inp_lport &&
2262 !pINData->inp_faddr.s_addr &&
2263 !pINData->inp_fport)
2264 continue;
2266 /* Fill in structure details */
2267 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2268 row.dwLocalPort = pINData->inp_lport;
2269 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
2270 row.dwRemotePort = pINData->inp_fport;
2271 row.dwState = TCPStateToMIBState (pTCPData->t_state);
2272 if (!match_class( class, row.dwState )) continue;
2273 if (class >= TCP_TABLE_OWNER_PID_LISTENER)
2274 row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
2275 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2277 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2278 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2280 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2281 break;
2284 done:
2285 HeapFree( GetProcessHeap(), 0, pMap );
2286 HeapFree (GetProcessHeap (), 0, Buf);
2288 #else
2289 FIXME( "not implemented\n" );
2290 ret = ERROR_NOT_SUPPORTED;
2291 #endif
2293 if (!table) return ERROR_OUTOFMEMORY;
2294 if (!ret)
2296 if (order && table->dwNumEntries)
2297 qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
2298 *tablep = table;
2300 else HeapFree( heap, flags, table );
2301 if (size) *size = get_tcp_table_sizes( class, count, NULL );
2302 TRACE( "returning ret %u table %p\n", ret, table );
2303 return ret;
2306 /******************************************************************
2307 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
2309 * Get the TCP connection table.
2310 * Like GetTcpTable(), but allocate the returned table from heap.
2312 * PARAMS
2313 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2314 * allocated and returned.
2315 * bOrder [In] whether to sort the table
2316 * heap [In] heap from which the table is allocated
2317 * flags [In] flags to HeapAlloc
2319 * RETURNS
2320 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2321 * returns otherwise.
2323 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
2324 HANDLE heap, DWORD flags )
2326 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
2328 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
2329 return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
2332 static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2334 DWORD table_size;
2336 switch (class)
2338 case UDP_TABLE_BASIC:
2340 table_size = FIELD_OFFSET(MIB_UDPTABLE, table[row_count]);
2341 if (row_size) *row_size = sizeof(MIB_UDPROW);
2342 break;
2344 case UDP_TABLE_OWNER_PID:
2346 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table[row_count]);
2347 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_PID);
2348 break;
2350 case UDP_TABLE_OWNER_MODULE:
2352 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table[row_count]);
2353 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_MODULE);
2354 break;
2356 default:
2357 ERR("unhandled class %u\n", class);
2358 return 0;
2360 return table_size;
2363 static MIB_UDPTABLE *append_udp_row( UDP_TABLE_CLASS class, HANDLE heap, DWORD flags,
2364 MIB_UDPTABLE *table, DWORD *count,
2365 const MIB_UDPROW_OWNER_MODULE *row, DWORD row_size )
2367 if (table->dwNumEntries >= *count)
2369 MIB_UDPTABLE *new_table;
2370 DWORD new_count = table->dwNumEntries * 2, new_table_size;
2372 new_table_size = get_udp_table_sizes( class, new_count, NULL );
2373 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
2375 HeapFree( heap, 0, table );
2376 return NULL;
2378 *count = new_count;
2379 table = new_table;
2381 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
2382 table->dwNumEntries++;
2383 return table;
2386 static int compare_udp_rows(const void *a, const void *b)
2388 const MIB_UDPROW *rowA = a;
2389 const MIB_UDPROW *rowB = b;
2390 int ret;
2392 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
2393 return rowA->dwLocalPort - rowB->dwLocalPort;
2396 DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2397 DWORD *size )
2399 MIB_UDPTABLE *table;
2400 MIB_UDPROW_OWNER_MODULE row;
2401 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2403 if (!(table_size = get_udp_table_sizes( class, count, &row_size )))
2404 return ERROR_INVALID_PARAMETER;
2406 if (!(table = HeapAlloc( heap, flags, table_size )))
2407 return ERROR_OUTOFMEMORY;
2409 table->dwNumEntries = 0;
2410 memset( &row, 0, sizeof(row) );
2412 #ifdef __linux__
2414 FILE *fp;
2416 if ((fp = fopen( "/proc/net/udp", "r" )))
2418 char buf[512], *ptr;
2419 struct pid_map *map = NULL;
2420 unsigned int dummy, num_entries = 0;
2421 int inode;
2423 if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
2425 /* skip header line */
2426 ptr = fgets( buf, sizeof(buf), fp );
2427 while ((ptr = fgets( buf, sizeof(buf), fp )))
2429 if (sscanf( ptr, "%u: %x:%x %*s %*s %*s %*s %*s %*s %*s %d", &dummy,
2430 &row.dwLocalAddr, &row.dwLocalPort, &inode ) != 4)
2431 continue;
2432 row.dwLocalPort = htons( row.dwLocalPort );
2434 if (class >= UDP_TABLE_OWNER_PID)
2435 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2436 if (class >= UDP_TABLE_OWNER_MODULE)
2438 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2439 row.u.dwFlags = 0;
2440 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2442 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size )))
2443 break;
2445 HeapFree( GetProcessHeap(), 0, map );
2446 fclose( fp );
2448 else ret = ERROR_NOT_SUPPORTED;
2450 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2452 void *data;
2453 int fd, len;
2454 mib2_udpEntry_t *entry;
2456 if ((fd = open_streams_mib( "udp" )) != -1)
2458 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
2460 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2462 row.dwLocalAddr = entry->udpLocalAddress;
2463 row.dwLocalPort = htons( entry->udpLocalPort );
2464 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size ))) break;
2466 HeapFree( GetProcessHeap(), 0, data );
2468 close( fd );
2470 else ret = ERROR_NOT_SUPPORTED;
2472 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2474 size_t Len = 0;
2475 char *Buf = NULL;
2476 struct xinpgen *pXIG, *pOrigXIG;
2477 struct pid_map *pMap = NULL;
2478 unsigned NumEntries;
2480 if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
2482 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2483 ret = ERROR_NOT_SUPPORTED;
2484 goto done;
2487 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2488 if (!Buf)
2490 ret = ERROR_OUTOFMEMORY;
2491 goto done;
2494 if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
2496 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2497 ret = ERROR_NOT_SUPPORTED;
2498 goto done;
2501 if (class >= UDP_TABLE_OWNER_PID)
2502 pMap = get_pid_map( &NumEntries );
2504 /* Might be nothing here; first entry is just a header it seems */
2505 if (Len <= sizeof (struct xinpgen)) goto done;
2507 pOrigXIG = (struct xinpgen *)Buf;
2508 pXIG = pOrigXIG;
2510 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2511 pXIG->xig_len > sizeof (struct xinpgen);
2512 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2514 struct inpcb *pINData;
2515 struct xsocket *pSockData;
2517 pINData = &((struct xinpcb *)pXIG)->xi_inp;
2518 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
2520 /* Ignore sockets for other protocols */
2521 if (pSockData->xso_protocol != IPPROTO_UDP)
2522 continue;
2524 /* Ignore PCBs that were freed while generating the data */
2525 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2526 continue;
2528 /* we're only interested in IPv4 addresses */
2529 if (!(pINData->inp_vflag & INP_IPV4) ||
2530 (pINData->inp_vflag & INP_IPV6))
2531 continue;
2533 /* If all 0's, skip it */
2534 if (!pINData->inp_laddr.s_addr &&
2535 !pINData->inp_lport)
2536 continue;
2538 /* Fill in structure details */
2539 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2540 row.dwLocalPort = pINData->inp_lport;
2541 if (class >= UDP_TABLE_OWNER_PID)
2542 row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
2543 if (class >= UDP_TABLE_OWNER_MODULE)
2545 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2546 row.u.dwFlags = 0;
2547 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2549 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size ))) break;
2552 done:
2553 HeapFree( GetProcessHeap(), 0, pMap );
2554 HeapFree (GetProcessHeap (), 0, Buf);
2556 #else
2557 FIXME( "not implemented\n" );
2558 ret = ERROR_NOT_SUPPORTED;
2559 #endif
2561 if (!table) return ERROR_OUTOFMEMORY;
2562 if (!ret)
2564 if (order && table->dwNumEntries)
2565 qsort( table->table, table->dwNumEntries, row_size, compare_udp_rows );
2566 *tablep = table;
2568 else HeapFree( heap, flags, table );
2569 if (size) *size = get_udp_table_sizes( class, count, NULL );
2570 TRACE( "returning ret %u table %p\n", ret, table );
2571 return ret;
2574 /******************************************************************
2575 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
2577 * Get the UDP listener table.
2578 * Like GetUdpTable(), but allocate the returned table from heap.
2580 * PARAMS
2581 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
2582 * allocated and returned.
2583 * bOrder [In] whether to sort the table
2584 * heap [In] heap from which the table is allocated
2585 * flags [In] flags to HeapAlloc
2587 * RETURNS
2588 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
2589 * returns otherwise.
2591 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
2592 HANDLE heap, DWORD flags)
2594 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
2596 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
2597 return build_udp_table( UDP_TABLE_BASIC, (void **)ppUdpTable, bOrder, heap, flags, NULL );