Take advantage of the recursive nature of .gitignore for Makefile entries.
[wine] / dlls / iphlpapi / ipstats.c
1 /* Copyright (C) 2003,2006 Juan Lang
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16  *
17  * This file implements statistics getting using the /proc filesystem exported
18  * by Linux, and maybe other OSes.
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
31 #endif
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
34 #endif
35 #ifdef HAVE_ARPA_INET_H
36 #include <arpa/inet.h>
37 #endif
38 #ifdef HAVE_NET_IF_H
39 #include <net/if.h>
40 #endif
41 #ifdef HAVE_NET_ROUTE_H
42 #include <net/route.h>
43 #endif
44 #ifdef HAVE_NET_IF_ARP_H
45 #include <net/if_arp.h>
46 #endif
47 #ifdef HAVE_NETINET_TCP_H
48 #include <netinet/tcp.h>
49 #endif
50 #ifdef HAVE_NETINET_TCP_FSM_H
51 #include <netinet/tcp_fsm.h>
52 #endif
53
54 #include "windef.h"
55 #include "winbase.h"
56 #include "iprtrmib.h"
57 #include "ifenum.h"
58 #include "ipstats.h"
59
60 #ifdef linux
61 #define TCPS_ESTABLISHED  1
62 #define TCPS_SYN_SENT     2
63 #define TCPS_SYN_RECEIVED 3
64 #define TCPS_FIN_WAIT_1   4
65 #define TCPS_FIN_WAIT_2   5
66 #define TCPS_TIME_WAIT    6
67 #define TCPS_CLOSED       7
68 #define TCPS_CLOSE_WAIT   8
69 #define TCPS_LAST_ACK     9
70 #define TCPS_LISTEN      10
71 #define TCPS_CLOSING     11
72 #endif
73
74 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
75 {
76   FILE *fp;
77
78   if (!name)
79     return ERROR_INVALID_PARAMETER;
80   if (!entry)
81     return ERROR_INVALID_PARAMETER;
82
83   /* get interface stats from /proc/net/dev, no error if can't
84      no inUnknownProtos, outNUcastPkts, outQLen */
85   fp = fopen("/proc/net/dev", "r");
86   if (fp) {
87     char buf[512] = { 0 }, *ptr;
88     int nameLen = strlen(name), nameFound = 0;
89
90
91     ptr = fgets(buf, sizeof(buf), fp);
92     while (ptr && !nameFound) {
93       while (*ptr && isspace(*ptr))
94         ptr++;
95       if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
96         nameFound = 1;
97       else
98         ptr = fgets(buf, sizeof(buf), fp);
99     }
100     if (nameFound) {
101       char *endPtr;
102
103       ptr += nameLen + 1;
104       if (ptr && *ptr) {
105         entry->dwInOctets = strtoul(ptr, &endPtr, 10);
106         ptr = endPtr;
107       }
108       if (ptr && *ptr) {
109         entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
110         ptr = endPtr;
111       }
112       if (ptr && *ptr) {
113         entry->dwInErrors = strtoul(ptr, &endPtr, 10);
114         ptr = endPtr;
115       }
116       if (ptr && *ptr) {
117         entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
118         ptr = endPtr;
119       }
120       if (ptr && *ptr) {
121         strtoul(ptr, &endPtr, 10); /* skip */
122         ptr = endPtr;
123       }
124       if (ptr && *ptr) {
125         strtoul(ptr, &endPtr, 10); /* skip */
126         ptr = endPtr;
127       }
128       if (ptr && *ptr) {
129         strtoul(ptr, &endPtr, 10); /* skip */
130         ptr = endPtr;
131       }
132       if (ptr && *ptr) {
133         entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
134         ptr = endPtr;
135       }
136       if (ptr && *ptr) {
137         entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
138         ptr = endPtr;
139       }
140       if (ptr && *ptr) {
141         entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
142         ptr = endPtr;
143       }
144       if (ptr && *ptr) {
145         entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
146         ptr = endPtr;
147       }
148       if (ptr && *ptr) {
149         entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
150         ptr = endPtr;
151       }
152     }
153     fclose(fp);
154   }
155   return NO_ERROR;
156 }
157
158 DWORD getICMPStats(MIB_ICMP *stats)
159 {
160   FILE *fp;
161
162   if (!stats)
163     return ERROR_INVALID_PARAMETER;
164
165   memset(stats, 0, sizeof(MIB_ICMP));
166   /* get most of these stats from /proc/net/snmp, no error if can't */
167   fp = fopen("/proc/net/snmp", "r");
168   if (fp) {
169     static const char hdr[] = "Icmp:";
170     char buf[512] = { 0 }, *ptr;
171
172     do {
173       ptr = fgets(buf, sizeof(buf), fp);
174     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
175     if (ptr) {
176       /* last line was a header, get another */
177       ptr = fgets(buf, sizeof(buf), fp);
178       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
179         char *endPtr;
180
181         ptr += sizeof(hdr);
182         if (ptr && *ptr) {
183           stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
184           ptr = endPtr;
185         }
186         if (ptr && *ptr) {
187           stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
188           ptr = endPtr;
189         }
190         if (ptr && *ptr) {
191           stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
192           ptr = endPtr;
193         }
194         if (ptr && *ptr) {
195           stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
196           ptr = endPtr;
197         }
198         if (ptr && *ptr) {
199           stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
200           ptr = endPtr;
201         }
202         if (ptr && *ptr) {
203           stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
204           ptr = endPtr;
205         }
206         if (ptr && *ptr) {
207           stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
208           ptr = endPtr;
209         }
210         if (ptr && *ptr) {
211           stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
212           ptr = endPtr;
213         }
214         if (ptr && *ptr) {
215           stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
216           ptr = endPtr;
217         }
218         if (ptr && *ptr) {
219           stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
220           ptr = endPtr;
221         }
222         if (ptr && *ptr) {
223           stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
224           ptr = endPtr;
225         }
226         if (ptr && *ptr) {
227           stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
228           ptr = endPtr;
229         }
230         if (ptr && *ptr) {
231           stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
232           ptr = endPtr;
233         }
234         if (ptr && *ptr) {
235           stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
236           ptr = endPtr;
237         }
238         if (ptr && *ptr) {
239           stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
240           ptr = endPtr;
241         }
242         if (ptr && *ptr) {
243           stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
244           ptr = endPtr;
245         }
246         if (ptr && *ptr) {
247           stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
248           ptr = endPtr;
249         }
250         if (ptr && *ptr) {
251           stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
252           ptr = endPtr;
253         }
254         if (ptr && *ptr) {
255           stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
256           ptr = endPtr;
257         }
258         if (ptr && *ptr) {
259           stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
260           ptr = endPtr;
261         }
262         if (ptr && *ptr) {
263           stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
264           ptr = endPtr;
265         }
266         if (ptr && *ptr) {
267           stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
268           ptr = endPtr;
269         }
270         if (ptr && *ptr) {
271           stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
272           ptr = endPtr;
273         }
274         if (ptr && *ptr) {
275           stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
276           ptr = endPtr;
277         }
278       }
279     }
280     fclose(fp);
281   }
282   return NO_ERROR;
283 }
284
285 DWORD getIPStats(PMIB_IPSTATS stats)
286 {
287   FILE *fp;
288
289   if (!stats)
290     return ERROR_INVALID_PARAMETER;
291
292   memset(stats, 0, sizeof(MIB_IPSTATS));
293   stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
294   stats->dwNumRoutes = getNumRoutes();
295
296   /* get most of these stats from /proc/net/snmp, no error if can't */
297   fp = fopen("/proc/net/snmp", "r");
298   if (fp) {
299     static const char hdr[] = "Ip:";
300     char buf[512] = { 0 }, *ptr;
301
302     do {
303       ptr = fgets(buf, sizeof(buf), fp);
304     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
305     if (ptr) {
306       /* last line was a header, get another */
307       ptr = fgets(buf, sizeof(buf), fp);
308       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
309         char *endPtr;
310
311         ptr += sizeof(hdr);
312         if (ptr && *ptr) {
313           stats->dwForwarding = strtoul(ptr, &endPtr, 10);
314           ptr = endPtr;
315         }
316         if (ptr && *ptr) {
317           stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
318           ptr = endPtr;
319         }
320         if (ptr && *ptr) {
321           stats->dwInReceives = strtoul(ptr, &endPtr, 10);
322           ptr = endPtr;
323         }
324         if (ptr && *ptr) {
325           stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
326           ptr = endPtr;
327         }
328         if (ptr && *ptr) {
329           stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
330           ptr = endPtr;
331         }
332         if (ptr && *ptr) {
333           stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
334           ptr = endPtr;
335         }
336         if (ptr && *ptr) {
337           stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
338           ptr = endPtr;
339         }
340         if (ptr && *ptr) {
341           stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
342           ptr = endPtr;
343         }
344         if (ptr && *ptr) {
345           stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
346           ptr = endPtr;
347         }
348         if (ptr && *ptr) {
349           stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
350           ptr = endPtr;
351         }
352         if (ptr && *ptr) {
353           stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
354           ptr = endPtr;
355         }
356         if (ptr && *ptr) {
357           stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
358           ptr = endPtr;
359         }
360         if (ptr && *ptr) {
361           stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
362           ptr = endPtr;
363         }
364         if (ptr && *ptr) {
365           stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
366           ptr = endPtr;
367         }
368         if (ptr && *ptr) {
369           stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
370           ptr = endPtr;
371         }
372         if (ptr && *ptr) {
373           stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
374           ptr = endPtr;
375         }
376         if (ptr && *ptr) {
377           stats->dwFragOks = strtoul(ptr, &endPtr, 10);
378           ptr = endPtr;
379         }
380         if (ptr && *ptr) {
381           stats->dwFragFails = strtoul(ptr, &endPtr, 10);
382           ptr = endPtr;
383         }
384         if (ptr && *ptr) {
385           stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
386           ptr = endPtr;
387         }
388         /* hmm, no routingDiscards */
389       }
390     }
391     fclose(fp);
392   }
393   return NO_ERROR;
394 }
395
396 DWORD getTCPStats(MIB_TCPSTATS *stats)
397 {
398   FILE *fp;
399
400   if (!stats)
401     return ERROR_INVALID_PARAMETER;
402
403   memset(stats, 0, sizeof(MIB_TCPSTATS));
404
405   /* get from /proc/net/snmp, no error if can't */
406   fp = fopen("/proc/net/snmp", "r");
407   if (fp) {
408     static const char hdr[] = "Tcp:";
409     char buf[512] = { 0 }, *ptr;
410
411
412     do {
413       ptr = fgets(buf, sizeof(buf), fp);
414     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
415     if (ptr) {
416       /* last line was a header, get another */
417       ptr = fgets(buf, sizeof(buf), fp);
418       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
419         char *endPtr;
420
421         ptr += sizeof(hdr);
422         if (ptr && *ptr) {
423           stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
424           ptr = endPtr;
425         }
426         if (ptr && *ptr) {
427           stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
428           ptr = endPtr;
429         }
430         if (ptr && *ptr) {
431           stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
432           ptr = endPtr;
433         }
434         if (ptr && *ptr) {
435           stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
436           ptr = endPtr;
437         }
438         if (ptr && *ptr) {
439           stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
440           ptr = endPtr;
441         }
442         if (ptr && *ptr) {
443           stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
444           ptr = endPtr;
445         }
446         if (ptr && *ptr) {
447           stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
448           ptr = endPtr;
449         }
450         if (ptr && *ptr) {
451           stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
452           ptr = endPtr;
453         }
454         if (ptr && *ptr) {
455           stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
456           ptr = endPtr;
457         }
458         if (ptr && *ptr) {
459           stats->dwInSegs = strtoul(ptr, &endPtr, 10);
460           ptr = endPtr;
461         }
462         if (ptr && *ptr) {
463           stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
464           ptr = endPtr;
465         }
466         if (ptr && *ptr) {
467           stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
468           ptr = endPtr;
469         }
470         if (ptr && *ptr) {
471           stats->dwInErrs = strtoul(ptr, &endPtr, 10);
472           ptr = endPtr;
473         }
474         if (ptr && *ptr) {
475           stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
476           ptr = endPtr;
477         }
478         stats->dwNumConns = getNumTcpEntries();
479       }
480     }
481     fclose(fp);
482   }
483   return NO_ERROR;
484 }
485
486 DWORD getUDPStats(MIB_UDPSTATS *stats)
487 {
488   FILE *fp;
489
490   if (!stats)
491     return ERROR_INVALID_PARAMETER;
492
493   memset(stats, 0, sizeof(MIB_UDPSTATS));
494
495   /* get from /proc/net/snmp, no error if can't */
496   fp = fopen("/proc/net/snmp", "r");
497   if (fp) {
498     static const char hdr[] = "Udp:";
499     char buf[512] = { 0 }, *ptr;
500
501
502     do {
503       ptr = fgets(buf, sizeof(buf), fp);
504     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
505     if (ptr) {
506       /* last line was a header, get another */
507       ptr = fgets(buf, sizeof(buf), fp);
508       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
509         char *endPtr;
510
511         ptr += sizeof(hdr);
512         if (ptr && *ptr) {
513           stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
514           ptr = endPtr;
515         }
516         if (ptr && *ptr) {
517           stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
518           ptr = endPtr;
519         }
520         if (ptr && *ptr) {
521           stats->dwInErrors = strtoul(ptr, &endPtr, 10);
522           ptr = endPtr;
523         }
524         if (ptr && *ptr) {
525           stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
526           ptr = endPtr;
527         }
528         if (ptr && *ptr) {
529           stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
530           ptr = endPtr;
531         }
532       }
533     }
534     fclose(fp);
535   }
536   return NO_ERROR;
537 }
538
539 static DWORD getNumWithOneHeader(const char *filename)
540 {
541   FILE *fp;
542   int ret = 0;
543
544   fp = fopen(filename, "r");
545   if (fp) {
546     char buf[512] = { 0 }, *ptr;
547
548
549     ptr = fgets(buf, sizeof(buf), fp);
550     if (ptr) {
551       do {
552         ptr = fgets(buf, sizeof(buf), fp);
553         if (ptr)
554           ret++;
555       } while (ptr);
556     }
557     fclose(fp);
558   }
559   return ret;
560 }
561
562 DWORD getNumRoutes(void)
563 {
564   return getNumWithOneHeader("/proc/net/route");
565 }
566
567 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
568  DWORD flags)
569 {
570   DWORD ret;
571
572   if (!ppIpForwardTable)
573     ret = ERROR_INVALID_PARAMETER;
574   else {
575     DWORD numRoutes = getNumRoutes();
576     PMIB_IPFORWARDTABLE table = HeapAlloc(heap, flags,
577      sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) * sizeof(MIB_IPFORWARDROW));
578
579     if (table) {
580       FILE *fp;
581
582       ret = NO_ERROR;
583       *ppIpForwardTable = table;
584       table->dwNumEntries = 0;
585       /* get from /proc/net/route, no error if can't */
586       fp = fopen("/proc/net/route", "r");
587       if (fp) {
588         char buf[512] = { 0 }, *ptr;
589
590         /* skip header line */
591         ptr = fgets(buf, sizeof(buf), fp);
592         while (ptr && table->dwNumEntries < numRoutes) {
593           memset(&table->table[table->dwNumEntries], 0,
594            sizeof(MIB_IPFORWARDROW));
595           ptr = fgets(buf, sizeof(buf), fp);
596           if (ptr) {
597             DWORD index;
598
599             while (!isspace(*ptr))
600               ptr++;
601             *ptr = '\0';
602             ptr++;
603             if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
604               char *endPtr;
605
606               table->table[table->dwNumEntries].dwForwardIfIndex = index;
607               if (*ptr) {
608                 table->table[table->dwNumEntries].dwForwardDest =
609                  strtoul(ptr, &endPtr, 16);
610                 ptr = endPtr;
611               }
612               if (ptr && *ptr) {
613                 table->table[table->dwNumEntries].dwForwardNextHop =
614                  strtoul(ptr, &endPtr, 16);
615                 ptr = endPtr;
616               }
617               if (ptr && *ptr) {
618                 DWORD flags = strtoul(ptr, &endPtr, 16);
619
620                 if (!(flags & RTF_UP))
621                   table->table[table->dwNumEntries].dwForwardType =
622                    MIB_IPROUTE_TYPE_INVALID;
623                 else if (flags & RTF_GATEWAY)
624                   table->table[table->dwNumEntries].dwForwardType =
625                    MIB_IPROUTE_TYPE_INDIRECT;
626                 else
627                   table->table[table->dwNumEntries].dwForwardType =
628                    MIB_IPROUTE_TYPE_DIRECT;
629                 ptr = endPtr;
630               }
631               if (ptr && *ptr) {
632                 strtoul(ptr, &endPtr, 16); /* refcount, skip */
633                 ptr = endPtr;
634               }
635               if (ptr && *ptr) {
636                 strtoul(ptr, &endPtr, 16); /* use, skip */
637                 ptr = endPtr;
638               }
639               if (ptr && *ptr) {
640                 table->table[table->dwNumEntries].dwForwardMetric1 =
641                  strtoul(ptr, &endPtr, 16);
642                 ptr = endPtr;
643               }
644               if (ptr && *ptr) {
645                 table->table[table->dwNumEntries].dwForwardMask =
646                  strtoul(ptr, &endPtr, 16);
647                 ptr = endPtr;
648               }
649               /* FIXME: other protos might be appropriate, e.g. the default
650                * route is typically set with MIB_IPPROTO_NETMGMT instead */
651               table->table[table->dwNumEntries].dwForwardProto =
652                MIB_IPPROTO_LOCAL;
653               table->dwNumEntries++;
654             }
655           }
656         }
657         fclose(fp);
658       }
659     }
660     else
661       ret = ERROR_OUTOFMEMORY;
662   }
663   return ret;
664 }
665
666 DWORD getNumArpEntries(void)
667 {
668   return getNumWithOneHeader("/proc/net/arp");
669 }
670
671 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
672 {
673   DWORD ret;
674
675   if (!ppIpNetTable)
676     ret = ERROR_INVALID_PARAMETER;
677   else {
678     DWORD numEntries = getNumArpEntries();
679     PMIB_IPNETTABLE table = HeapAlloc(heap, flags,
680      sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
681
682     if (table) {
683       FILE *fp;
684
685       ret = NO_ERROR;
686       *ppIpNetTable = table;
687       table->dwNumEntries = 0;
688       /* get from /proc/net/arp, no error if can't */
689       fp = fopen("/proc/net/arp", "r");
690       if (fp) {
691         char buf[512] = { 0 }, *ptr;
692
693         /* skip header line */
694         ptr = fgets(buf, sizeof(buf), fp);
695         while (ptr && table->dwNumEntries < numEntries) {
696           ptr = fgets(buf, sizeof(buf), fp);
697           if (ptr) {
698             char *endPtr;
699
700             memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
701             table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
702             while (ptr && *ptr && !isspace(*ptr))
703               ptr++;
704
705             if (ptr && *ptr) {
706               strtoul(ptr, &endPtr, 16); /* hw type (skip) */
707               ptr = endPtr;
708             }
709             if (ptr && *ptr) {
710               DWORD flags = strtoul(ptr, &endPtr, 16);
711
712 #ifdef ATF_COM
713               if (flags & ATF_COM)
714                 table->table[table->dwNumEntries].dwType =
715                  MIB_IPNET_TYPE_DYNAMIC;
716               else
717 #endif
718 #ifdef ATF_PERM
719               if (flags & ATF_PERM)
720                 table->table[table->dwNumEntries].dwType =
721                  MIB_IPNET_TYPE_STATIC;
722               else
723 #endif
724                 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
725
726               ptr = endPtr;
727             }
728             while (ptr && *ptr && isspace(*ptr))
729               ptr++;
730             while (ptr && *ptr && !isspace(*ptr)) {
731               DWORD byte = strtoul(ptr, &endPtr, 16);
732
733               if (endPtr && *endPtr) {
734                 endPtr++;
735                 table->table[table->dwNumEntries].bPhysAddr[
736                  table->table[table->dwNumEntries].dwPhysAddrLen++] =
737                  byte & 0x0ff;
738               }
739               ptr = endPtr;
740             }
741             if (ptr && *ptr) {
742               strtoul(ptr, &endPtr, 16); /* mask (skip) */
743               ptr = endPtr;
744             }
745             getInterfaceIndexByName(ptr,
746              &table->table[table->dwNumEntries].dwIndex);
747             table->dwNumEntries++;
748           }
749         }
750         fclose(fp);
751       }
752     }
753     else
754       ret = ERROR_OUTOFMEMORY;
755   }
756   return ret;
757 }
758
759 DWORD getNumUdpEntries(void)
760 {
761   return getNumWithOneHeader("/proc/net/udp");
762 }
763
764 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
765 {
766   DWORD ret;
767
768   if (!ppUdpTable)
769     ret = ERROR_INVALID_PARAMETER;
770   else {
771     DWORD numEntries = getNumUdpEntries();
772     PMIB_UDPTABLE table = HeapAlloc(heap, flags,
773      sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
774
775     if (table) {
776       FILE *fp;
777
778       ret = NO_ERROR;
779       *ppUdpTable = table;
780       table->dwNumEntries = 0;
781       /* get from /proc/net/udp, no error if can't */
782       fp = fopen("/proc/net/udp", "r");
783       if (fp) {
784         char buf[512] = { 0 }, *ptr;
785
786         /* skip header line */
787         ptr = fgets(buf, sizeof(buf), fp);
788         while (ptr && table->dwNumEntries < numEntries) {
789           memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
790           ptr = fgets(buf, sizeof(buf), fp);
791           if (ptr) {
792             char *endPtr;
793
794             if (ptr && *ptr) {
795               strtoul(ptr, &endPtr, 16); /* skip */
796               ptr = endPtr;
797             }
798             if (ptr && *ptr) {
799               ptr++;
800               table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
801                &endPtr, 16);
802               ptr = endPtr;
803             }
804             if (ptr && *ptr) {
805               ptr++;
806               table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
807                &endPtr, 16);
808               ptr = endPtr;
809             }
810             table->dwNumEntries++;
811           }
812         }
813         fclose(fp);
814       }
815     }
816     else
817       ret = ERROR_OUTOFMEMORY;
818   }
819   return ret;
820 }
821
822 DWORD getNumTcpEntries(void)
823 {
824   return getNumWithOneHeader("/proc/net/tcp");
825 }
826
827 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags)
828 {
829   DWORD ret;
830
831   if (!ppTcpTable)
832     ret = ERROR_INVALID_PARAMETER;
833   else {
834     DWORD numEntries = getNumTcpEntries();
835     PMIB_TCPTABLE table = HeapAlloc(heap, flags,
836      sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW));
837
838     if (table) {
839       FILE *fp;
840
841       ret = NO_ERROR;
842       *ppTcpTable = table;
843       table->dwNumEntries = 0;
844       /* get from /proc/net/tcp, no error if can't */
845       fp = fopen("/proc/net/tcp", "r");
846       if (fp) {
847         char buf[512] = { 0 }, *ptr;
848
849         /* skip header line */
850         ptr = fgets(buf, sizeof(buf), fp);
851         while (ptr && table->dwNumEntries < numEntries) {
852           memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
853           ptr = fgets(buf, sizeof(buf), fp);
854           if (ptr) {
855             char *endPtr;
856
857             while (ptr && *ptr && *ptr != ':')
858               ptr++;
859             if (ptr && *ptr)
860               ptr++;
861             if (ptr && *ptr) {
862               table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
863                &endPtr, 16);
864               ptr = endPtr;
865             }
866             if (ptr && *ptr) {
867               ptr++;
868               table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
869                &endPtr, 16);
870               ptr = endPtr;
871             }
872             if (ptr && *ptr) {
873               table->table[table->dwNumEntries].dwRemoteAddr = strtoul(ptr,
874                &endPtr, 16);
875               ptr = endPtr;
876             }
877             if (ptr && *ptr) {
878               ptr++;
879               table->table[table->dwNumEntries].dwRemotePort = strtoul(ptr,
880                &endPtr, 16);
881               ptr = endPtr;
882             }
883             if (ptr && *ptr) {
884               DWORD state = strtoul(ptr, &endPtr, 16);
885
886               switch (state)
887               {
888                 case TCPS_ESTABLISHED:
889                   table->table[table->dwNumEntries].dwState =
890                    MIB_TCP_STATE_ESTAB;
891                   break;
892                 case TCPS_SYN_SENT:
893                   table->table[table->dwNumEntries].dwState =
894                    MIB_TCP_STATE_SYN_SENT;
895                   break;
896                 case TCPS_SYN_RECEIVED:
897                   table->table[table->dwNumEntries].dwState =
898                    MIB_TCP_STATE_SYN_RCVD;
899                   break;
900                 case TCPS_FIN_WAIT_1:
901                   table->table[table->dwNumEntries].dwState =
902                    MIB_TCP_STATE_FIN_WAIT1;
903                   break;
904                 case TCPS_FIN_WAIT_2:
905                   table->table[table->dwNumEntries].dwState =
906                    MIB_TCP_STATE_FIN_WAIT2;
907                   break;
908                 case TCPS_TIME_WAIT:
909                   table->table[table->dwNumEntries].dwState =
910                    MIB_TCP_STATE_TIME_WAIT;
911                   break;
912                 case TCPS_CLOSED:
913                   table->table[table->dwNumEntries].dwState =
914                    MIB_TCP_STATE_CLOSED;
915                   break;
916                 case TCPS_CLOSE_WAIT:
917                   table->table[table->dwNumEntries].dwState =
918                    MIB_TCP_STATE_CLOSE_WAIT;
919                   break;
920                 case TCPS_LAST_ACK:
921                   table->table[table->dwNumEntries].dwState =
922                    MIB_TCP_STATE_LAST_ACK;
923                   break;
924                 case TCPS_LISTEN:
925                   table->table[table->dwNumEntries].dwState =
926                    MIB_TCP_STATE_LISTEN;
927                   break;
928                 case TCPS_CLOSING:
929                   table->table[table->dwNumEntries].dwState =
930                    MIB_TCP_STATE_CLOSING;
931                   break;
932               }
933               ptr = endPtr;
934             }
935             table->dwNumEntries++;
936           }
937         }
938         fclose(fp);
939       }
940     }
941     else
942       ret = ERROR_OUTOFMEMORY;
943   }
944   return ret;
945 }