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 DWORD size = sizeof(MIB_IPFORWARDTABLE);
781 PMIB_IPFORWARDTABLE table;
784 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
785 table = HeapAlloc(heap, flags, size);
787 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
788 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
790 char *buf, *lim, *next, *addrPtr;
791 struct rt_msghdr *rtm;
793 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
795 ERR ("sysctl 1 failed!\n");
796 HeapFree (GetProcessHeap (), 0, table);
800 buf = HeapAlloc (GetProcessHeap (), 0, needed);
803 HeapFree (GetProcessHeap (), 0, table);
804 return ERROR_OUTOFMEMORY;
807 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
809 ERR ("sysctl 2 failed!\n");
810 HeapFree (GetProcessHeap (), 0, table);
811 HeapFree (GetProcessHeap (), 0, buf);
815 *ppIpForwardTable = table;
816 table->dwNumEntries = 0;
819 for (next = buf; next < lim; next += rtm->rtm_msglen)
823 rtm = (struct rt_msghdr *)next;
825 if (rtm->rtm_type != RTM_GET)
827 WARN ("Got unexpected message type 0x%x!\n",
832 /* Ignore all entries except for gateway routes which aren't
834 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
835 (rtm->rtm_flags & RTF_MULTICAST))
838 memset (&table->table[table->dwNumEntries], 0,
839 sizeof (MIB_IPFORWARDROW));
840 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
841 table->table[table->dwNumEntries].dwForwardType =
842 MIB_IPROUTE_TYPE_INDIRECT;
843 table->table[table->dwNumEntries].dwForwardMetric1 =
844 rtm->rtm_rmx.rmx_hopcount;
845 table->table[table->dwNumEntries].dwForwardProto =
848 addrPtr = (char *)(rtm + 1);
850 for (i = 1; i; i <<= 1)
855 if (!(i & rtm->rtm_addrs))
858 sa = (struct sockaddr *)addrPtr;
859 ADVANCE (addrPtr, sa);
861 /* default routes are encoded by length-zero sockaddr */
864 else if (sa->sa_family != AF_INET)
866 ERR ("Received unsupported sockaddr family 0x%x\n",
872 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
874 addr = sin->sin_addr.s_addr;
880 table->table[table->dwNumEntries].dwForwardDest = addr;
884 table->table[table->dwNumEntries].dwForwardNextHop = addr;
888 table->table[table->dwNumEntries].dwForwardMask = addr;
892 ERR ("Unexpected address type 0x%x\n", i);
896 table->dwNumEntries++;
899 HeapFree (GetProcessHeap (), 0, buf);
905 *ppIpForwardTable = table;
906 table->dwNumEntries = 0;
907 /* get from /proc/net/route, no error if can't */
908 fp = fopen("/proc/net/route", "r");
910 char buf[512] = { 0 }, *ptr;
912 /* skip header line */
913 ptr = fgets(buf, sizeof(buf), fp);
914 while (ptr && table->dwNumEntries < numRoutes) {
915 memset(&table->table[table->dwNumEntries], 0,
916 sizeof(MIB_IPFORWARDROW));
917 ptr = fgets(buf, sizeof(buf), fp);
921 while (!isspace(*ptr))
925 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
928 table->table[table->dwNumEntries].dwForwardIfIndex = index;
930 table->table[table->dwNumEntries].dwForwardDest =
931 strtoul(ptr, &endPtr, 16);
935 table->table[table->dwNumEntries].dwForwardNextHop =
936 strtoul(ptr, &endPtr, 16);
940 DWORD flags = strtoul(ptr, &endPtr, 16);
942 if (!(flags & RTF_UP))
943 table->table[table->dwNumEntries].dwForwardType =
944 MIB_IPROUTE_TYPE_INVALID;
945 else if (flags & RTF_GATEWAY)
946 table->table[table->dwNumEntries].dwForwardType =
947 MIB_IPROUTE_TYPE_INDIRECT;
949 table->table[table->dwNumEntries].dwForwardType =
950 MIB_IPROUTE_TYPE_DIRECT;
954 strtoul(ptr, &endPtr, 16); /* refcount, skip */
958 strtoul(ptr, &endPtr, 16); /* use, skip */
962 table->table[table->dwNumEntries].dwForwardMetric1 =
963 strtoul(ptr, &endPtr, 16);
967 table->table[table->dwNumEntries].dwForwardMask =
968 strtoul(ptr, &endPtr, 16);
971 /* FIXME: other protos might be appropriate, e.g. the default
972 * route is typically set with MIB_IPPROTO_NETMGMT instead */
973 table->table[table->dwNumEntries].dwForwardProto =
975 table->dwNumEntries++;
983 ERR ("unimplemented!\n");
984 return ERROR_NOT_SUPPORTED;
989 ret = ERROR_OUTOFMEMORY;
994 DWORD getNumArpEntries(void)
996 return getNumWithOneHeader("/proc/net/arp");
999 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1003 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1004 ERR ("unimplemented!\n");
1005 return ERROR_NOT_SUPPORTED;
1009 ret = ERROR_INVALID_PARAMETER;
1011 DWORD numEntries = getNumArpEntries();
1012 DWORD size = sizeof(MIB_IPNETTABLE);
1013 PMIB_IPNETTABLE table;
1016 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1017 table = HeapAlloc(heap, flags, size);
1022 *ppIpNetTable = table;
1023 table->dwNumEntries = 0;
1024 /* get from /proc/net/arp, no error if can't */
1025 fp = fopen("/proc/net/arp", "r");
1027 char buf[512] = { 0 }, *ptr;
1029 /* skip header line */
1030 ptr = fgets(buf, sizeof(buf), fp);
1031 while (ptr && table->dwNumEntries < numEntries) {
1032 ptr = fgets(buf, sizeof(buf), fp);
1036 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1037 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1038 while (ptr && *ptr && !isspace(*ptr))
1042 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1046 DWORD flags = strtoul(ptr, &endPtr, 16);
1049 if (flags & ATF_COM)
1050 table->table[table->dwNumEntries].dwType =
1051 MIB_IPNET_TYPE_DYNAMIC;
1055 if (flags & ATF_PERM)
1056 table->table[table->dwNumEntries].dwType =
1057 MIB_IPNET_TYPE_STATIC;
1060 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1064 while (ptr && *ptr && isspace(*ptr))
1066 while (ptr && *ptr && !isspace(*ptr)) {
1067 DWORD byte = strtoul(ptr, &endPtr, 16);
1069 if (endPtr && *endPtr) {
1071 table->table[table->dwNumEntries].bPhysAddr[
1072 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1078 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1081 getInterfaceIndexByName(ptr,
1082 &table->table[table->dwNumEntries].dwIndex);
1083 table->dwNumEntries++;
1089 ret = ERROR_NOT_SUPPORTED;
1092 ret = ERROR_OUTOFMEMORY;
1097 DWORD getNumUdpEntries(void)
1099 return getNumWithOneHeader("/proc/net/udp");
1102 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1106 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1107 ERR ("unimplemented!\n");
1108 return ERROR_NOT_SUPPORTED;
1112 ret = ERROR_INVALID_PARAMETER;
1114 DWORD numEntries = getNumUdpEntries();
1115 DWORD size = sizeof(MIB_UDPTABLE);
1116 PMIB_UDPTABLE table;
1119 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1120 table = HeapAlloc(heap, flags, size);
1125 *ppUdpTable = table;
1126 table->dwNumEntries = 0;
1127 /* get from /proc/net/udp, no error if can't */
1128 fp = fopen("/proc/net/udp", "r");
1130 char buf[512] = { 0 }, *ptr;
1132 /* skip header line */
1133 ptr = fgets(buf, sizeof(buf), fp);
1134 while (ptr && table->dwNumEntries < numEntries) {
1135 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1136 ptr = fgets(buf, sizeof(buf), fp);
1141 strtoul(ptr, &endPtr, 16); /* skip */
1146 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1152 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1156 table->dwNumEntries++;
1162 ret = ERROR_NOT_SUPPORTED;
1165 ret = ERROR_OUTOFMEMORY;
1171 DWORD getNumTcpEntries(void)
1173 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1174 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1176 return getNumWithOneHeader ("/proc/net/tcp");
1181 /* Why not a lookup table? Because the TCPS_* constants are different
1182 on different platforms */
1183 static DWORD TCPStateToMIBState (int state)
1187 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1188 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1189 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1190 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1191 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1192 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1193 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1194 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1195 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1196 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1198 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1203 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1207 PMIB_TCPTABLE table;
1208 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1211 struct xinpgen *pXIG, *pOrigXIG;
1214 char buf[512] = { 0 }, *ptr;
1218 return ERROR_INVALID_PARAMETER;
1220 numEntries = getNumTcpEntries ();
1224 DWORD size = sizeof(MIB_TCPTABLE);
1227 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1228 *ppTcpTable = HeapAlloc (heap, flags, size);
1231 ERR ("Out of memory!\n");
1232 return ERROR_OUTOFMEMORY;
1234 maxEntries = numEntries;
1237 table = *ppTcpTable;
1238 table->dwNumEntries = 0;
1242 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1244 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1246 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1247 return ERROR_OUTOFMEMORY;
1250 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1253 ERR ("Out of memory!\n");
1254 return ERROR_OUTOFMEMORY;
1257 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1259 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1260 HeapFree (GetProcessHeap (), 0, Buf);
1261 return ERROR_OUTOFMEMORY;
1264 /* Might be nothing here; first entry is just a header it seems */
1265 if (Len <= sizeof (struct xinpgen))
1267 HeapFree (GetProcessHeap (), 0, Buf);
1271 pOrigXIG = (struct xinpgen *)Buf;
1274 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1275 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1276 (table->dwNumEntries < maxEntries);
1277 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1279 struct tcpcb *pTCPData = NULL;
1280 struct inpcb *pINData;
1281 struct xsocket *pSockData;
1283 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1284 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1285 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1287 /* Ignore sockets for other protocols */
1288 if (pSockData->xso_protocol != IPPROTO_TCP)
1291 /* Ignore PCBs that were freed while generating the data */
1292 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1295 /* we're only interested in IPv4 addresses */
1296 if (!(pINData->inp_vflag & INP_IPV4) ||
1297 (pINData->inp_vflag & INP_IPV6))
1300 /* If all 0's, skip it */
1301 if (!pINData->inp_laddr.s_addr &&
1302 !pINData->inp_lport &&
1303 !pINData->inp_faddr.s_addr &&
1304 !pINData->inp_fport)
1307 /* Fill in structure details */
1308 table->table[table->dwNumEntries].dwLocalAddr =
1309 pINData->inp_laddr.s_addr;
1310 table->table[table->dwNumEntries].dwLocalPort =
1312 table->table[table->dwNumEntries].dwRemoteAddr =
1313 pINData->inp_faddr.s_addr;
1314 table->table[table->dwNumEntries].dwRemotePort =
1316 table->table[table->dwNumEntries].dwState =
1317 TCPStateToMIBState (pTCPData->t_state);
1319 table->dwNumEntries++;
1322 HeapFree (GetProcessHeap (), 0, Buf);
1324 /* get from /proc/net/tcp, no error if can't */
1325 fp = fopen("/proc/net/tcp", "r");
1327 return ERROR_NOT_SUPPORTED;
1329 /* skip header line */
1330 ptr = fgets(buf, sizeof(buf), fp);
1331 while (ptr && table->dwNumEntries < maxEntries) {
1332 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1333 ptr = fgets(buf, sizeof(buf), fp);
1337 while (ptr && *ptr && *ptr != ':')
1342 table->table[table->dwNumEntries].dwLocalAddr =
1343 strtoul(ptr, &endPtr, 16);
1348 table->table[table->dwNumEntries].dwLocalPort =
1349 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1353 table->table[table->dwNumEntries].dwRemoteAddr =
1354 strtoul(ptr, &endPtr, 16);
1359 table->table[table->dwNumEntries].dwRemotePort =
1360 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1364 DWORD state = strtoul(ptr, &endPtr, 16);
1366 table->table[table->dwNumEntries].dwState =
1367 TCPStateToMIBState (state);
1370 table->dwNumEntries++;