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