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.
23 #include "wine/port.h"
24 #include "wine/debug.h"
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
46 #ifdef HAVE_NET_ROUTE_H
47 #include <net/route.h>
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/tcp.h>
55 #ifdef HAVE_NETINET_TCP_FSM_H
56 #include <netinet/tcp_fsm.h>
59 #ifdef HAVE_NETINET_IN_PCB_H
60 #include <netinet/in_pcb.h>
62 #ifdef HAVE_NETINET_TCP_VAR_H
63 #include <netinet/tcp_var.h>
65 #ifdef HAVE_NETINET_IP_VAR_H
66 #include <netinet/ip_var.h>
69 #ifdef HAVE_SYS_SYSCTL_H
70 #include <sys/sysctl.h>
75 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
78 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
87 #ifndef HAVE_NETINET_TCP_FSM_H
88 #define TCPS_ESTABLISHED 1
89 #define TCPS_SYN_SENT 2
90 #define TCPS_SYN_RECEIVED 3
91 #define TCPS_FIN_WAIT_1 4
92 #define TCPS_FIN_WAIT_2 5
93 #define TCPS_TIME_WAIT 6
95 #define TCPS_CLOSE_WAIT 8
96 #define TCPS_LAST_ACK 9
97 #define TCPS_LISTEN 10
98 #define TCPS_CLOSING 11
101 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
103 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
108 return ERROR_INVALID_PARAMETER;
110 return ERROR_INVALID_PARAMETER;
112 /* get interface stats from /proc/net/dev, no error if can't
113 no inUnknownProtos, outNUcastPkts, outQLen */
114 fp = fopen("/proc/net/dev", "r");
116 char buf[512] = { 0 }, *ptr;
117 int nameLen = strlen(name), nameFound = 0;
120 ptr = fgets(buf, sizeof(buf), fp);
121 while (ptr && !nameFound) {
122 while (*ptr && isspace(*ptr))
124 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
127 ptr = fgets(buf, sizeof(buf), fp);
134 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
138 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
142 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
146 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
150 strtoul(ptr, &endPtr, 10); /* skip */
154 strtoul(ptr, &endPtr, 10); /* skip */
158 strtoul(ptr, &endPtr, 10); /* skip */
162 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
166 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
170 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
174 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
178 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
186 ERR ("unimplemented!\n");
187 return ERROR_NOT_SUPPORTED;
193 DWORD getICMPStats(MIB_ICMP *stats)
198 return ERROR_INVALID_PARAMETER;
200 memset(stats, 0, sizeof(MIB_ICMP));
201 /* get most of these stats from /proc/net/snmp, no error if can't */
202 fp = fopen("/proc/net/snmp", "r");
204 static const char hdr[] = "Icmp:";
205 char buf[512] = { 0 }, *ptr;
208 ptr = fgets(buf, sizeof(buf), fp);
209 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
211 /* last line was a header, get another */
212 ptr = fgets(buf, sizeof(buf), fp);
213 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
218 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
222 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
226 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
230 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
234 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
238 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
242 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
246 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
250 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
254 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
258 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
262 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
266 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
270 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
274 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
278 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
282 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
286 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
290 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
294 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
298 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
302 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
306 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
310 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
319 ERR ("unimplemented!\n");
320 return ERROR_NOT_SUPPORTED;
326 DWORD getIPStats(PMIB_IPSTATS stats)
331 return ERROR_INVALID_PARAMETER;
333 memset(stats, 0, sizeof(MIB_IPSTATS));
334 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
335 stats->dwNumRoutes = getNumRoutes();
337 /* get most of these stats from /proc/net/snmp, no error if can't */
338 fp = fopen("/proc/net/snmp", "r");
340 static const char hdr[] = "Ip:";
341 char buf[512] = { 0 }, *ptr;
344 ptr = fgets(buf, sizeof(buf), fp);
345 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
347 /* last line was a header, get another */
348 ptr = fgets(buf, sizeof(buf), fp);
349 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
354 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
358 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
362 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
366 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
370 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
374 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
378 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
382 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
386 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
390 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
394 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
398 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
402 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
406 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
410 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
414 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
418 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
422 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
426 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
429 /* hmm, no routingDiscards */
436 ERR ("unimplemented!\n");
437 return ERROR_NOT_SUPPORTED;
443 DWORD getTCPStats(MIB_TCPSTATS *stats)
448 return ERROR_INVALID_PARAMETER;
450 memset(stats, 0, sizeof(MIB_TCPSTATS));
452 /* get from /proc/net/snmp, no error if can't */
453 fp = fopen("/proc/net/snmp", "r");
455 static const char hdr[] = "Tcp:";
456 char buf[512] = { 0 }, *ptr;
460 ptr = fgets(buf, sizeof(buf), fp);
461 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
463 /* last line was a header, get another */
464 ptr = fgets(buf, sizeof(buf), fp);
465 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
470 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
474 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
478 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
482 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
486 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
490 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
494 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
498 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
502 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
506 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
510 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
514 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
518 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
522 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
525 stats->dwNumConns = getNumTcpEntries();
532 ERR ("unimplemented!\n");
533 return ERROR_NOT_SUPPORTED;
539 DWORD getUDPStats(MIB_UDPSTATS *stats)
544 return ERROR_INVALID_PARAMETER;
546 memset(stats, 0, sizeof(MIB_UDPSTATS));
548 /* get from /proc/net/snmp, no error if can't */
549 fp = fopen("/proc/net/snmp", "r");
551 static const char hdr[] = "Udp:";
552 char buf[512] = { 0 }, *ptr;
556 ptr = fgets(buf, sizeof(buf), fp);
557 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
559 /* last line was a header, get another */
560 ptr = fgets(buf, sizeof(buf), fp);
561 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
566 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
570 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
574 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
578 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
582 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
591 ERR ("unimplemented!\n");
592 return ERROR_NOT_SUPPORTED;
598 static DWORD getNumWithOneHeader(const char *filename)
600 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
603 struct xinpgen *pXIG, *pOrigXIG;
605 DWORD NumEntries = 0;
607 if (!strcmp (filename, "net.inet.tcp.pcblist"))
608 Protocol = IPPROTO_TCP;
609 else if (!strcmp (filename, "net.inet.udp.pcblist"))
610 Protocol = IPPROTO_UDP;
613 ERR ("Unsupported mib '%s', needs protocol mapping\n",
618 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
620 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
624 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
627 ERR ("Out of memory!\n");
631 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
633 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
634 HeapFree (GetProcessHeap (), 0, Buf);
638 /* Might be nothing here; first entry is just a header it seems */
639 if (Len <= sizeof (struct xinpgen))
641 HeapFree (GetProcessHeap (), 0, Buf);
645 pOrigXIG = (struct xinpgen *)Buf;
648 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
649 pXIG->xig_len > sizeof (struct xinpgen);
650 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
652 struct tcpcb *pTCPData = NULL;
653 struct inpcb *pINData;
654 struct xsocket *pSockData;
656 if (Protocol == IPPROTO_TCP)
658 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
659 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
660 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
664 pINData = &((struct xinpcb *)pXIG)->xi_inp;
665 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
668 /* Ignore sockets for other protocols */
669 if (pSockData->xso_protocol != Protocol)
672 /* Ignore PCBs that were freed while generating the data */
673 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
676 /* we're only interested in IPv4 addresses */
677 if (!(pINData->inp_vflag & INP_IPV4) ||
678 (pINData->inp_vflag & INP_IPV6))
681 /* If all 0's, skip it */
682 if (!pINData->inp_laddr.s_addr &&
683 !pINData->inp_lport &&
684 !pINData->inp_faddr.s_addr &&
691 HeapFree (GetProcessHeap (), 0, Buf);
697 fp = fopen(filename, "r");
699 char buf[512] = { 0 }, *ptr;
702 ptr = fgets(buf, sizeof(buf), fp);
705 ptr = fgets(buf, sizeof(buf), fp);
713 ERR ("Unable to open '%s' to count entries!\n", filename);
719 DWORD getNumRoutes(void)
721 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
722 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
724 char *buf, *lim, *next;
725 struct rt_msghdr *rtm;
726 DWORD RouteCount = 0;
728 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
730 ERR ("sysctl 1 failed!\n");
734 buf = HeapAlloc (GetProcessHeap (), 0, needed);
737 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
739 ERR ("sysctl 2 failed!\n");
740 HeapFree (GetProcessHeap (), 0, buf);
745 for (next = buf; next < lim; next += rtm->rtm_msglen)
747 rtm = (struct rt_msghdr *)next;
749 if (rtm->rtm_type != RTM_GET)
751 WARN ("Got unexpected message type 0x%x!\n",
756 /* Ignore all entries except for gateway routes which aren't
758 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
764 HeapFree (GetProcessHeap (), 0, buf);
767 return getNumWithOneHeader("/proc/net/route");
771 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
776 if (!ppIpForwardTable)
777 ret = ERROR_INVALID_PARAMETER;
779 DWORD numRoutes = getNumRoutes();
780 PMIB_IPFORWARDTABLE table = HeapAlloc(heap, flags,
781 sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) * sizeof(MIB_IPFORWARDROW));
784 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
785 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
787 char *buf, *lim, *next, *addrPtr;
788 struct rt_msghdr *rtm;
790 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
792 ERR ("sysctl 1 failed!\n");
793 HeapFree (GetProcessHeap (), 0, table);
797 buf = HeapAlloc (GetProcessHeap (), 0, needed);
800 HeapFree (GetProcessHeap (), 0, table);
801 return ERROR_OUTOFMEMORY;
804 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
806 ERR ("sysctl 2 failed!\n");
807 HeapFree (GetProcessHeap (), 0, table);
808 HeapFree (GetProcessHeap (), 0, buf);
812 *ppIpForwardTable = table;
813 table->dwNumEntries = 0;
816 for (next = buf; next < lim; next += rtm->rtm_msglen)
820 rtm = (struct rt_msghdr *)next;
822 if (rtm->rtm_type != RTM_GET)
824 WARN ("Got unexpected message type 0x%x!\n",
829 /* Ignore all entries except for gateway routes which aren't
831 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
832 (rtm->rtm_flags & RTF_MULTICAST))
835 memset (&table->table[table->dwNumEntries], 0,
836 sizeof (MIB_IPFORWARDROW));
837 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
838 table->table[table->dwNumEntries].dwForwardType =
839 MIB_IPROUTE_TYPE_INDIRECT;
840 table->table[table->dwNumEntries].dwForwardMetric1 =
841 rtm->rtm_rmx.rmx_hopcount;
842 table->table[table->dwNumEntries].dwForwardProto =
845 addrPtr = (char *)(rtm + 1);
847 for (i = 1; i; i <<= 1)
852 if (!(i & rtm->rtm_addrs))
855 sa = (struct sockaddr *)addrPtr;
856 ADVANCE (addrPtr, sa);
858 /* default routes are encoded by length-zero sockaddr */
861 else if (sa->sa_family != AF_INET)
863 ERR ("Received unsupported sockaddr family 0x%x\n",
869 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
871 addr = sin->sin_addr.s_addr;
877 table->table[table->dwNumEntries].dwForwardDest = addr;
881 table->table[table->dwNumEntries].dwForwardNextHop = addr;
885 table->table[table->dwNumEntries].dwForwardMask = addr;
889 ERR ("Unexpected address type 0x%x\n", i);
893 table->dwNumEntries++;
896 HeapFree (GetProcessHeap (), 0, buf);
902 *ppIpForwardTable = table;
903 table->dwNumEntries = 0;
904 /* get from /proc/net/route, no error if can't */
905 fp = fopen("/proc/net/route", "r");
907 char buf[512] = { 0 }, *ptr;
909 /* skip header line */
910 ptr = fgets(buf, sizeof(buf), fp);
911 while (ptr && table->dwNumEntries < numRoutes) {
912 memset(&table->table[table->dwNumEntries], 0,
913 sizeof(MIB_IPFORWARDROW));
914 ptr = fgets(buf, sizeof(buf), fp);
918 while (!isspace(*ptr))
922 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
925 table->table[table->dwNumEntries].dwForwardIfIndex = index;
927 table->table[table->dwNumEntries].dwForwardDest =
928 strtoul(ptr, &endPtr, 16);
932 table->table[table->dwNumEntries].dwForwardNextHop =
933 strtoul(ptr, &endPtr, 16);
937 DWORD flags = strtoul(ptr, &endPtr, 16);
939 if (!(flags & RTF_UP))
940 table->table[table->dwNumEntries].dwForwardType =
941 MIB_IPROUTE_TYPE_INVALID;
942 else if (flags & RTF_GATEWAY)
943 table->table[table->dwNumEntries].dwForwardType =
944 MIB_IPROUTE_TYPE_INDIRECT;
946 table->table[table->dwNumEntries].dwForwardType =
947 MIB_IPROUTE_TYPE_DIRECT;
951 strtoul(ptr, &endPtr, 16); /* refcount, skip */
955 strtoul(ptr, &endPtr, 16); /* use, skip */
959 table->table[table->dwNumEntries].dwForwardMetric1 =
960 strtoul(ptr, &endPtr, 16);
964 table->table[table->dwNumEntries].dwForwardMask =
965 strtoul(ptr, &endPtr, 16);
968 /* FIXME: other protos might be appropriate, e.g. the default
969 * route is typically set with MIB_IPPROTO_NETMGMT instead */
970 table->table[table->dwNumEntries].dwForwardProto =
972 table->dwNumEntries++;
980 ERR ("unimplemented!\n");
981 return ERROR_NOT_SUPPORTED;
986 ret = ERROR_OUTOFMEMORY;
991 DWORD getNumArpEntries(void)
993 return getNumWithOneHeader("/proc/net/arp");
996 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1000 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1001 ERR ("unimplemented!\n");
1002 return ERROR_NOT_SUPPORTED;
1006 ret = ERROR_INVALID_PARAMETER;
1008 DWORD numEntries = getNumArpEntries();
1009 PMIB_IPNETTABLE table = HeapAlloc(heap, flags,
1010 sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
1016 *ppIpNetTable = table;
1017 table->dwNumEntries = 0;
1018 /* get from /proc/net/arp, no error if can't */
1019 fp = fopen("/proc/net/arp", "r");
1021 char buf[512] = { 0 }, *ptr;
1023 /* skip header line */
1024 ptr = fgets(buf, sizeof(buf), fp);
1025 while (ptr && table->dwNumEntries < numEntries) {
1026 ptr = fgets(buf, sizeof(buf), fp);
1030 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1031 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1032 while (ptr && *ptr && !isspace(*ptr))
1036 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1040 DWORD flags = strtoul(ptr, &endPtr, 16);
1043 if (flags & ATF_COM)
1044 table->table[table->dwNumEntries].dwType =
1045 MIB_IPNET_TYPE_DYNAMIC;
1049 if (flags & ATF_PERM)
1050 table->table[table->dwNumEntries].dwType =
1051 MIB_IPNET_TYPE_STATIC;
1054 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1058 while (ptr && *ptr && isspace(*ptr))
1060 while (ptr && *ptr && !isspace(*ptr)) {
1061 DWORD byte = strtoul(ptr, &endPtr, 16);
1063 if (endPtr && *endPtr) {
1065 table->table[table->dwNumEntries].bPhysAddr[
1066 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1072 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1075 getInterfaceIndexByName(ptr,
1076 &table->table[table->dwNumEntries].dwIndex);
1077 table->dwNumEntries++;
1083 ret = ERROR_NOT_SUPPORTED;
1086 ret = ERROR_OUTOFMEMORY;
1091 DWORD getNumUdpEntries(void)
1093 return getNumWithOneHeader("/proc/net/udp");
1096 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1100 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1101 ERR ("unimplemented!\n");
1102 return ERROR_NOT_SUPPORTED;
1106 ret = ERROR_INVALID_PARAMETER;
1108 DWORD numEntries = getNumUdpEntries();
1109 PMIB_UDPTABLE table = HeapAlloc(heap, flags,
1110 sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
1116 *ppUdpTable = table;
1117 table->dwNumEntries = 0;
1118 /* get from /proc/net/udp, no error if can't */
1119 fp = fopen("/proc/net/udp", "r");
1121 char buf[512] = { 0 }, *ptr;
1123 /* skip header line */
1124 ptr = fgets(buf, sizeof(buf), fp);
1125 while (ptr && table->dwNumEntries < numEntries) {
1126 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1127 ptr = fgets(buf, sizeof(buf), fp);
1132 strtoul(ptr, &endPtr, 16); /* skip */
1137 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1143 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1147 table->dwNumEntries++;
1153 ret = ERROR_NOT_SUPPORTED;
1156 ret = ERROR_OUTOFMEMORY;
1162 DWORD getNumTcpEntries(void)
1164 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1165 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1167 return getNumWithOneHeader ("/proc/net/tcp");
1172 /* Why not a lookup table? Because the TCPS_* constants are different
1173 on different platforms */
1174 static DWORD TCPStateToMIBState (int state)
1178 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1179 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1180 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1181 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1182 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1183 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1184 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1185 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1186 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1187 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1189 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1194 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1198 PMIB_TCPTABLE table;
1199 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1202 struct xinpgen *pXIG, *pOrigXIG;
1205 char buf[512] = { 0 }, *ptr;
1209 return ERROR_INVALID_PARAMETER;
1211 numEntries = getNumTcpEntries ();
1215 *ppTcpTable = HeapAlloc (heap, flags,
1216 sizeof (MIB_TCPTABLE) +
1217 (numEntries - 1) * sizeof (MIB_TCPROW));
1220 ERR ("Out of memory!\n");
1221 return ERROR_OUTOFMEMORY;
1223 maxEntries = numEntries;
1226 table = *ppTcpTable;
1227 table->dwNumEntries = 0;
1231 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1233 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1235 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1236 return ERROR_OUTOFMEMORY;
1239 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1242 ERR ("Out of memory!\n");
1243 return ERROR_OUTOFMEMORY;
1246 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1248 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1249 HeapFree (GetProcessHeap (), 0, Buf);
1250 return ERROR_OUTOFMEMORY;
1253 /* Might be nothing here; first entry is just a header it seems */
1254 if (Len <= sizeof (struct xinpgen))
1256 HeapFree (GetProcessHeap (), 0, Buf);
1260 pOrigXIG = (struct xinpgen *)Buf;
1263 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1264 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1265 (table->dwNumEntries < maxEntries);
1266 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1268 struct tcpcb *pTCPData = NULL;
1269 struct inpcb *pINData;
1270 struct xsocket *pSockData;
1272 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1273 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1274 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1276 /* Ignore sockets for other protocols */
1277 if (pSockData->xso_protocol != IPPROTO_TCP)
1280 /* Ignore PCBs that were freed while generating the data */
1281 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1284 /* we're only interested in IPv4 addresses */
1285 if (!(pINData->inp_vflag & INP_IPV4) ||
1286 (pINData->inp_vflag & INP_IPV6))
1289 /* If all 0's, skip it */
1290 if (!pINData->inp_laddr.s_addr &&
1291 !pINData->inp_lport &&
1292 !pINData->inp_faddr.s_addr &&
1293 !pINData->inp_fport)
1296 /* Fill in structure details */
1297 table->table[table->dwNumEntries].dwLocalAddr =
1298 pINData->inp_laddr.s_addr;
1299 table->table[table->dwNumEntries].dwLocalPort =
1301 table->table[table->dwNumEntries].dwRemoteAddr =
1302 pINData->inp_faddr.s_addr;
1303 table->table[table->dwNumEntries].dwRemotePort =
1305 table->table[table->dwNumEntries].dwState =
1306 TCPStateToMIBState (pTCPData->t_state);
1308 table->dwNumEntries++;
1311 HeapFree (GetProcessHeap (), 0, Buf);
1313 /* get from /proc/net/tcp, no error if can't */
1314 fp = fopen("/proc/net/tcp", "r");
1316 return ERROR_NOT_SUPPORTED;
1318 /* skip header line */
1319 ptr = fgets(buf, sizeof(buf), fp);
1320 while (ptr && table->dwNumEntries < maxEntries) {
1321 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1322 ptr = fgets(buf, sizeof(buf), fp);
1326 while (ptr && *ptr && *ptr != ':')
1331 table->table[table->dwNumEntries].dwLocalAddr =
1332 strtoul(ptr, &endPtr, 16);
1337 table->table[table->dwNumEntries].dwLocalPort =
1338 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1342 table->table[table->dwNumEntries].dwRemoteAddr =
1343 strtoul(ptr, &endPtr, 16);
1348 table->table[table->dwNumEntries].dwRemotePort =
1349 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1353 DWORD state = strtoul(ptr, &endPtr, 16);
1355 table->table[table->dwNumEntries].dwState =
1356 TCPStateToMIBState (state);
1359 table->dwNumEntries++;