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