configure: Fix the netinet header checks for Mac OS and Solaris.
[wine/gsoc_dplay.git] / dlls / iphlpapi / ipstats.c
blob5e40219ccfaf377af3567bea35ad5f250572bf4c
1 /* Copyright (C) 2003,2006 Juan Lang
2 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * This file implements statistics getting using the /proc filesystem exported
19 * by Linux, and maybe other OSes.
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_ALIAS_H
32 #include <alias.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_SYS_SOCKETVAR_H
38 #include <sys/socketvar.h>
39 #endif
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_NET_IF_H
47 #include <net/if.h>
48 #endif
49 #ifdef HAVE_NET_IF_DL_H
50 #include <net/if_dl.h>
51 #endif
52 #ifdef HAVE_NET_IF_TYPES_H
53 #include <net/if_types.h>
54 #endif
55 #ifdef HAVE_NET_ROUTE_H
56 #include <net/route.h>
57 #endif
58 #ifdef HAVE_NET_IF_ARP_H
59 #include <net/if_arp.h>
60 #endif
61 #ifdef HAVE_NETINET_IF_ETHER_H
62 #include <netinet/if_ether.h>
63 #endif
64 #ifdef HAVE_NETINET_IP_H
65 #include <netinet/ip.h>
66 #endif
67 #ifdef HAVE_NETINET_TCP_H
68 #include <netinet/tcp.h>
69 #endif
70 #ifdef HAVE_NETINET_TCP_FSM_H
71 #include <netinet/tcp_fsm.h>
72 #endif
73 #ifdef HAVE_NETINET_IN_PCB_H
74 #include <netinet/in_pcb.h>
75 #endif
76 #ifdef HAVE_NETINET_TCP_VAR_H
77 #include <netinet/tcp_var.h>
78 #endif
79 #ifdef HAVE_NETINET_TCP_TIMER_H
80 #include <netinet/tcp_timer.h>
81 #endif
82 #ifdef HAVE_NETINET_IP_ICMP_H
83 #include <netinet/ip_icmp.h>
84 #endif
85 #ifdef HAVE_NETINET_ICMP_VAR_H
86 #include <netinet/icmp_var.h>
87 #endif
88 #ifdef HAVE_NETINET_IP_VAR_H
89 #include <netinet/ip_var.h>
90 #endif
91 #ifdef HAVE_NETINET_UDP_H
92 #include <netinet/udp.h>
93 #endif
94 #ifdef HAVE_NETINET_UDP_VAR_H
95 #include <netinet/udp_var.h>
96 #endif
98 #ifdef HAVE_SYS_SYSCTL_H
99 #include <sys/sysctl.h>
100 #endif
102 #ifndef ROUNDUP
103 #define ROUNDUP(a) \
104 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
105 #endif
106 #ifndef ADVANCE
107 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
108 #endif
110 #include "windef.h"
111 #include "winbase.h"
112 #include "iprtrmib.h"
113 #include "ifenum.h"
114 #include "ipstats.h"
116 #ifndef HAVE_NETINET_TCP_FSM_H
117 #define TCPS_ESTABLISHED 1
118 #define TCPS_SYN_SENT 2
119 #define TCPS_SYN_RECEIVED 3
120 #define TCPS_FIN_WAIT_1 4
121 #define TCPS_FIN_WAIT_2 5
122 #define TCPS_TIME_WAIT 6
123 #define TCPS_CLOSED 7
124 #define TCPS_CLOSE_WAIT 8
125 #define TCPS_LAST_ACK 9
126 #define TCPS_LISTEN 10
127 #define TCPS_CLOSING 11
128 #endif
130 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
132 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
134 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
135 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
136 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
138 size_t needed;
139 char *buf, *end;
140 struct if_msghdr *ifm;
141 struct if_data ifdata;
142 if (!name || !entry)
143 return ERROR_INVALID_PARAMETER;
145 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
147 ERR ("failed to get size of iflist\n");
148 return ERROR_NOT_SUPPORTED;
150 buf = HeapAlloc (GetProcessHeap (), 0, needed);
151 if (!buf) return ERROR_NOT_SUPPORTED;
152 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
154 ERR ("failed to get iflist\n");
155 HeapFree (GetProcessHeap (), 0, buf);
156 return ERROR_NOT_SUPPORTED;
158 else
159 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
161 ifm = (struct if_msghdr *) buf;
162 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
164 ifdata = ifm->ifm_data;
165 entry->dwMtu = ifdata.ifi_mtu;
166 entry->dwSpeed = ifdata.ifi_baudrate;
167 entry->dwInOctets = ifdata.ifi_ibytes;
168 entry->dwInErrors = ifdata.ifi_ierrors;
169 entry->dwInDiscards = ifdata.ifi_iqdrops;
170 entry->dwInUcastPkts = ifdata.ifi_ipackets;
171 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
172 entry->dwOutOctets = ifdata.ifi_obytes;
173 entry->dwOutUcastPkts = ifdata.ifi_opackets;
174 entry->dwOutErrors = ifdata.ifi_oerrors;
175 HeapFree (GetProcessHeap (), 0, buf);
176 return NO_ERROR;
179 HeapFree (GetProcessHeap (), 0, buf);
180 return ERROR_NOT_SUPPORTED;
181 #else
182 /* get interface stats from /proc/net/dev, no error if can't
183 no inUnknownProtos, outNUcastPkts, outQLen */
184 FILE *fp;
186 if (!name || !entry)
187 return ERROR_INVALID_PARAMETER;
188 fp = fopen("/proc/net/dev", "r");
189 if (fp) {
190 char buf[512] = { 0 }, *ptr;
191 int nameLen = strlen(name), nameFound = 0;
194 ptr = fgets(buf, sizeof(buf), fp);
195 while (ptr && !nameFound) {
196 while (*ptr && isspace(*ptr))
197 ptr++;
198 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
199 nameFound = 1;
200 else
201 ptr = fgets(buf, sizeof(buf), fp);
203 if (nameFound) {
204 char *endPtr;
206 ptr += nameLen + 1;
207 if (ptr && *ptr) {
208 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
209 ptr = endPtr;
211 if (ptr && *ptr) {
212 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
213 ptr = endPtr;
215 if (ptr && *ptr) {
216 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
217 ptr = endPtr;
219 if (ptr && *ptr) {
220 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
221 ptr = endPtr;
223 if (ptr && *ptr) {
224 strtoul(ptr, &endPtr, 10); /* skip */
225 ptr = endPtr;
227 if (ptr && *ptr) {
228 strtoul(ptr, &endPtr, 10); /* skip */
229 ptr = endPtr;
231 if (ptr && *ptr) {
232 strtoul(ptr, &endPtr, 10); /* skip */
233 ptr = endPtr;
235 if (ptr && *ptr) {
236 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
237 ptr = endPtr;
239 if (ptr && *ptr) {
240 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
241 ptr = endPtr;
243 if (ptr && *ptr) {
244 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
245 ptr = endPtr;
247 if (ptr && *ptr) {
248 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
249 ptr = endPtr;
251 if (ptr && *ptr) {
252 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
253 ptr = endPtr;
256 fclose(fp);
258 else
260 ERR ("unimplemented!\n");
261 return ERROR_NOT_SUPPORTED;
264 return NO_ERROR;
265 #endif
268 DWORD getICMPStats(MIB_ICMP *stats)
270 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
271 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
272 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
273 size_t needed;
274 struct icmpstat icmp_stat;
275 int i;
277 if (!stats)
278 return ERROR_INVALID_PARAMETER;
280 needed = sizeof(icmp_stat);
281 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
283 ERR ("failed to get icmpstat\n");
284 return ERROR_NOT_SUPPORTED;
288 /*in stats */
289 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
290 for(i = 0; i <= ICMP_MAXTYPE; i++)
291 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
293 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
295 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
296 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
297 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
298 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
299 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
300 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
301 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
302 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
303 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
304 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
305 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
308 /* out stats */
309 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
310 for(i = 0; i <= ICMP_MAXTYPE; i++)
311 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
313 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
315 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
316 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
317 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
318 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
319 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
320 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
321 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
322 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
323 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
324 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
325 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
327 return NO_ERROR;
328 #else
329 FILE *fp;
331 if (!stats)
332 return ERROR_INVALID_PARAMETER;
334 memset(stats, 0, sizeof(MIB_ICMP));
335 /* get most of these stats from /proc/net/snmp, no error if can't */
336 fp = fopen("/proc/net/snmp", "r");
337 if (fp) {
338 static const char hdr[] = "Icmp:";
339 char buf[512] = { 0 }, *ptr;
341 do {
342 ptr = fgets(buf, sizeof(buf), fp);
343 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
344 if (ptr) {
345 /* last line was a header, get another */
346 ptr = fgets(buf, sizeof(buf), fp);
347 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
348 char *endPtr;
350 ptr += sizeof(hdr);
351 if (ptr && *ptr) {
352 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
353 ptr = endPtr;
355 if (ptr && *ptr) {
356 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
357 ptr = endPtr;
359 if (ptr && *ptr) {
360 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
361 ptr = endPtr;
363 if (ptr && *ptr) {
364 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
365 ptr = endPtr;
367 if (ptr && *ptr) {
368 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
369 ptr = endPtr;
371 if (ptr && *ptr) {
372 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
373 ptr = endPtr;
375 if (ptr && *ptr) {
376 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
377 ptr = endPtr;
379 if (ptr && *ptr) {
380 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
381 ptr = endPtr;
383 if (ptr && *ptr) {
384 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
385 ptr = endPtr;
387 if (ptr && *ptr) {
388 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
389 ptr = endPtr;
391 if (ptr && *ptr) {
392 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
393 ptr = endPtr;
395 if (ptr && *ptr) {
396 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
397 ptr = endPtr;
399 if (ptr && *ptr) {
400 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
401 ptr = endPtr;
403 if (ptr && *ptr) {
404 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
405 ptr = endPtr;
407 if (ptr && *ptr) {
408 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
409 ptr = endPtr;
411 if (ptr && *ptr) {
412 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
413 ptr = endPtr;
415 if (ptr && *ptr) {
416 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
417 ptr = endPtr;
419 if (ptr && *ptr) {
420 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
421 ptr = endPtr;
423 if (ptr && *ptr) {
424 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
425 ptr = endPtr;
427 if (ptr && *ptr) {
428 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
429 ptr = endPtr;
431 if (ptr && *ptr) {
432 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
433 ptr = endPtr;
435 if (ptr && *ptr) {
436 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
437 ptr = endPtr;
439 if (ptr && *ptr) {
440 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
441 ptr = endPtr;
443 if (ptr && *ptr) {
444 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
445 ptr = endPtr;
449 fclose(fp);
451 else
453 ERR ("unimplemented!\n");
454 return ERROR_NOT_SUPPORTED;
457 return NO_ERROR;
458 #endif
461 DWORD getIPStats(PMIB_IPSTATS stats)
463 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
464 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
465 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
466 int ip_ttl, ip_forwarding;
467 struct ipstat ip_stat;
468 size_t needed;
470 if (!stats)
471 return ERROR_INVALID_PARAMETER;
473 needed = sizeof(ip_stat);
474 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
476 ERR ("failed to get ipstat\n");
477 return ERROR_NOT_SUPPORTED;
480 needed = sizeof(ip_ttl);
481 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
483 ERR ("failed to get ip Default TTL\n");
484 return ERROR_NOT_SUPPORTED;
487 needed = sizeof(ip_forwarding);
488 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
490 ERR ("failed to get ip forwarding\n");
491 return ERROR_NOT_SUPPORTED;
494 stats->dwForwarding = ip_forwarding;
495 stats->dwDefaultTTL = ip_ttl;
496 stats->dwInDelivers = ip_stat.ips_delivered;
497 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
498 stats->dwInAddrErrors = ip_stat.ips_cantforward;
499 stats->dwInReceives = ip_stat.ips_total;
500 stats->dwForwDatagrams = ip_stat.ips_forward;
501 stats->dwInUnknownProtos = ip_stat.ips_noproto;
502 stats->dwInDiscards = ip_stat.ips_fragdropped;
503 stats->dwOutDiscards = ip_stat.ips_odropped;
504 stats->dwReasmOks = ip_stat.ips_reassembled;
505 stats->dwFragOks = ip_stat.ips_fragmented;
506 stats->dwFragFails = ip_stat.ips_cantfrag;
507 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
508 stats->dwOutNoRoutes = ip_stat.ips_noroute;
509 stats->dwOutRequests = ip_stat.ips_localout;
510 stats->dwReasmReqds = ip_stat.ips_fragments;
512 return NO_ERROR;
513 #else
514 FILE *fp;
516 if (!stats)
517 return ERROR_INVALID_PARAMETER;
519 memset(stats, 0, sizeof(MIB_IPSTATS));
520 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
521 stats->dwNumRoutes = getNumRoutes();
523 /* get most of these stats from /proc/net/snmp, no error if can't */
524 fp = fopen("/proc/net/snmp", "r");
525 if (fp) {
526 static const char hdr[] = "Ip:";
527 char buf[512] = { 0 }, *ptr;
529 do {
530 ptr = fgets(buf, sizeof(buf), fp);
531 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
532 if (ptr) {
533 /* last line was a header, get another */
534 ptr = fgets(buf, sizeof(buf), fp);
535 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
536 char *endPtr;
538 ptr += sizeof(hdr);
539 if (ptr && *ptr) {
540 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
541 ptr = endPtr;
543 if (ptr && *ptr) {
544 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
545 ptr = endPtr;
547 if (ptr && *ptr) {
548 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
549 ptr = endPtr;
551 if (ptr && *ptr) {
552 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
553 ptr = endPtr;
555 if (ptr && *ptr) {
556 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
557 ptr = endPtr;
559 if (ptr && *ptr) {
560 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
561 ptr = endPtr;
563 if (ptr && *ptr) {
564 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
565 ptr = endPtr;
567 if (ptr && *ptr) {
568 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
569 ptr = endPtr;
571 if (ptr && *ptr) {
572 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
573 ptr = endPtr;
575 if (ptr && *ptr) {
576 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
577 ptr = endPtr;
579 if (ptr && *ptr) {
580 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
581 ptr = endPtr;
583 if (ptr && *ptr) {
584 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
585 ptr = endPtr;
587 if (ptr && *ptr) {
588 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
589 ptr = endPtr;
591 if (ptr && *ptr) {
592 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
593 ptr = endPtr;
595 if (ptr && *ptr) {
596 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
597 ptr = endPtr;
599 if (ptr && *ptr) {
600 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
601 ptr = endPtr;
603 if (ptr && *ptr) {
604 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
605 ptr = endPtr;
607 if (ptr && *ptr) {
608 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
609 ptr = endPtr;
611 if (ptr && *ptr) {
612 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
613 ptr = endPtr;
615 /* hmm, no routingDiscards */
618 fclose(fp);
620 else
622 ERR ("unimplemented!\n");
623 return ERROR_NOT_SUPPORTED;
626 return NO_ERROR;
627 #endif
630 DWORD getTCPStats(MIB_TCPSTATS *stats)
632 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
633 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
634 #define TCPTV_MIN 2
635 #define TCPTV_REXMTMAX 128
636 #endif
637 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
638 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
639 #define hz 1000
640 struct tcpstat tcp_stat;
641 size_t needed;
643 if (!stats)
644 return ERROR_INVALID_PARAMETER;
645 needed = sizeof(tcp_stat);
647 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
649 ERR ("failed to get tcpstat\n");
650 return ERROR_NOT_SUPPORTED;
653 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
654 stats->dwRtoMin = TCPTV_MIN;
655 stats->dwRtoMax = TCPTV_REXMTMAX;
656 stats->dwMaxConn = -1;
657 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
658 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
659 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
660 stats->dwEstabResets = tcp_stat.tcps_drops;
661 stats->dwCurrEstab = 0;
662 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
663 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
664 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
665 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
666 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
667 stats->dwNumConns = tcp_stat.tcps_connects;
669 return NO_ERROR;
671 #else
672 FILE *fp;
674 if (!stats)
675 return ERROR_INVALID_PARAMETER;
677 memset(stats, 0, sizeof(MIB_TCPSTATS));
679 /* get from /proc/net/snmp, no error if can't */
680 fp = fopen("/proc/net/snmp", "r");
681 if (fp) {
682 static const char hdr[] = "Tcp:";
683 char buf[512] = { 0 }, *ptr;
686 do {
687 ptr = fgets(buf, sizeof(buf), fp);
688 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
689 if (ptr) {
690 /* last line was a header, get another */
691 ptr = fgets(buf, sizeof(buf), fp);
692 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
693 char *endPtr;
695 ptr += sizeof(hdr);
696 if (ptr && *ptr) {
697 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
698 ptr = endPtr;
700 if (ptr && *ptr) {
701 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
702 ptr = endPtr;
704 if (ptr && *ptr) {
705 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
706 ptr = endPtr;
708 if (ptr && *ptr) {
709 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
710 ptr = endPtr;
712 if (ptr && *ptr) {
713 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
714 ptr = endPtr;
716 if (ptr && *ptr) {
717 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
718 ptr = endPtr;
720 if (ptr && *ptr) {
721 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
722 ptr = endPtr;
724 if (ptr && *ptr) {
725 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
726 ptr = endPtr;
728 if (ptr && *ptr) {
729 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
730 ptr = endPtr;
732 if (ptr && *ptr) {
733 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
734 ptr = endPtr;
736 if (ptr && *ptr) {
737 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
738 ptr = endPtr;
740 if (ptr && *ptr) {
741 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
742 ptr = endPtr;
744 if (ptr && *ptr) {
745 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
746 ptr = endPtr;
748 if (ptr && *ptr) {
749 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
750 ptr = endPtr;
752 stats->dwNumConns = getNumTcpEntries();
755 fclose(fp);
757 else
759 ERR ("unimplemented!\n");
760 return ERROR_NOT_SUPPORTED;
763 return NO_ERROR;
764 #endif
767 DWORD getUDPStats(MIB_UDPSTATS *stats)
769 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
770 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
771 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
772 struct udpstat udp_stat;
773 size_t needed;
774 if (!stats)
775 return ERROR_INVALID_PARAMETER;
777 needed = sizeof(udp_stat);
779 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
781 ERR ("failed to get udpstat\n");
782 return ERROR_NOT_SUPPORTED;
785 stats->dwInDatagrams = udp_stat.udps_ipackets;
786 stats->dwOutDatagrams = udp_stat.udps_opackets;
787 stats->dwNoPorts = udp_stat.udps_noport;
788 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
789 stats->dwNumAddrs = getNumUdpEntries();
791 return NO_ERROR;
792 #else
793 FILE *fp;
795 if (!stats)
796 return ERROR_INVALID_PARAMETER;
798 memset(stats, 0, sizeof(MIB_UDPSTATS));
800 /* get from /proc/net/snmp, no error if can't */
801 fp = fopen("/proc/net/snmp", "r");
802 if (fp) {
803 static const char hdr[] = "Udp:";
804 char buf[512] = { 0 }, *ptr;
807 do {
808 ptr = fgets(buf, sizeof(buf), fp);
809 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
810 if (ptr) {
811 /* last line was a header, get another */
812 ptr = fgets(buf, sizeof(buf), fp);
813 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
814 char *endPtr;
816 ptr += sizeof(hdr);
817 if (ptr && *ptr) {
818 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
819 ptr = endPtr;
821 if (ptr && *ptr) {
822 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
823 ptr = endPtr;
825 if (ptr && *ptr) {
826 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
827 ptr = endPtr;
829 if (ptr && *ptr) {
830 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
831 ptr = endPtr;
833 if (ptr && *ptr) {
834 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
835 ptr = endPtr;
839 fclose(fp);
841 else
843 ERR ("unimplemented!\n");
844 return ERROR_NOT_SUPPORTED;
847 return NO_ERROR;
848 #endif
851 static DWORD getNumWithOneHeader(const char *filename)
853 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
854 size_t Len = 0;
855 char *Buf;
856 struct xinpgen *pXIG, *pOrigXIG;
857 int Protocol;
858 DWORD NumEntries = 0;
860 if (!strcmp (filename, "net.inet.tcp.pcblist"))
861 Protocol = IPPROTO_TCP;
862 else if (!strcmp (filename, "net.inet.udp.pcblist"))
863 Protocol = IPPROTO_UDP;
864 else
866 ERR ("Unsupported mib '%s', needs protocol mapping\n",
867 filename);
868 return 0;
871 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
873 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
874 return 0;
877 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
878 if (!Buf)
880 ERR ("Out of memory!\n");
881 return 0;
884 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
886 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
887 HeapFree (GetProcessHeap (), 0, Buf);
888 return 0;
891 /* Might be nothing here; first entry is just a header it seems */
892 if (Len <= sizeof (struct xinpgen))
894 HeapFree (GetProcessHeap (), 0, Buf);
895 return 0;
898 pOrigXIG = (struct xinpgen *)Buf;
899 pXIG = pOrigXIG;
901 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
902 pXIG->xig_len > sizeof (struct xinpgen);
903 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
905 struct tcpcb *pTCPData = NULL;
906 struct inpcb *pINData;
907 struct xsocket *pSockData;
909 if (Protocol == IPPROTO_TCP)
911 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
912 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
913 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
915 else
917 pINData = &((struct xinpcb *)pXIG)->xi_inp;
918 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
921 /* Ignore sockets for other protocols */
922 if (pSockData->xso_protocol != Protocol)
923 continue;
925 /* Ignore PCBs that were freed while generating the data */
926 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
927 continue;
929 /* we're only interested in IPv4 addresses */
930 if (!(pINData->inp_vflag & INP_IPV4) ||
931 (pINData->inp_vflag & INP_IPV6))
932 continue;
934 /* If all 0's, skip it */
935 if (!pINData->inp_laddr.s_addr &&
936 !pINData->inp_lport &&
937 !pINData->inp_faddr.s_addr &&
938 !pINData->inp_fport)
939 continue;
941 NumEntries++;
944 HeapFree (GetProcessHeap (), 0, Buf);
945 return NumEntries;
946 #else
947 FILE *fp;
948 int ret = 0;
950 fp = fopen(filename, "r");
951 if (fp) {
952 char buf[512] = { 0 }, *ptr;
955 ptr = fgets(buf, sizeof(buf), fp);
956 if (ptr) {
957 do {
958 ptr = fgets(buf, sizeof(buf), fp);
959 if (ptr)
960 ret++;
961 } while (ptr);
963 fclose(fp);
965 else
966 ERR ("Unable to open '%s' to count entries!\n", filename);
968 return ret;
969 #endif
972 DWORD getNumRoutes(void)
974 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
975 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
976 size_t needed;
977 char *buf, *lim, *next;
978 struct rt_msghdr *rtm;
979 DWORD RouteCount = 0;
981 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
983 ERR ("sysctl 1 failed!\n");
984 return 0;
987 buf = HeapAlloc (GetProcessHeap (), 0, needed);
988 if (!buf) return 0;
990 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
992 ERR ("sysctl 2 failed!\n");
993 HeapFree (GetProcessHeap (), 0, buf);
994 return 0;
997 lim = buf + needed;
998 for (next = buf; next < lim; next += rtm->rtm_msglen)
1000 rtm = (struct rt_msghdr *)next;
1002 if (rtm->rtm_type != RTM_GET)
1004 WARN ("Got unexpected message type 0x%x!\n",
1005 rtm->rtm_type);
1006 continue;
1009 /* Ignore all entries except for gateway routes which aren't
1010 multicast */
1011 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1012 continue;
1014 RouteCount++;
1017 HeapFree (GetProcessHeap (), 0, buf);
1018 return RouteCount;
1019 #else
1020 return getNumWithOneHeader("/proc/net/route");
1021 #endif
1024 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1025 DWORD flags)
1027 DWORD ret;
1029 if (!ppIpForwardTable)
1030 ret = ERROR_INVALID_PARAMETER;
1031 else {
1032 DWORD numRoutes = getNumRoutes();
1033 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1034 PMIB_IPFORWARDTABLE table;
1036 if (numRoutes > 1)
1037 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1038 table = HeapAlloc(heap, flags, size);
1039 if (table) {
1040 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1041 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1042 size_t needed;
1043 char *buf, *lim, *next, *addrPtr;
1044 struct rt_msghdr *rtm;
1046 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1048 ERR ("sysctl 1 failed!\n");
1049 HeapFree (GetProcessHeap (), 0, table);
1050 return NO_ERROR;
1053 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1054 if (!buf)
1056 HeapFree (GetProcessHeap (), 0, table);
1057 return ERROR_OUTOFMEMORY;
1060 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1062 ERR ("sysctl 2 failed!\n");
1063 HeapFree (GetProcessHeap (), 0, table);
1064 HeapFree (GetProcessHeap (), 0, buf);
1065 return NO_ERROR;
1068 *ppIpForwardTable = table;
1069 table->dwNumEntries = 0;
1071 lim = buf + needed;
1072 for (next = buf; next < lim; next += rtm->rtm_msglen)
1074 int i;
1076 rtm = (struct rt_msghdr *)next;
1078 if (rtm->rtm_type != RTM_GET)
1080 WARN ("Got unexpected message type 0x%x!\n",
1081 rtm->rtm_type);
1082 continue;
1085 /* Ignore all entries except for gateway routes which aren't
1086 multicast */
1087 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1088 (rtm->rtm_flags & RTF_MULTICAST))
1089 continue;
1091 memset (&table->table[table->dwNumEntries], 0,
1092 sizeof (MIB_IPFORWARDROW));
1093 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1094 table->table[table->dwNumEntries].dwForwardType =
1095 MIB_IPROUTE_TYPE_INDIRECT;
1096 table->table[table->dwNumEntries].dwForwardMetric1 =
1097 rtm->rtm_rmx.rmx_hopcount;
1098 table->table[table->dwNumEntries].dwForwardProto =
1099 MIB_IPPROTO_LOCAL;
1101 addrPtr = (char *)(rtm + 1);
1103 for (i = 1; i; i <<= 1)
1105 struct sockaddr *sa;
1106 DWORD addr;
1108 if (!(i & rtm->rtm_addrs))
1109 continue;
1111 sa = (struct sockaddr *)addrPtr;
1112 ADVANCE (addrPtr, sa);
1114 /* default routes are encoded by length-zero sockaddr */
1115 if (sa->sa_len == 0)
1116 addr = 0;
1117 else if (sa->sa_family != AF_INET)
1119 WARN ("Received unsupported sockaddr family 0x%x\n",
1120 sa->sa_family);
1121 addr = 0;
1123 else
1125 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1127 addr = sin->sin_addr.s_addr;
1130 switch (i)
1132 case RTA_DST:
1133 table->table[table->dwNumEntries].dwForwardDest = addr;
1134 break;
1136 case RTA_GATEWAY:
1137 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1138 break;
1140 case RTA_NETMASK:
1141 table->table[table->dwNumEntries].dwForwardMask = addr;
1142 break;
1144 default:
1145 WARN ("Unexpected address type 0x%x\n", i);
1149 table->dwNumEntries++;
1152 HeapFree (GetProcessHeap (), 0, buf);
1153 ret = NO_ERROR;
1154 #else
1155 FILE *fp;
1157 ret = NO_ERROR;
1158 *ppIpForwardTable = table;
1159 table->dwNumEntries = 0;
1160 /* get from /proc/net/route, no error if can't */
1161 fp = fopen("/proc/net/route", "r");
1162 if (fp) {
1163 char buf[512] = { 0 }, *ptr;
1165 /* skip header line */
1166 ptr = fgets(buf, sizeof(buf), fp);
1167 while (ptr && table->dwNumEntries < numRoutes) {
1168 memset(&table->table[table->dwNumEntries], 0,
1169 sizeof(MIB_IPFORWARDROW));
1170 ptr = fgets(buf, sizeof(buf), fp);
1171 if (ptr) {
1172 DWORD index;
1174 while (!isspace(*ptr))
1175 ptr++;
1176 *ptr = '\0';
1177 ptr++;
1178 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1179 char *endPtr;
1181 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1182 if (*ptr) {
1183 table->table[table->dwNumEntries].dwForwardDest =
1184 strtoul(ptr, &endPtr, 16);
1185 ptr = endPtr;
1187 if (ptr && *ptr) {
1188 table->table[table->dwNumEntries].dwForwardNextHop =
1189 strtoul(ptr, &endPtr, 16);
1190 ptr = endPtr;
1192 if (ptr && *ptr) {
1193 DWORD flags = strtoul(ptr, &endPtr, 16);
1195 if (!(flags & RTF_UP))
1196 table->table[table->dwNumEntries].dwForwardType =
1197 MIB_IPROUTE_TYPE_INVALID;
1198 else if (flags & RTF_GATEWAY)
1199 table->table[table->dwNumEntries].dwForwardType =
1200 MIB_IPROUTE_TYPE_INDIRECT;
1201 else
1202 table->table[table->dwNumEntries].dwForwardType =
1203 MIB_IPROUTE_TYPE_DIRECT;
1204 ptr = endPtr;
1206 if (ptr && *ptr) {
1207 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1208 ptr = endPtr;
1210 if (ptr && *ptr) {
1211 strtoul(ptr, &endPtr, 16); /* use, skip */
1212 ptr = endPtr;
1214 if (ptr && *ptr) {
1215 table->table[table->dwNumEntries].dwForwardMetric1 =
1216 strtoul(ptr, &endPtr, 16);
1217 ptr = endPtr;
1219 if (ptr && *ptr) {
1220 table->table[table->dwNumEntries].dwForwardMask =
1221 strtoul(ptr, &endPtr, 16);
1222 ptr = endPtr;
1224 /* FIXME: other protos might be appropriate, e.g. the default
1225 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1226 table->table[table->dwNumEntries].dwForwardProto =
1227 MIB_IPPROTO_LOCAL;
1228 table->dwNumEntries++;
1232 fclose(fp);
1234 else
1236 ERR ("unimplemented!\n");
1237 return ERROR_NOT_SUPPORTED;
1239 #endif
1241 else
1242 ret = ERROR_OUTOFMEMORY;
1244 return ret;
1247 DWORD getNumArpEntries(void)
1249 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1250 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1251 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1252 DWORD arpEntries = 0;
1253 size_t needed;
1254 char *buf, *lim, *next;
1255 struct rt_msghdr *rtm;
1256 struct sockaddr_inarp *sinarp;
1257 struct sockaddr_dl *sdl;
1259 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1261 ERR ("failed to get size of arp table\n");
1262 return 0;
1265 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1266 if (!buf) return 0;
1268 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1270 ERR ("failed to get arp table\n");
1271 HeapFree (GetProcessHeap (), 0, buf);
1272 return 0;
1275 lim = buf + needed;
1276 next = buf;
1277 while(next < lim)
1279 rtm = (struct rt_msghdr *)next;
1280 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1281 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1282 if(sdl->sdl_alen) /* arp entry */
1283 arpEntries++;
1284 next += rtm->rtm_msglen;
1286 HeapFree (GetProcessHeap (), 0, buf);
1287 return arpEntries;
1288 #endif
1289 return getNumWithOneHeader("/proc/net/arp");
1292 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1294 DWORD ret = NO_ERROR;
1295 if (!ppIpNetTable)
1296 ret = ERROR_INVALID_PARAMETER;
1297 else {
1298 DWORD numEntries = getNumArpEntries();
1299 DWORD size = sizeof(MIB_IPNETTABLE);
1300 PMIB_IPNETTABLE table;
1302 if (numEntries > 1)
1303 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1304 table = HeapAlloc(heap, flags, size);
1305 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1306 if (table)
1308 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1309 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1310 size_t needed;
1311 char *buf, *lim, *next;
1312 struct rt_msghdr *rtm;
1313 struct sockaddr_inarp *sinarp;
1314 struct sockaddr_dl *sdl;
1316 *ppIpNetTable = table;
1317 table->dwNumEntries = 0;
1319 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1321 ERR ("failed to get size of arp table\n");
1322 return ERROR_NOT_SUPPORTED;
1325 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1326 if (!buf) return ERROR_OUTOFMEMORY;
1328 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1330 ERR ("failed to get arp table\n");
1331 HeapFree (GetProcessHeap (), 0, buf);
1332 return ERROR_NOT_SUPPORTED;
1335 lim = buf + needed;
1336 next = buf;
1337 while(next < lim)
1339 rtm = (struct rt_msghdr *)next;
1340 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1341 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1342 if(sdl->sdl_alen) /* arp entry */
1344 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1345 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1346 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1347 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1348 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1350 table->table[table->dwNumEntries].bPhysAddr[
1351 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1352 byte & 0x0ff;
1353 if(rtm->rtm_rmx.rmx_expire == 0)
1354 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1355 else if(sinarp->sin_other & SIN_PROXY)
1356 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1357 else if(rtm->rtm_rmx.rmx_expire != 0)
1358 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1359 else
1360 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1362 table->dwNumEntries++;
1364 next += rtm->rtm_msglen;
1366 HeapFree (GetProcessHeap (), 0, buf);
1368 else
1369 ret = ERROR_OUTOFMEMORY;
1370 return ret;
1371 #endif
1373 if (table) {
1374 FILE *fp;
1375 *ppIpNetTable = table;
1376 table->dwNumEntries = 0;
1377 /* get from /proc/net/arp, no error if can't */
1378 fp = fopen("/proc/net/arp", "r");
1379 if (fp) {
1380 char buf[512] = { 0 }, *ptr;
1382 /* skip header line */
1383 ptr = fgets(buf, sizeof(buf), fp);
1384 while (ptr && table->dwNumEntries < numEntries) {
1385 ptr = fgets(buf, sizeof(buf), fp);
1386 if (ptr) {
1387 char *endPtr;
1389 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1390 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1391 while (ptr && *ptr && !isspace(*ptr))
1392 ptr++;
1394 if (ptr && *ptr) {
1395 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1396 ptr = endPtr;
1398 if (ptr && *ptr) {
1399 DWORD flags = strtoul(ptr, &endPtr, 16);
1401 #ifdef ATF_COM
1402 if (flags & ATF_COM)
1403 table->table[table->dwNumEntries].dwType =
1404 MIB_IPNET_TYPE_DYNAMIC;
1405 else
1406 #endif
1407 #ifdef ATF_PERM
1408 if (flags & ATF_PERM)
1409 table->table[table->dwNumEntries].dwType =
1410 MIB_IPNET_TYPE_STATIC;
1411 else
1412 #endif
1413 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1415 ptr = endPtr;
1417 while (ptr && *ptr && isspace(*ptr))
1418 ptr++;
1419 while (ptr && *ptr && !isspace(*ptr)) {
1420 DWORD byte = strtoul(ptr, &endPtr, 16);
1422 if (endPtr && *endPtr) {
1423 endPtr++;
1424 table->table[table->dwNumEntries].bPhysAddr[
1425 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1426 byte & 0x0ff;
1428 ptr = endPtr;
1430 if (ptr && *ptr) {
1431 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1432 ptr = endPtr;
1434 getInterfaceIndexByName(ptr,
1435 &table->table[table->dwNumEntries].dwIndex);
1436 table->dwNumEntries++;
1439 fclose(fp);
1441 else
1442 ret = ERROR_NOT_SUPPORTED;
1444 else
1445 ret = ERROR_OUTOFMEMORY;
1447 return ret;
1450 DWORD getNumUdpEntries(void)
1452 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1453 return getNumWithOneHeader ("net.inet.udp.pcblist");
1454 #else
1455 return getNumWithOneHeader("/proc/net/udp");
1456 #endif
1459 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1461 DWORD ret;
1463 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1464 ERR ("unimplemented!\n");
1465 return ERROR_NOT_SUPPORTED;
1466 #endif
1468 if (!ppUdpTable)
1469 ret = ERROR_INVALID_PARAMETER;
1470 else {
1471 DWORD numEntries = getNumUdpEntries();
1472 DWORD size = sizeof(MIB_UDPTABLE);
1473 PMIB_UDPTABLE table;
1475 if (numEntries > 1)
1476 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1477 table = HeapAlloc(heap, flags, size);
1478 if (table) {
1479 FILE *fp;
1481 ret = NO_ERROR;
1482 *ppUdpTable = table;
1483 table->dwNumEntries = 0;
1484 /* get from /proc/net/udp, no error if can't */
1485 fp = fopen("/proc/net/udp", "r");
1486 if (fp) {
1487 char buf[512] = { 0 }, *ptr;
1489 /* skip header line */
1490 ptr = fgets(buf, sizeof(buf), fp);
1491 while (ptr && table->dwNumEntries < numEntries) {
1492 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1493 ptr = fgets(buf, sizeof(buf), fp);
1494 if (ptr) {
1495 char *endPtr;
1497 if (ptr && *ptr) {
1498 strtoul(ptr, &endPtr, 16); /* skip */
1499 ptr = endPtr;
1501 if (ptr && *ptr) {
1502 ptr++;
1503 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1504 &endPtr, 16);
1505 ptr = endPtr;
1507 if (ptr && *ptr) {
1508 ptr++;
1509 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1510 &endPtr, 16);
1511 ptr = endPtr;
1513 table->dwNumEntries++;
1516 fclose(fp);
1518 else
1519 ret = ERROR_NOT_SUPPORTED;
1521 else
1522 ret = ERROR_OUTOFMEMORY;
1524 return ret;
1528 DWORD getNumTcpEntries(void)
1530 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1531 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1532 #else
1533 return getNumWithOneHeader ("/proc/net/tcp");
1534 #endif
1538 /* Why not a lookup table? Because the TCPS_* constants are different
1539 on different platforms */
1540 static DWORD TCPStateToMIBState (int state)
1542 switch (state)
1544 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1545 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1546 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1547 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1548 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1549 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1550 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1551 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1552 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1553 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1554 default:
1555 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1560 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1561 DWORD flags)
1563 DWORD numEntries;
1564 PMIB_TCPTABLE table;
1565 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1566 size_t Len = 0;
1567 char *Buf;
1568 struct xinpgen *pXIG, *pOrigXIG;
1569 #else
1570 FILE *fp;
1571 char buf[512] = { 0 }, *ptr;
1572 #endif
1574 if (!ppTcpTable)
1575 return ERROR_INVALID_PARAMETER;
1577 numEntries = getNumTcpEntries ();
1579 if (!*ppTcpTable)
1581 DWORD size = sizeof(MIB_TCPTABLE);
1583 if (numEntries > 1)
1584 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1585 *ppTcpTable = HeapAlloc (heap, flags, size);
1586 if (!*ppTcpTable)
1588 ERR ("Out of memory!\n");
1589 return ERROR_OUTOFMEMORY;
1591 maxEntries = numEntries;
1594 table = *ppTcpTable;
1595 table->dwNumEntries = 0;
1596 if (!numEntries)
1597 return NO_ERROR;
1599 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1601 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1603 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1604 return ERROR_OUTOFMEMORY;
1607 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1608 if (!Buf)
1610 ERR ("Out of memory!\n");
1611 return ERROR_OUTOFMEMORY;
1614 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1616 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1617 HeapFree (GetProcessHeap (), 0, Buf);
1618 return ERROR_OUTOFMEMORY;
1621 /* Might be nothing here; first entry is just a header it seems */
1622 if (Len <= sizeof (struct xinpgen))
1624 HeapFree (GetProcessHeap (), 0, Buf);
1625 return NO_ERROR;
1628 pOrigXIG = (struct xinpgen *)Buf;
1629 pXIG = pOrigXIG;
1631 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1632 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1633 (table->dwNumEntries < maxEntries);
1634 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1636 struct tcpcb *pTCPData = NULL;
1637 struct inpcb *pINData;
1638 struct xsocket *pSockData;
1640 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1641 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1642 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1644 /* Ignore sockets for other protocols */
1645 if (pSockData->xso_protocol != IPPROTO_TCP)
1646 continue;
1648 /* Ignore PCBs that were freed while generating the data */
1649 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1650 continue;
1652 /* we're only interested in IPv4 addresses */
1653 if (!(pINData->inp_vflag & INP_IPV4) ||
1654 (pINData->inp_vflag & INP_IPV6))
1655 continue;
1657 /* If all 0's, skip it */
1658 if (!pINData->inp_laddr.s_addr &&
1659 !pINData->inp_lport &&
1660 !pINData->inp_faddr.s_addr &&
1661 !pINData->inp_fport)
1662 continue;
1664 /* Fill in structure details */
1665 table->table[table->dwNumEntries].dwLocalAddr =
1666 pINData->inp_laddr.s_addr;
1667 table->table[table->dwNumEntries].dwLocalPort =
1668 pINData->inp_lport;
1669 table->table[table->dwNumEntries].dwRemoteAddr =
1670 pINData->inp_faddr.s_addr;
1671 table->table[table->dwNumEntries].dwRemotePort =
1672 pINData->inp_fport;
1673 table->table[table->dwNumEntries].dwState =
1674 TCPStateToMIBState (pTCPData->t_state);
1676 table->dwNumEntries++;
1679 HeapFree (GetProcessHeap (), 0, Buf);
1680 #else
1681 /* get from /proc/net/tcp, no error if can't */
1682 fp = fopen("/proc/net/tcp", "r");
1683 if (!fp)
1684 return ERROR_NOT_SUPPORTED;
1686 /* skip header line */
1687 ptr = fgets(buf, sizeof(buf), fp);
1688 while (ptr && table->dwNumEntries < maxEntries) {
1689 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1690 ptr = fgets(buf, sizeof(buf), fp);
1691 if (ptr) {
1692 char *endPtr;
1694 while (ptr && *ptr && *ptr != ':')
1695 ptr++;
1696 if (ptr && *ptr)
1697 ptr++;
1698 if (ptr && *ptr) {
1699 table->table[table->dwNumEntries].dwLocalAddr =
1700 strtoul(ptr, &endPtr, 16);
1701 ptr = endPtr;
1703 if (ptr && *ptr) {
1704 ptr++;
1705 table->table[table->dwNumEntries].dwLocalPort =
1706 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1707 ptr = endPtr;
1709 if (ptr && *ptr) {
1710 table->table[table->dwNumEntries].dwRemoteAddr =
1711 strtoul(ptr, &endPtr, 16);
1712 ptr = endPtr;
1714 if (ptr && *ptr) {
1715 ptr++;
1716 table->table[table->dwNumEntries].dwRemotePort =
1717 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1718 ptr = endPtr;
1720 if (ptr && *ptr) {
1721 DWORD state = strtoul(ptr, &endPtr, 16);
1723 table->table[table->dwNumEntries].dwState =
1724 TCPStateToMIBState (state);
1725 ptr = endPtr;
1727 table->dwNumEntries++;
1730 fclose(fp);
1731 #endif
1733 return NO_ERROR;