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