mountmgr: Store the contents of the device symlink in the drive object.
[wine/multimedia.git] / dlls / iphlpapi / ipstats.c
blob3fc91ebdea7bf2bba4aaa02090d6d01888e43165
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 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
135 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
137 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
138 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
139 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
141 size_t needed;
142 char *buf, *end;
143 struct if_msghdr *ifm;
144 struct if_data ifdata;
145 if (!name || !entry)
146 return ERROR_INVALID_PARAMETER;
148 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
150 ERR ("failed to get size of iflist\n");
151 return ERROR_NOT_SUPPORTED;
153 buf = HeapAlloc (GetProcessHeap (), 0, needed);
154 if (!buf) return ERROR_NOT_SUPPORTED;
155 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
157 ERR ("failed to get iflist\n");
158 HeapFree (GetProcessHeap (), 0, buf);
159 return ERROR_NOT_SUPPORTED;
161 else
162 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
164 ifm = (struct if_msghdr *) buf;
165 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
167 ifdata = ifm->ifm_data;
168 entry->dwMtu = ifdata.ifi_mtu;
169 entry->dwSpeed = ifdata.ifi_baudrate;
170 entry->dwInOctets = ifdata.ifi_ibytes;
171 entry->dwInErrors = ifdata.ifi_ierrors;
172 entry->dwInDiscards = ifdata.ifi_iqdrops;
173 entry->dwInUcastPkts = ifdata.ifi_ipackets;
174 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
175 entry->dwOutOctets = ifdata.ifi_obytes;
176 entry->dwOutUcastPkts = ifdata.ifi_opackets;
177 entry->dwOutErrors = ifdata.ifi_oerrors;
178 HeapFree (GetProcessHeap (), 0, buf);
179 return NO_ERROR;
182 HeapFree (GetProcessHeap (), 0, buf);
183 return ERROR_NOT_SUPPORTED;
184 #else
185 /* get interface stats from /proc/net/dev, no error if can't
186 no inUnknownProtos, outNUcastPkts, outQLen */
187 FILE *fp;
189 if (!name || !entry)
190 return ERROR_INVALID_PARAMETER;
191 fp = fopen("/proc/net/dev", "r");
192 if (fp) {
193 char buf[512] = { 0 }, *ptr;
194 int nameLen = strlen(name), nameFound = 0;
197 ptr = fgets(buf, sizeof(buf), fp);
198 while (ptr && !nameFound) {
199 while (*ptr && isspace(*ptr))
200 ptr++;
201 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
202 nameFound = 1;
203 else
204 ptr = fgets(buf, sizeof(buf), fp);
206 if (nameFound) {
207 char *endPtr;
209 ptr += nameLen + 1;
210 if (ptr && *ptr) {
211 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
212 ptr = endPtr;
214 if (ptr && *ptr) {
215 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
216 ptr = endPtr;
218 if (ptr && *ptr) {
219 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
220 ptr = endPtr;
222 if (ptr && *ptr) {
223 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
224 ptr = endPtr;
226 if (ptr && *ptr) {
227 strtoul(ptr, &endPtr, 10); /* skip */
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 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
240 ptr = endPtr;
242 if (ptr && *ptr) {
243 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
244 ptr = endPtr;
246 if (ptr && *ptr) {
247 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
248 ptr = endPtr;
250 if (ptr && *ptr) {
251 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
252 ptr = endPtr;
254 if (ptr && *ptr) {
255 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
256 ptr = endPtr;
259 fclose(fp);
261 else
263 ERR ("unimplemented!\n");
264 return ERROR_NOT_SUPPORTED;
267 return NO_ERROR;
268 #endif
271 DWORD getICMPStats(MIB_ICMP *stats)
273 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
274 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
275 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
276 size_t needed;
277 struct icmpstat icmp_stat;
278 int i;
280 if (!stats)
281 return ERROR_INVALID_PARAMETER;
283 needed = sizeof(icmp_stat);
284 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
286 ERR ("failed to get icmpstat\n");
287 return ERROR_NOT_SUPPORTED;
291 /*in stats */
292 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
293 for(i = 0; i <= ICMP_MAXTYPE; i++)
294 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
296 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
298 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
299 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
300 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
301 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
302 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
303 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
304 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
305 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
306 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
307 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
308 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
311 /* out stats */
312 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
313 for(i = 0; i <= ICMP_MAXTYPE; i++)
314 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
316 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
318 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
319 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
320 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
321 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
322 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
323 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
324 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
325 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
326 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
327 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
328 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
330 return NO_ERROR;
331 #else
332 FILE *fp;
334 if (!stats)
335 return ERROR_INVALID_PARAMETER;
337 memset(stats, 0, sizeof(MIB_ICMP));
338 /* get most of these stats from /proc/net/snmp, no error if can't */
339 fp = fopen("/proc/net/snmp", "r");
340 if (fp) {
341 static const char hdr[] = "Icmp:";
342 char buf[512] = { 0 }, *ptr;
344 do {
345 ptr = fgets(buf, sizeof(buf), fp);
346 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
347 if (ptr) {
348 /* last line was a header, get another */
349 ptr = fgets(buf, sizeof(buf), fp);
350 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
351 char *endPtr;
353 ptr += sizeof(hdr);
354 if (ptr && *ptr) {
355 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
356 ptr = endPtr;
358 if (ptr && *ptr) {
359 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
360 ptr = endPtr;
362 if (ptr && *ptr) {
363 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
364 ptr = endPtr;
366 if (ptr && *ptr) {
367 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
368 ptr = endPtr;
370 if (ptr && *ptr) {
371 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
372 ptr = endPtr;
374 if (ptr && *ptr) {
375 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
376 ptr = endPtr;
378 if (ptr && *ptr) {
379 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
380 ptr = endPtr;
382 if (ptr && *ptr) {
383 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
384 ptr = endPtr;
386 if (ptr && *ptr) {
387 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
388 ptr = endPtr;
390 if (ptr && *ptr) {
391 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
392 ptr = endPtr;
394 if (ptr && *ptr) {
395 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
396 ptr = endPtr;
398 if (ptr && *ptr) {
399 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
400 ptr = endPtr;
402 if (ptr && *ptr) {
403 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
404 ptr = endPtr;
406 if (ptr && *ptr) {
407 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
408 ptr = endPtr;
410 if (ptr && *ptr) {
411 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
412 ptr = endPtr;
414 if (ptr && *ptr) {
415 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
416 ptr = endPtr;
418 if (ptr && *ptr) {
419 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
420 ptr = endPtr;
422 if (ptr && *ptr) {
423 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
424 ptr = endPtr;
426 if (ptr && *ptr) {
427 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
428 ptr = endPtr;
430 if (ptr && *ptr) {
431 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
432 ptr = endPtr;
434 if (ptr && *ptr) {
435 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
436 ptr = endPtr;
438 if (ptr && *ptr) {
439 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
440 ptr = endPtr;
442 if (ptr && *ptr) {
443 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
444 ptr = endPtr;
446 if (ptr && *ptr) {
447 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
448 ptr = endPtr;
452 fclose(fp);
454 else
456 ERR ("unimplemented!\n");
457 return ERROR_NOT_SUPPORTED;
460 return NO_ERROR;
461 #endif
464 DWORD getIPStats(PMIB_IPSTATS stats)
466 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
467 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
468 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
469 int ip_ttl, ip_forwarding;
470 struct ipstat ip_stat;
471 size_t needed;
473 if (!stats)
474 return ERROR_INVALID_PARAMETER;
476 needed = sizeof(ip_stat);
477 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
479 ERR ("failed to get ipstat\n");
480 return ERROR_NOT_SUPPORTED;
483 needed = sizeof(ip_ttl);
484 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
486 ERR ("failed to get ip Default TTL\n");
487 return ERROR_NOT_SUPPORTED;
490 needed = sizeof(ip_forwarding);
491 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
493 ERR ("failed to get ip forwarding\n");
494 return ERROR_NOT_SUPPORTED;
497 stats->dwForwarding = ip_forwarding;
498 stats->dwDefaultTTL = ip_ttl;
499 stats->dwInDelivers = ip_stat.ips_delivered;
500 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
501 stats->dwInAddrErrors = ip_stat.ips_cantforward;
502 stats->dwInReceives = ip_stat.ips_total;
503 stats->dwForwDatagrams = ip_stat.ips_forward;
504 stats->dwInUnknownProtos = ip_stat.ips_noproto;
505 stats->dwInDiscards = ip_stat.ips_fragdropped;
506 stats->dwOutDiscards = ip_stat.ips_odropped;
507 stats->dwReasmOks = ip_stat.ips_reassembled;
508 stats->dwFragOks = ip_stat.ips_fragmented;
509 stats->dwFragFails = ip_stat.ips_cantfrag;
510 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
511 stats->dwOutNoRoutes = ip_stat.ips_noroute;
512 stats->dwOutRequests = ip_stat.ips_localout;
513 stats->dwReasmReqds = ip_stat.ips_fragments;
515 return NO_ERROR;
516 #else
517 FILE *fp;
519 if (!stats)
520 return ERROR_INVALID_PARAMETER;
522 memset(stats, 0, sizeof(MIB_IPSTATS));
523 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
524 stats->dwNumRoutes = getNumRoutes();
526 /* get most of these stats from /proc/net/snmp, no error if can't */
527 fp = fopen("/proc/net/snmp", "r");
528 if (fp) {
529 static const char hdr[] = "Ip:";
530 char buf[512] = { 0 }, *ptr;
532 do {
533 ptr = fgets(buf, sizeof(buf), fp);
534 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
535 if (ptr) {
536 /* last line was a header, get another */
537 ptr = fgets(buf, sizeof(buf), fp);
538 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
539 char *endPtr;
541 ptr += sizeof(hdr);
542 if (ptr && *ptr) {
543 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
544 ptr = endPtr;
546 if (ptr && *ptr) {
547 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
548 ptr = endPtr;
550 if (ptr && *ptr) {
551 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
552 ptr = endPtr;
554 if (ptr && *ptr) {
555 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
556 ptr = endPtr;
558 if (ptr && *ptr) {
559 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
560 ptr = endPtr;
562 if (ptr && *ptr) {
563 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
564 ptr = endPtr;
566 if (ptr && *ptr) {
567 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
568 ptr = endPtr;
570 if (ptr && *ptr) {
571 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
572 ptr = endPtr;
574 if (ptr && *ptr) {
575 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
576 ptr = endPtr;
578 if (ptr && *ptr) {
579 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
580 ptr = endPtr;
582 if (ptr && *ptr) {
583 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
584 ptr = endPtr;
586 if (ptr && *ptr) {
587 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
588 ptr = endPtr;
590 if (ptr && *ptr) {
591 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
592 ptr = endPtr;
594 if (ptr && *ptr) {
595 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
596 ptr = endPtr;
598 if (ptr && *ptr) {
599 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
600 ptr = endPtr;
602 if (ptr && *ptr) {
603 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
604 ptr = endPtr;
606 if (ptr && *ptr) {
607 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
608 ptr = endPtr;
610 if (ptr && *ptr) {
611 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
612 ptr = endPtr;
614 if (ptr && *ptr) {
615 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
616 ptr = endPtr;
618 /* hmm, no routingDiscards */
621 fclose(fp);
623 else
625 ERR ("unimplemented!\n");
626 return ERROR_NOT_SUPPORTED;
629 return NO_ERROR;
630 #endif
633 DWORD getTCPStats(MIB_TCPSTATS *stats)
635 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
636 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
637 #define TCPTV_MIN 2
638 #define TCPTV_REXMTMAX 128
639 #endif
640 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
641 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
642 #define hz 1000
643 struct tcpstat tcp_stat;
644 size_t needed;
646 if (!stats)
647 return ERROR_INVALID_PARAMETER;
648 needed = sizeof(tcp_stat);
650 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
652 ERR ("failed to get tcpstat\n");
653 return ERROR_NOT_SUPPORTED;
656 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
657 stats->dwRtoMin = TCPTV_MIN;
658 stats->dwRtoMax = TCPTV_REXMTMAX;
659 stats->dwMaxConn = -1;
660 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
661 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
662 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
663 stats->dwEstabResets = tcp_stat.tcps_drops;
664 stats->dwCurrEstab = 0;
665 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
666 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
667 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
668 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
669 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
670 stats->dwNumConns = tcp_stat.tcps_connects;
672 return NO_ERROR;
674 #else
675 FILE *fp;
677 if (!stats)
678 return ERROR_INVALID_PARAMETER;
680 memset(stats, 0, sizeof(MIB_TCPSTATS));
682 /* get from /proc/net/snmp, no error if can't */
683 fp = fopen("/proc/net/snmp", "r");
684 if (fp) {
685 static const char hdr[] = "Tcp:";
686 char buf[512] = { 0 }, *ptr;
689 do {
690 ptr = fgets(buf, sizeof(buf), fp);
691 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
692 if (ptr) {
693 /* last line was a header, get another */
694 ptr = fgets(buf, sizeof(buf), fp);
695 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
696 char *endPtr;
698 ptr += sizeof(hdr);
699 if (ptr && *ptr) {
700 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
701 ptr = endPtr;
703 if (ptr && *ptr) {
704 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
705 ptr = endPtr;
707 if (ptr && *ptr) {
708 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
709 ptr = endPtr;
711 if (ptr && *ptr) {
712 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
713 ptr = endPtr;
715 if (ptr && *ptr) {
716 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
717 ptr = endPtr;
719 if (ptr && *ptr) {
720 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
721 ptr = endPtr;
723 if (ptr && *ptr) {
724 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
725 ptr = endPtr;
727 if (ptr && *ptr) {
728 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
729 ptr = endPtr;
731 if (ptr && *ptr) {
732 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
733 ptr = endPtr;
735 if (ptr && *ptr) {
736 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
737 ptr = endPtr;
739 if (ptr && *ptr) {
740 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
741 ptr = endPtr;
743 if (ptr && *ptr) {
744 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
745 ptr = endPtr;
747 if (ptr && *ptr) {
748 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
749 ptr = endPtr;
751 if (ptr && *ptr) {
752 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
753 ptr = endPtr;
755 stats->dwNumConns = getNumTcpEntries();
758 fclose(fp);
760 else
762 ERR ("unimplemented!\n");
763 return ERROR_NOT_SUPPORTED;
766 return NO_ERROR;
767 #endif
770 DWORD getUDPStats(MIB_UDPSTATS *stats)
772 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
773 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
774 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
775 struct udpstat udp_stat;
776 size_t needed;
777 if (!stats)
778 return ERROR_INVALID_PARAMETER;
780 needed = sizeof(udp_stat);
782 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
784 ERR ("failed to get udpstat\n");
785 return ERROR_NOT_SUPPORTED;
788 stats->dwInDatagrams = udp_stat.udps_ipackets;
789 stats->dwOutDatagrams = udp_stat.udps_opackets;
790 stats->dwNoPorts = udp_stat.udps_noport;
791 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
792 stats->dwNumAddrs = getNumUdpEntries();
794 return NO_ERROR;
795 #else
796 FILE *fp;
798 if (!stats)
799 return ERROR_INVALID_PARAMETER;
801 memset(stats, 0, sizeof(MIB_UDPSTATS));
803 /* get from /proc/net/snmp, no error if can't */
804 fp = fopen("/proc/net/snmp", "r");
805 if (fp) {
806 static const char hdr[] = "Udp:";
807 char buf[512] = { 0 }, *ptr;
810 do {
811 ptr = fgets(buf, sizeof(buf), fp);
812 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
813 if (ptr) {
814 /* last line was a header, get another */
815 ptr = fgets(buf, sizeof(buf), fp);
816 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
817 char *endPtr;
819 ptr += sizeof(hdr);
820 if (ptr && *ptr) {
821 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
822 ptr = endPtr;
824 if (ptr && *ptr) {
825 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
826 ptr = endPtr;
828 if (ptr && *ptr) {
829 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
830 ptr = endPtr;
832 if (ptr && *ptr) {
833 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
834 ptr = endPtr;
836 if (ptr && *ptr) {
837 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
838 ptr = endPtr;
842 fclose(fp);
844 else
846 ERR ("unimplemented!\n");
847 return ERROR_NOT_SUPPORTED;
850 return NO_ERROR;
851 #endif
854 static DWORD getNumWithOneHeader(const char *filename)
856 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
857 size_t Len = 0;
858 char *Buf;
859 struct xinpgen *pXIG, *pOrigXIG;
860 int Protocol;
861 DWORD NumEntries = 0;
863 if (!strcmp (filename, "net.inet.tcp.pcblist"))
864 Protocol = IPPROTO_TCP;
865 else if (!strcmp (filename, "net.inet.udp.pcblist"))
866 Protocol = IPPROTO_UDP;
867 else
869 ERR ("Unsupported mib '%s', needs protocol mapping\n",
870 filename);
871 return 0;
874 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
876 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
877 return 0;
880 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
881 if (!Buf)
883 ERR ("Out of memory!\n");
884 return 0;
887 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
889 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
890 HeapFree (GetProcessHeap (), 0, Buf);
891 return 0;
894 /* Might be nothing here; first entry is just a header it seems */
895 if (Len <= sizeof (struct xinpgen))
897 HeapFree (GetProcessHeap (), 0, Buf);
898 return 0;
901 pOrigXIG = (struct xinpgen *)Buf;
902 pXIG = pOrigXIG;
904 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
905 pXIG->xig_len > sizeof (struct xinpgen);
906 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
908 struct tcpcb *pTCPData = NULL;
909 struct inpcb *pINData;
910 struct xsocket *pSockData;
912 if (Protocol == IPPROTO_TCP)
914 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
915 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
916 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
918 else
920 pINData = &((struct xinpcb *)pXIG)->xi_inp;
921 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
924 /* Ignore sockets for other protocols */
925 if (pSockData->xso_protocol != Protocol)
926 continue;
928 /* Ignore PCBs that were freed while generating the data */
929 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
930 continue;
932 /* we're only interested in IPv4 addresses */
933 if (!(pINData->inp_vflag & INP_IPV4) ||
934 (pINData->inp_vflag & INP_IPV6))
935 continue;
937 /* If all 0's, skip it */
938 if (!pINData->inp_laddr.s_addr &&
939 !pINData->inp_lport &&
940 !pINData->inp_faddr.s_addr &&
941 !pINData->inp_fport)
942 continue;
944 NumEntries++;
947 HeapFree (GetProcessHeap (), 0, Buf);
948 return NumEntries;
949 #else
950 FILE *fp;
951 int ret = 0;
953 fp = fopen(filename, "r");
954 if (fp) {
955 char buf[512] = { 0 }, *ptr;
958 ptr = fgets(buf, sizeof(buf), fp);
959 if (ptr) {
960 do {
961 ptr = fgets(buf, sizeof(buf), fp);
962 if (ptr)
963 ret++;
964 } while (ptr);
966 fclose(fp);
968 else
969 ERR ("Unable to open '%s' to count entries!\n", filename);
971 return ret;
972 #endif
975 DWORD getNumRoutes(void)
977 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
978 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
979 size_t needed;
980 char *buf, *lim, *next;
981 struct rt_msghdr *rtm;
982 DWORD RouteCount = 0;
984 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
986 ERR ("sysctl 1 failed!\n");
987 return 0;
990 buf = HeapAlloc (GetProcessHeap (), 0, needed);
991 if (!buf) return 0;
993 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
995 ERR ("sysctl 2 failed!\n");
996 HeapFree (GetProcessHeap (), 0, buf);
997 return 0;
1000 lim = buf + needed;
1001 for (next = buf; next < lim; next += rtm->rtm_msglen)
1003 rtm = (struct rt_msghdr *)next;
1005 if (rtm->rtm_type != RTM_GET)
1007 WARN ("Got unexpected message type 0x%x!\n",
1008 rtm->rtm_type);
1009 continue;
1012 /* Ignore all entries except for gateway routes which aren't
1013 multicast */
1014 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1015 continue;
1017 RouteCount++;
1020 HeapFree (GetProcessHeap (), 0, buf);
1021 return RouteCount;
1022 #else
1023 return getNumWithOneHeader("/proc/net/route");
1024 #endif
1027 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1028 DWORD flags)
1030 DWORD ret;
1032 if (!ppIpForwardTable)
1033 ret = ERROR_INVALID_PARAMETER;
1034 else {
1035 DWORD numRoutes = getNumRoutes();
1036 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1037 PMIB_IPFORWARDTABLE table;
1039 if (numRoutes > 1)
1040 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1041 table = HeapAlloc(heap, flags, size);
1042 if (table) {
1043 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1044 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1045 size_t needed;
1046 char *buf, *lim, *next, *addrPtr;
1047 struct rt_msghdr *rtm;
1049 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1051 ERR ("sysctl 1 failed!\n");
1052 HeapFree (GetProcessHeap (), 0, table);
1053 return NO_ERROR;
1056 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1057 if (!buf)
1059 HeapFree (GetProcessHeap (), 0, table);
1060 return ERROR_OUTOFMEMORY;
1063 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1065 ERR ("sysctl 2 failed!\n");
1066 HeapFree (GetProcessHeap (), 0, table);
1067 HeapFree (GetProcessHeap (), 0, buf);
1068 return NO_ERROR;
1071 *ppIpForwardTable = table;
1072 table->dwNumEntries = 0;
1074 lim = buf + needed;
1075 for (next = buf; next < lim; next += rtm->rtm_msglen)
1077 int i;
1079 rtm = (struct rt_msghdr *)next;
1081 if (rtm->rtm_type != RTM_GET)
1083 WARN ("Got unexpected message type 0x%x!\n",
1084 rtm->rtm_type);
1085 continue;
1088 /* Ignore all entries except for gateway routes which aren't
1089 multicast */
1090 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1091 (rtm->rtm_flags & RTF_MULTICAST))
1092 continue;
1094 memset (&table->table[table->dwNumEntries], 0,
1095 sizeof (MIB_IPFORWARDROW));
1096 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1097 table->table[table->dwNumEntries].dwForwardType =
1098 MIB_IPROUTE_TYPE_INDIRECT;
1099 table->table[table->dwNumEntries].dwForwardMetric1 =
1100 rtm->rtm_rmx.rmx_hopcount;
1101 table->table[table->dwNumEntries].dwForwardProto =
1102 MIB_IPPROTO_LOCAL;
1104 addrPtr = (char *)(rtm + 1);
1106 for (i = 1; i; i <<= 1)
1108 struct sockaddr *sa;
1109 DWORD addr;
1111 if (!(i & rtm->rtm_addrs))
1112 continue;
1114 sa = (struct sockaddr *)addrPtr;
1115 ADVANCE (addrPtr, sa);
1117 /* default routes are encoded by length-zero sockaddr */
1118 if (sa->sa_len == 0)
1119 addr = 0;
1120 else if (sa->sa_family != AF_INET)
1122 WARN ("Received unsupported sockaddr family 0x%x\n",
1123 sa->sa_family);
1124 addr = 0;
1126 else
1128 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1130 addr = sin->sin_addr.s_addr;
1133 switch (i)
1135 case RTA_DST:
1136 table->table[table->dwNumEntries].dwForwardDest = addr;
1137 break;
1139 case RTA_GATEWAY:
1140 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1141 break;
1143 case RTA_NETMASK:
1144 table->table[table->dwNumEntries].dwForwardMask = addr;
1145 break;
1147 default:
1148 WARN ("Unexpected address type 0x%x\n", i);
1152 table->dwNumEntries++;
1155 HeapFree (GetProcessHeap (), 0, buf);
1156 ret = NO_ERROR;
1157 #else
1158 FILE *fp;
1160 ret = NO_ERROR;
1161 *ppIpForwardTable = table;
1162 table->dwNumEntries = 0;
1163 /* get from /proc/net/route, no error if can't */
1164 fp = fopen("/proc/net/route", "r");
1165 if (fp) {
1166 char buf[512] = { 0 }, *ptr;
1168 /* skip header line */
1169 ptr = fgets(buf, sizeof(buf), fp);
1170 while (ptr && table->dwNumEntries < numRoutes) {
1171 memset(&table->table[table->dwNumEntries], 0,
1172 sizeof(MIB_IPFORWARDROW));
1173 ptr = fgets(buf, sizeof(buf), fp);
1174 if (ptr) {
1175 DWORD index;
1177 while (!isspace(*ptr))
1178 ptr++;
1179 *ptr = '\0';
1180 ptr++;
1181 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1182 char *endPtr;
1184 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1185 if (*ptr) {
1186 table->table[table->dwNumEntries].dwForwardDest =
1187 strtoul(ptr, &endPtr, 16);
1188 ptr = endPtr;
1190 if (ptr && *ptr) {
1191 table->table[table->dwNumEntries].dwForwardNextHop =
1192 strtoul(ptr, &endPtr, 16);
1193 ptr = endPtr;
1195 if (ptr && *ptr) {
1196 DWORD flags = strtoul(ptr, &endPtr, 16);
1198 if (!(flags & RTF_UP))
1199 table->table[table->dwNumEntries].dwForwardType =
1200 MIB_IPROUTE_TYPE_INVALID;
1201 else if (flags & RTF_GATEWAY)
1202 table->table[table->dwNumEntries].dwForwardType =
1203 MIB_IPROUTE_TYPE_INDIRECT;
1204 else
1205 table->table[table->dwNumEntries].dwForwardType =
1206 MIB_IPROUTE_TYPE_DIRECT;
1207 ptr = endPtr;
1209 if (ptr && *ptr) {
1210 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1211 ptr = endPtr;
1213 if (ptr && *ptr) {
1214 strtoul(ptr, &endPtr, 16); /* use, skip */
1215 ptr = endPtr;
1217 if (ptr && *ptr) {
1218 table->table[table->dwNumEntries].dwForwardMetric1 =
1219 strtoul(ptr, &endPtr, 16);
1220 ptr = endPtr;
1222 if (ptr && *ptr) {
1223 table->table[table->dwNumEntries].dwForwardMask =
1224 strtoul(ptr, &endPtr, 16);
1225 ptr = endPtr;
1227 /* FIXME: other protos might be appropriate, e.g. the default
1228 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1229 table->table[table->dwNumEntries].dwForwardProto =
1230 MIB_IPPROTO_LOCAL;
1231 table->dwNumEntries++;
1235 fclose(fp);
1237 else
1239 ERR ("unimplemented!\n");
1240 return ERROR_NOT_SUPPORTED;
1242 #endif
1244 else
1245 ret = ERROR_OUTOFMEMORY;
1247 return ret;
1250 DWORD getNumArpEntries(void)
1252 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1253 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1254 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1255 DWORD arpEntries = 0;
1256 size_t needed;
1257 char *buf, *lim, *next;
1258 struct rt_msghdr *rtm;
1259 struct sockaddr_inarp *sinarp;
1260 struct sockaddr_dl *sdl;
1262 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1264 ERR ("failed to get size of arp table\n");
1265 return 0;
1268 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1269 if (!buf) return 0;
1271 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1273 ERR ("failed to get arp table\n");
1274 HeapFree (GetProcessHeap (), 0, buf);
1275 return 0;
1278 lim = buf + needed;
1279 next = buf;
1280 while(next < lim)
1282 rtm = (struct rt_msghdr *)next;
1283 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1284 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1285 if(sdl->sdl_alen) /* arp entry */
1286 arpEntries++;
1287 next += rtm->rtm_msglen;
1289 HeapFree (GetProcessHeap (), 0, buf);
1290 return arpEntries;
1291 #endif
1292 return getNumWithOneHeader("/proc/net/arp");
1295 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1297 DWORD ret = NO_ERROR;
1298 if (!ppIpNetTable)
1299 ret = ERROR_INVALID_PARAMETER;
1300 else {
1301 DWORD numEntries = getNumArpEntries();
1302 DWORD size = sizeof(MIB_IPNETTABLE);
1303 PMIB_IPNETTABLE table;
1305 if (numEntries > 1)
1306 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1307 table = HeapAlloc(heap, flags, size);
1308 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1309 if (table)
1311 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1312 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1313 size_t needed;
1314 char *buf, *lim, *next;
1315 struct rt_msghdr *rtm;
1316 struct sockaddr_inarp *sinarp;
1317 struct sockaddr_dl *sdl;
1319 *ppIpNetTable = table;
1320 table->dwNumEntries = 0;
1322 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1324 ERR ("failed to get size of arp table\n");
1325 return ERROR_NOT_SUPPORTED;
1328 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1329 if (!buf) return ERROR_OUTOFMEMORY;
1331 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1333 ERR ("failed to get arp table\n");
1334 HeapFree (GetProcessHeap (), 0, buf);
1335 return ERROR_NOT_SUPPORTED;
1338 lim = buf + needed;
1339 next = buf;
1340 while(next < lim)
1342 rtm = (struct rt_msghdr *)next;
1343 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1344 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1345 if(sdl->sdl_alen) /* arp entry */
1347 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1348 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1349 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1350 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1351 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1353 table->table[table->dwNumEntries].bPhysAddr[
1354 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1355 byte & 0x0ff;
1356 if(rtm->rtm_rmx.rmx_expire == 0)
1357 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1358 else if(sinarp->sin_other & SIN_PROXY)
1359 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1360 else if(rtm->rtm_rmx.rmx_expire != 0)
1361 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1362 else
1363 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1365 table->dwNumEntries++;
1367 next += rtm->rtm_msglen;
1369 HeapFree (GetProcessHeap (), 0, buf);
1371 else
1372 ret = ERROR_OUTOFMEMORY;
1373 return ret;
1374 #endif
1376 if (table) {
1377 FILE *fp;
1378 *ppIpNetTable = table;
1379 table->dwNumEntries = 0;
1380 /* get from /proc/net/arp, no error if can't */
1381 fp = fopen("/proc/net/arp", "r");
1382 if (fp) {
1383 char buf[512] = { 0 }, *ptr;
1385 /* skip header line */
1386 ptr = fgets(buf, sizeof(buf), fp);
1387 while (ptr && table->dwNumEntries < numEntries) {
1388 ptr = fgets(buf, sizeof(buf), fp);
1389 if (ptr) {
1390 char *endPtr;
1392 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1393 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1394 while (ptr && *ptr && !isspace(*ptr))
1395 ptr++;
1397 if (ptr && *ptr) {
1398 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1399 ptr = endPtr;
1401 if (ptr && *ptr) {
1402 DWORD flags = strtoul(ptr, &endPtr, 16);
1404 #ifdef ATF_COM
1405 if (flags & ATF_COM)
1406 table->table[table->dwNumEntries].dwType =
1407 MIB_IPNET_TYPE_DYNAMIC;
1408 else
1409 #endif
1410 #ifdef ATF_PERM
1411 if (flags & ATF_PERM)
1412 table->table[table->dwNumEntries].dwType =
1413 MIB_IPNET_TYPE_STATIC;
1414 else
1415 #endif
1416 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1418 ptr = endPtr;
1420 while (ptr && *ptr && isspace(*ptr))
1421 ptr++;
1422 while (ptr && *ptr && !isspace(*ptr)) {
1423 DWORD byte = strtoul(ptr, &endPtr, 16);
1425 if (endPtr && *endPtr) {
1426 endPtr++;
1427 table->table[table->dwNumEntries].bPhysAddr[
1428 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1429 byte & 0x0ff;
1431 ptr = endPtr;
1433 if (ptr && *ptr) {
1434 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1435 ptr = endPtr;
1437 getInterfaceIndexByName(ptr,
1438 &table->table[table->dwNumEntries].dwIndex);
1439 table->dwNumEntries++;
1442 fclose(fp);
1444 else
1445 ret = ERROR_NOT_SUPPORTED;
1447 else
1448 ret = ERROR_OUTOFMEMORY;
1450 return ret;
1453 DWORD getNumUdpEntries(void)
1455 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1456 return getNumWithOneHeader ("net.inet.udp.pcblist");
1457 #else
1458 return getNumWithOneHeader("/proc/net/udp");
1459 #endif
1462 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1464 DWORD ret;
1466 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1467 ERR ("unimplemented!\n");
1468 return ERROR_NOT_SUPPORTED;
1469 #endif
1471 if (!ppUdpTable)
1472 ret = ERROR_INVALID_PARAMETER;
1473 else {
1474 DWORD numEntries = getNumUdpEntries();
1475 DWORD size = sizeof(MIB_UDPTABLE);
1476 PMIB_UDPTABLE table;
1478 if (numEntries > 1)
1479 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1480 table = HeapAlloc(heap, flags, size);
1481 if (table) {
1482 FILE *fp;
1484 ret = NO_ERROR;
1485 *ppUdpTable = table;
1486 table->dwNumEntries = 0;
1487 /* get from /proc/net/udp, no error if can't */
1488 fp = fopen("/proc/net/udp", "r");
1489 if (fp) {
1490 char buf[512] = { 0 }, *ptr;
1492 /* skip header line */
1493 ptr = fgets(buf, sizeof(buf), fp);
1494 while (ptr && table->dwNumEntries < numEntries) {
1495 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1496 ptr = fgets(buf, sizeof(buf), fp);
1497 if (ptr) {
1498 char *endPtr;
1500 if (ptr && *ptr) {
1501 strtoul(ptr, &endPtr, 16); /* skip */
1502 ptr = endPtr;
1504 if (ptr && *ptr) {
1505 ptr++;
1506 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1507 &endPtr, 16);
1508 ptr = endPtr;
1510 if (ptr && *ptr) {
1511 ptr++;
1512 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1513 &endPtr, 16);
1514 ptr = endPtr;
1516 table->dwNumEntries++;
1519 fclose(fp);
1521 else
1522 ret = ERROR_NOT_SUPPORTED;
1524 else
1525 ret = ERROR_OUTOFMEMORY;
1527 return ret;
1531 DWORD getNumTcpEntries(void)
1533 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1534 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1535 #else
1536 return getNumWithOneHeader ("/proc/net/tcp");
1537 #endif
1541 /* Why not a lookup table? Because the TCPS_* constants are different
1542 on different platforms */
1543 static DWORD TCPStateToMIBState (int state)
1545 switch (state)
1547 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1548 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1549 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1550 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1551 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1552 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1553 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1554 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1555 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1556 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1557 default:
1558 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1563 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1564 DWORD flags)
1566 DWORD numEntries;
1567 PMIB_TCPTABLE table;
1568 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1569 size_t Len = 0;
1570 char *Buf;
1571 struct xinpgen *pXIG, *pOrigXIG;
1572 #else
1573 FILE *fp;
1574 char buf[512] = { 0 }, *ptr;
1575 #endif
1577 if (!ppTcpTable)
1578 return ERROR_INVALID_PARAMETER;
1580 numEntries = getNumTcpEntries ();
1582 if (!*ppTcpTable)
1584 DWORD size = sizeof(MIB_TCPTABLE);
1586 if (numEntries > 1)
1587 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1588 *ppTcpTable = HeapAlloc (heap, flags, size);
1589 if (!*ppTcpTable)
1591 ERR ("Out of memory!\n");
1592 return ERROR_OUTOFMEMORY;
1594 maxEntries = numEntries;
1597 table = *ppTcpTable;
1598 table->dwNumEntries = 0;
1599 if (!numEntries)
1600 return NO_ERROR;
1602 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1604 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1606 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1607 return ERROR_OUTOFMEMORY;
1610 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1611 if (!Buf)
1613 ERR ("Out of memory!\n");
1614 return ERROR_OUTOFMEMORY;
1617 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1619 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1620 HeapFree (GetProcessHeap (), 0, Buf);
1621 return ERROR_OUTOFMEMORY;
1624 /* Might be nothing here; first entry is just a header it seems */
1625 if (Len <= sizeof (struct xinpgen))
1627 HeapFree (GetProcessHeap (), 0, Buf);
1628 return NO_ERROR;
1631 pOrigXIG = (struct xinpgen *)Buf;
1632 pXIG = pOrigXIG;
1634 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1635 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1636 (table->dwNumEntries < maxEntries);
1637 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1639 struct tcpcb *pTCPData = NULL;
1640 struct inpcb *pINData;
1641 struct xsocket *pSockData;
1643 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1644 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1645 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1647 /* Ignore sockets for other protocols */
1648 if (pSockData->xso_protocol != IPPROTO_TCP)
1649 continue;
1651 /* Ignore PCBs that were freed while generating the data */
1652 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1653 continue;
1655 /* we're only interested in IPv4 addresses */
1656 if (!(pINData->inp_vflag & INP_IPV4) ||
1657 (pINData->inp_vflag & INP_IPV6))
1658 continue;
1660 /* If all 0's, skip it */
1661 if (!pINData->inp_laddr.s_addr &&
1662 !pINData->inp_lport &&
1663 !pINData->inp_faddr.s_addr &&
1664 !pINData->inp_fport)
1665 continue;
1667 /* Fill in structure details */
1668 table->table[table->dwNumEntries].dwLocalAddr =
1669 pINData->inp_laddr.s_addr;
1670 table->table[table->dwNumEntries].dwLocalPort =
1671 pINData->inp_lport;
1672 table->table[table->dwNumEntries].dwRemoteAddr =
1673 pINData->inp_faddr.s_addr;
1674 table->table[table->dwNumEntries].dwRemotePort =
1675 pINData->inp_fport;
1676 table->table[table->dwNumEntries].dwState =
1677 TCPStateToMIBState (pTCPData->t_state);
1679 table->dwNumEntries++;
1682 HeapFree (GetProcessHeap (), 0, Buf);
1683 #else
1684 /* get from /proc/net/tcp, no error if can't */
1685 fp = fopen("/proc/net/tcp", "r");
1686 if (!fp)
1687 return ERROR_NOT_SUPPORTED;
1689 /* skip header line */
1690 ptr = fgets(buf, sizeof(buf), fp);
1691 while (ptr && table->dwNumEntries < maxEntries) {
1692 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1693 ptr = fgets(buf, sizeof(buf), fp);
1694 if (ptr) {
1695 char *endPtr;
1697 while (ptr && *ptr && *ptr != ':')
1698 ptr++;
1699 if (ptr && *ptr)
1700 ptr++;
1701 if (ptr && *ptr) {
1702 table->table[table->dwNumEntries].dwLocalAddr =
1703 strtoul(ptr, &endPtr, 16);
1704 ptr = endPtr;
1706 if (ptr && *ptr) {
1707 ptr++;
1708 table->table[table->dwNumEntries].dwLocalPort =
1709 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1710 ptr = endPtr;
1712 if (ptr && *ptr) {
1713 table->table[table->dwNumEntries].dwRemoteAddr =
1714 strtoul(ptr, &endPtr, 16);
1715 ptr = endPtr;
1717 if (ptr && *ptr) {
1718 ptr++;
1719 table->table[table->dwNumEntries].dwRemotePort =
1720 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1721 ptr = endPtr;
1723 if (ptr && *ptr) {
1724 DWORD state = strtoul(ptr, &endPtr, 16);
1726 table->table[table->dwNumEntries].dwState =
1727 TCPStateToMIBState (state);
1728 ptr = endPtr;
1730 table->dwNumEntries++;
1733 fclose(fp);
1734 #endif
1736 return NO_ERROR;