iphlpapi: Implement getNumUdpEntries on FreeBSD.
[wine/gsoc_dplay.git] / dlls / iphlpapi / ipstats.c
blobfa2826df1962af46718a33118cf48a117eb4ef84
1 /* Copyright (C) 2003,2006 Juan Lang
2 * Copyright (C) 2007 TransGaming Technologies Inc.
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * This file implements statistics getting using the /proc filesystem exported
19 * by Linux, and maybe other OSes.
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43 #ifdef HAVE_NET_IF_H
44 #include <net/if.h>
45 #endif
46 #ifdef HAVE_NET_IF_TYPES_H
47 #include <net/if_types.h>
48 #endif
49 #ifdef HAVE_NET_ROUTE_H
50 #include <net/route.h>
51 #endif
52 #ifdef HAVE_NET_IF_ARP_H
53 #include <net/if_arp.h>
54 #endif
55 #ifdef HAVE_NETINET_TCP_H
56 #include <netinet/tcp.h>
57 #endif
58 #ifdef HAVE_NETINET_TCP_FSM_H
59 #include <netinet/tcp_fsm.h>
60 #endif
62 #ifdef HAVE_NETINET_IN_PCB_H
63 #include <netinet/in_pcb.h>
64 #endif
65 #ifdef HAVE_NETINET_TCP_VAR_H
66 #include <netinet/tcp_var.h>
67 #endif
68 #ifdef HAVE_NETINET_IP_VAR_H
69 #include <netinet/ip_var.h>
70 #endif
72 #ifdef HAVE_SYS_SYSCTL_H
73 #include <sys/sysctl.h>
74 #endif
76 #ifndef ROUNDUP
77 #define ROUNDUP(a) \
78 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
79 #endif
80 #ifndef ADVANCE
81 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
82 #endif
84 #include "windef.h"
85 #include "winbase.h"
86 #include "iprtrmib.h"
87 #include "ifenum.h"
88 #include "ipstats.h"
90 #ifndef HAVE_NETINET_TCP_FSM_H
91 #define TCPS_ESTABLISHED 1
92 #define TCPS_SYN_SENT 2
93 #define TCPS_SYN_RECEIVED 3
94 #define TCPS_FIN_WAIT_1 4
95 #define TCPS_FIN_WAIT_2 5
96 #define TCPS_TIME_WAIT 6
97 #define TCPS_CLOSED 7
98 #define TCPS_CLOSE_WAIT 8
99 #define TCPS_LAST_ACK 9
100 #define TCPS_LISTEN 10
101 #define TCPS_CLOSING 11
102 #endif
104 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
106 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
108 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
109 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
110 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
112 size_t needed;
113 char *buf, *end;
114 struct if_msghdr *ifm;
115 struct if_data ifdata;
116 if (!name || !entry)
117 return ERROR_INVALID_PARAMETER;
119 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
121 ERR ("failed to get size of iflist\n");
122 return ERROR_NOT_SUPPORTED;
124 buf = HeapAlloc (GetProcessHeap (), 0, needed);
125 if (!buf) return ERROR_NOT_SUPPORTED;
126 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
128 ERR ("failed to get iflist\n");
129 HeapFree (GetProcessHeap (), 0, buf);
130 return ERROR_NOT_SUPPORTED;
132 else
133 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
135 ifm = (struct if_msghdr *) buf;
136 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
138 ifdata = ifm->ifm_data;
139 entry->dwMtu = ifdata.ifi_mtu;
140 entry->dwSpeed = ifdata.ifi_baudrate;
141 entry->dwInOctets = ifdata.ifi_ibytes;
142 entry->dwInErrors = ifdata.ifi_ierrors;
143 entry->dwInDiscards = ifdata.ifi_iqdrops;
144 entry->dwInUcastPkts = ifdata.ifi_ipackets;
145 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
146 entry->dwOutOctets = ifdata.ifi_obytes;
147 entry->dwOutUcastPkts = ifdata.ifi_opackets;
148 entry->dwOutErrors = ifdata.ifi_oerrors;
149 HeapFree (GetProcessHeap (), 0, buf);
150 return NO_ERROR;
153 HeapFree (GetProcessHeap (), 0, buf);
154 return ERROR_NOT_SUPPORTED;
155 #else
156 /* get interface stats from /proc/net/dev, no error if can't
157 no inUnknownProtos, outNUcastPkts, outQLen */
158 FILE *fp;
160 if (!name || !entry)
161 return ERROR_INVALID_PARAMETER;
162 fp = fopen("/proc/net/dev", "r");
163 if (fp) {
164 char buf[512] = { 0 }, *ptr;
165 int nameLen = strlen(name), nameFound = 0;
168 ptr = fgets(buf, sizeof(buf), fp);
169 while (ptr && !nameFound) {
170 while (*ptr && isspace(*ptr))
171 ptr++;
172 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
173 nameFound = 1;
174 else
175 ptr = fgets(buf, sizeof(buf), fp);
177 if (nameFound) {
178 char *endPtr;
180 ptr += nameLen + 1;
181 if (ptr && *ptr) {
182 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
183 ptr = endPtr;
185 if (ptr && *ptr) {
186 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
187 ptr = endPtr;
189 if (ptr && *ptr) {
190 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
191 ptr = endPtr;
193 if (ptr && *ptr) {
194 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
195 ptr = endPtr;
197 if (ptr && *ptr) {
198 strtoul(ptr, &endPtr, 10); /* skip */
199 ptr = endPtr;
201 if (ptr && *ptr) {
202 strtoul(ptr, &endPtr, 10); /* skip */
203 ptr = endPtr;
205 if (ptr && *ptr) {
206 strtoul(ptr, &endPtr, 10); /* skip */
207 ptr = endPtr;
209 if (ptr && *ptr) {
210 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
211 ptr = endPtr;
213 if (ptr && *ptr) {
214 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
215 ptr = endPtr;
217 if (ptr && *ptr) {
218 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
219 ptr = endPtr;
221 if (ptr && *ptr) {
222 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
223 ptr = endPtr;
225 if (ptr && *ptr) {
226 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
227 ptr = endPtr;
230 fclose(fp);
232 else
234 ERR ("unimplemented!\n");
235 return ERROR_NOT_SUPPORTED;
238 return NO_ERROR;
239 #endif
242 DWORD getICMPStats(MIB_ICMP *stats)
244 FILE *fp;
246 if (!stats)
247 return ERROR_INVALID_PARAMETER;
249 memset(stats, 0, sizeof(MIB_ICMP));
250 /* get most of these stats from /proc/net/snmp, no error if can't */
251 fp = fopen("/proc/net/snmp", "r");
252 if (fp) {
253 static const char hdr[] = "Icmp:";
254 char buf[512] = { 0 }, *ptr;
256 do {
257 ptr = fgets(buf, sizeof(buf), fp);
258 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
259 if (ptr) {
260 /* last line was a header, get another */
261 ptr = fgets(buf, sizeof(buf), fp);
262 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
263 char *endPtr;
265 ptr += sizeof(hdr);
266 if (ptr && *ptr) {
267 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
268 ptr = endPtr;
270 if (ptr && *ptr) {
271 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
272 ptr = endPtr;
274 if (ptr && *ptr) {
275 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
276 ptr = endPtr;
278 if (ptr && *ptr) {
279 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
280 ptr = endPtr;
282 if (ptr && *ptr) {
283 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
284 ptr = endPtr;
286 if (ptr && *ptr) {
287 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
288 ptr = endPtr;
290 if (ptr && *ptr) {
291 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
292 ptr = endPtr;
294 if (ptr && *ptr) {
295 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
296 ptr = endPtr;
298 if (ptr && *ptr) {
299 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
300 ptr = endPtr;
302 if (ptr && *ptr) {
303 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
304 ptr = endPtr;
306 if (ptr && *ptr) {
307 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
308 ptr = endPtr;
310 if (ptr && *ptr) {
311 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
312 ptr = endPtr;
314 if (ptr && *ptr) {
315 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
316 ptr = endPtr;
318 if (ptr && *ptr) {
319 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
320 ptr = endPtr;
322 if (ptr && *ptr) {
323 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
324 ptr = endPtr;
326 if (ptr && *ptr) {
327 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
328 ptr = endPtr;
330 if (ptr && *ptr) {
331 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
332 ptr = endPtr;
334 if (ptr && *ptr) {
335 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
336 ptr = endPtr;
338 if (ptr && *ptr) {
339 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
340 ptr = endPtr;
342 if (ptr && *ptr) {
343 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
344 ptr = endPtr;
346 if (ptr && *ptr) {
347 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
348 ptr = endPtr;
350 if (ptr && *ptr) {
351 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
352 ptr = endPtr;
354 if (ptr && *ptr) {
355 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
356 ptr = endPtr;
358 if (ptr && *ptr) {
359 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
360 ptr = endPtr;
364 fclose(fp);
366 else
368 ERR ("unimplemented!\n");
369 return ERROR_NOT_SUPPORTED;
372 return NO_ERROR;
375 DWORD getIPStats(PMIB_IPSTATS stats)
377 FILE *fp;
379 if (!stats)
380 return ERROR_INVALID_PARAMETER;
382 memset(stats, 0, sizeof(MIB_IPSTATS));
383 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
384 stats->dwNumRoutes = getNumRoutes();
386 /* get most of these stats from /proc/net/snmp, no error if can't */
387 fp = fopen("/proc/net/snmp", "r");
388 if (fp) {
389 static const char hdr[] = "Ip:";
390 char buf[512] = { 0 }, *ptr;
392 do {
393 ptr = fgets(buf, sizeof(buf), fp);
394 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
395 if (ptr) {
396 /* last line was a header, get another */
397 ptr = fgets(buf, sizeof(buf), fp);
398 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
399 char *endPtr;
401 ptr += sizeof(hdr);
402 if (ptr && *ptr) {
403 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
404 ptr = endPtr;
406 if (ptr && *ptr) {
407 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
408 ptr = endPtr;
410 if (ptr && *ptr) {
411 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
412 ptr = endPtr;
414 if (ptr && *ptr) {
415 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
416 ptr = endPtr;
418 if (ptr && *ptr) {
419 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
420 ptr = endPtr;
422 if (ptr && *ptr) {
423 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
424 ptr = endPtr;
426 if (ptr && *ptr) {
427 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
428 ptr = endPtr;
430 if (ptr && *ptr) {
431 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
432 ptr = endPtr;
434 if (ptr && *ptr) {
435 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
436 ptr = endPtr;
438 if (ptr && *ptr) {
439 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
440 ptr = endPtr;
442 if (ptr && *ptr) {
443 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
444 ptr = endPtr;
446 if (ptr && *ptr) {
447 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
448 ptr = endPtr;
450 if (ptr && *ptr) {
451 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
452 ptr = endPtr;
454 if (ptr && *ptr) {
455 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
456 ptr = endPtr;
458 if (ptr && *ptr) {
459 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
460 ptr = endPtr;
462 if (ptr && *ptr) {
463 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
464 ptr = endPtr;
466 if (ptr && *ptr) {
467 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
468 ptr = endPtr;
470 if (ptr && *ptr) {
471 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
472 ptr = endPtr;
474 if (ptr && *ptr) {
475 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
476 ptr = endPtr;
478 /* hmm, no routingDiscards */
481 fclose(fp);
483 else
485 ERR ("unimplemented!\n");
486 return ERROR_NOT_SUPPORTED;
489 return NO_ERROR;
492 DWORD getTCPStats(MIB_TCPSTATS *stats)
494 FILE *fp;
496 if (!stats)
497 return ERROR_INVALID_PARAMETER;
499 memset(stats, 0, sizeof(MIB_TCPSTATS));
501 /* get from /proc/net/snmp, no error if can't */
502 fp = fopen("/proc/net/snmp", "r");
503 if (fp) {
504 static const char hdr[] = "Tcp:";
505 char buf[512] = { 0 }, *ptr;
508 do {
509 ptr = fgets(buf, sizeof(buf), fp);
510 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
511 if (ptr) {
512 /* last line was a header, get another */
513 ptr = fgets(buf, sizeof(buf), fp);
514 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
515 char *endPtr;
517 ptr += sizeof(hdr);
518 if (ptr && *ptr) {
519 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
520 ptr = endPtr;
522 if (ptr && *ptr) {
523 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
524 ptr = endPtr;
526 if (ptr && *ptr) {
527 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
528 ptr = endPtr;
530 if (ptr && *ptr) {
531 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
532 ptr = endPtr;
534 if (ptr && *ptr) {
535 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
536 ptr = endPtr;
538 if (ptr && *ptr) {
539 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
540 ptr = endPtr;
542 if (ptr && *ptr) {
543 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
544 ptr = endPtr;
546 if (ptr && *ptr) {
547 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
548 ptr = endPtr;
550 if (ptr && *ptr) {
551 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
552 ptr = endPtr;
554 if (ptr && *ptr) {
555 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
556 ptr = endPtr;
558 if (ptr && *ptr) {
559 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
560 ptr = endPtr;
562 if (ptr && *ptr) {
563 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
564 ptr = endPtr;
566 if (ptr && *ptr) {
567 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
568 ptr = endPtr;
570 if (ptr && *ptr) {
571 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
572 ptr = endPtr;
574 stats->dwNumConns = getNumTcpEntries();
577 fclose(fp);
579 else
581 ERR ("unimplemented!\n");
582 return ERROR_NOT_SUPPORTED;
585 return NO_ERROR;
588 DWORD getUDPStats(MIB_UDPSTATS *stats)
590 FILE *fp;
592 if (!stats)
593 return ERROR_INVALID_PARAMETER;
595 memset(stats, 0, sizeof(MIB_UDPSTATS));
597 /* get from /proc/net/snmp, no error if can't */
598 fp = fopen("/proc/net/snmp", "r");
599 if (fp) {
600 static const char hdr[] = "Udp:";
601 char buf[512] = { 0 }, *ptr;
604 do {
605 ptr = fgets(buf, sizeof(buf), fp);
606 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
607 if (ptr) {
608 /* last line was a header, get another */
609 ptr = fgets(buf, sizeof(buf), fp);
610 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
611 char *endPtr;
613 ptr += sizeof(hdr);
614 if (ptr && *ptr) {
615 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
616 ptr = endPtr;
618 if (ptr && *ptr) {
619 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
620 ptr = endPtr;
622 if (ptr && *ptr) {
623 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
624 ptr = endPtr;
626 if (ptr && *ptr) {
627 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
628 ptr = endPtr;
630 if (ptr && *ptr) {
631 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
632 ptr = endPtr;
636 fclose(fp);
638 else
640 ERR ("unimplemented!\n");
641 return ERROR_NOT_SUPPORTED;
644 return NO_ERROR;
647 static DWORD getNumWithOneHeader(const char *filename)
649 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
650 size_t Len = 0;
651 char *Buf;
652 struct xinpgen *pXIG, *pOrigXIG;
653 int Protocol;
654 DWORD NumEntries = 0;
656 if (!strcmp (filename, "net.inet.tcp.pcblist"))
657 Protocol = IPPROTO_TCP;
658 else if (!strcmp (filename, "net.inet.udp.pcblist"))
659 Protocol = IPPROTO_UDP;
660 else
662 ERR ("Unsupported mib '%s', needs protocol mapping\n",
663 filename);
664 return 0;
667 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
669 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
670 return 0;
673 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
674 if (!Buf)
676 ERR ("Out of memory!\n");
677 return 0;
680 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
682 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
683 HeapFree (GetProcessHeap (), 0, Buf);
684 return 0;
687 /* Might be nothing here; first entry is just a header it seems */
688 if (Len <= sizeof (struct xinpgen))
690 HeapFree (GetProcessHeap (), 0, Buf);
691 return 0;
694 pOrigXIG = (struct xinpgen *)Buf;
695 pXIG = pOrigXIG;
697 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
698 pXIG->xig_len > sizeof (struct xinpgen);
699 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
701 struct tcpcb *pTCPData = NULL;
702 struct inpcb *pINData;
703 struct xsocket *pSockData;
705 if (Protocol == IPPROTO_TCP)
707 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
708 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
709 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
711 else
713 pINData = &((struct xinpcb *)pXIG)->xi_inp;
714 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
717 /* Ignore sockets for other protocols */
718 if (pSockData->xso_protocol != Protocol)
719 continue;
721 /* Ignore PCBs that were freed while generating the data */
722 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
723 continue;
725 /* we're only interested in IPv4 addresses */
726 if (!(pINData->inp_vflag & INP_IPV4) ||
727 (pINData->inp_vflag & INP_IPV6))
728 continue;
730 /* If all 0's, skip it */
731 if (!pINData->inp_laddr.s_addr &&
732 !pINData->inp_lport &&
733 !pINData->inp_faddr.s_addr &&
734 !pINData->inp_fport)
735 continue;
737 NumEntries++;
740 HeapFree (GetProcessHeap (), 0, Buf);
741 return NumEntries;
742 #else
743 FILE *fp;
744 int ret = 0;
746 fp = fopen(filename, "r");
747 if (fp) {
748 char buf[512] = { 0 }, *ptr;
751 ptr = fgets(buf, sizeof(buf), fp);
752 if (ptr) {
753 do {
754 ptr = fgets(buf, sizeof(buf), fp);
755 if (ptr)
756 ret++;
757 } while (ptr);
759 fclose(fp);
761 else
762 ERR ("Unable to open '%s' to count entries!\n", filename);
764 return ret;
765 #endif
768 DWORD getNumRoutes(void)
770 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
771 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
772 size_t needed;
773 char *buf, *lim, *next;
774 struct rt_msghdr *rtm;
775 DWORD RouteCount = 0;
777 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
779 ERR ("sysctl 1 failed!\n");
780 return 0;
783 buf = HeapAlloc (GetProcessHeap (), 0, needed);
784 if (!buf) return 0;
786 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
788 ERR ("sysctl 2 failed!\n");
789 HeapFree (GetProcessHeap (), 0, buf);
790 return 0;
793 lim = buf + needed;
794 for (next = buf; next < lim; next += rtm->rtm_msglen)
796 rtm = (struct rt_msghdr *)next;
798 if (rtm->rtm_type != RTM_GET)
800 WARN ("Got unexpected message type 0x%x!\n",
801 rtm->rtm_type);
802 continue;
805 /* Ignore all entries except for gateway routes which aren't
806 multicast */
807 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
808 continue;
810 RouteCount++;
813 HeapFree (GetProcessHeap (), 0, buf);
814 return RouteCount;
815 #else
816 return getNumWithOneHeader("/proc/net/route");
817 #endif
820 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
821 DWORD flags)
823 DWORD ret;
825 if (!ppIpForwardTable)
826 ret = ERROR_INVALID_PARAMETER;
827 else {
828 DWORD numRoutes = getNumRoutes();
829 DWORD size = sizeof(MIB_IPFORWARDTABLE);
830 PMIB_IPFORWARDTABLE table;
832 if (numRoutes > 1)
833 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
834 table = HeapAlloc(heap, flags, size);
835 if (table) {
836 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
837 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
838 size_t needed;
839 char *buf, *lim, *next, *addrPtr;
840 struct rt_msghdr *rtm;
842 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
844 ERR ("sysctl 1 failed!\n");
845 HeapFree (GetProcessHeap (), 0, table);
846 return NO_ERROR;
849 buf = HeapAlloc (GetProcessHeap (), 0, needed);
850 if (!buf)
852 HeapFree (GetProcessHeap (), 0, table);
853 return ERROR_OUTOFMEMORY;
856 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
858 ERR ("sysctl 2 failed!\n");
859 HeapFree (GetProcessHeap (), 0, table);
860 HeapFree (GetProcessHeap (), 0, buf);
861 return NO_ERROR;
864 *ppIpForwardTable = table;
865 table->dwNumEntries = 0;
867 lim = buf + needed;
868 for (next = buf; next < lim; next += rtm->rtm_msglen)
870 int i;
872 rtm = (struct rt_msghdr *)next;
874 if (rtm->rtm_type != RTM_GET)
876 WARN ("Got unexpected message type 0x%x!\n",
877 rtm->rtm_type);
878 continue;
881 /* Ignore all entries except for gateway routes which aren't
882 multicast */
883 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
884 (rtm->rtm_flags & RTF_MULTICAST))
885 continue;
887 memset (&table->table[table->dwNumEntries], 0,
888 sizeof (MIB_IPFORWARDROW));
889 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
890 table->table[table->dwNumEntries].dwForwardType =
891 MIB_IPROUTE_TYPE_INDIRECT;
892 table->table[table->dwNumEntries].dwForwardMetric1 =
893 rtm->rtm_rmx.rmx_hopcount;
894 table->table[table->dwNumEntries].dwForwardProto =
895 MIB_IPPROTO_LOCAL;
897 addrPtr = (char *)(rtm + 1);
899 for (i = 1; i; i <<= 1)
901 struct sockaddr *sa;
902 DWORD addr;
904 if (!(i & rtm->rtm_addrs))
905 continue;
907 sa = (struct sockaddr *)addrPtr;
908 ADVANCE (addrPtr, sa);
910 /* default routes are encoded by length-zero sockaddr */
911 if (sa->sa_len == 0)
912 addr = 0;
913 else if (sa->sa_family != AF_INET)
915 ERR ("Received unsupported sockaddr family 0x%x\n",
916 sa->sa_family);
917 addr = 0;
919 else
921 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
923 addr = sin->sin_addr.s_addr;
926 switch (i)
928 case RTA_DST:
929 table->table[table->dwNumEntries].dwForwardDest = addr;
930 break;
932 case RTA_GATEWAY:
933 table->table[table->dwNumEntries].dwForwardNextHop = addr;
934 break;
936 case RTA_NETMASK:
937 table->table[table->dwNumEntries].dwForwardMask = addr;
938 break;
940 default:
941 ERR ("Unexpected address type 0x%x\n", i);
945 table->dwNumEntries++;
948 HeapFree (GetProcessHeap (), 0, buf);
949 ret = NO_ERROR;
950 #else
951 FILE *fp;
953 ret = NO_ERROR;
954 *ppIpForwardTable = table;
955 table->dwNumEntries = 0;
956 /* get from /proc/net/route, no error if can't */
957 fp = fopen("/proc/net/route", "r");
958 if (fp) {
959 char buf[512] = { 0 }, *ptr;
961 /* skip header line */
962 ptr = fgets(buf, sizeof(buf), fp);
963 while (ptr && table->dwNumEntries < numRoutes) {
964 memset(&table->table[table->dwNumEntries], 0,
965 sizeof(MIB_IPFORWARDROW));
966 ptr = fgets(buf, sizeof(buf), fp);
967 if (ptr) {
968 DWORD index;
970 while (!isspace(*ptr))
971 ptr++;
972 *ptr = '\0';
973 ptr++;
974 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
975 char *endPtr;
977 table->table[table->dwNumEntries].dwForwardIfIndex = index;
978 if (*ptr) {
979 table->table[table->dwNumEntries].dwForwardDest =
980 strtoul(ptr, &endPtr, 16);
981 ptr = endPtr;
983 if (ptr && *ptr) {
984 table->table[table->dwNumEntries].dwForwardNextHop =
985 strtoul(ptr, &endPtr, 16);
986 ptr = endPtr;
988 if (ptr && *ptr) {
989 DWORD flags = strtoul(ptr, &endPtr, 16);
991 if (!(flags & RTF_UP))
992 table->table[table->dwNumEntries].dwForwardType =
993 MIB_IPROUTE_TYPE_INVALID;
994 else if (flags & RTF_GATEWAY)
995 table->table[table->dwNumEntries].dwForwardType =
996 MIB_IPROUTE_TYPE_INDIRECT;
997 else
998 table->table[table->dwNumEntries].dwForwardType =
999 MIB_IPROUTE_TYPE_DIRECT;
1000 ptr = endPtr;
1002 if (ptr && *ptr) {
1003 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1004 ptr = endPtr;
1006 if (ptr && *ptr) {
1007 strtoul(ptr, &endPtr, 16); /* use, skip */
1008 ptr = endPtr;
1010 if (ptr && *ptr) {
1011 table->table[table->dwNumEntries].dwForwardMetric1 =
1012 strtoul(ptr, &endPtr, 16);
1013 ptr = endPtr;
1015 if (ptr && *ptr) {
1016 table->table[table->dwNumEntries].dwForwardMask =
1017 strtoul(ptr, &endPtr, 16);
1018 ptr = endPtr;
1020 /* FIXME: other protos might be appropriate, e.g. the default
1021 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1022 table->table[table->dwNumEntries].dwForwardProto =
1023 MIB_IPPROTO_LOCAL;
1024 table->dwNumEntries++;
1028 fclose(fp);
1030 else
1032 ERR ("unimplemented!\n");
1033 return ERROR_NOT_SUPPORTED;
1035 #endif
1037 else
1038 ret = ERROR_OUTOFMEMORY;
1040 return ret;
1043 DWORD getNumArpEntries(void)
1045 return getNumWithOneHeader("/proc/net/arp");
1048 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1050 DWORD ret;
1052 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1053 ERR ("unimplemented!\n");
1054 return ERROR_NOT_SUPPORTED;
1055 #endif
1057 if (!ppIpNetTable)
1058 ret = ERROR_INVALID_PARAMETER;
1059 else {
1060 DWORD numEntries = getNumArpEntries();
1061 DWORD size = sizeof(MIB_IPNETTABLE);
1062 PMIB_IPNETTABLE table;
1064 if (numEntries > 1)
1065 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1066 table = HeapAlloc(heap, flags, size);
1067 if (table) {
1068 FILE *fp;
1070 ret = NO_ERROR;
1071 *ppIpNetTable = table;
1072 table->dwNumEntries = 0;
1073 /* get from /proc/net/arp, no error if can't */
1074 fp = fopen("/proc/net/arp", "r");
1075 if (fp) {
1076 char buf[512] = { 0 }, *ptr;
1078 /* skip header line */
1079 ptr = fgets(buf, sizeof(buf), fp);
1080 while (ptr && table->dwNumEntries < numEntries) {
1081 ptr = fgets(buf, sizeof(buf), fp);
1082 if (ptr) {
1083 char *endPtr;
1085 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1086 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1087 while (ptr && *ptr && !isspace(*ptr))
1088 ptr++;
1090 if (ptr && *ptr) {
1091 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1092 ptr = endPtr;
1094 if (ptr && *ptr) {
1095 DWORD flags = strtoul(ptr, &endPtr, 16);
1097 #ifdef ATF_COM
1098 if (flags & ATF_COM)
1099 table->table[table->dwNumEntries].dwType =
1100 MIB_IPNET_TYPE_DYNAMIC;
1101 else
1102 #endif
1103 #ifdef ATF_PERM
1104 if (flags & ATF_PERM)
1105 table->table[table->dwNumEntries].dwType =
1106 MIB_IPNET_TYPE_STATIC;
1107 else
1108 #endif
1109 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1111 ptr = endPtr;
1113 while (ptr && *ptr && isspace(*ptr))
1114 ptr++;
1115 while (ptr && *ptr && !isspace(*ptr)) {
1116 DWORD byte = strtoul(ptr, &endPtr, 16);
1118 if (endPtr && *endPtr) {
1119 endPtr++;
1120 table->table[table->dwNumEntries].bPhysAddr[
1121 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1122 byte & 0x0ff;
1124 ptr = endPtr;
1126 if (ptr && *ptr) {
1127 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1128 ptr = endPtr;
1130 getInterfaceIndexByName(ptr,
1131 &table->table[table->dwNumEntries].dwIndex);
1132 table->dwNumEntries++;
1135 fclose(fp);
1137 else
1138 ret = ERROR_NOT_SUPPORTED;
1140 else
1141 ret = ERROR_OUTOFMEMORY;
1143 return ret;
1146 DWORD getNumUdpEntries(void)
1148 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1149 return getNumWithOneHeader ("net.inet.udp.pcblist");
1150 #else
1151 return getNumWithOneHeader("/proc/net/udp");
1152 #endif
1155 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1157 DWORD ret;
1159 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1160 ERR ("unimplemented!\n");
1161 return ERROR_NOT_SUPPORTED;
1162 #endif
1164 if (!ppUdpTable)
1165 ret = ERROR_INVALID_PARAMETER;
1166 else {
1167 DWORD numEntries = getNumUdpEntries();
1168 DWORD size = sizeof(MIB_UDPTABLE);
1169 PMIB_UDPTABLE table;
1171 if (numEntries > 1)
1172 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1173 table = HeapAlloc(heap, flags, size);
1174 if (table) {
1175 FILE *fp;
1177 ret = NO_ERROR;
1178 *ppUdpTable = table;
1179 table->dwNumEntries = 0;
1180 /* get from /proc/net/udp, no error if can't */
1181 fp = fopen("/proc/net/udp", "r");
1182 if (fp) {
1183 char buf[512] = { 0 }, *ptr;
1185 /* skip header line */
1186 ptr = fgets(buf, sizeof(buf), fp);
1187 while (ptr && table->dwNumEntries < numEntries) {
1188 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1189 ptr = fgets(buf, sizeof(buf), fp);
1190 if (ptr) {
1191 char *endPtr;
1193 if (ptr && *ptr) {
1194 strtoul(ptr, &endPtr, 16); /* skip */
1195 ptr = endPtr;
1197 if (ptr && *ptr) {
1198 ptr++;
1199 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1200 &endPtr, 16);
1201 ptr = endPtr;
1203 if (ptr && *ptr) {
1204 ptr++;
1205 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1206 &endPtr, 16);
1207 ptr = endPtr;
1209 table->dwNumEntries++;
1212 fclose(fp);
1214 else
1215 ret = ERROR_NOT_SUPPORTED;
1217 else
1218 ret = ERROR_OUTOFMEMORY;
1220 return ret;
1224 DWORD getNumTcpEntries(void)
1226 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1227 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1228 #else
1229 return getNumWithOneHeader ("/proc/net/tcp");
1230 #endif
1234 /* Why not a lookup table? Because the TCPS_* constants are different
1235 on different platforms */
1236 static DWORD TCPStateToMIBState (int state)
1238 switch (state)
1240 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1241 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1242 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1243 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1244 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1245 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1246 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1247 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1248 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1249 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1250 default:
1251 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1256 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1257 DWORD flags)
1259 DWORD numEntries;
1260 PMIB_TCPTABLE table;
1261 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1262 size_t Len = 0;
1263 char *Buf;
1264 struct xinpgen *pXIG, *pOrigXIG;
1265 #else
1266 FILE *fp;
1267 char buf[512] = { 0 }, *ptr;
1268 #endif
1270 if (!ppTcpTable)
1271 return ERROR_INVALID_PARAMETER;
1273 numEntries = getNumTcpEntries ();
1275 if (!*ppTcpTable)
1277 DWORD size = sizeof(MIB_TCPTABLE);
1279 if (numEntries > 1)
1280 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1281 *ppTcpTable = HeapAlloc (heap, flags, size);
1282 if (!*ppTcpTable)
1284 ERR ("Out of memory!\n");
1285 return ERROR_OUTOFMEMORY;
1287 maxEntries = numEntries;
1290 table = *ppTcpTable;
1291 table->dwNumEntries = 0;
1292 if (!numEntries)
1293 return NO_ERROR;
1295 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1297 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1299 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1300 return ERROR_OUTOFMEMORY;
1303 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1304 if (!Buf)
1306 ERR ("Out of memory!\n");
1307 return ERROR_OUTOFMEMORY;
1310 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1312 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1313 HeapFree (GetProcessHeap (), 0, Buf);
1314 return ERROR_OUTOFMEMORY;
1317 /* Might be nothing here; first entry is just a header it seems */
1318 if (Len <= sizeof (struct xinpgen))
1320 HeapFree (GetProcessHeap (), 0, Buf);
1321 return NO_ERROR;
1324 pOrigXIG = (struct xinpgen *)Buf;
1325 pXIG = pOrigXIG;
1327 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1328 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1329 (table->dwNumEntries < maxEntries);
1330 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1332 struct tcpcb *pTCPData = NULL;
1333 struct inpcb *pINData;
1334 struct xsocket *pSockData;
1336 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1337 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1338 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1340 /* Ignore sockets for other protocols */
1341 if (pSockData->xso_protocol != IPPROTO_TCP)
1342 continue;
1344 /* Ignore PCBs that were freed while generating the data */
1345 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1346 continue;
1348 /* we're only interested in IPv4 addresses */
1349 if (!(pINData->inp_vflag & INP_IPV4) ||
1350 (pINData->inp_vflag & INP_IPV6))
1351 continue;
1353 /* If all 0's, skip it */
1354 if (!pINData->inp_laddr.s_addr &&
1355 !pINData->inp_lport &&
1356 !pINData->inp_faddr.s_addr &&
1357 !pINData->inp_fport)
1358 continue;
1360 /* Fill in structure details */
1361 table->table[table->dwNumEntries].dwLocalAddr =
1362 pINData->inp_laddr.s_addr;
1363 table->table[table->dwNumEntries].dwLocalPort =
1364 pINData->inp_lport;
1365 table->table[table->dwNumEntries].dwRemoteAddr =
1366 pINData->inp_faddr.s_addr;
1367 table->table[table->dwNumEntries].dwRemotePort =
1368 pINData->inp_fport;
1369 table->table[table->dwNumEntries].dwState =
1370 TCPStateToMIBState (pTCPData->t_state);
1372 table->dwNumEntries++;
1375 HeapFree (GetProcessHeap (), 0, Buf);
1376 #else
1377 /* get from /proc/net/tcp, no error if can't */
1378 fp = fopen("/proc/net/tcp", "r");
1379 if (!fp)
1380 return ERROR_NOT_SUPPORTED;
1382 /* skip header line */
1383 ptr = fgets(buf, sizeof(buf), fp);
1384 while (ptr && table->dwNumEntries < maxEntries) {
1385 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1386 ptr = fgets(buf, sizeof(buf), fp);
1387 if (ptr) {
1388 char *endPtr;
1390 while (ptr && *ptr && *ptr != ':')
1391 ptr++;
1392 if (ptr && *ptr)
1393 ptr++;
1394 if (ptr && *ptr) {
1395 table->table[table->dwNumEntries].dwLocalAddr =
1396 strtoul(ptr, &endPtr, 16);
1397 ptr = endPtr;
1399 if (ptr && *ptr) {
1400 ptr++;
1401 table->table[table->dwNumEntries].dwLocalPort =
1402 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1403 ptr = endPtr;
1405 if (ptr && *ptr) {
1406 table->table[table->dwNumEntries].dwRemoteAddr =
1407 strtoul(ptr, &endPtr, 16);
1408 ptr = endPtr;
1410 if (ptr && *ptr) {
1411 ptr++;
1412 table->table[table->dwNumEntries].dwRemotePort =
1413 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1414 ptr = endPtr;
1416 if (ptr && *ptr) {
1417 DWORD state = strtoul(ptr, &endPtr, 16);
1419 table->table[table->dwNumEntries].dwState =
1420 TCPStateToMIBState (state);
1421 ptr = endPtr;
1423 table->dwNumEntries++;
1426 fclose(fp);
1427 #endif
1429 return NO_ERROR;