iphlpapi: Reimplement GetTcpTable to avoid parsing the same information three times.
[wine/multimedia.git] / dlls / iphlpapi / ipstats.c
blob49e18080b1d286b7cd181a509db9a689f119f35d
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 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
154 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
155 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
157 size_t needed;
158 char *buf, *end;
159 struct if_msghdr *ifm;
160 struct if_data ifdata;
161 if (!name || !entry)
162 return ERROR_INVALID_PARAMETER;
164 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
166 ERR ("failed to get size of iflist\n");
167 return ERROR_NOT_SUPPORTED;
169 buf = HeapAlloc (GetProcessHeap (), 0, needed);
170 if (!buf) return ERROR_NOT_SUPPORTED;
171 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
173 ERR ("failed to get iflist\n");
174 HeapFree (GetProcessHeap (), 0, buf);
175 return ERROR_NOT_SUPPORTED;
177 else
178 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
180 ifm = (struct if_msghdr *) buf;
181 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
183 ifdata = ifm->ifm_data;
184 entry->dwMtu = ifdata.ifi_mtu;
185 entry->dwSpeed = ifdata.ifi_baudrate;
186 entry->dwInOctets = ifdata.ifi_ibytes;
187 entry->dwInErrors = ifdata.ifi_ierrors;
188 entry->dwInDiscards = ifdata.ifi_iqdrops;
189 entry->dwInUcastPkts = ifdata.ifi_ipackets;
190 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
191 entry->dwOutOctets = ifdata.ifi_obytes;
192 entry->dwOutUcastPkts = ifdata.ifi_opackets;
193 entry->dwOutErrors = ifdata.ifi_oerrors;
194 HeapFree (GetProcessHeap (), 0, buf);
195 return NO_ERROR;
198 HeapFree (GetProcessHeap (), 0, buf);
199 return ERROR_NOT_SUPPORTED;
200 #else
201 /* get interface stats from /proc/net/dev, no error if can't
202 no inUnknownProtos, outNUcastPkts, outQLen */
203 FILE *fp;
205 if (!name || !entry)
206 return ERROR_INVALID_PARAMETER;
207 fp = fopen("/proc/net/dev", "r");
208 if (fp) {
209 char buf[512] = { 0 }, *ptr;
210 int nameLen = strlen(name), nameFound = 0;
213 ptr = fgets(buf, sizeof(buf), fp);
214 while (ptr && !nameFound) {
215 while (*ptr && isspace(*ptr))
216 ptr++;
217 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
218 nameFound = 1;
219 else
220 ptr = fgets(buf, sizeof(buf), fp);
222 if (nameFound) {
223 char *endPtr;
225 ptr += nameLen + 1;
226 if (ptr && *ptr) {
227 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
228 ptr = endPtr;
230 if (ptr && *ptr) {
231 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
232 ptr = endPtr;
234 if (ptr && *ptr) {
235 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
236 ptr = endPtr;
238 if (ptr && *ptr) {
239 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
240 ptr = endPtr;
242 if (ptr && *ptr) {
243 strtoul(ptr, &endPtr, 10); /* skip */
244 ptr = endPtr;
246 if (ptr && *ptr) {
247 strtoul(ptr, &endPtr, 10); /* skip */
248 ptr = endPtr;
250 if (ptr && *ptr) {
251 strtoul(ptr, &endPtr, 10); /* skip */
252 ptr = endPtr;
254 if (ptr && *ptr) {
255 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
256 ptr = endPtr;
258 if (ptr && *ptr) {
259 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
260 ptr = endPtr;
262 if (ptr && *ptr) {
263 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
264 ptr = endPtr;
266 if (ptr && *ptr) {
267 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
268 ptr = endPtr;
270 if (ptr && *ptr) {
271 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
272 ptr = endPtr;
275 fclose(fp);
277 else
279 ERR ("unimplemented!\n");
280 return ERROR_NOT_SUPPORTED;
283 return NO_ERROR;
284 #endif
287 DWORD getICMPStats(MIB_ICMP *stats)
289 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
290 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
291 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
292 size_t needed;
293 struct icmpstat icmp_stat;
294 int i;
296 if (!stats)
297 return ERROR_INVALID_PARAMETER;
299 needed = sizeof(icmp_stat);
300 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
302 ERR ("failed to get icmpstat\n");
303 return ERROR_NOT_SUPPORTED;
307 /*in stats */
308 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
309 for(i = 0; i <= ICMP_MAXTYPE; i++)
310 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
312 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
314 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
315 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
316 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
317 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
318 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
319 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
320 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
321 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
322 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
323 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
324 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
326 #ifdef HAVE_ICPS_OUTHIST
327 /* out stats */
328 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
329 for(i = 0; i <= ICMP_MAXTYPE; i++)
330 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
332 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
334 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
335 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
336 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
337 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
338 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
339 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
340 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
341 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
342 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
343 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
344 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
345 #else /* ICPS_OUTHIST */
346 memset( &stats->stats.icmpOutStats, 0, sizeof(stats->stats.icmpOutStats) );
347 #endif /* ICPS_OUTHIST */
349 return NO_ERROR;
351 #else /* ICMPCTL_STATS */
352 FILE *fp;
354 if (!stats)
355 return ERROR_INVALID_PARAMETER;
357 memset(stats, 0, sizeof(MIB_ICMP));
358 /* get most of these stats from /proc/net/snmp, no error if can't */
359 fp = fopen("/proc/net/snmp", "r");
360 if (fp) {
361 static const char hdr[] = "Icmp:";
362 char buf[512] = { 0 }, *ptr;
364 do {
365 ptr = fgets(buf, sizeof(buf), fp);
366 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
367 if (ptr) {
368 /* last line was a header, get another */
369 ptr = fgets(buf, sizeof(buf), fp);
370 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
371 char *endPtr;
373 ptr += sizeof(hdr);
374 if (ptr && *ptr) {
375 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
376 ptr = endPtr;
378 if (ptr && *ptr) {
379 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
380 ptr = endPtr;
382 if (ptr && *ptr) {
383 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
384 ptr = endPtr;
386 if (ptr && *ptr) {
387 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
388 ptr = endPtr;
390 if (ptr && *ptr) {
391 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
392 ptr = endPtr;
394 if (ptr && *ptr) {
395 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
396 ptr = endPtr;
398 if (ptr && *ptr) {
399 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
400 ptr = endPtr;
402 if (ptr && *ptr) {
403 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
404 ptr = endPtr;
406 if (ptr && *ptr) {
407 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
408 ptr = endPtr;
410 if (ptr && *ptr) {
411 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
412 ptr = endPtr;
414 if (ptr && *ptr) {
415 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
416 ptr = endPtr;
418 if (ptr && *ptr) {
419 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
420 ptr = endPtr;
422 if (ptr && *ptr) {
423 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
424 ptr = endPtr;
426 if (ptr && *ptr) {
427 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
428 ptr = endPtr;
430 if (ptr && *ptr) {
431 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
432 ptr = endPtr;
434 if (ptr && *ptr) {
435 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
436 ptr = endPtr;
438 if (ptr && *ptr) {
439 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
440 ptr = endPtr;
442 if (ptr && *ptr) {
443 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
444 ptr = endPtr;
446 if (ptr && *ptr) {
447 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
448 ptr = endPtr;
450 if (ptr && *ptr) {
451 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
452 ptr = endPtr;
454 if (ptr && *ptr) {
455 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
456 ptr = endPtr;
458 if (ptr && *ptr) {
459 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
460 ptr = endPtr;
462 if (ptr && *ptr) {
463 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
464 ptr = endPtr;
466 if (ptr && *ptr) {
467 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
468 ptr = endPtr;
472 fclose(fp);
474 else
476 ERR ("unimplemented!\n");
477 return ERROR_NOT_SUPPORTED;
480 return NO_ERROR;
481 #endif
484 DWORD getIPStats(PMIB_IPSTATS stats)
486 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
487 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
488 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
489 int ip_ttl, ip_forwarding;
490 struct ipstat ip_stat;
491 size_t needed;
493 if (!stats)
494 return ERROR_INVALID_PARAMETER;
496 needed = sizeof(ip_stat);
497 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
499 ERR ("failed to get ipstat\n");
500 return ERROR_NOT_SUPPORTED;
503 needed = sizeof(ip_ttl);
504 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
506 ERR ("failed to get ip Default TTL\n");
507 return ERROR_NOT_SUPPORTED;
510 needed = sizeof(ip_forwarding);
511 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
513 ERR ("failed to get ip forwarding\n");
514 return ERROR_NOT_SUPPORTED;
517 stats->dwForwarding = ip_forwarding;
518 stats->dwDefaultTTL = ip_ttl;
519 stats->dwInDelivers = ip_stat.ips_delivered;
520 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
521 stats->dwInAddrErrors = ip_stat.ips_cantforward;
522 stats->dwInReceives = ip_stat.ips_total;
523 stats->dwForwDatagrams = ip_stat.ips_forward;
524 stats->dwInUnknownProtos = ip_stat.ips_noproto;
525 stats->dwInDiscards = ip_stat.ips_fragdropped;
526 stats->dwOutDiscards = ip_stat.ips_odropped;
527 stats->dwReasmOks = ip_stat.ips_reassembled;
528 stats->dwFragOks = ip_stat.ips_fragmented;
529 stats->dwFragFails = ip_stat.ips_cantfrag;
530 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
531 stats->dwOutNoRoutes = ip_stat.ips_noroute;
532 stats->dwOutRequests = ip_stat.ips_localout;
533 stats->dwReasmReqds = ip_stat.ips_fragments;
535 return NO_ERROR;
536 #else
537 FILE *fp;
539 if (!stats)
540 return ERROR_INVALID_PARAMETER;
542 memset(stats, 0, sizeof(MIB_IPSTATS));
543 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
544 stats->dwNumRoutes = getNumRoutes();
546 /* get most of these stats from /proc/net/snmp, no error if can't */
547 fp = fopen("/proc/net/snmp", "r");
548 if (fp) {
549 static const char hdr[] = "Ip:";
550 char buf[512] = { 0 }, *ptr;
552 do {
553 ptr = fgets(buf, sizeof(buf), fp);
554 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
555 if (ptr) {
556 /* last line was a header, get another */
557 ptr = fgets(buf, sizeof(buf), fp);
558 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
559 char *endPtr;
561 ptr += sizeof(hdr);
562 if (ptr && *ptr) {
563 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
564 ptr = endPtr;
566 if (ptr && *ptr) {
567 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
568 ptr = endPtr;
570 if (ptr && *ptr) {
571 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
572 ptr = endPtr;
574 if (ptr && *ptr) {
575 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
576 ptr = endPtr;
578 if (ptr && *ptr) {
579 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
580 ptr = endPtr;
582 if (ptr && *ptr) {
583 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
584 ptr = endPtr;
586 if (ptr && *ptr) {
587 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
588 ptr = endPtr;
590 if (ptr && *ptr) {
591 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
592 ptr = endPtr;
594 if (ptr && *ptr) {
595 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
596 ptr = endPtr;
598 if (ptr && *ptr) {
599 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
600 ptr = endPtr;
602 if (ptr && *ptr) {
603 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
604 ptr = endPtr;
606 if (ptr && *ptr) {
607 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
608 ptr = endPtr;
610 if (ptr && *ptr) {
611 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
612 ptr = endPtr;
614 if (ptr && *ptr) {
615 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
616 ptr = endPtr;
618 if (ptr && *ptr) {
619 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
620 ptr = endPtr;
622 if (ptr && *ptr) {
623 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
624 ptr = endPtr;
626 if (ptr && *ptr) {
627 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
628 ptr = endPtr;
630 if (ptr && *ptr) {
631 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
632 ptr = endPtr;
634 if (ptr && *ptr) {
635 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
636 ptr = endPtr;
638 /* hmm, no routingDiscards */
641 fclose(fp);
643 else
645 ERR ("unimplemented!\n");
646 return ERROR_NOT_SUPPORTED;
649 return NO_ERROR;
650 #endif
653 DWORD getTCPStats(MIB_TCPSTATS *stats)
655 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
656 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
657 #define TCPTV_MIN 2
658 #define TCPTV_REXMTMAX 128
659 #endif
660 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
661 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
662 #define hz 1000
663 struct tcpstat tcp_stat;
664 size_t needed;
666 if (!stats)
667 return ERROR_INVALID_PARAMETER;
668 needed = sizeof(tcp_stat);
670 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
672 ERR ("failed to get tcpstat\n");
673 return ERROR_NOT_SUPPORTED;
676 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
677 stats->dwRtoMin = TCPTV_MIN;
678 stats->dwRtoMax = TCPTV_REXMTMAX;
679 stats->dwMaxConn = -1;
680 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
681 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
682 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
683 stats->dwEstabResets = tcp_stat.tcps_drops;
684 stats->dwCurrEstab = 0;
685 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
686 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
687 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
688 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
689 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
690 stats->dwNumConns = tcp_stat.tcps_connects;
692 return NO_ERROR;
694 #else
695 FILE *fp;
697 if (!stats)
698 return ERROR_INVALID_PARAMETER;
700 memset(stats, 0, sizeof(MIB_TCPSTATS));
702 /* get from /proc/net/snmp, no error if can't */
703 fp = fopen("/proc/net/snmp", "r");
704 if (fp) {
705 static const char hdr[] = "Tcp:";
706 char buf[512] = { 0 }, *ptr;
709 do {
710 ptr = fgets(buf, sizeof(buf), fp);
711 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
712 if (ptr) {
713 /* last line was a header, get another */
714 ptr = fgets(buf, sizeof(buf), fp);
715 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
716 char *endPtr;
718 ptr += sizeof(hdr);
719 if (ptr && *ptr) {
720 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
721 ptr = endPtr;
723 if (ptr && *ptr) {
724 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
725 ptr = endPtr;
727 if (ptr && *ptr) {
728 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
729 ptr = endPtr;
731 if (ptr && *ptr) {
732 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
733 ptr = endPtr;
735 if (ptr && *ptr) {
736 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
737 ptr = endPtr;
739 if (ptr && *ptr) {
740 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
741 ptr = endPtr;
743 if (ptr && *ptr) {
744 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
745 ptr = endPtr;
747 if (ptr && *ptr) {
748 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
749 ptr = endPtr;
751 if (ptr && *ptr) {
752 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
753 ptr = endPtr;
755 if (ptr && *ptr) {
756 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
757 ptr = endPtr;
759 if (ptr && *ptr) {
760 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
761 ptr = endPtr;
763 if (ptr && *ptr) {
764 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
765 ptr = endPtr;
767 if (ptr && *ptr) {
768 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
769 ptr = endPtr;
771 if (ptr && *ptr) {
772 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
773 ptr = endPtr;
775 stats->dwNumConns = getNumTcpEntries();
778 fclose(fp);
780 else
782 ERR ("unimplemented!\n");
783 return ERROR_NOT_SUPPORTED;
786 return NO_ERROR;
787 #endif
790 DWORD getUDPStats(MIB_UDPSTATS *stats)
792 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
793 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
794 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
795 struct udpstat udp_stat;
796 size_t needed;
797 if (!stats)
798 return ERROR_INVALID_PARAMETER;
800 needed = sizeof(udp_stat);
802 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
804 ERR ("failed to get udpstat\n");
805 return ERROR_NOT_SUPPORTED;
808 stats->dwInDatagrams = udp_stat.udps_ipackets;
809 stats->dwOutDatagrams = udp_stat.udps_opackets;
810 stats->dwNoPorts = udp_stat.udps_noport;
811 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
812 stats->dwNumAddrs = getNumUdpEntries();
814 return NO_ERROR;
815 #else
816 FILE *fp;
818 if (!stats)
819 return ERROR_INVALID_PARAMETER;
821 memset(stats, 0, sizeof(MIB_UDPSTATS));
823 /* get from /proc/net/snmp, no error if can't */
824 fp = fopen("/proc/net/snmp", "r");
825 if (fp) {
826 static const char hdr[] = "Udp:";
827 char buf[512] = { 0 }, *ptr;
830 do {
831 ptr = fgets(buf, sizeof(buf), fp);
832 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
833 if (ptr) {
834 /* last line was a header, get another */
835 ptr = fgets(buf, sizeof(buf), fp);
836 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
837 char *endPtr;
839 ptr += sizeof(hdr);
840 if (ptr && *ptr) {
841 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
842 ptr = endPtr;
844 if (ptr && *ptr) {
845 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
846 ptr = endPtr;
848 if (ptr && *ptr) {
849 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
850 ptr = endPtr;
852 if (ptr && *ptr) {
853 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
854 ptr = endPtr;
856 if (ptr && *ptr) {
857 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
858 ptr = endPtr;
862 fclose(fp);
864 else
866 ERR ("unimplemented!\n");
867 return ERROR_NOT_SUPPORTED;
870 return NO_ERROR;
871 #endif
874 static DWORD getNumWithOneHeader(const char *filename)
876 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
877 size_t Len = 0;
878 char *Buf;
879 struct xinpgen *pXIG, *pOrigXIG;
880 int Protocol;
881 DWORD NumEntries = 0;
883 if (!strcmp (filename, "net.inet.tcp.pcblist"))
884 Protocol = IPPROTO_TCP;
885 else if (!strcmp (filename, "net.inet.udp.pcblist"))
886 Protocol = IPPROTO_UDP;
887 else
889 ERR ("Unsupported mib '%s', needs protocol mapping\n",
890 filename);
891 return 0;
894 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
896 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
897 return 0;
900 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
901 if (!Buf)
903 ERR ("Out of memory!\n");
904 return 0;
907 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
909 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
910 HeapFree (GetProcessHeap (), 0, Buf);
911 return 0;
914 /* Might be nothing here; first entry is just a header it seems */
915 if (Len <= sizeof (struct xinpgen))
917 HeapFree (GetProcessHeap (), 0, Buf);
918 return 0;
921 pOrigXIG = (struct xinpgen *)Buf;
922 pXIG = pOrigXIG;
924 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
925 pXIG->xig_len > sizeof (struct xinpgen);
926 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
928 struct tcpcb *pTCPData = NULL;
929 struct inpcb *pINData;
930 struct xsocket *pSockData;
932 if (Protocol == IPPROTO_TCP)
934 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
935 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
936 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
938 else
940 pINData = &((struct xinpcb *)pXIG)->xi_inp;
941 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
944 /* Ignore sockets for other protocols */
945 if (pSockData->xso_protocol != Protocol)
946 continue;
948 /* Ignore PCBs that were freed while generating the data */
949 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
950 continue;
952 /* we're only interested in IPv4 addresses */
953 if (!(pINData->inp_vflag & INP_IPV4) ||
954 (pINData->inp_vflag & INP_IPV6))
955 continue;
957 /* If all 0's, skip it */
958 if (!pINData->inp_laddr.s_addr &&
959 !pINData->inp_lport &&
960 !pINData->inp_faddr.s_addr &&
961 !pINData->inp_fport)
962 continue;
964 NumEntries++;
967 HeapFree (GetProcessHeap (), 0, Buf);
968 return NumEntries;
969 #else
970 FILE *fp;
971 int ret = 0;
973 fp = fopen(filename, "r");
974 if (fp) {
975 char buf[512] = { 0 }, *ptr;
978 ptr = fgets(buf, sizeof(buf), fp);
979 if (ptr) {
980 do {
981 ptr = fgets(buf, sizeof(buf), fp);
982 if (ptr)
983 ret++;
984 } while (ptr);
986 fclose(fp);
988 else
989 ERR ("Unable to open '%s' to count entries!\n", filename);
991 return ret;
992 #endif
995 DWORD getNumRoutes(void)
997 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
998 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
999 size_t needed;
1000 char *buf, *lim, *next;
1001 struct rt_msghdr *rtm;
1002 DWORD RouteCount = 0;
1004 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1006 ERR ("sysctl 1 failed!\n");
1007 return 0;
1010 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1011 if (!buf) return 0;
1013 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1015 ERR ("sysctl 2 failed!\n");
1016 HeapFree (GetProcessHeap (), 0, buf);
1017 return 0;
1020 lim = buf + needed;
1021 for (next = buf; next < lim; next += rtm->rtm_msglen)
1023 rtm = (struct rt_msghdr *)next;
1025 if (rtm->rtm_type != RTM_GET)
1027 WARN ("Got unexpected message type 0x%x!\n",
1028 rtm->rtm_type);
1029 continue;
1032 /* Ignore all entries except for gateway routes which aren't
1033 multicast */
1034 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1035 continue;
1037 RouteCount++;
1040 HeapFree (GetProcessHeap (), 0, buf);
1041 return RouteCount;
1042 #else
1043 return getNumWithOneHeader("/proc/net/route");
1044 #endif
1047 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1048 DWORD flags)
1050 DWORD ret;
1052 if (!ppIpForwardTable)
1053 ret = ERROR_INVALID_PARAMETER;
1054 else {
1055 DWORD numRoutes = getNumRoutes();
1056 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1057 PMIB_IPFORWARDTABLE table;
1059 if (numRoutes > 1)
1060 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1061 table = HeapAlloc(heap, flags, size);
1062 if (table) {
1063 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1064 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1065 size_t needed;
1066 char *buf, *lim, *next, *addrPtr;
1067 struct rt_msghdr *rtm;
1069 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1071 ERR ("sysctl 1 failed!\n");
1072 HeapFree (GetProcessHeap (), 0, table);
1073 return NO_ERROR;
1076 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1077 if (!buf)
1079 HeapFree (GetProcessHeap (), 0, table);
1080 return ERROR_OUTOFMEMORY;
1083 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1085 ERR ("sysctl 2 failed!\n");
1086 HeapFree (GetProcessHeap (), 0, table);
1087 HeapFree (GetProcessHeap (), 0, buf);
1088 return NO_ERROR;
1091 *ppIpForwardTable = table;
1092 table->dwNumEntries = 0;
1094 lim = buf + needed;
1095 for (next = buf; next < lim; next += rtm->rtm_msglen)
1097 int i;
1099 rtm = (struct rt_msghdr *)next;
1101 if (rtm->rtm_type != RTM_GET)
1103 WARN ("Got unexpected message type 0x%x!\n",
1104 rtm->rtm_type);
1105 continue;
1108 /* Ignore all entries except for gateway routes which aren't
1109 multicast */
1110 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1111 (rtm->rtm_flags & RTF_MULTICAST))
1112 continue;
1114 memset (&table->table[table->dwNumEntries], 0,
1115 sizeof (MIB_IPFORWARDROW));
1116 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1117 table->table[table->dwNumEntries].dwForwardType =
1118 MIB_IPROUTE_TYPE_INDIRECT;
1119 table->table[table->dwNumEntries].dwForwardMetric1 =
1120 rtm->rtm_rmx.rmx_hopcount;
1121 table->table[table->dwNumEntries].dwForwardProto =
1122 MIB_IPPROTO_LOCAL;
1124 addrPtr = (char *)(rtm + 1);
1126 for (i = 1; i; i <<= 1)
1128 struct sockaddr *sa;
1129 DWORD addr;
1131 if (!(i & rtm->rtm_addrs))
1132 continue;
1134 sa = (struct sockaddr *)addrPtr;
1135 ADVANCE (addrPtr, sa);
1137 /* default routes are encoded by length-zero sockaddr */
1138 if (sa->sa_len == 0)
1139 addr = 0;
1140 else if (sa->sa_family != AF_INET)
1142 WARN ("Received unsupported sockaddr family 0x%x\n",
1143 sa->sa_family);
1144 addr = 0;
1146 else
1148 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1150 addr = sin->sin_addr.s_addr;
1153 switch (i)
1155 case RTA_DST:
1156 table->table[table->dwNumEntries].dwForwardDest = addr;
1157 break;
1159 case RTA_GATEWAY:
1160 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1161 break;
1163 case RTA_NETMASK:
1164 table->table[table->dwNumEntries].dwForwardMask = addr;
1165 break;
1167 default:
1168 WARN ("Unexpected address type 0x%x\n", i);
1172 table->dwNumEntries++;
1175 HeapFree (GetProcessHeap (), 0, buf);
1176 ret = NO_ERROR;
1177 #else
1178 FILE *fp;
1180 ret = NO_ERROR;
1181 *ppIpForwardTable = table;
1182 table->dwNumEntries = 0;
1183 /* get from /proc/net/route, no error if can't */
1184 fp = fopen("/proc/net/route", "r");
1185 if (fp) {
1186 char buf[512] = { 0 }, *ptr;
1188 /* skip header line */
1189 ptr = fgets(buf, sizeof(buf), fp);
1190 while (ptr && table->dwNumEntries < numRoutes) {
1191 memset(&table->table[table->dwNumEntries], 0,
1192 sizeof(MIB_IPFORWARDROW));
1193 ptr = fgets(buf, sizeof(buf), fp);
1194 if (ptr) {
1195 DWORD index;
1197 while (!isspace(*ptr))
1198 ptr++;
1199 *ptr = '\0';
1200 ptr++;
1201 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1202 char *endPtr;
1204 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1205 if (*ptr) {
1206 table->table[table->dwNumEntries].dwForwardDest =
1207 strtoul(ptr, &endPtr, 16);
1208 ptr = endPtr;
1210 if (ptr && *ptr) {
1211 table->table[table->dwNumEntries].dwForwardNextHop =
1212 strtoul(ptr, &endPtr, 16);
1213 ptr = endPtr;
1215 if (ptr && *ptr) {
1216 DWORD flags = strtoul(ptr, &endPtr, 16);
1218 if (!(flags & RTF_UP))
1219 table->table[table->dwNumEntries].dwForwardType =
1220 MIB_IPROUTE_TYPE_INVALID;
1221 else if (flags & RTF_GATEWAY)
1222 table->table[table->dwNumEntries].dwForwardType =
1223 MIB_IPROUTE_TYPE_INDIRECT;
1224 else
1225 table->table[table->dwNumEntries].dwForwardType =
1226 MIB_IPROUTE_TYPE_DIRECT;
1227 ptr = endPtr;
1229 if (ptr && *ptr) {
1230 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1231 ptr = endPtr;
1233 if (ptr && *ptr) {
1234 strtoul(ptr, &endPtr, 16); /* use, skip */
1235 ptr = endPtr;
1237 if (ptr && *ptr) {
1238 table->table[table->dwNumEntries].dwForwardMetric1 =
1239 strtoul(ptr, &endPtr, 16);
1240 ptr = endPtr;
1242 if (ptr && *ptr) {
1243 table->table[table->dwNumEntries].dwForwardMask =
1244 strtoul(ptr, &endPtr, 16);
1245 ptr = endPtr;
1247 /* FIXME: other protos might be appropriate, e.g. the default
1248 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1249 table->table[table->dwNumEntries].dwForwardProto =
1250 MIB_IPPROTO_LOCAL;
1251 table->dwNumEntries++;
1255 fclose(fp);
1257 else
1259 ERR ("unimplemented!\n");
1260 return ERROR_NOT_SUPPORTED;
1262 #endif
1264 else
1265 ret = ERROR_OUTOFMEMORY;
1267 return ret;
1270 DWORD getNumArpEntries(void)
1272 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1273 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1274 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1275 DWORD arpEntries = 0;
1276 size_t needed;
1277 char *buf, *lim, *next;
1278 struct rt_msghdr *rtm;
1279 struct sockaddr_inarp *sinarp;
1280 struct sockaddr_dl *sdl;
1282 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1284 ERR ("failed to get size of arp table\n");
1285 return 0;
1288 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1289 if (!buf) return 0;
1291 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1293 ERR ("failed to get arp table\n");
1294 HeapFree (GetProcessHeap (), 0, buf);
1295 return 0;
1298 lim = buf + needed;
1299 next = buf;
1300 while(next < lim)
1302 rtm = (struct rt_msghdr *)next;
1303 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1304 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1305 if(sdl->sdl_alen) /* arp entry */
1306 arpEntries++;
1307 next += rtm->rtm_msglen;
1309 HeapFree (GetProcessHeap (), 0, buf);
1310 return arpEntries;
1311 #endif
1312 return getNumWithOneHeader("/proc/net/arp");
1315 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1317 DWORD ret = NO_ERROR;
1318 if (!ppIpNetTable)
1319 ret = ERROR_INVALID_PARAMETER;
1320 else {
1321 DWORD numEntries = getNumArpEntries();
1322 DWORD size = sizeof(MIB_IPNETTABLE);
1323 PMIB_IPNETTABLE table;
1325 if (numEntries > 1)
1326 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1327 table = HeapAlloc(heap, flags, size);
1328 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1329 if (table)
1331 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1332 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1333 size_t needed;
1334 char *buf, *lim, *next;
1335 struct rt_msghdr *rtm;
1336 struct sockaddr_inarp *sinarp;
1337 struct sockaddr_dl *sdl;
1339 *ppIpNetTable = table;
1340 table->dwNumEntries = 0;
1342 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1344 ERR ("failed to get size of arp table\n");
1345 return ERROR_NOT_SUPPORTED;
1348 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1349 if (!buf) return ERROR_OUTOFMEMORY;
1351 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1353 ERR ("failed to get arp table\n");
1354 HeapFree (GetProcessHeap (), 0, buf);
1355 return ERROR_NOT_SUPPORTED;
1358 lim = buf + needed;
1359 next = buf;
1360 while(next < lim)
1362 rtm = (struct rt_msghdr *)next;
1363 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1364 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1365 if(sdl->sdl_alen) /* arp entry */
1367 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1368 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1369 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1370 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1371 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1373 table->table[table->dwNumEntries].bPhysAddr[
1374 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1375 byte & 0x0ff;
1376 if(rtm->rtm_rmx.rmx_expire == 0)
1377 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1378 else if(sinarp->sin_other & SIN_PROXY)
1379 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1380 else if(rtm->rtm_rmx.rmx_expire != 0)
1381 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1382 else
1383 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1385 table->dwNumEntries++;
1387 next += rtm->rtm_msglen;
1389 HeapFree (GetProcessHeap (), 0, buf);
1391 else
1392 ret = ERROR_OUTOFMEMORY;
1393 return ret;
1394 #endif
1396 if (table) {
1397 FILE *fp;
1398 *ppIpNetTable = table;
1399 table->dwNumEntries = 0;
1400 /* get from /proc/net/arp, no error if can't */
1401 fp = fopen("/proc/net/arp", "r");
1402 if (fp) {
1403 char buf[512] = { 0 }, *ptr;
1405 /* skip header line */
1406 ptr = fgets(buf, sizeof(buf), fp);
1407 while (ptr && table->dwNumEntries < numEntries) {
1408 ptr = fgets(buf, sizeof(buf), fp);
1409 if (ptr) {
1410 char *endPtr;
1412 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1413 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1414 while (ptr && *ptr && !isspace(*ptr))
1415 ptr++;
1417 if (ptr && *ptr) {
1418 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1419 ptr = endPtr;
1421 if (ptr && *ptr) {
1422 DWORD flags = strtoul(ptr, &endPtr, 16);
1424 #ifdef ATF_COM
1425 if (flags & ATF_COM)
1426 table->table[table->dwNumEntries].dwType =
1427 MIB_IPNET_TYPE_DYNAMIC;
1428 else
1429 #endif
1430 #ifdef ATF_PERM
1431 if (flags & ATF_PERM)
1432 table->table[table->dwNumEntries].dwType =
1433 MIB_IPNET_TYPE_STATIC;
1434 else
1435 #endif
1436 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1438 ptr = endPtr;
1440 while (ptr && *ptr && isspace(*ptr))
1441 ptr++;
1442 while (ptr && *ptr && !isspace(*ptr)) {
1443 DWORD byte = strtoul(ptr, &endPtr, 16);
1445 if (endPtr && *endPtr) {
1446 endPtr++;
1447 table->table[table->dwNumEntries].bPhysAddr[
1448 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1449 byte & 0x0ff;
1451 ptr = endPtr;
1453 if (ptr && *ptr) {
1454 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1455 ptr = endPtr;
1457 getInterfaceIndexByName(ptr,
1458 &table->table[table->dwNumEntries].dwIndex);
1459 table->dwNumEntries++;
1462 fclose(fp);
1464 else
1465 ret = ERROR_NOT_SUPPORTED;
1467 else
1468 ret = ERROR_OUTOFMEMORY;
1470 return ret;
1473 DWORD getNumUdpEntries(void)
1475 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1476 return getNumWithOneHeader ("net.inet.udp.pcblist");
1477 #else
1478 return getNumWithOneHeader("/proc/net/udp");
1479 #endif
1482 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1483 DWORD *count, const MIB_UDPROW *row )
1485 if (table->dwNumEntries >= *count)
1487 MIB_UDPTABLE *new_table;
1488 DWORD new_count = table->dwNumEntries * 2;
1490 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1492 HeapFree( heap, 0, table );
1493 return NULL;
1495 *count = new_count;
1496 table = new_table;
1498 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1499 return table;
1502 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1504 MIB_UDPTABLE *table;
1505 MIB_UDPROW row;
1506 DWORD ret = NO_ERROR, count = 16;
1508 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1510 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1511 return ERROR_OUTOFMEMORY;
1513 table->dwNumEntries = 0;
1515 #ifdef __linux__
1517 FILE *fp;
1519 if ((fp = fopen("/proc/net/udp", "r")))
1521 char buf[512], *ptr;
1522 DWORD dummy;
1524 /* skip header line */
1525 ptr = fgets(buf, sizeof(buf), fp);
1526 while ((ptr = fgets(buf, sizeof(buf), fp)))
1528 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1529 continue;
1530 row.dwLocalPort = htons( row.dwLocalPort );
1531 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1532 break;
1534 fclose(fp);
1536 else ret = ERROR_NOT_SUPPORTED;
1538 #else
1539 FIXME( "not implemented\n" );
1540 ret = ERROR_NOT_SUPPORTED;
1541 #endif
1543 if (!table) return ERROR_OUTOFMEMORY;
1544 if (!ret) *ppUdpTable = table;
1545 else HeapFree( heap, flags, table );
1546 return ret;
1550 DWORD getNumTcpEntries(void)
1552 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1553 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1554 #else
1555 return getNumWithOneHeader ("/proc/net/tcp");
1556 #endif
1559 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1560 DWORD *count, const MIB_TCPROW *row )
1562 if (table->dwNumEntries >= *count)
1564 MIB_TCPTABLE *new_table;
1565 DWORD new_count = table->dwNumEntries * 2;
1567 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1569 HeapFree( heap, 0, table );
1570 return NULL;
1572 *count = new_count;
1573 table = new_table;
1575 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1576 return table;
1580 /* Why not a lookup table? Because the TCPS_* constants are different
1581 on different platforms */
1582 static DWORD TCPStateToMIBState (int state)
1584 switch (state)
1586 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1587 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1588 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1589 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1590 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1591 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1592 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1593 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1594 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1595 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1596 default:
1597 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1602 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags)
1604 MIB_TCPTABLE *table;
1605 MIB_TCPROW row;
1606 DWORD ret = NO_ERROR, count = 16;
1608 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1610 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1611 return ERROR_OUTOFMEMORY;
1613 table->dwNumEntries = 0;
1615 #ifdef __linux__
1617 FILE *fp;
1619 if ((fp = fopen("/proc/net/tcp", "r")))
1621 char buf[512], *ptr;
1622 DWORD dummy;
1624 /* skip header line */
1625 ptr = fgets(buf, sizeof(buf), fp);
1626 while ((ptr = fgets(buf, sizeof(buf), fp)))
1628 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1629 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1630 continue;
1631 row.dwLocalPort = htons( row.dwLocalPort );
1632 row.dwRemotePort = htons( row.dwRemotePort );
1633 row.dwState = TCPStateToMIBState( row.dwState );
1634 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1635 break;
1637 fclose( fp );
1639 else ret = ERROR_NOT_SUPPORTED;
1641 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1643 size_t Len = 0;
1644 char *Buf = NULL;
1645 struct xinpgen *pXIG, *pOrigXIG;
1647 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1649 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1650 ret = ERROR_NOT_SUPPORTED;
1651 goto done;
1654 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1655 if (!Buf)
1657 ret = ERROR_OUTOFMEMORY;
1658 goto done;
1661 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1663 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1664 ret = ERROR_NOT_SUPPORTED;
1665 goto done;
1668 /* Might be nothing here; first entry is just a header it seems */
1669 if (Len <= sizeof (struct xinpgen)) goto done;
1671 pOrigXIG = (struct xinpgen *)Buf;
1672 pXIG = pOrigXIG;
1674 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1675 pXIG->xig_len > sizeof (struct xinpgen);
1676 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1678 struct tcpcb *pTCPData = NULL;
1679 struct inpcb *pINData;
1680 struct xsocket *pSockData;
1682 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1683 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1684 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1686 /* Ignore sockets for other protocols */
1687 if (pSockData->xso_protocol != IPPROTO_TCP)
1688 continue;
1690 /* Ignore PCBs that were freed while generating the data */
1691 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1692 continue;
1694 /* we're only interested in IPv4 addresses */
1695 if (!(pINData->inp_vflag & INP_IPV4) ||
1696 (pINData->inp_vflag & INP_IPV6))
1697 continue;
1699 /* If all 0's, skip it */
1700 if (!pINData->inp_laddr.s_addr &&
1701 !pINData->inp_lport &&
1702 !pINData->inp_faddr.s_addr &&
1703 !pINData->inp_fport)
1704 continue;
1706 /* Fill in structure details */
1707 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1708 row.dwLocalPort = pINData->inp_lport;
1709 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1710 row.dwRemotePort = pINData->inp_fport;
1711 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1712 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1715 done:
1716 HeapFree (GetProcessHeap (), 0, Buf);
1718 #else
1719 FIXME( "not implemented\n" );
1720 ret = ERROR_NOT_SUPPORTED;
1721 #endif
1723 if (!table) return ERROR_OUTOFMEMORY;
1724 if (!ret) *ppTcpTable = table;
1725 else HeapFree( heap, flags, table );
1726 return ret;