push c6fcfc519a04d046be60ec60e33d075a2146cc03
[wine/hacks.git] / dlls / iphlpapi / ipstats.c
blob85f91e2a1445c157fcbe66726d4d379cfe3f55a8
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_IN_SYSTM_H
83 #include <netinet/in_systm.h>
84 #endif
85 #ifdef HAVE_NETINET_IP_ICMP_H
86 #include <netinet/ip_icmp.h>
87 #endif
88 #ifdef HAVE_NETINET_ICMP_VAR_H
89 #include <netinet/icmp_var.h>
90 #endif
91 #ifdef HAVE_NETINET_IP_VAR_H
92 #include <netinet/ip_var.h>
93 #endif
94 #ifdef HAVE_NETINET_UDP_H
95 #include <netinet/udp.h>
96 #endif
97 #ifdef HAVE_NETINET_UDP_VAR_H
98 #include <netinet/udp_var.h>
99 #endif
101 #ifdef HAVE_SYS_SYSCTL_H
102 #include <sys/sysctl.h>
103 #endif
105 #ifndef ROUNDUP
106 #define ROUNDUP(a) \
107 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
108 #endif
109 #ifndef ADVANCE
110 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
111 #endif
113 #include "windef.h"
114 #include "winbase.h"
115 #include "iprtrmib.h"
116 #include "ifenum.h"
117 #include "ipstats.h"
119 #ifndef HAVE_NETINET_TCP_FSM_H
120 #define TCPS_ESTABLISHED 1
121 #define TCPS_SYN_SENT 2
122 #define TCPS_SYN_RECEIVED 3
123 #define TCPS_FIN_WAIT_1 4
124 #define TCPS_FIN_WAIT_2 5
125 #define TCPS_TIME_WAIT 6
126 #define TCPS_CLOSED 7
127 #define TCPS_CLOSE_WAIT 8
128 #define TCPS_LAST_ACK 9
129 #define TCPS_LISTEN 10
130 #define TCPS_CLOSING 11
131 #endif
133 #ifndef RTF_MULTICAST
134 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
135 #endif
137 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
139 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
141 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
142 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
143 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
145 size_t needed;
146 char *buf, *end;
147 struct if_msghdr *ifm;
148 struct if_data ifdata;
149 if (!name || !entry)
150 return ERROR_INVALID_PARAMETER;
152 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
154 ERR ("failed to get size of iflist\n");
155 return ERROR_NOT_SUPPORTED;
157 buf = HeapAlloc (GetProcessHeap (), 0, needed);
158 if (!buf) return ERROR_NOT_SUPPORTED;
159 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
161 ERR ("failed to get iflist\n");
162 HeapFree (GetProcessHeap (), 0, buf);
163 return ERROR_NOT_SUPPORTED;
165 else
166 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
168 ifm = (struct if_msghdr *) buf;
169 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
171 ifdata = ifm->ifm_data;
172 entry->dwMtu = ifdata.ifi_mtu;
173 entry->dwSpeed = ifdata.ifi_baudrate;
174 entry->dwInOctets = ifdata.ifi_ibytes;
175 entry->dwInErrors = ifdata.ifi_ierrors;
176 entry->dwInDiscards = ifdata.ifi_iqdrops;
177 entry->dwInUcastPkts = ifdata.ifi_ipackets;
178 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
179 entry->dwOutOctets = ifdata.ifi_obytes;
180 entry->dwOutUcastPkts = ifdata.ifi_opackets;
181 entry->dwOutErrors = ifdata.ifi_oerrors;
182 HeapFree (GetProcessHeap (), 0, buf);
183 return NO_ERROR;
186 HeapFree (GetProcessHeap (), 0, buf);
187 return ERROR_NOT_SUPPORTED;
188 #else
189 /* get interface stats from /proc/net/dev, no error if can't
190 no inUnknownProtos, outNUcastPkts, outQLen */
191 FILE *fp;
193 if (!name || !entry)
194 return ERROR_INVALID_PARAMETER;
195 fp = fopen("/proc/net/dev", "r");
196 if (fp) {
197 char buf[512] = { 0 }, *ptr;
198 int nameLen = strlen(name), nameFound = 0;
201 ptr = fgets(buf, sizeof(buf), fp);
202 while (ptr && !nameFound) {
203 while (*ptr && isspace(*ptr))
204 ptr++;
205 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
206 nameFound = 1;
207 else
208 ptr = fgets(buf, sizeof(buf), fp);
210 if (nameFound) {
211 char *endPtr;
213 ptr += nameLen + 1;
214 if (ptr && *ptr) {
215 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
216 ptr = endPtr;
218 if (ptr && *ptr) {
219 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
220 ptr = endPtr;
222 if (ptr && *ptr) {
223 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
224 ptr = endPtr;
226 if (ptr && *ptr) {
227 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
228 ptr = endPtr;
230 if (ptr && *ptr) {
231 strtoul(ptr, &endPtr, 10); /* skip */
232 ptr = endPtr;
234 if (ptr && *ptr) {
235 strtoul(ptr, &endPtr, 10); /* skip */
236 ptr = endPtr;
238 if (ptr && *ptr) {
239 strtoul(ptr, &endPtr, 10); /* skip */
240 ptr = endPtr;
242 if (ptr && *ptr) {
243 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
244 ptr = endPtr;
246 if (ptr && *ptr) {
247 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
248 ptr = endPtr;
250 if (ptr && *ptr) {
251 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
252 ptr = endPtr;
254 if (ptr && *ptr) {
255 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
256 ptr = endPtr;
258 if (ptr && *ptr) {
259 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
260 ptr = endPtr;
263 fclose(fp);
265 else
267 ERR ("unimplemented!\n");
268 return ERROR_NOT_SUPPORTED;
271 return NO_ERROR;
272 #endif
275 DWORD getICMPStats(MIB_ICMP *stats)
277 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
278 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
279 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
280 size_t needed;
281 struct icmpstat icmp_stat;
282 int i;
284 if (!stats)
285 return ERROR_INVALID_PARAMETER;
287 needed = sizeof(icmp_stat);
288 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
290 ERR ("failed to get icmpstat\n");
291 return ERROR_NOT_SUPPORTED;
295 /*in stats */
296 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
297 for(i = 0; i <= ICMP_MAXTYPE; i++)
298 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
300 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
302 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
303 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
304 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
305 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
306 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
307 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
308 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
309 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
310 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
311 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
312 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
315 /* out stats */
316 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
317 for(i = 0; i <= ICMP_MAXTYPE; i++)
318 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
320 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
322 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
323 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
324 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
325 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
326 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
327 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
328 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
329 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
330 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
331 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
332 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
334 return NO_ERROR;
335 #else
336 FILE *fp;
338 if (!stats)
339 return ERROR_INVALID_PARAMETER;
341 memset(stats, 0, sizeof(MIB_ICMP));
342 /* get most of these stats from /proc/net/snmp, no error if can't */
343 fp = fopen("/proc/net/snmp", "r");
344 if (fp) {
345 static const char hdr[] = "Icmp:";
346 char buf[512] = { 0 }, *ptr;
348 do {
349 ptr = fgets(buf, sizeof(buf), fp);
350 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
351 if (ptr) {
352 /* last line was a header, get another */
353 ptr = fgets(buf, sizeof(buf), fp);
354 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
355 char *endPtr;
357 ptr += sizeof(hdr);
358 if (ptr && *ptr) {
359 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
360 ptr = endPtr;
362 if (ptr && *ptr) {
363 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
364 ptr = endPtr;
366 if (ptr && *ptr) {
367 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
368 ptr = endPtr;
370 if (ptr && *ptr) {
371 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
372 ptr = endPtr;
374 if (ptr && *ptr) {
375 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
376 ptr = endPtr;
378 if (ptr && *ptr) {
379 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
380 ptr = endPtr;
382 if (ptr && *ptr) {
383 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
384 ptr = endPtr;
386 if (ptr && *ptr) {
387 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
388 ptr = endPtr;
390 if (ptr && *ptr) {
391 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
392 ptr = endPtr;
394 if (ptr && *ptr) {
395 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
396 ptr = endPtr;
398 if (ptr && *ptr) {
399 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
400 ptr = endPtr;
402 if (ptr && *ptr) {
403 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
404 ptr = endPtr;
406 if (ptr && *ptr) {
407 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
408 ptr = endPtr;
410 if (ptr && *ptr) {
411 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
412 ptr = endPtr;
414 if (ptr && *ptr) {
415 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
416 ptr = endPtr;
418 if (ptr && *ptr) {
419 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
420 ptr = endPtr;
422 if (ptr && *ptr) {
423 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
424 ptr = endPtr;
426 if (ptr && *ptr) {
427 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
428 ptr = endPtr;
430 if (ptr && *ptr) {
431 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
432 ptr = endPtr;
434 if (ptr && *ptr) {
435 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
436 ptr = endPtr;
438 if (ptr && *ptr) {
439 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
440 ptr = endPtr;
442 if (ptr && *ptr) {
443 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
444 ptr = endPtr;
446 if (ptr && *ptr) {
447 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
448 ptr = endPtr;
450 if (ptr && *ptr) {
451 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
452 ptr = endPtr;
456 fclose(fp);
458 else
460 ERR ("unimplemented!\n");
461 return ERROR_NOT_SUPPORTED;
464 return NO_ERROR;
465 #endif
468 DWORD getIPStats(PMIB_IPSTATS stats)
470 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
471 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
472 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
473 int ip_ttl, ip_forwarding;
474 struct ipstat ip_stat;
475 size_t needed;
477 if (!stats)
478 return ERROR_INVALID_PARAMETER;
480 needed = sizeof(ip_stat);
481 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
483 ERR ("failed to get ipstat\n");
484 return ERROR_NOT_SUPPORTED;
487 needed = sizeof(ip_ttl);
488 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
490 ERR ("failed to get ip Default TTL\n");
491 return ERROR_NOT_SUPPORTED;
494 needed = sizeof(ip_forwarding);
495 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
497 ERR ("failed to get ip forwarding\n");
498 return ERROR_NOT_SUPPORTED;
501 stats->dwForwarding = ip_forwarding;
502 stats->dwDefaultTTL = ip_ttl;
503 stats->dwInDelivers = ip_stat.ips_delivered;
504 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
505 stats->dwInAddrErrors = ip_stat.ips_cantforward;
506 stats->dwInReceives = ip_stat.ips_total;
507 stats->dwForwDatagrams = ip_stat.ips_forward;
508 stats->dwInUnknownProtos = ip_stat.ips_noproto;
509 stats->dwInDiscards = ip_stat.ips_fragdropped;
510 stats->dwOutDiscards = ip_stat.ips_odropped;
511 stats->dwReasmOks = ip_stat.ips_reassembled;
512 stats->dwFragOks = ip_stat.ips_fragmented;
513 stats->dwFragFails = ip_stat.ips_cantfrag;
514 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
515 stats->dwOutNoRoutes = ip_stat.ips_noroute;
516 stats->dwOutRequests = ip_stat.ips_localout;
517 stats->dwReasmReqds = ip_stat.ips_fragments;
519 return NO_ERROR;
520 #else
521 FILE *fp;
523 if (!stats)
524 return ERROR_INVALID_PARAMETER;
526 memset(stats, 0, sizeof(MIB_IPSTATS));
527 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
528 stats->dwNumRoutes = getNumRoutes();
530 /* get most of these stats from /proc/net/snmp, no error if can't */
531 fp = fopen("/proc/net/snmp", "r");
532 if (fp) {
533 static const char hdr[] = "Ip:";
534 char buf[512] = { 0 }, *ptr;
536 do {
537 ptr = fgets(buf, sizeof(buf), fp);
538 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
539 if (ptr) {
540 /* last line was a header, get another */
541 ptr = fgets(buf, sizeof(buf), fp);
542 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
543 char *endPtr;
545 ptr += sizeof(hdr);
546 if (ptr && *ptr) {
547 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
548 ptr = endPtr;
550 if (ptr && *ptr) {
551 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
552 ptr = endPtr;
554 if (ptr && *ptr) {
555 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
556 ptr = endPtr;
558 if (ptr && *ptr) {
559 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
560 ptr = endPtr;
562 if (ptr && *ptr) {
563 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
564 ptr = endPtr;
566 if (ptr && *ptr) {
567 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
568 ptr = endPtr;
570 if (ptr && *ptr) {
571 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
572 ptr = endPtr;
574 if (ptr && *ptr) {
575 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
576 ptr = endPtr;
578 if (ptr && *ptr) {
579 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
580 ptr = endPtr;
582 if (ptr && *ptr) {
583 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
584 ptr = endPtr;
586 if (ptr && *ptr) {
587 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
588 ptr = endPtr;
590 if (ptr && *ptr) {
591 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
592 ptr = endPtr;
594 if (ptr && *ptr) {
595 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
596 ptr = endPtr;
598 if (ptr && *ptr) {
599 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
600 ptr = endPtr;
602 if (ptr && *ptr) {
603 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
604 ptr = endPtr;
606 if (ptr && *ptr) {
607 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
608 ptr = endPtr;
610 if (ptr && *ptr) {
611 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
612 ptr = endPtr;
614 if (ptr && *ptr) {
615 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
616 ptr = endPtr;
618 if (ptr && *ptr) {
619 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
620 ptr = endPtr;
622 /* hmm, no routingDiscards */
625 fclose(fp);
627 else
629 ERR ("unimplemented!\n");
630 return ERROR_NOT_SUPPORTED;
633 return NO_ERROR;
634 #endif
637 DWORD getTCPStats(MIB_TCPSTATS *stats)
639 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
640 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
641 #define TCPTV_MIN 2
642 #define TCPTV_REXMTMAX 128
643 #endif
644 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
645 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
646 #define hz 1000
647 struct tcpstat tcp_stat;
648 size_t needed;
650 if (!stats)
651 return ERROR_INVALID_PARAMETER;
652 needed = sizeof(tcp_stat);
654 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
656 ERR ("failed to get tcpstat\n");
657 return ERROR_NOT_SUPPORTED;
660 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
661 stats->dwRtoMin = TCPTV_MIN;
662 stats->dwRtoMax = TCPTV_REXMTMAX;
663 stats->dwMaxConn = -1;
664 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
665 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
666 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
667 stats->dwEstabResets = tcp_stat.tcps_drops;
668 stats->dwCurrEstab = 0;
669 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
670 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
671 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
672 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
673 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
674 stats->dwNumConns = tcp_stat.tcps_connects;
676 return NO_ERROR;
678 #else
679 FILE *fp;
681 if (!stats)
682 return ERROR_INVALID_PARAMETER;
684 memset(stats, 0, sizeof(MIB_TCPSTATS));
686 /* get from /proc/net/snmp, no error if can't */
687 fp = fopen("/proc/net/snmp", "r");
688 if (fp) {
689 static const char hdr[] = "Tcp:";
690 char buf[512] = { 0 }, *ptr;
693 do {
694 ptr = fgets(buf, sizeof(buf), fp);
695 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
696 if (ptr) {
697 /* last line was a header, get another */
698 ptr = fgets(buf, sizeof(buf), fp);
699 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
700 char *endPtr;
702 ptr += sizeof(hdr);
703 if (ptr && *ptr) {
704 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
705 ptr = endPtr;
707 if (ptr && *ptr) {
708 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
709 ptr = endPtr;
711 if (ptr && *ptr) {
712 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
713 ptr = endPtr;
715 if (ptr && *ptr) {
716 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
717 ptr = endPtr;
719 if (ptr && *ptr) {
720 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
721 ptr = endPtr;
723 if (ptr && *ptr) {
724 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
725 ptr = endPtr;
727 if (ptr && *ptr) {
728 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
729 ptr = endPtr;
731 if (ptr && *ptr) {
732 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
733 ptr = endPtr;
735 if (ptr && *ptr) {
736 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
737 ptr = endPtr;
739 if (ptr && *ptr) {
740 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
741 ptr = endPtr;
743 if (ptr && *ptr) {
744 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
745 ptr = endPtr;
747 if (ptr && *ptr) {
748 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
749 ptr = endPtr;
751 if (ptr && *ptr) {
752 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
753 ptr = endPtr;
755 if (ptr && *ptr) {
756 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
757 ptr = endPtr;
759 stats->dwNumConns = getNumTcpEntries();
762 fclose(fp);
764 else
766 ERR ("unimplemented!\n");
767 return ERROR_NOT_SUPPORTED;
770 return NO_ERROR;
771 #endif
774 DWORD getUDPStats(MIB_UDPSTATS *stats)
776 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
777 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
778 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
779 struct udpstat udp_stat;
780 size_t needed;
781 if (!stats)
782 return ERROR_INVALID_PARAMETER;
784 needed = sizeof(udp_stat);
786 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
788 ERR ("failed to get udpstat\n");
789 return ERROR_NOT_SUPPORTED;
792 stats->dwInDatagrams = udp_stat.udps_ipackets;
793 stats->dwOutDatagrams = udp_stat.udps_opackets;
794 stats->dwNoPorts = udp_stat.udps_noport;
795 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
796 stats->dwNumAddrs = getNumUdpEntries();
798 return NO_ERROR;
799 #else
800 FILE *fp;
802 if (!stats)
803 return ERROR_INVALID_PARAMETER;
805 memset(stats, 0, sizeof(MIB_UDPSTATS));
807 /* get from /proc/net/snmp, no error if can't */
808 fp = fopen("/proc/net/snmp", "r");
809 if (fp) {
810 static const char hdr[] = "Udp:";
811 char buf[512] = { 0 }, *ptr;
814 do {
815 ptr = fgets(buf, sizeof(buf), fp);
816 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
817 if (ptr) {
818 /* last line was a header, get another */
819 ptr = fgets(buf, sizeof(buf), fp);
820 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
821 char *endPtr;
823 ptr += sizeof(hdr);
824 if (ptr && *ptr) {
825 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
826 ptr = endPtr;
828 if (ptr && *ptr) {
829 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
830 ptr = endPtr;
832 if (ptr && *ptr) {
833 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
834 ptr = endPtr;
836 if (ptr && *ptr) {
837 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
838 ptr = endPtr;
840 if (ptr && *ptr) {
841 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
842 ptr = endPtr;
846 fclose(fp);
848 else
850 ERR ("unimplemented!\n");
851 return ERROR_NOT_SUPPORTED;
854 return NO_ERROR;
855 #endif
858 static DWORD getNumWithOneHeader(const char *filename)
860 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
861 size_t Len = 0;
862 char *Buf;
863 struct xinpgen *pXIG, *pOrigXIG;
864 int Protocol;
865 DWORD NumEntries = 0;
867 if (!strcmp (filename, "net.inet.tcp.pcblist"))
868 Protocol = IPPROTO_TCP;
869 else if (!strcmp (filename, "net.inet.udp.pcblist"))
870 Protocol = IPPROTO_UDP;
871 else
873 ERR ("Unsupported mib '%s', needs protocol mapping\n",
874 filename);
875 return 0;
878 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
880 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
881 return 0;
884 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
885 if (!Buf)
887 ERR ("Out of memory!\n");
888 return 0;
891 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
893 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
894 HeapFree (GetProcessHeap (), 0, Buf);
895 return 0;
898 /* Might be nothing here; first entry is just a header it seems */
899 if (Len <= sizeof (struct xinpgen))
901 HeapFree (GetProcessHeap (), 0, Buf);
902 return 0;
905 pOrigXIG = (struct xinpgen *)Buf;
906 pXIG = pOrigXIG;
908 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
909 pXIG->xig_len > sizeof (struct xinpgen);
910 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
912 struct tcpcb *pTCPData = NULL;
913 struct inpcb *pINData;
914 struct xsocket *pSockData;
916 if (Protocol == IPPROTO_TCP)
918 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
919 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
920 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
922 else
924 pINData = &((struct xinpcb *)pXIG)->xi_inp;
925 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
928 /* Ignore sockets for other protocols */
929 if (pSockData->xso_protocol != Protocol)
930 continue;
932 /* Ignore PCBs that were freed while generating the data */
933 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
934 continue;
936 /* we're only interested in IPv4 addresses */
937 if (!(pINData->inp_vflag & INP_IPV4) ||
938 (pINData->inp_vflag & INP_IPV6))
939 continue;
941 /* If all 0's, skip it */
942 if (!pINData->inp_laddr.s_addr &&
943 !pINData->inp_lport &&
944 !pINData->inp_faddr.s_addr &&
945 !pINData->inp_fport)
946 continue;
948 NumEntries++;
951 HeapFree (GetProcessHeap (), 0, Buf);
952 return NumEntries;
953 #else
954 FILE *fp;
955 int ret = 0;
957 fp = fopen(filename, "r");
958 if (fp) {
959 char buf[512] = { 0 }, *ptr;
962 ptr = fgets(buf, sizeof(buf), fp);
963 if (ptr) {
964 do {
965 ptr = fgets(buf, sizeof(buf), fp);
966 if (ptr)
967 ret++;
968 } while (ptr);
970 fclose(fp);
972 else
973 ERR ("Unable to open '%s' to count entries!\n", filename);
975 return ret;
976 #endif
979 DWORD getNumRoutes(void)
981 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
982 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
983 size_t needed;
984 char *buf, *lim, *next;
985 struct rt_msghdr *rtm;
986 DWORD RouteCount = 0;
988 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
990 ERR ("sysctl 1 failed!\n");
991 return 0;
994 buf = HeapAlloc (GetProcessHeap (), 0, needed);
995 if (!buf) return 0;
997 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
999 ERR ("sysctl 2 failed!\n");
1000 HeapFree (GetProcessHeap (), 0, buf);
1001 return 0;
1004 lim = buf + needed;
1005 for (next = buf; next < lim; next += rtm->rtm_msglen)
1007 rtm = (struct rt_msghdr *)next;
1009 if (rtm->rtm_type != RTM_GET)
1011 WARN ("Got unexpected message type 0x%x!\n",
1012 rtm->rtm_type);
1013 continue;
1016 /* Ignore all entries except for gateway routes which aren't
1017 multicast */
1018 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1019 continue;
1021 RouteCount++;
1024 HeapFree (GetProcessHeap (), 0, buf);
1025 return RouteCount;
1026 #else
1027 return getNumWithOneHeader("/proc/net/route");
1028 #endif
1031 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1032 DWORD flags)
1034 DWORD ret;
1036 if (!ppIpForwardTable)
1037 ret = ERROR_INVALID_PARAMETER;
1038 else {
1039 DWORD numRoutes = getNumRoutes();
1040 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1041 PMIB_IPFORWARDTABLE table;
1043 if (numRoutes > 1)
1044 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1045 table = HeapAlloc(heap, flags, size);
1046 if (table) {
1047 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1048 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1049 size_t needed;
1050 char *buf, *lim, *next, *addrPtr;
1051 struct rt_msghdr *rtm;
1053 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1055 ERR ("sysctl 1 failed!\n");
1056 HeapFree (GetProcessHeap (), 0, table);
1057 return NO_ERROR;
1060 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1061 if (!buf)
1063 HeapFree (GetProcessHeap (), 0, table);
1064 return ERROR_OUTOFMEMORY;
1067 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1069 ERR ("sysctl 2 failed!\n");
1070 HeapFree (GetProcessHeap (), 0, table);
1071 HeapFree (GetProcessHeap (), 0, buf);
1072 return NO_ERROR;
1075 *ppIpForwardTable = table;
1076 table->dwNumEntries = 0;
1078 lim = buf + needed;
1079 for (next = buf; next < lim; next += rtm->rtm_msglen)
1081 int i;
1083 rtm = (struct rt_msghdr *)next;
1085 if (rtm->rtm_type != RTM_GET)
1087 WARN ("Got unexpected message type 0x%x!\n",
1088 rtm->rtm_type);
1089 continue;
1092 /* Ignore all entries except for gateway routes which aren't
1093 multicast */
1094 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1095 (rtm->rtm_flags & RTF_MULTICAST))
1096 continue;
1098 memset (&table->table[table->dwNumEntries], 0,
1099 sizeof (MIB_IPFORWARDROW));
1100 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1101 table->table[table->dwNumEntries].dwForwardType =
1102 MIB_IPROUTE_TYPE_INDIRECT;
1103 table->table[table->dwNumEntries].dwForwardMetric1 =
1104 rtm->rtm_rmx.rmx_hopcount;
1105 table->table[table->dwNumEntries].dwForwardProto =
1106 MIB_IPPROTO_LOCAL;
1108 addrPtr = (char *)(rtm + 1);
1110 for (i = 1; i; i <<= 1)
1112 struct sockaddr *sa;
1113 DWORD addr;
1115 if (!(i & rtm->rtm_addrs))
1116 continue;
1118 sa = (struct sockaddr *)addrPtr;
1119 ADVANCE (addrPtr, sa);
1121 /* default routes are encoded by length-zero sockaddr */
1122 if (sa->sa_len == 0)
1123 addr = 0;
1124 else if (sa->sa_family != AF_INET)
1126 WARN ("Received unsupported sockaddr family 0x%x\n",
1127 sa->sa_family);
1128 addr = 0;
1130 else
1132 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1134 addr = sin->sin_addr.s_addr;
1137 switch (i)
1139 case RTA_DST:
1140 table->table[table->dwNumEntries].dwForwardDest = addr;
1141 break;
1143 case RTA_GATEWAY:
1144 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1145 break;
1147 case RTA_NETMASK:
1148 table->table[table->dwNumEntries].dwForwardMask = addr;
1149 break;
1151 default:
1152 WARN ("Unexpected address type 0x%x\n", i);
1156 table->dwNumEntries++;
1159 HeapFree (GetProcessHeap (), 0, buf);
1160 ret = NO_ERROR;
1161 #else
1162 FILE *fp;
1164 ret = NO_ERROR;
1165 *ppIpForwardTable = table;
1166 table->dwNumEntries = 0;
1167 /* get from /proc/net/route, no error if can't */
1168 fp = fopen("/proc/net/route", "r");
1169 if (fp) {
1170 char buf[512] = { 0 }, *ptr;
1172 /* skip header line */
1173 ptr = fgets(buf, sizeof(buf), fp);
1174 while (ptr && table->dwNumEntries < numRoutes) {
1175 memset(&table->table[table->dwNumEntries], 0,
1176 sizeof(MIB_IPFORWARDROW));
1177 ptr = fgets(buf, sizeof(buf), fp);
1178 if (ptr) {
1179 DWORD index;
1181 while (!isspace(*ptr))
1182 ptr++;
1183 *ptr = '\0';
1184 ptr++;
1185 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1186 char *endPtr;
1188 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1189 if (*ptr) {
1190 table->table[table->dwNumEntries].dwForwardDest =
1191 strtoul(ptr, &endPtr, 16);
1192 ptr = endPtr;
1194 if (ptr && *ptr) {
1195 table->table[table->dwNumEntries].dwForwardNextHop =
1196 strtoul(ptr, &endPtr, 16);
1197 ptr = endPtr;
1199 if (ptr && *ptr) {
1200 DWORD flags = strtoul(ptr, &endPtr, 16);
1202 if (!(flags & RTF_UP))
1203 table->table[table->dwNumEntries].dwForwardType =
1204 MIB_IPROUTE_TYPE_INVALID;
1205 else if (flags & RTF_GATEWAY)
1206 table->table[table->dwNumEntries].dwForwardType =
1207 MIB_IPROUTE_TYPE_INDIRECT;
1208 else
1209 table->table[table->dwNumEntries].dwForwardType =
1210 MIB_IPROUTE_TYPE_DIRECT;
1211 ptr = endPtr;
1213 if (ptr && *ptr) {
1214 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1215 ptr = endPtr;
1217 if (ptr && *ptr) {
1218 strtoul(ptr, &endPtr, 16); /* use, skip */
1219 ptr = endPtr;
1221 if (ptr && *ptr) {
1222 table->table[table->dwNumEntries].dwForwardMetric1 =
1223 strtoul(ptr, &endPtr, 16);
1224 ptr = endPtr;
1226 if (ptr && *ptr) {
1227 table->table[table->dwNumEntries].dwForwardMask =
1228 strtoul(ptr, &endPtr, 16);
1229 ptr = endPtr;
1231 /* FIXME: other protos might be appropriate, e.g. the default
1232 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1233 table->table[table->dwNumEntries].dwForwardProto =
1234 MIB_IPPROTO_LOCAL;
1235 table->dwNumEntries++;
1239 fclose(fp);
1241 else
1243 ERR ("unimplemented!\n");
1244 return ERROR_NOT_SUPPORTED;
1246 #endif
1248 else
1249 ret = ERROR_OUTOFMEMORY;
1251 return ret;
1254 DWORD getNumArpEntries(void)
1256 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1257 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1258 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1259 DWORD arpEntries = 0;
1260 size_t needed;
1261 char *buf, *lim, *next;
1262 struct rt_msghdr *rtm;
1263 struct sockaddr_inarp *sinarp;
1264 struct sockaddr_dl *sdl;
1266 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1268 ERR ("failed to get size of arp table\n");
1269 return 0;
1272 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1273 if (!buf) return 0;
1275 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1277 ERR ("failed to get arp table\n");
1278 HeapFree (GetProcessHeap (), 0, buf);
1279 return 0;
1282 lim = buf + needed;
1283 next = buf;
1284 while(next < lim)
1286 rtm = (struct rt_msghdr *)next;
1287 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1288 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1289 if(sdl->sdl_alen) /* arp entry */
1290 arpEntries++;
1291 next += rtm->rtm_msglen;
1293 HeapFree (GetProcessHeap (), 0, buf);
1294 return arpEntries;
1295 #endif
1296 return getNumWithOneHeader("/proc/net/arp");
1299 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1301 DWORD ret = NO_ERROR;
1302 if (!ppIpNetTable)
1303 ret = ERROR_INVALID_PARAMETER;
1304 else {
1305 DWORD numEntries = getNumArpEntries();
1306 DWORD size = sizeof(MIB_IPNETTABLE);
1307 PMIB_IPNETTABLE table;
1309 if (numEntries > 1)
1310 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1311 table = HeapAlloc(heap, flags, size);
1312 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1313 if (table)
1315 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1316 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1317 size_t needed;
1318 char *buf, *lim, *next;
1319 struct rt_msghdr *rtm;
1320 struct sockaddr_inarp *sinarp;
1321 struct sockaddr_dl *sdl;
1323 *ppIpNetTable = table;
1324 table->dwNumEntries = 0;
1326 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1328 ERR ("failed to get size of arp table\n");
1329 return ERROR_NOT_SUPPORTED;
1332 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1333 if (!buf) return ERROR_OUTOFMEMORY;
1335 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1337 ERR ("failed to get arp table\n");
1338 HeapFree (GetProcessHeap (), 0, buf);
1339 return ERROR_NOT_SUPPORTED;
1342 lim = buf + needed;
1343 next = buf;
1344 while(next < lim)
1346 rtm = (struct rt_msghdr *)next;
1347 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1348 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1349 if(sdl->sdl_alen) /* arp entry */
1351 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1352 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1353 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1354 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1355 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1357 table->table[table->dwNumEntries].bPhysAddr[
1358 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1359 byte & 0x0ff;
1360 if(rtm->rtm_rmx.rmx_expire == 0)
1361 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1362 else if(sinarp->sin_other & SIN_PROXY)
1363 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1364 else if(rtm->rtm_rmx.rmx_expire != 0)
1365 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1366 else
1367 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1369 table->dwNumEntries++;
1371 next += rtm->rtm_msglen;
1373 HeapFree (GetProcessHeap (), 0, buf);
1375 else
1376 ret = ERROR_OUTOFMEMORY;
1377 return ret;
1378 #endif
1380 if (table) {
1381 FILE *fp;
1382 *ppIpNetTable = table;
1383 table->dwNumEntries = 0;
1384 /* get from /proc/net/arp, no error if can't */
1385 fp = fopen("/proc/net/arp", "r");
1386 if (fp) {
1387 char buf[512] = { 0 }, *ptr;
1389 /* skip header line */
1390 ptr = fgets(buf, sizeof(buf), fp);
1391 while (ptr && table->dwNumEntries < numEntries) {
1392 ptr = fgets(buf, sizeof(buf), fp);
1393 if (ptr) {
1394 char *endPtr;
1396 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1397 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1398 while (ptr && *ptr && !isspace(*ptr))
1399 ptr++;
1401 if (ptr && *ptr) {
1402 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1403 ptr = endPtr;
1405 if (ptr && *ptr) {
1406 DWORD flags = strtoul(ptr, &endPtr, 16);
1408 #ifdef ATF_COM
1409 if (flags & ATF_COM)
1410 table->table[table->dwNumEntries].dwType =
1411 MIB_IPNET_TYPE_DYNAMIC;
1412 else
1413 #endif
1414 #ifdef ATF_PERM
1415 if (flags & ATF_PERM)
1416 table->table[table->dwNumEntries].dwType =
1417 MIB_IPNET_TYPE_STATIC;
1418 else
1419 #endif
1420 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1422 ptr = endPtr;
1424 while (ptr && *ptr && isspace(*ptr))
1425 ptr++;
1426 while (ptr && *ptr && !isspace(*ptr)) {
1427 DWORD byte = strtoul(ptr, &endPtr, 16);
1429 if (endPtr && *endPtr) {
1430 endPtr++;
1431 table->table[table->dwNumEntries].bPhysAddr[
1432 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1433 byte & 0x0ff;
1435 ptr = endPtr;
1437 if (ptr && *ptr) {
1438 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1439 ptr = endPtr;
1441 getInterfaceIndexByName(ptr,
1442 &table->table[table->dwNumEntries].dwIndex);
1443 table->dwNumEntries++;
1446 fclose(fp);
1448 else
1449 ret = ERROR_NOT_SUPPORTED;
1451 else
1452 ret = ERROR_OUTOFMEMORY;
1454 return ret;
1457 DWORD getNumUdpEntries(void)
1459 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1460 return getNumWithOneHeader ("net.inet.udp.pcblist");
1461 #else
1462 return getNumWithOneHeader("/proc/net/udp");
1463 #endif
1466 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1468 DWORD ret;
1470 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1471 ERR ("unimplemented!\n");
1472 return ERROR_NOT_SUPPORTED;
1473 #endif
1475 if (!ppUdpTable)
1476 ret = ERROR_INVALID_PARAMETER;
1477 else {
1478 DWORD numEntries = getNumUdpEntries();
1479 DWORD size = sizeof(MIB_UDPTABLE);
1480 PMIB_UDPTABLE table;
1482 if (numEntries > 1)
1483 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1484 table = HeapAlloc(heap, flags, size);
1485 if (table) {
1486 FILE *fp;
1488 ret = NO_ERROR;
1489 *ppUdpTable = table;
1490 table->dwNumEntries = 0;
1491 /* get from /proc/net/udp, no error if can't */
1492 fp = fopen("/proc/net/udp", "r");
1493 if (fp) {
1494 char buf[512] = { 0 }, *ptr;
1496 /* skip header line */
1497 ptr = fgets(buf, sizeof(buf), fp);
1498 while (ptr && table->dwNumEntries < numEntries) {
1499 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1500 ptr = fgets(buf, sizeof(buf), fp);
1501 if (ptr) {
1502 char *endPtr;
1504 if (ptr && *ptr) {
1505 strtoul(ptr, &endPtr, 16); /* skip */
1506 ptr = endPtr;
1508 if (ptr && *ptr) {
1509 ptr++;
1510 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1511 &endPtr, 16);
1512 ptr = endPtr;
1514 if (ptr && *ptr) {
1515 ptr++;
1516 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1517 &endPtr, 16);
1518 ptr = endPtr;
1520 table->dwNumEntries++;
1523 fclose(fp);
1525 else
1526 ret = ERROR_NOT_SUPPORTED;
1528 else
1529 ret = ERROR_OUTOFMEMORY;
1531 return ret;
1535 DWORD getNumTcpEntries(void)
1537 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1538 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1539 #else
1540 return getNumWithOneHeader ("/proc/net/tcp");
1541 #endif
1545 /* Why not a lookup table? Because the TCPS_* constants are different
1546 on different platforms */
1547 static DWORD TCPStateToMIBState (int state)
1549 switch (state)
1551 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1552 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1553 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1554 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1555 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1556 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1557 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1558 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1559 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1560 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1561 default:
1562 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1567 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1568 DWORD flags)
1570 DWORD numEntries;
1571 PMIB_TCPTABLE table;
1572 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1573 size_t Len = 0;
1574 char *Buf;
1575 struct xinpgen *pXIG, *pOrigXIG;
1576 #else
1577 FILE *fp;
1578 char buf[512] = { 0 }, *ptr;
1579 #endif
1581 if (!ppTcpTable)
1582 return ERROR_INVALID_PARAMETER;
1584 numEntries = getNumTcpEntries ();
1586 if (!*ppTcpTable)
1588 DWORD size = sizeof(MIB_TCPTABLE);
1590 if (numEntries > 1)
1591 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1592 *ppTcpTable = HeapAlloc (heap, flags, size);
1593 if (!*ppTcpTable)
1595 ERR ("Out of memory!\n");
1596 return ERROR_OUTOFMEMORY;
1598 maxEntries = numEntries;
1601 table = *ppTcpTable;
1602 table->dwNumEntries = 0;
1603 if (!numEntries)
1604 return NO_ERROR;
1606 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1608 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1610 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1611 return ERROR_OUTOFMEMORY;
1614 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1615 if (!Buf)
1617 ERR ("Out of memory!\n");
1618 return ERROR_OUTOFMEMORY;
1621 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1623 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1624 HeapFree (GetProcessHeap (), 0, Buf);
1625 return ERROR_OUTOFMEMORY;
1628 /* Might be nothing here; first entry is just a header it seems */
1629 if (Len <= sizeof (struct xinpgen))
1631 HeapFree (GetProcessHeap (), 0, Buf);
1632 return NO_ERROR;
1635 pOrigXIG = (struct xinpgen *)Buf;
1636 pXIG = pOrigXIG;
1638 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1639 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1640 (table->dwNumEntries < maxEntries);
1641 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1643 struct tcpcb *pTCPData = NULL;
1644 struct inpcb *pINData;
1645 struct xsocket *pSockData;
1647 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1648 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1649 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1651 /* Ignore sockets for other protocols */
1652 if (pSockData->xso_protocol != IPPROTO_TCP)
1653 continue;
1655 /* Ignore PCBs that were freed while generating the data */
1656 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1657 continue;
1659 /* we're only interested in IPv4 addresses */
1660 if (!(pINData->inp_vflag & INP_IPV4) ||
1661 (pINData->inp_vflag & INP_IPV6))
1662 continue;
1664 /* If all 0's, skip it */
1665 if (!pINData->inp_laddr.s_addr &&
1666 !pINData->inp_lport &&
1667 !pINData->inp_faddr.s_addr &&
1668 !pINData->inp_fport)
1669 continue;
1671 /* Fill in structure details */
1672 table->table[table->dwNumEntries].dwLocalAddr =
1673 pINData->inp_laddr.s_addr;
1674 table->table[table->dwNumEntries].dwLocalPort =
1675 pINData->inp_lport;
1676 table->table[table->dwNumEntries].dwRemoteAddr =
1677 pINData->inp_faddr.s_addr;
1678 table->table[table->dwNumEntries].dwRemotePort =
1679 pINData->inp_fport;
1680 table->table[table->dwNumEntries].dwState =
1681 TCPStateToMIBState (pTCPData->t_state);
1683 table->dwNumEntries++;
1686 HeapFree (GetProcessHeap (), 0, Buf);
1687 #else
1688 /* get from /proc/net/tcp, no error if can't */
1689 fp = fopen("/proc/net/tcp", "r");
1690 if (!fp)
1691 return ERROR_NOT_SUPPORTED;
1693 /* skip header line */
1694 ptr = fgets(buf, sizeof(buf), fp);
1695 while (ptr && table->dwNumEntries < maxEntries) {
1696 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1697 ptr = fgets(buf, sizeof(buf), fp);
1698 if (ptr) {
1699 char *endPtr;
1701 while (ptr && *ptr && *ptr != ':')
1702 ptr++;
1703 if (ptr && *ptr)
1704 ptr++;
1705 if (ptr && *ptr) {
1706 table->table[table->dwNumEntries].dwLocalAddr =
1707 strtoul(ptr, &endPtr, 16);
1708 ptr = endPtr;
1710 if (ptr && *ptr) {
1711 ptr++;
1712 table->table[table->dwNumEntries].dwLocalPort =
1713 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1714 ptr = endPtr;
1716 if (ptr && *ptr) {
1717 table->table[table->dwNumEntries].dwRemoteAddr =
1718 strtoul(ptr, &endPtr, 16);
1719 ptr = endPtr;
1721 if (ptr && *ptr) {
1722 ptr++;
1723 table->table[table->dwNumEntries].dwRemotePort =
1724 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1725 ptr = endPtr;
1727 if (ptr && *ptr) {
1728 DWORD state = strtoul(ptr, &endPtr, 16);
1730 table->table[table->dwNumEntries].dwState =
1731 TCPStateToMIBState (state);
1732 ptr = endPtr;
1734 table->dwNumEntries++;
1737 fclose(fp);
1738 #endif
1740 return NO_ERROR;