push b5232b2081a0e20e4bf07d6ded424d0101e4a589
[wine/hacks.git] / dlls / iphlpapi / ipstats.c
blob69dd978a94b9d131d99ed22f1e92c86f16a86f8e
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_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43 #ifdef HAVE_NET_IF_H
44 #include <net/if.h>
45 #endif
46 #ifdef HAVE_NET_ROUTE_H
47 #include <net/route.h>
48 #endif
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
51 #endif
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/tcp.h>
54 #endif
55 #ifdef HAVE_NETINET_TCP_FSM_H
56 #include <netinet/tcp_fsm.h>
57 #endif
59 #ifdef HAVE_NETINET_IN_PCB_H
60 #include <netinet/in_pcb.h>
61 #endif
62 #ifdef HAVE_NETINET_TCP_VAR_H
63 #include <netinet/tcp_var.h>
64 #endif
65 #ifdef HAVE_NETINET_IP_VAR_H
66 #include <netinet/ip_var.h>
67 #endif
69 #ifdef HAVE_SYS_SYSCTL_H
70 #include <sys/sysctl.h>
71 #endif
73 #ifndef ROUNDUP
74 #define ROUNDUP(a) \
75 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
76 #endif
77 #ifndef ADVANCE
78 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
79 #endif
81 #include "windef.h"
82 #include "winbase.h"
83 #include "iprtrmib.h"
84 #include "ifenum.h"
85 #include "ipstats.h"
87 #ifndef HAVE_NETINET_TCP_FSM_H
88 #define TCPS_ESTABLISHED 1
89 #define TCPS_SYN_SENT 2
90 #define TCPS_SYN_RECEIVED 3
91 #define TCPS_FIN_WAIT_1 4
92 #define TCPS_FIN_WAIT_2 5
93 #define TCPS_TIME_WAIT 6
94 #define TCPS_CLOSED 7
95 #define TCPS_CLOSE_WAIT 8
96 #define TCPS_LAST_ACK 9
97 #define TCPS_LISTEN 10
98 #define TCPS_CLOSING 11
99 #endif
101 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
103 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
105 FILE *fp;
107 if (!name)
108 return ERROR_INVALID_PARAMETER;
109 if (!entry)
110 return ERROR_INVALID_PARAMETER;
112 /* get interface stats from /proc/net/dev, no error if can't
113 no inUnknownProtos, outNUcastPkts, outQLen */
114 fp = fopen("/proc/net/dev", "r");
115 if (fp) {
116 char buf[512] = { 0 }, *ptr;
117 int nameLen = strlen(name), nameFound = 0;
120 ptr = fgets(buf, sizeof(buf), fp);
121 while (ptr && !nameFound) {
122 while (*ptr && isspace(*ptr))
123 ptr++;
124 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
125 nameFound = 1;
126 else
127 ptr = fgets(buf, sizeof(buf), fp);
129 if (nameFound) {
130 char *endPtr;
132 ptr += nameLen + 1;
133 if (ptr && *ptr) {
134 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
135 ptr = endPtr;
137 if (ptr && *ptr) {
138 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
139 ptr = endPtr;
141 if (ptr && *ptr) {
142 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
143 ptr = endPtr;
145 if (ptr && *ptr) {
146 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
147 ptr = endPtr;
149 if (ptr && *ptr) {
150 strtoul(ptr, &endPtr, 10); /* skip */
151 ptr = endPtr;
153 if (ptr && *ptr) {
154 strtoul(ptr, &endPtr, 10); /* skip */
155 ptr = endPtr;
157 if (ptr && *ptr) {
158 strtoul(ptr, &endPtr, 10); /* skip */
159 ptr = endPtr;
161 if (ptr && *ptr) {
162 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
163 ptr = endPtr;
165 if (ptr && *ptr) {
166 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
167 ptr = endPtr;
169 if (ptr && *ptr) {
170 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
171 ptr = endPtr;
173 if (ptr && *ptr) {
174 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
175 ptr = endPtr;
177 if (ptr && *ptr) {
178 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
179 ptr = endPtr;
182 fclose(fp);
184 else
185 ERR ("unimplemented!\n");
187 return NO_ERROR;
190 DWORD getICMPStats(MIB_ICMP *stats)
192 FILE *fp;
194 if (!stats)
195 return ERROR_INVALID_PARAMETER;
197 memset(stats, 0, sizeof(MIB_ICMP));
198 /* get most of these stats from /proc/net/snmp, no error if can't */
199 fp = fopen("/proc/net/snmp", "r");
200 if (fp) {
201 static const char hdr[] = "Icmp:";
202 char buf[512] = { 0 }, *ptr;
204 do {
205 ptr = fgets(buf, sizeof(buf), fp);
206 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
207 if (ptr) {
208 /* last line was a header, get another */
209 ptr = fgets(buf, sizeof(buf), fp);
210 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
211 char *endPtr;
213 ptr += sizeof(hdr);
214 if (ptr && *ptr) {
215 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
216 ptr = endPtr;
218 if (ptr && *ptr) {
219 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
220 ptr = endPtr;
222 if (ptr && *ptr) {
223 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
224 ptr = endPtr;
226 if (ptr && *ptr) {
227 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
228 ptr = endPtr;
230 if (ptr && *ptr) {
231 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
232 ptr = endPtr;
234 if (ptr && *ptr) {
235 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
236 ptr = endPtr;
238 if (ptr && *ptr) {
239 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
240 ptr = endPtr;
242 if (ptr && *ptr) {
243 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
244 ptr = endPtr;
246 if (ptr && *ptr) {
247 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
248 ptr = endPtr;
250 if (ptr && *ptr) {
251 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
252 ptr = endPtr;
254 if (ptr && *ptr) {
255 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
256 ptr = endPtr;
258 if (ptr && *ptr) {
259 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
260 ptr = endPtr;
262 if (ptr && *ptr) {
263 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
264 ptr = endPtr;
266 if (ptr && *ptr) {
267 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
268 ptr = endPtr;
270 if (ptr && *ptr) {
271 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
272 ptr = endPtr;
274 if (ptr && *ptr) {
275 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
276 ptr = endPtr;
278 if (ptr && *ptr) {
279 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
280 ptr = endPtr;
282 if (ptr && *ptr) {
283 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
284 ptr = endPtr;
286 if (ptr && *ptr) {
287 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
288 ptr = endPtr;
290 if (ptr && *ptr) {
291 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
292 ptr = endPtr;
294 if (ptr && *ptr) {
295 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
296 ptr = endPtr;
298 if (ptr && *ptr) {
299 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
300 ptr = endPtr;
302 if (ptr && *ptr) {
303 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
304 ptr = endPtr;
306 if (ptr && *ptr) {
307 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
308 ptr = endPtr;
312 fclose(fp);
314 else
315 ERR ("unimplemented!\n");
317 return NO_ERROR;
320 DWORD getIPStats(PMIB_IPSTATS stats)
322 FILE *fp;
324 if (!stats)
325 return ERROR_INVALID_PARAMETER;
327 memset(stats, 0, sizeof(MIB_IPSTATS));
328 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
329 stats->dwNumRoutes = getNumRoutes();
331 /* get most of these stats from /proc/net/snmp, no error if can't */
332 fp = fopen("/proc/net/snmp", "r");
333 if (fp) {
334 static const char hdr[] = "Ip:";
335 char buf[512] = { 0 }, *ptr;
337 do {
338 ptr = fgets(buf, sizeof(buf), fp);
339 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
340 if (ptr) {
341 /* last line was a header, get another */
342 ptr = fgets(buf, sizeof(buf), fp);
343 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
344 char *endPtr;
346 ptr += sizeof(hdr);
347 if (ptr && *ptr) {
348 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
349 ptr = endPtr;
351 if (ptr && *ptr) {
352 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
353 ptr = endPtr;
355 if (ptr && *ptr) {
356 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
357 ptr = endPtr;
359 if (ptr && *ptr) {
360 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
361 ptr = endPtr;
363 if (ptr && *ptr) {
364 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
365 ptr = endPtr;
367 if (ptr && *ptr) {
368 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
369 ptr = endPtr;
371 if (ptr && *ptr) {
372 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
373 ptr = endPtr;
375 if (ptr && *ptr) {
376 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
377 ptr = endPtr;
379 if (ptr && *ptr) {
380 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
381 ptr = endPtr;
383 if (ptr && *ptr) {
384 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
385 ptr = endPtr;
387 if (ptr && *ptr) {
388 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
389 ptr = endPtr;
391 if (ptr && *ptr) {
392 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
393 ptr = endPtr;
395 if (ptr && *ptr) {
396 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
397 ptr = endPtr;
399 if (ptr && *ptr) {
400 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
401 ptr = endPtr;
403 if (ptr && *ptr) {
404 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
405 ptr = endPtr;
407 if (ptr && *ptr) {
408 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
409 ptr = endPtr;
411 if (ptr && *ptr) {
412 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
413 ptr = endPtr;
415 if (ptr && *ptr) {
416 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
417 ptr = endPtr;
419 if (ptr && *ptr) {
420 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
421 ptr = endPtr;
423 /* hmm, no routingDiscards */
426 fclose(fp);
428 else
429 ERR ("unimplemented!\n");
431 return NO_ERROR;
434 DWORD getTCPStats(MIB_TCPSTATS *stats)
436 FILE *fp;
438 if (!stats)
439 return ERROR_INVALID_PARAMETER;
441 memset(stats, 0, sizeof(MIB_TCPSTATS));
443 /* get from /proc/net/snmp, no error if can't */
444 fp = fopen("/proc/net/snmp", "r");
445 if (fp) {
446 static const char hdr[] = "Tcp:";
447 char buf[512] = { 0 }, *ptr;
450 do {
451 ptr = fgets(buf, sizeof(buf), fp);
452 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
453 if (ptr) {
454 /* last line was a header, get another */
455 ptr = fgets(buf, sizeof(buf), fp);
456 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
457 char *endPtr;
459 ptr += sizeof(hdr);
460 if (ptr && *ptr) {
461 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
462 ptr = endPtr;
464 if (ptr && *ptr) {
465 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
466 ptr = endPtr;
468 if (ptr && *ptr) {
469 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
470 ptr = endPtr;
472 if (ptr && *ptr) {
473 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
474 ptr = endPtr;
476 if (ptr && *ptr) {
477 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
478 ptr = endPtr;
480 if (ptr && *ptr) {
481 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
482 ptr = endPtr;
484 if (ptr && *ptr) {
485 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
486 ptr = endPtr;
488 if (ptr && *ptr) {
489 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
490 ptr = endPtr;
492 if (ptr && *ptr) {
493 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
494 ptr = endPtr;
496 if (ptr && *ptr) {
497 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
498 ptr = endPtr;
500 if (ptr && *ptr) {
501 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
502 ptr = endPtr;
504 if (ptr && *ptr) {
505 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
506 ptr = endPtr;
508 if (ptr && *ptr) {
509 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
510 ptr = endPtr;
512 if (ptr && *ptr) {
513 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
514 ptr = endPtr;
516 stats->dwNumConns = getNumTcpEntries();
519 fclose(fp);
521 else
522 ERR ("unimplemented!\n");
524 return NO_ERROR;
527 DWORD getUDPStats(MIB_UDPSTATS *stats)
529 FILE *fp;
531 if (!stats)
532 return ERROR_INVALID_PARAMETER;
534 memset(stats, 0, sizeof(MIB_UDPSTATS));
536 /* get from /proc/net/snmp, no error if can't */
537 fp = fopen("/proc/net/snmp", "r");
538 if (fp) {
539 static const char hdr[] = "Udp:";
540 char buf[512] = { 0 }, *ptr;
543 do {
544 ptr = fgets(buf, sizeof(buf), fp);
545 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
546 if (ptr) {
547 /* last line was a header, get another */
548 ptr = fgets(buf, sizeof(buf), fp);
549 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
550 char *endPtr;
552 ptr += sizeof(hdr);
553 if (ptr && *ptr) {
554 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
555 ptr = endPtr;
557 if (ptr && *ptr) {
558 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
559 ptr = endPtr;
561 if (ptr && *ptr) {
562 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
563 ptr = endPtr;
565 if (ptr && *ptr) {
566 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
567 ptr = endPtr;
569 if (ptr && *ptr) {
570 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
571 ptr = endPtr;
575 fclose(fp);
577 else
578 ERR ("unimplemented!\n");
580 return NO_ERROR;
583 static DWORD getNumWithOneHeader(const char *filename)
585 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
586 size_t Len = 0;
587 char *Buf;
588 struct xinpgen *pXIG, *pOrigXIG;
589 int Protocol;
590 DWORD NumEntries = 0;
592 if (!strcmp (filename, "net.inet.tcp.pcblist"))
593 Protocol = IPPROTO_TCP;
594 else if (!strcmp (filename, "net.inet.udp.pcblist"))
595 Protocol = IPPROTO_UDP;
596 else
598 ERR ("Unsupported mib '%s', needs protocol mapping\n",
599 filename);
600 return 0;
603 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
605 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
606 return 0;
609 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
610 if (!Buf)
612 ERR ("Out of memory!\n");
613 return 0;
616 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
618 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
619 HeapFree (GetProcessHeap (), 0, Buf);
620 return 0;
623 /* Might be nothing here; first entry is just a header it seems */
624 if (Len <= sizeof (struct xinpgen))
626 HeapFree (GetProcessHeap (), 0, Buf);
627 return 0;
630 pOrigXIG = (struct xinpgen *)Buf;
631 pXIG = pOrigXIG;
633 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
634 pXIG->xig_len > sizeof (struct xinpgen);
635 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
637 struct tcpcb *pTCPData = NULL;
638 struct inpcb *pINData;
639 struct xsocket *pSockData;
641 if (Protocol == IPPROTO_TCP)
643 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
644 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
645 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
647 else
649 pINData = &((struct xinpcb *)pXIG)->xi_inp;
650 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
653 /* Ignore sockets for other protocols */
654 if (pSockData->xso_protocol != Protocol)
655 continue;
657 /* Ignore PCBs that were freed while generating the data */
658 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
659 continue;
661 /* we're only interested in IPv4 addresses */
662 if (!(pINData->inp_vflag & INP_IPV4) ||
663 (pINData->inp_vflag & INP_IPV6))
664 continue;
666 /* If all 0's, skip it */
667 if (!pINData->inp_laddr.s_addr &&
668 !pINData->inp_lport &&
669 !pINData->inp_faddr.s_addr &&
670 !pINData->inp_fport)
671 continue;
673 NumEntries++;
676 HeapFree (GetProcessHeap (), 0, Buf);
677 return NumEntries;
678 #else
679 FILE *fp;
680 int ret = 0;
682 fp = fopen(filename, "r");
683 if (fp) {
684 char buf[512] = { 0 }, *ptr;
687 ptr = fgets(buf, sizeof(buf), fp);
688 if (ptr) {
689 do {
690 ptr = fgets(buf, sizeof(buf), fp);
691 if (ptr)
692 ret++;
693 } while (ptr);
695 fclose(fp);
697 else
698 ERR ("Unable to open '%s' to count entries!\n", filename);
700 return ret;
701 #endif
704 DWORD getNumRoutes(void)
706 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
707 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
708 size_t needed;
709 char *buf, *lim, *next;
710 struct rt_msghdr *rtm;
711 DWORD RouteCount = 0;
713 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
715 ERR ("sysctl 1 failed!\n");
716 return 0;
719 buf = HeapAlloc (GetProcessHeap (), 0, needed);
720 if (!buf) return 0;
722 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
724 ERR ("sysctl 2 failed!\n");
725 HeapFree (GetProcessHeap (), 0, buf);
726 return 0;
729 lim = buf + needed;
730 for (next = buf; next < lim; next += rtm->rtm_msglen)
732 rtm = (struct rt_msghdr *)next;
734 if (rtm->rtm_type != RTM_GET)
736 WARN ("Got unexpected message type 0x%x!\n",
737 rtm->rtm_type);
738 continue;
741 /* Ignore all entries except for gateway routes which aren't
742 multicast */
743 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
744 continue;
746 RouteCount++;
749 HeapFree (GetProcessHeap (), 0, buf);
750 return RouteCount;
751 #else
752 return getNumWithOneHeader("/proc/net/route");
753 #endif
756 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
757 DWORD flags)
759 DWORD ret;
761 if (!ppIpForwardTable)
762 ret = ERROR_INVALID_PARAMETER;
763 else {
764 DWORD numRoutes = getNumRoutes();
765 PMIB_IPFORWARDTABLE table = HeapAlloc(heap, flags,
766 sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) * sizeof(MIB_IPFORWARDROW));
768 if (table) {
769 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
770 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
771 size_t needed;
772 char *buf, *lim, *next, *addrPtr;
773 struct rt_msghdr *rtm;
775 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
777 ERR ("sysctl 1 failed!\n");
778 HeapFree (GetProcessHeap (), 0, table);
779 return NO_ERROR;
782 buf = HeapAlloc (GetProcessHeap (), 0, needed);
783 if (!buf)
785 HeapFree (GetProcessHeap (), 0, table);
786 return ERROR_OUTOFMEMORY;
789 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
791 ERR ("sysctl 2 failed!\n");
792 HeapFree (GetProcessHeap (), 0, table);
793 HeapFree (GetProcessHeap (), 0, buf);
794 return NO_ERROR;
797 *ppIpForwardTable = table;
798 table->dwNumEntries = 0;
800 lim = buf + needed;
801 for (next = buf; next < lim; next += rtm->rtm_msglen)
803 int i;
805 rtm = (struct rt_msghdr *)next;
807 if (rtm->rtm_type != RTM_GET)
809 WARN ("Got unexpected message type 0x%x!\n",
810 rtm->rtm_type);
811 continue;
814 /* Ignore all entries except for gateway routes which aren't
815 multicast */
816 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
817 (rtm->rtm_flags & RTF_MULTICAST))
818 continue;
820 memset (&table->table[table->dwNumEntries], 0,
821 sizeof (MIB_IPFORWARDROW));
822 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
823 table->table[table->dwNumEntries].dwForwardType =
824 MIB_IPROUTE_TYPE_INDIRECT;
825 table->table[table->dwNumEntries].dwForwardMetric1 =
826 rtm->rtm_rmx.rmx_hopcount;
827 table->table[table->dwNumEntries].dwForwardProto =
828 MIB_IPPROTO_LOCAL;
830 addrPtr = (char *)(rtm + 1);
832 for (i = 1; i; i <<= 1)
834 struct sockaddr *sa;
835 DWORD addr;
837 if (!(i & rtm->rtm_addrs))
838 continue;
840 sa = (struct sockaddr *)addrPtr;
841 ADVANCE (addrPtr, sa);
843 /* default routes are encoded by length-zero sockaddr */
844 if (sa->sa_len == 0)
845 addr = 0;
846 else if (sa->sa_family != AF_INET)
848 ERR ("Received unsupported sockaddr family 0x%x\n",
849 sa->sa_family);
850 addr = 0;
852 else
854 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
856 addr = sin->sin_addr.s_addr;
859 switch (i)
861 case RTA_DST:
862 table->table[table->dwNumEntries].dwForwardDest = addr;
863 break;
865 case RTA_GATEWAY:
866 table->table[table->dwNumEntries].dwForwardNextHop = addr;
867 break;
869 case RTA_NETMASK:
870 table->table[table->dwNumEntries].dwForwardMask = addr;
871 break;
873 default:
874 ERR ("Unexpected address type 0x%x\n", i);
878 table->dwNumEntries++;
881 HeapFree (GetProcessHeap (), 0, buf);
882 ret = NO_ERROR;
883 #else
884 FILE *fp;
886 ret = NO_ERROR;
887 *ppIpForwardTable = table;
888 table->dwNumEntries = 0;
889 /* get from /proc/net/route, no error if can't */
890 fp = fopen("/proc/net/route", "r");
891 if (fp) {
892 char buf[512] = { 0 }, *ptr;
894 /* skip header line */
895 ptr = fgets(buf, sizeof(buf), fp);
896 while (ptr && table->dwNumEntries < numRoutes) {
897 memset(&table->table[table->dwNumEntries], 0,
898 sizeof(MIB_IPFORWARDROW));
899 ptr = fgets(buf, sizeof(buf), fp);
900 if (ptr) {
901 DWORD index;
903 while (!isspace(*ptr))
904 ptr++;
905 *ptr = '\0';
906 ptr++;
907 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
908 char *endPtr;
910 table->table[table->dwNumEntries].dwForwardIfIndex = index;
911 if (*ptr) {
912 table->table[table->dwNumEntries].dwForwardDest =
913 strtoul(ptr, &endPtr, 16);
914 ptr = endPtr;
916 if (ptr && *ptr) {
917 table->table[table->dwNumEntries].dwForwardNextHop =
918 strtoul(ptr, &endPtr, 16);
919 ptr = endPtr;
921 if (ptr && *ptr) {
922 DWORD flags = strtoul(ptr, &endPtr, 16);
924 if (!(flags & RTF_UP))
925 table->table[table->dwNumEntries].dwForwardType =
926 MIB_IPROUTE_TYPE_INVALID;
927 else if (flags & RTF_GATEWAY)
928 table->table[table->dwNumEntries].dwForwardType =
929 MIB_IPROUTE_TYPE_INDIRECT;
930 else
931 table->table[table->dwNumEntries].dwForwardType =
932 MIB_IPROUTE_TYPE_DIRECT;
933 ptr = endPtr;
935 if (ptr && *ptr) {
936 strtoul(ptr, &endPtr, 16); /* refcount, skip */
937 ptr = endPtr;
939 if (ptr && *ptr) {
940 strtoul(ptr, &endPtr, 16); /* use, skip */
941 ptr = endPtr;
943 if (ptr && *ptr) {
944 table->table[table->dwNumEntries].dwForwardMetric1 =
945 strtoul(ptr, &endPtr, 16);
946 ptr = endPtr;
948 if (ptr && *ptr) {
949 table->table[table->dwNumEntries].dwForwardMask =
950 strtoul(ptr, &endPtr, 16);
951 ptr = endPtr;
953 /* FIXME: other protos might be appropriate, e.g. the default
954 * route is typically set with MIB_IPPROTO_NETMGMT instead */
955 table->table[table->dwNumEntries].dwForwardProto =
956 MIB_IPPROTO_LOCAL;
957 table->dwNumEntries++;
961 fclose(fp);
963 else
965 ERR ("unimplemented!\n");
966 return ERROR_INVALID_PARAMETER;
968 #endif
970 else
971 ret = ERROR_OUTOFMEMORY;
973 return ret;
976 DWORD getNumArpEntries(void)
978 return getNumWithOneHeader("/proc/net/arp");
981 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
983 DWORD ret;
985 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
986 ERR ("unimplemented!\n");
987 return ERROR_INVALID_PARAMETER;
988 #endif
990 if (!ppIpNetTable)
991 ret = ERROR_INVALID_PARAMETER;
992 else {
993 DWORD numEntries = getNumArpEntries();
994 PMIB_IPNETTABLE table = HeapAlloc(heap, flags,
995 sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
997 if (table) {
998 FILE *fp;
1000 ret = NO_ERROR;
1001 *ppIpNetTable = table;
1002 table->dwNumEntries = 0;
1003 /* get from /proc/net/arp, no error if can't */
1004 fp = fopen("/proc/net/arp", "r");
1005 if (fp) {
1006 char buf[512] = { 0 }, *ptr;
1008 /* skip header line */
1009 ptr = fgets(buf, sizeof(buf), fp);
1010 while (ptr && table->dwNumEntries < numEntries) {
1011 ptr = fgets(buf, sizeof(buf), fp);
1012 if (ptr) {
1013 char *endPtr;
1015 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1016 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1017 while (ptr && *ptr && !isspace(*ptr))
1018 ptr++;
1020 if (ptr && *ptr) {
1021 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1022 ptr = endPtr;
1024 if (ptr && *ptr) {
1025 DWORD flags = strtoul(ptr, &endPtr, 16);
1027 #ifdef ATF_COM
1028 if (flags & ATF_COM)
1029 table->table[table->dwNumEntries].dwType =
1030 MIB_IPNET_TYPE_DYNAMIC;
1031 else
1032 #endif
1033 #ifdef ATF_PERM
1034 if (flags & ATF_PERM)
1035 table->table[table->dwNumEntries].dwType =
1036 MIB_IPNET_TYPE_STATIC;
1037 else
1038 #endif
1039 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1041 ptr = endPtr;
1043 while (ptr && *ptr && isspace(*ptr))
1044 ptr++;
1045 while (ptr && *ptr && !isspace(*ptr)) {
1046 DWORD byte = strtoul(ptr, &endPtr, 16);
1048 if (endPtr && *endPtr) {
1049 endPtr++;
1050 table->table[table->dwNumEntries].bPhysAddr[
1051 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1052 byte & 0x0ff;
1054 ptr = endPtr;
1056 if (ptr && *ptr) {
1057 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1058 ptr = endPtr;
1060 getInterfaceIndexByName(ptr,
1061 &table->table[table->dwNumEntries].dwIndex);
1062 table->dwNumEntries++;
1065 fclose(fp);
1068 else
1069 ret = ERROR_OUTOFMEMORY;
1071 return ret;
1074 DWORD getNumUdpEntries(void)
1076 return getNumWithOneHeader("/proc/net/udp");
1079 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1081 DWORD ret;
1083 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1084 ERR ("unimplemented!\n");
1085 return ERROR_INVALID_PARAMETER;
1086 #endif
1088 if (!ppUdpTable)
1089 ret = ERROR_INVALID_PARAMETER;
1090 else {
1091 DWORD numEntries = getNumUdpEntries();
1092 PMIB_UDPTABLE table = HeapAlloc(heap, flags,
1093 sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
1095 if (table) {
1096 FILE *fp;
1098 ret = NO_ERROR;
1099 *ppUdpTable = table;
1100 table->dwNumEntries = 0;
1101 /* get from /proc/net/udp, no error if can't */
1102 fp = fopen("/proc/net/udp", "r");
1103 if (fp) {
1104 char buf[512] = { 0 }, *ptr;
1106 /* skip header line */
1107 ptr = fgets(buf, sizeof(buf), fp);
1108 while (ptr && table->dwNumEntries < numEntries) {
1109 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1110 ptr = fgets(buf, sizeof(buf), fp);
1111 if (ptr) {
1112 char *endPtr;
1114 if (ptr && *ptr) {
1115 strtoul(ptr, &endPtr, 16); /* skip */
1116 ptr = endPtr;
1118 if (ptr && *ptr) {
1119 ptr++;
1120 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1121 &endPtr, 16);
1122 ptr = endPtr;
1124 if (ptr && *ptr) {
1125 ptr++;
1126 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1127 &endPtr, 16);
1128 ptr = endPtr;
1130 table->dwNumEntries++;
1133 fclose(fp);
1136 else
1137 ret = ERROR_OUTOFMEMORY;
1139 return ret;
1143 DWORD getNumTcpEntries(void)
1145 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1146 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1147 #else
1148 return getNumWithOneHeader ("/proc/net/tcp");
1149 #endif
1153 /* Why not a lookup table? Because the TCPS_* constants are different
1154 on different platforms */
1155 static DWORD TCPStateToMIBState (int state)
1157 switch (state)
1159 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1160 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1161 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1162 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1163 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1164 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1165 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1166 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1167 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1168 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1169 default:
1170 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1175 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1176 DWORD flags)
1178 DWORD numEntries;
1179 PMIB_TCPTABLE table;
1180 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1181 size_t Len = 0;
1182 char *Buf;
1183 struct xinpgen *pXIG, *pOrigXIG;
1184 #else
1185 FILE *fp;
1186 char buf[512] = { 0 }, *ptr;
1187 #endif
1189 if (!ppTcpTable)
1190 return ERROR_INVALID_PARAMETER;
1192 numEntries = getNumTcpEntries ();
1194 if (!*ppTcpTable)
1196 *ppTcpTable = HeapAlloc (heap, flags,
1197 sizeof (MIB_TCPTABLE) +
1198 (numEntries - 1) * sizeof (MIB_TCPROW));
1199 if (!*ppTcpTable)
1201 ERR ("Out of memory!\n");
1202 return ERROR_OUTOFMEMORY;
1204 maxEntries = numEntries;
1207 table = *ppTcpTable;
1208 table->dwNumEntries = 0;
1209 if (!numEntries)
1210 return NO_ERROR;
1212 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1214 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1216 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1217 return ERROR_OUTOFMEMORY;
1220 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1221 if (!Buf)
1223 ERR ("Out of memory!\n");
1224 return ERROR_OUTOFMEMORY;
1227 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1229 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1230 HeapFree (GetProcessHeap (), 0, Buf);
1231 return ERROR_OUTOFMEMORY;
1234 /* Might be nothing here; first entry is just a header it seems */
1235 if (Len <= sizeof (struct xinpgen))
1237 HeapFree (GetProcessHeap (), 0, Buf);
1238 return NO_ERROR;
1241 pOrigXIG = (struct xinpgen *)Buf;
1242 pXIG = pOrigXIG;
1244 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1245 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1246 (table->dwNumEntries < maxEntries);
1247 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1249 struct tcpcb *pTCPData = NULL;
1250 struct inpcb *pINData;
1251 struct xsocket *pSockData;
1253 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1254 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1255 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1257 /* Ignore sockets for other protocols */
1258 if (pSockData->xso_protocol != IPPROTO_TCP)
1259 continue;
1261 /* Ignore PCBs that were freed while generating the data */
1262 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1263 continue;
1265 /* we're only interested in IPv4 addresses */
1266 if (!(pINData->inp_vflag & INP_IPV4) ||
1267 (pINData->inp_vflag & INP_IPV6))
1268 continue;
1270 /* If all 0's, skip it */
1271 if (!pINData->inp_laddr.s_addr &&
1272 !pINData->inp_lport &&
1273 !pINData->inp_faddr.s_addr &&
1274 !pINData->inp_fport)
1275 continue;
1277 /* Fill in structure details */
1278 table->table[table->dwNumEntries].dwLocalAddr =
1279 pINData->inp_laddr.s_addr;
1280 table->table[table->dwNumEntries].dwLocalPort =
1281 pINData->inp_lport;
1282 table->table[table->dwNumEntries].dwRemoteAddr =
1283 pINData->inp_faddr.s_addr;
1284 table->table[table->dwNumEntries].dwRemotePort =
1285 pINData->inp_fport;
1286 table->table[table->dwNumEntries].dwState =
1287 TCPStateToMIBState (pTCPData->t_state);
1289 table->dwNumEntries++;
1292 HeapFree (GetProcessHeap (), 0, Buf);
1293 #else
1294 /* get from /proc/net/tcp, no error if can't */
1295 fp = fopen("/proc/net/tcp", "r");
1296 if (!fp)
1297 return NO_ERROR;
1299 /* skip header line */
1300 ptr = fgets(buf, sizeof(buf), fp);
1301 while (ptr && table->dwNumEntries < maxEntries) {
1302 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1303 ptr = fgets(buf, sizeof(buf), fp);
1304 if (ptr) {
1305 char *endPtr;
1307 while (ptr && *ptr && *ptr != ':')
1308 ptr++;
1309 if (ptr && *ptr)
1310 ptr++;
1311 if (ptr && *ptr) {
1312 table->table[table->dwNumEntries].dwLocalAddr =
1313 strtoul(ptr, &endPtr, 16);
1314 ptr = endPtr;
1316 if (ptr && *ptr) {
1317 ptr++;
1318 table->table[table->dwNumEntries].dwLocalPort =
1319 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1320 ptr = endPtr;
1322 if (ptr && *ptr) {
1323 table->table[table->dwNumEntries].dwRemoteAddr =
1324 strtoul(ptr, &endPtr, 16);
1325 ptr = endPtr;
1327 if (ptr && *ptr) {
1328 ptr++;
1329 table->table[table->dwNumEntries].dwRemotePort =
1330 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1331 ptr = endPtr;
1333 if (ptr && *ptr) {
1334 DWORD state = strtoul(ptr, &endPtr, 16);
1336 table->table[table->dwNumEntries].dwState =
1337 TCPStateToMIBState (state);
1338 ptr = endPtr;
1340 table->dwNumEntries++;
1343 fclose(fp);
1344 #endif
1346 return NO_ERROR;