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