Delete all Trailing spaces in code.
[reactos.git] / reactos / dll / win32 / iphlpapi / ipstats_reactos.c
1 /* Copyright (C) 2003 Art Yerkes
2 * A reimplementation of ifenum.c by Juan Lang
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * This file is implemented on the IOCTL_TCP_QUERY_INFORMATION_EX ioctl on
19 * tcpip.sys
20 */
21
22 #include <roscfg.h>
23 #include <stdio.h>
24
25 #include "iphlpapi_private.h"
26 #include "ipstats.h"
27 #include "ifenum.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
30
31 #ifndef TCPS_ESTABLISHED
32 # define TCPS_ESTABLISHED TCP_ESTABLISHED
33 #endif
34 #ifndef TCPS_SYN_SENT
35 # define TCPS_SYN_SENT TCP_SYN_SENT
36 #endif
37 #ifndef TCPS_SYN_RECEIVED
38 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
39 #endif
40 #ifndef TCPS_FIN_WAIT_1
41 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
42 #endif
43 #ifndef TCPS_FIN_WAIT_2
44 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
45 #endif
46 #ifndef TCPS_TIME_WAIT
47 # define TCPS_TIME_WAIT TCP_TIME_WAIT
48 #endif
49 #ifndef TCPS_CLOSED
50 # define TCPS_CLOSED TCP_CLOSE
51 #endif
52 #ifndef TCPS_CLOSE_WAIT
53 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
54 #endif
55 #ifndef TCPS_LAST_ACK
56 # define TCPS_LAST_ACK TCP_LAST_ACK
57 #endif
58 #ifndef TCPS_LISTEN
59 # define TCPS_LISTEN TCP_LISTEN
60 #endif
61 #ifndef TCPS_CLOSING
62 # define TCPS_CLOSING TCP_CLOSING
63 #endif
64
65 BOOL isIpEntity( HANDLE tcpFile, TDIEntityID *ent ) {
66 DWORD entityType, returnedLen;
67 NTSTATUS status;
68 TCP_REQUEST_QUERY_INFORMATION_EX req;
69
70 req.ID.toi_class = INFO_CLASS_GENERIC;
71 req.ID.toi_type = INFO_TYPE_PROVIDER;
72 req.ID.toi_id = ENTITY_TYPE_ID;
73 req.ID.toi_entity = *ent;
74
75 status =
76 DeviceIoControl
77 ( tcpFile,
78 IOCTL_TCP_QUERY_INFORMATION_EX,
79 &req,
80 sizeof(req),
81 &entityType,
82 sizeof(entityType),
83 &returnedLen,
84 NULL );
85
86 TRACE("Ent: %04x:d -> %04x\n",
87 ent->tei_entity, ent->tei_instance, entityType );
88
89 return NT_SUCCESS(status) && entityType == CL_NL_IP;
90 }
91
92 NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
93 DWORD numEntities = 0;
94 DWORD numRoutes = 0;
95 TDIEntityID *entitySet = 0;
96 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
97 int i;
98
99 if( !NT_SUCCESS(status) )
100 return status;
101
102 for( i = 0; i < numEntities; i++ ) {
103 if( isIpEntity( tcpFile, &entitySet[i] ) ) {
104 TRACE("Entity %d is an IP Entity\n", i);
105 if( numRoutes == index ) break;
106 else numRoutes++;
107 }
108 }
109
110 if( numRoutes == index && i < numEntities ) {
111 TRACE("Index %d is entity #%d - %04x:%08x\n", index, i,
112 entitySet[i].tei_entity, entitySet[i].tei_instance );
113 memcpy( ent, &entitySet[i], sizeof(*ent) );
114 tdiFreeThingSet( entitySet );
115 return STATUS_SUCCESS;
116 } else {
117 tdiFreeThingSet( entitySet );
118 return STATUS_UNSUCCESSFUL;
119 }
120 }
121
122 NTSTATUS tdiGetMibForIpEntity
123 ( HANDLE tcpFile, TDIEntityID *ent, IPSNMPInfo *entry ) {
124 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
125 NTSTATUS status = STATUS_SUCCESS;
126 DWORD returnSize;
127
128 memset( entry, 0, sizeof( *entry ) );
129
130 TRACE("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n",
131 (DWORD)tcpFile, ent->tei_instance);
132
133 req.ID.toi_class = INFO_CLASS_PROTOCOL;
134 req.ID.toi_type = INFO_TYPE_PROVIDER;
135 req.ID.toi_id = IP_MIB_STATS_ID;
136 req.ID.toi_entity = *ent;
137
138 status = DeviceIoControl( tcpFile,
139 IOCTL_TCP_QUERY_INFORMATION_EX,
140 &req,
141 sizeof(req),
142 entry,
143 sizeof(*entry),
144 &returnSize,
145 NULL );
146
147 TRACE("TdiGetMibForIpEntity() => {\n"
148 " ipsi_forwarding ............ %d\n"
149 " ipsi_defaultttl ............ %d\n"
150 " ipsi_inreceives ............ %d\n"
151 " ipsi_indelivers ............ %d\n"
152 " ipsi_outrequests ........... %d\n"
153 " ipsi_routingdiscards ....... %d\n"
154 " ipsi_outdiscards ........... %d\n"
155 " ipsi_outnoroutes ........... %d\n"
156 " ipsi_numif ................. %d\n"
157 " ipsi_numaddr ............... %d\n"
158 " ipsi_numroutes ............. %d\n"
159 "} status %08x\n",
160 entry->ipsi_forwarding,
161 entry->ipsi_defaultttl,
162 entry->ipsi_inreceives,
163 entry->ipsi_indelivers,
164 entry->ipsi_outrequests,
165 entry->ipsi_routingdiscards,
166 entry->ipsi_outdiscards,
167 entry->ipsi_outnoroutes,
168 entry->ipsi_numif,
169 entry->ipsi_numaddr,
170 entry->ipsi_numroutes,
171 status);
172
173 return status;
174 }
175
176 NTSTATUS tdiGetRoutesForIpEntity
177 ( HANDLE tcpFile, TDIEntityID *ent, IPRouteEntry **routes, PDWORD numRoutes ) {
178 NTSTATUS status = STATUS_SUCCESS;
179
180 TRACE("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
181 (DWORD)tcpFile, ent->tei_instance);
182
183 status = tdiGetSetOfThings( tcpFile,
184 INFO_CLASS_PROTOCOL,
185 INFO_TYPE_PROVIDER,
186 IP_MIB_ROUTETABLE_ENTRY_ID,
187 ent->tei_entity,
188 0,
189 0,
190 sizeof(IPRouteEntry),
191 (PVOID *)routes,
192 numRoutes);
193
194 return status;
195 }
196
197 NTSTATUS tdiGetIpAddrsForIpEntity
198 ( HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs, PDWORD numAddrs ) {
199 NTSTATUS status;
200
201 TRACE("TdiGetIpAddrsForIpEntity(tcpFile %x,entityId %x)\n",
202 (DWORD)tcpFile, ent->tei_instance);
203
204 status = tdiGetSetOfThings( tcpFile,
205 INFO_CLASS_PROTOCOL,
206 INFO_TYPE_PROVIDER,
207 IP_MIB_ADDRTABLE_ENTRY_ID,
208 ent->tei_entity,
209 0,
210 0,
211 sizeof(IPAddrEntry),
212 (PVOID *)addrs,
213 numAddrs );
214
215 return status;
216 }
217
218 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
219 {
220 if (!name)
221 return ERROR_INVALID_PARAMETER;
222 if (!entry)
223 return ERROR_INVALID_PARAMETER;
224
225 return NO_ERROR;
226 }
227
228 DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry)
229 {
230 return ERROR_INVALID_PARAMETER;
231 }
232
233 DWORD getICMPStats(MIB_ICMP *stats)
234 {
235 FILE *fp;
236
237 if (!stats)
238 return ERROR_INVALID_PARAMETER;
239
240 memset(stats, 0, sizeof(MIB_ICMP));
241 /* get most of these stats from /proc/net/snmp, no error if can't */
242 fp = fopen("/proc/net/snmp", "r");
243 if (fp) {
244 const char hdr[] = "Icmp:";
245 char buf[512] = { 0 }, *ptr;
246
247 do {
248 ptr = fgets(buf, sizeof(buf), fp);
249 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
250 if (ptr) {
251 /* last line was a header, get another */
252 ptr = fgets(buf, sizeof(buf), fp);
253 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
254 char *endPtr;
255
256 ptr += sizeof(hdr);
257 if (ptr && *ptr) {
258 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
259 ptr = endPtr;
260 }
261 if (ptr && *ptr) {
262 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
263 ptr = endPtr;
264 }
265 if (ptr && *ptr) {
266 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
267 ptr = endPtr;
268 }
269 if (ptr && *ptr) {
270 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
271 ptr = endPtr;
272 }
273 if (ptr && *ptr) {
274 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
275 ptr = endPtr;
276 }
277 if (ptr && *ptr) {
278 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
279 ptr = endPtr;
280 }
281 if (ptr && *ptr) {
282 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
283 ptr = endPtr;
284 }
285 if (ptr && *ptr) {
286 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
287 ptr = endPtr;
288 }
289 if (ptr && *ptr) {
290 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
291 ptr = endPtr;
292 }
293 if (ptr && *ptr) {
294 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
295 ptr = endPtr;
296 }
297 if (ptr && *ptr) {
298 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
299 ptr = endPtr;
300 }
301 if (ptr && *ptr) {
302 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
303 ptr = endPtr;
304 }
305 if (ptr && *ptr) {
306 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
307 ptr = endPtr;
308 }
309 if (ptr && *ptr) {
310 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
311 ptr = endPtr;
312 }
313 if (ptr && *ptr) {
314 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
315 ptr = endPtr;
316 }
317 if (ptr && *ptr) {
318 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
319 ptr = endPtr;
320 }
321 if (ptr && *ptr) {
322 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
323 ptr = endPtr;
324 }
325 if (ptr && *ptr) {
326 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
327 ptr = endPtr;
328 }
329 if (ptr && *ptr) {
330 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
331 ptr = endPtr;
332 }
333 if (ptr && *ptr) {
334 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
335 ptr = endPtr;
336 }
337 if (ptr && *ptr) {
338 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
339 ptr = endPtr;
340 }
341 if (ptr && *ptr) {
342 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
343 ptr = endPtr;
344 }
345 if (ptr && *ptr) {
346 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
347 ptr = endPtr;
348 }
349 if (ptr && *ptr) {
350 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
351 ptr = endPtr;
352 }
353 }
354 }
355 fclose(fp);
356 }
357 return NO_ERROR;
358 }
359
360 DWORD getIPStats(PMIB_IPSTATS stats, DWORD family)
361 {
362 if (!stats)
363 return ERROR_INVALID_PARAMETER;
364 return NO_ERROR;
365 }
366
367 DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family)
368 {
369 if (!stats)
370 return ERROR_INVALID_PARAMETER;
371 return NO_ERROR;
372 }
373
374 DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family)
375 {
376 if (!stats)
377 return ERROR_INVALID_PARAMETER;
378 return NO_ERROR;
379 }
380
381 static DWORD getNumWithOneHeader(const char *filename)
382 {
383 return 0;
384 }
385
386 DWORD getNumRoutes(void)
387 {
388 DWORD numEntities, numRoutes = 0;
389 TDIEntityID *entitySet;
390 HANDLE tcpFile;
391 int i;
392 NTSTATUS status;
393
394 TRACE("called.\n");
395
396 status = openTcpFile( &tcpFile );
397
398 if( !NT_SUCCESS(status) ) {
399 TRACE("failure: %08x\n", (int)status );
400 return 0;
401 }
402
403 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
404
405 if( !NT_SUCCESS(status) ) {
406 TRACE("failure: %08x\n", (int)status );
407 return 0;
408 }
409
410 for( i = 0; i < numEntities; i++ ) {
411 if( isIpEntity( tcpFile, &entitySet[i] ) ) {
412 IPSNMPInfo isnmp;
413 memset( &isnmp, 0, sizeof( isnmp ) );
414 status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp );
415 if( !NT_SUCCESS(status) ) {
416 tdiFreeThingSet( entitySet );
417 return status;
418 }
419 numRoutes += isnmp.ipsi_numroutes;
420 }
421 }
422
423 TRACE("numRoutes: %d\n", (int)numRoutes);
424
425 closeTcpFile( tcpFile );
426
427 return numRoutes;
428 }
429
430 VOID HexDump( PCHAR Data, DWORD Len ) {
431 int i;
432
433 for( i = 0; i < Len; i++ ) {
434 if( !(i & 0xf) ) {
435 if( i ) fprintf(stderr,"\n");
436 fprintf(stderr,"%08x:", i);
437 }
438 fprintf( stderr, " %02x", Data[i] & 0xff );
439 }
440 fprintf(stderr,"\n");
441 }
442
443 RouteTable *getRouteTable(void)
444 {
445 RouteTable *out_route_table;
446 DWORD numRoutes = getNumRoutes(), routesAdded = 0;
447 IPSNMPInfo snmpInfo;
448 TDIEntityID ent;
449 HANDLE tcpFile;
450 NTSTATUS status = openTcpFile( &tcpFile );
451 int i;
452
453 if( !NT_SUCCESS(status) )
454 return 0;
455
456 TRACE("GETTING ROUTE TABLE\n");
457
458 out_route_table = HeapAlloc( GetProcessHeap(), 0,
459 sizeof(RouteTable) +
460 (sizeof(RouteEntry) * (numRoutes - 1)) );
461
462 out_route_table->numRoutes = numRoutes;
463
464 for( i = 0; routesAdded < numRoutes; i++ ) {
465 int j;
466 IPRouteEntry *route_set;
467
468 getNthIpEntity( tcpFile, i, &ent );
469 tdiGetMibForIpEntity( tcpFile, &ent, &snmpInfo );
470
471 TRACE( "%d routes in instance %d\n", snmpInfo.ipsi_numroutes, i );
472
473 tdiGetRoutesForIpEntity( tcpFile, &ent, &route_set, &numRoutes );
474
475 if( !route_set ) {
476 closeTcpFile( tcpFile );
477 HeapFree( GetProcessHeap(), 0, out_route_table );
478 return 0;
479 }
480
481 TRACE("Route set returned\n");
482 #if 0
483 HexDump( route_set,
484 sizeof( IPRouteEntry ) *
485 snmpInfo.ipsi_numroutes );
486 #endif
487
488 for( j = 0; j < snmpInfo.ipsi_numroutes; j++ ) {
489 int routeNum = j + routesAdded;
490 out_route_table->routes[routeNum].dest =
491 route_set[j].ire_dest;
492 out_route_table->routes[routeNum].mask =
493 route_set[j].ire_mask;
494 out_route_table->routes[routeNum].gateway =
495 route_set[j].ire_gw;
496 out_route_table->routes[routeNum].ifIndex =
497 route_set[j].ire_index;
498 out_route_table->routes[routeNum].metric =
499 route_set[j].ire_metric1;
500 }
501
502 if( route_set ) tdiFreeThingSet( route_set );
503
504 routesAdded += snmpInfo.ipsi_numroutes;
505 }
506
507 TRACE("Return: %08x, %08x\n", status, out_route_table);
508
509 return out_route_table;
510 }
511
512 DWORD getNumArpEntries(void)
513 {
514 DWORD numEntities;
515 TDIEntityID *entitySet = NULL;
516 HANDLE tcpFile;
517 int i, totalNumber = 0;
518 NTSTATUS status;
519 PMIB_IPNETROW IpArpTable = NULL;
520 DWORD returnSize;
521
522 TRACE("called.\n");
523
524 status = openTcpFile( &tcpFile );
525
526 if( !NT_SUCCESS(status) ) {
527 TRACE("failure: %08x\n", (int)status );
528 return 0;
529 }
530
531 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
532
533 for( i = 0; i < numEntities; i++ ) {
534 if( isInterface( &entitySet[i] ) &&
535 hasArp( tcpFile, &entitySet[i] ) ) {
536
537 status = tdiGetSetOfThings( tcpFile,
538 INFO_CLASS_PROTOCOL,
539 INFO_TYPE_PROVIDER,
540 IP_MIB_ARPTABLE_ENTRY_ID,
541 AT_ENTITY,
542 entitySet[i].tei_instance,
543 0,
544 sizeof(MIB_IPNETROW),
545 (PVOID *)&IpArpTable,
546 &returnSize );
547
548 if( status == STATUS_SUCCESS ) totalNumber += returnSize;
549 if( IpArpTable ) tdiFreeThingSet( IpArpTable );
550 }
551 }
552
553 closeTcpFile( tcpFile );
554 if( IpArpTable ) tdiFreeThingSet( IpArpTable );
555 if( entitySet ) tdiFreeThingSet( entitySet );
556 return totalNumber;
557 }
558
559 PMIB_IPNETTABLE getArpTable(void)
560 {
561 DWORD numEntities, returnSize;
562 TDIEntityID *entitySet;
563 HANDLE tcpFile;
564 int i, row = 0, totalNumber;
565 NTSTATUS status;
566 PMIB_IPNETTABLE IpArpTable = NULL;
567 PMIB_IPNETROW AdapterArpTable = NULL;
568
569 TRACE("called.\n");
570
571 totalNumber = getNumArpEntries();
572
573 status = openTcpFile( &tcpFile );
574
575 if( !NT_SUCCESS(status) ) {
576 TRACE("failure: %08x\n", (int)status );
577 return 0;
578 }
579
580 IpArpTable = HeapAlloc
581 ( GetProcessHeap(), 0,
582 sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber) );
583
584 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
585
586 for( i = 0; i < numEntities; i++ ) {
587 if( isIpEntity( tcpFile, &entitySet[i] ) &&
588 hasArp( tcpFile, &entitySet[i] ) ) {
589
590 status = tdiGetSetOfThings( tcpFile,
591 INFO_CLASS_PROTOCOL,
592 INFO_TYPE_PROVIDER,
593 IP_MIB_ARPTABLE_ENTRY_ID,
594 AT_ENTITY,
595 entitySet[i].tei_instance,
596 0,
597 sizeof(MIB_IPNETROW),
598 (PVOID *)&AdapterArpTable,
599 &returnSize );
600
601 if( status == STATUS_SUCCESS ) {
602 for( row = 0; row < returnSize; row++ )
603 IpArpTable->table[row] = AdapterArpTable[row];
604 }
605
606 if( AdapterArpTable ) tdiFreeThingSet( AdapterArpTable );
607 }
608 }
609
610 tdiFreeThingSet( entitySet );
611 IpArpTable->dwNumEntries = row;
612
613 return IpArpTable;
614 }
615
616 DWORD getNumUdpEntries(void)
617 {
618 return getNumWithOneHeader("/proc/net/udp");
619 }
620
621 PMIB_UDPTABLE getUdpTable(void)
622 {
623 DWORD numEntries = getNumUdpEntries();
624 PMIB_UDPTABLE ret;
625
626 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
627 (numEntries - 1) * sizeof(MIB_UDPROW));
628 if (ret) {
629 FILE *fp;
630
631 /* get from /proc/net/udp, no error if can't */
632 fp = fopen("/proc/net/udp", "r");
633 if (fp) {
634 char buf[512] = { 0 }, *ptr;
635
636 /* skip header line */
637 ptr = fgets(buf, sizeof(buf), fp);
638 while (ptr && ret->dwNumEntries < numEntries) {
639 ptr = fgets(buf, sizeof(buf), fp);
640 if (ptr) {
641 char *endPtr;
642
643 if (ptr && *ptr) {
644 strtoul(ptr, &endPtr, 16); /* skip */
645 ptr = endPtr;
646 }
647 if (ptr && *ptr) {
648 ptr++;
649 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
650 16);
651 ptr = endPtr;
652 }
653 if (ptr && *ptr) {
654 ptr++;
655 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
656 16);
657 ptr = endPtr;
658 }
659 ret->dwNumEntries++;
660 }
661 }
662 fclose(fp);
663 }
664 }
665 return ret;
666 }
667
668 DWORD getNumTcpEntries(void)
669 {
670 return getNumWithOneHeader("/proc/net/tcp");
671 }
672
673 PMIB_TCPTABLE getTcpTable(void)
674 {
675 return 0;
676 }