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