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