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);
185 ERR ("unimplemented!\n");
190 DWORD getICMPStats(MIB_ICMP *stats)
195 return ERROR_INVALID_PARAMETER;
197 memset(stats, 0, sizeof(MIB_ICMP));
198 /* get most of these stats from /proc/net/snmp, no error if can't */
199 fp = fopen("/proc/net/snmp", "r");
201 static const char hdr[] = "Icmp:";
202 char buf[512] = { 0 }, *ptr;
205 ptr = fgets(buf, sizeof(buf), fp);
206 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
208 /* last line was a header, get another */
209 ptr = fgets(buf, sizeof(buf), fp);
210 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
215 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
219 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
223 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
227 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
231 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
235 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
239 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
243 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
247 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
251 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
255 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
259 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
263 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
267 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
271 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
275 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
279 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
283 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
287 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
291 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
295 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
299 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
303 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
307 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
315 ERR ("unimplemented!\n");
320 DWORD getIPStats(PMIB_IPSTATS stats)
325 return ERROR_INVALID_PARAMETER;
327 memset(stats, 0, sizeof(MIB_IPSTATS));
328 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
329 stats->dwNumRoutes = getNumRoutes();
331 /* get most of these stats from /proc/net/snmp, no error if can't */
332 fp = fopen("/proc/net/snmp", "r");
334 static const char hdr[] = "Ip:";
335 char buf[512] = { 0 }, *ptr;
338 ptr = fgets(buf, sizeof(buf), fp);
339 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
341 /* last line was a header, get another */
342 ptr = fgets(buf, sizeof(buf), fp);
343 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
348 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
352 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
356 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
360 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
364 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
368 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
372 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
376 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
380 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
384 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
388 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
392 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
396 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
400 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
404 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
408 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
412 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
416 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
420 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
423 /* hmm, no routingDiscards */
429 ERR ("unimplemented!\n");
434 DWORD getTCPStats(MIB_TCPSTATS *stats)
439 return ERROR_INVALID_PARAMETER;
441 memset(stats, 0, sizeof(MIB_TCPSTATS));
443 /* get from /proc/net/snmp, no error if can't */
444 fp = fopen("/proc/net/snmp", "r");
446 static const char hdr[] = "Tcp:";
447 char buf[512] = { 0 }, *ptr;
451 ptr = fgets(buf, sizeof(buf), fp);
452 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
454 /* last line was a header, get another */
455 ptr = fgets(buf, sizeof(buf), fp);
456 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
461 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
465 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
469 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
473 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
477 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
481 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
485 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
489 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
493 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
497 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
501 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
505 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
509 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
513 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
516 stats->dwNumConns = getNumTcpEntries();
522 ERR ("unimplemented!\n");
527 DWORD getUDPStats(MIB_UDPSTATS *stats)
532 return ERROR_INVALID_PARAMETER;
534 memset(stats, 0, sizeof(MIB_UDPSTATS));
536 /* get from /proc/net/snmp, no error if can't */
537 fp = fopen("/proc/net/snmp", "r");
539 static const char hdr[] = "Udp:";
540 char buf[512] = { 0 }, *ptr;
544 ptr = fgets(buf, sizeof(buf), fp);
545 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
547 /* last line was a header, get another */
548 ptr = fgets(buf, sizeof(buf), fp);
549 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
554 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
558 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
562 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
566 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
570 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
578 ERR ("unimplemented!\n");
583 static DWORD getNumWithOneHeader(const char *filename)
585 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
588 struct xinpgen *pXIG, *pOrigXIG;
590 DWORD NumEntries = 0;
592 if (!strcmp (filename, "net.inet.tcp.pcblist"))
593 Protocol = IPPROTO_TCP;
594 else if (!strcmp (filename, "net.inet.udp.pcblist"))
595 Protocol = IPPROTO_UDP;
598 ERR ("Unsupported mib '%s', needs protocol mapping\n",
603 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
605 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
609 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
612 ERR ("Out of memory!\n");
616 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
618 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
619 HeapFree (GetProcessHeap (), 0, Buf);
623 /* Might be nothing here; first entry is just a header it seems */
624 if (Len <= sizeof (struct xinpgen))
626 HeapFree (GetProcessHeap (), 0, Buf);
630 pOrigXIG = (struct xinpgen *)Buf;
633 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
634 pXIG->xig_len > sizeof (struct xinpgen);
635 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
637 struct tcpcb *pTCPData = NULL;
638 struct inpcb *pINData;
639 struct xsocket *pSockData;
641 if (Protocol == IPPROTO_TCP)
643 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
644 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
645 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
649 pINData = &((struct xinpcb *)pXIG)->xi_inp;
650 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
653 /* Ignore sockets for other protocols */
654 if (pSockData->xso_protocol != Protocol)
657 /* Ignore PCBs that were freed while generating the data */
658 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
661 /* we're only interested in IPv4 addresses */
662 if (!(pINData->inp_vflag & INP_IPV4) ||
663 (pINData->inp_vflag & INP_IPV6))
666 /* If all 0's, skip it */
667 if (!pINData->inp_laddr.s_addr &&
668 !pINData->inp_lport &&
669 !pINData->inp_faddr.s_addr &&
676 HeapFree (GetProcessHeap (), 0, Buf);
682 fp = fopen(filename, "r");
684 char buf[512] = { 0 }, *ptr;
687 ptr = fgets(buf, sizeof(buf), fp);
690 ptr = fgets(buf, sizeof(buf), fp);
698 ERR ("Unable to open '%s' to count entries!\n", filename);
704 DWORD getNumRoutes(void)
706 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
707 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
709 char *buf, *lim, *next;
710 struct rt_msghdr *rtm;
711 DWORD RouteCount = 0;
713 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
715 ERR ("sysctl 1 failed!\n");
719 buf = HeapAlloc (GetProcessHeap (), 0, needed);
722 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
724 ERR ("sysctl 2 failed!\n");
725 HeapFree (GetProcessHeap (), 0, buf);
730 for (next = buf; next < lim; next += rtm->rtm_msglen)
732 rtm = (struct rt_msghdr *)next;
734 if (rtm->rtm_type != RTM_GET)
736 WARN ("Got unexpected message type 0x%x!\n",
741 /* Ignore all entries except for gateway routes which aren't
743 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
749 HeapFree (GetProcessHeap (), 0, buf);
752 return getNumWithOneHeader("/proc/net/route");
756 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
761 if (!ppIpForwardTable)
762 ret = ERROR_INVALID_PARAMETER;
764 DWORD numRoutes = getNumRoutes();
765 PMIB_IPFORWARDTABLE table = HeapAlloc(heap, flags,
766 sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) * sizeof(MIB_IPFORWARDROW));
769 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
770 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
772 char *buf, *lim, *next, *addrPtr;
773 struct rt_msghdr *rtm;
775 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
777 ERR ("sysctl 1 failed!\n");
778 HeapFree (GetProcessHeap (), 0, table);
782 buf = HeapAlloc (GetProcessHeap (), 0, needed);
785 HeapFree (GetProcessHeap (), 0, table);
786 return ERROR_OUTOFMEMORY;
789 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
791 ERR ("sysctl 2 failed!\n");
792 HeapFree (GetProcessHeap (), 0, table);
793 HeapFree (GetProcessHeap (), 0, buf);
797 *ppIpForwardTable = table;
798 table->dwNumEntries = 0;
801 for (next = buf; next < lim; next += rtm->rtm_msglen)
805 rtm = (struct rt_msghdr *)next;
807 if (rtm->rtm_type != RTM_GET)
809 WARN ("Got unexpected message type 0x%x!\n",
814 /* Ignore all entries except for gateway routes which aren't
816 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
817 (rtm->rtm_flags & RTF_MULTICAST))
820 memset (&table->table[table->dwNumEntries], 0,
821 sizeof (MIB_IPFORWARDROW));
822 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
823 table->table[table->dwNumEntries].dwForwardType =
824 MIB_IPROUTE_TYPE_INDIRECT;
825 table->table[table->dwNumEntries].dwForwardMetric1 =
826 rtm->rtm_rmx.rmx_hopcount;
827 table->table[table->dwNumEntries].dwForwardProto =
830 addrPtr = (char *)(rtm + 1);
832 for (i = 1; i; i <<= 1)
837 if (!(i & rtm->rtm_addrs))
840 sa = (struct sockaddr *)addrPtr;
841 ADVANCE (addrPtr, sa);
843 /* default routes are encoded by length-zero sockaddr */
846 else if (sa->sa_family != AF_INET)
848 ERR ("Received unsupported sockaddr family 0x%x\n",
854 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
856 addr = sin->sin_addr.s_addr;
862 table->table[table->dwNumEntries].dwForwardDest = addr;
866 table->table[table->dwNumEntries].dwForwardNextHop = addr;
870 table->table[table->dwNumEntries].dwForwardMask = addr;
874 ERR ("Unexpected address type 0x%x\n", i);
878 table->dwNumEntries++;
881 HeapFree (GetProcessHeap (), 0, buf);
887 *ppIpForwardTable = table;
888 table->dwNumEntries = 0;
889 /* get from /proc/net/route, no error if can't */
890 fp = fopen("/proc/net/route", "r");
892 char buf[512] = { 0 }, *ptr;
894 /* skip header line */
895 ptr = fgets(buf, sizeof(buf), fp);
896 while (ptr && table->dwNumEntries < numRoutes) {
897 memset(&table->table[table->dwNumEntries], 0,
898 sizeof(MIB_IPFORWARDROW));
899 ptr = fgets(buf, sizeof(buf), fp);
903 while (!isspace(*ptr))
907 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
910 table->table[table->dwNumEntries].dwForwardIfIndex = index;
912 table->table[table->dwNumEntries].dwForwardDest =
913 strtoul(ptr, &endPtr, 16);
917 table->table[table->dwNumEntries].dwForwardNextHop =
918 strtoul(ptr, &endPtr, 16);
922 DWORD flags = strtoul(ptr, &endPtr, 16);
924 if (!(flags & RTF_UP))
925 table->table[table->dwNumEntries].dwForwardType =
926 MIB_IPROUTE_TYPE_INVALID;
927 else if (flags & RTF_GATEWAY)
928 table->table[table->dwNumEntries].dwForwardType =
929 MIB_IPROUTE_TYPE_INDIRECT;
931 table->table[table->dwNumEntries].dwForwardType =
932 MIB_IPROUTE_TYPE_DIRECT;
936 strtoul(ptr, &endPtr, 16); /* refcount, skip */
940 strtoul(ptr, &endPtr, 16); /* use, skip */
944 table->table[table->dwNumEntries].dwForwardMetric1 =
945 strtoul(ptr, &endPtr, 16);
949 table->table[table->dwNumEntries].dwForwardMask =
950 strtoul(ptr, &endPtr, 16);
953 /* FIXME: other protos might be appropriate, e.g. the default
954 * route is typically set with MIB_IPPROTO_NETMGMT instead */
955 table->table[table->dwNumEntries].dwForwardProto =
957 table->dwNumEntries++;
965 ERR ("unimplemented!\n");
966 return ERROR_INVALID_PARAMETER;
971 ret = ERROR_OUTOFMEMORY;
976 DWORD getNumArpEntries(void)
978 return getNumWithOneHeader("/proc/net/arp");
981 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
985 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
986 ERR ("unimplemented!\n");
987 return ERROR_INVALID_PARAMETER;
991 ret = ERROR_INVALID_PARAMETER;
993 DWORD numEntries = getNumArpEntries();
994 PMIB_IPNETTABLE table = HeapAlloc(heap, flags,
995 sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
1001 *ppIpNetTable = table;
1002 table->dwNumEntries = 0;
1003 /* get from /proc/net/arp, no error if can't */
1004 fp = fopen("/proc/net/arp", "r");
1006 char buf[512] = { 0 }, *ptr;
1008 /* skip header line */
1009 ptr = fgets(buf, sizeof(buf), fp);
1010 while (ptr && table->dwNumEntries < numEntries) {
1011 ptr = fgets(buf, sizeof(buf), fp);
1015 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1016 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1017 while (ptr && *ptr && !isspace(*ptr))
1021 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1025 DWORD flags = strtoul(ptr, &endPtr, 16);
1028 if (flags & ATF_COM)
1029 table->table[table->dwNumEntries].dwType =
1030 MIB_IPNET_TYPE_DYNAMIC;
1034 if (flags & ATF_PERM)
1035 table->table[table->dwNumEntries].dwType =
1036 MIB_IPNET_TYPE_STATIC;
1039 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1043 while (ptr && *ptr && isspace(*ptr))
1045 while (ptr && *ptr && !isspace(*ptr)) {
1046 DWORD byte = strtoul(ptr, &endPtr, 16);
1048 if (endPtr && *endPtr) {
1050 table->table[table->dwNumEntries].bPhysAddr[
1051 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1057 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1060 getInterfaceIndexByName(ptr,
1061 &table->table[table->dwNumEntries].dwIndex);
1062 table->dwNumEntries++;
1069 ret = ERROR_OUTOFMEMORY;
1074 DWORD getNumUdpEntries(void)
1076 return getNumWithOneHeader("/proc/net/udp");
1079 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1083 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1084 ERR ("unimplemented!\n");
1085 return ERROR_INVALID_PARAMETER;
1089 ret = ERROR_INVALID_PARAMETER;
1091 DWORD numEntries = getNumUdpEntries();
1092 PMIB_UDPTABLE table = HeapAlloc(heap, flags,
1093 sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
1099 *ppUdpTable = table;
1100 table->dwNumEntries = 0;
1101 /* get from /proc/net/udp, no error if can't */
1102 fp = fopen("/proc/net/udp", "r");
1104 char buf[512] = { 0 }, *ptr;
1106 /* skip header line */
1107 ptr = fgets(buf, sizeof(buf), fp);
1108 while (ptr && table->dwNumEntries < numEntries) {
1109 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1110 ptr = fgets(buf, sizeof(buf), fp);
1115 strtoul(ptr, &endPtr, 16); /* skip */
1120 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1126 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1130 table->dwNumEntries++;
1137 ret = ERROR_OUTOFMEMORY;
1143 DWORD getNumTcpEntries(void)
1145 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1146 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1148 return getNumWithOneHeader ("/proc/net/tcp");
1153 /* Why not a lookup table? Because the TCPS_* constants are different
1154 on different platforms */
1155 static DWORD TCPStateToMIBState (int state)
1159 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1160 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1161 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1162 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1163 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1164 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1165 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1166 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1167 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1168 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1170 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1175 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1179 PMIB_TCPTABLE table;
1180 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1183 struct xinpgen *pXIG, *pOrigXIG;
1186 char buf[512] = { 0 }, *ptr;
1190 return ERROR_INVALID_PARAMETER;
1192 numEntries = getNumTcpEntries ();
1196 *ppTcpTable = HeapAlloc (heap, flags,
1197 sizeof (MIB_TCPTABLE) +
1198 (numEntries - 1) * sizeof (MIB_TCPROW));
1201 ERR ("Out of memory!\n");
1202 return ERROR_OUTOFMEMORY;
1204 maxEntries = numEntries;
1207 table = *ppTcpTable;
1208 table->dwNumEntries = 0;
1212 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1214 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1216 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1217 return ERROR_OUTOFMEMORY;
1220 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1223 ERR ("Out of memory!\n");
1224 return ERROR_OUTOFMEMORY;
1227 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1229 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1230 HeapFree (GetProcessHeap (), 0, Buf);
1231 return ERROR_OUTOFMEMORY;
1234 /* Might be nothing here; first entry is just a header it seems */
1235 if (Len <= sizeof (struct xinpgen))
1237 HeapFree (GetProcessHeap (), 0, Buf);
1241 pOrigXIG = (struct xinpgen *)Buf;
1244 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1245 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1246 (table->dwNumEntries < maxEntries);
1247 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1249 struct tcpcb *pTCPData = NULL;
1250 struct inpcb *pINData;
1251 struct xsocket *pSockData;
1253 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1254 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1255 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1257 /* Ignore sockets for other protocols */
1258 if (pSockData->xso_protocol != IPPROTO_TCP)
1261 /* Ignore PCBs that were freed while generating the data */
1262 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1265 /* we're only interested in IPv4 addresses */
1266 if (!(pINData->inp_vflag & INP_IPV4) ||
1267 (pINData->inp_vflag & INP_IPV6))
1270 /* If all 0's, skip it */
1271 if (!pINData->inp_laddr.s_addr &&
1272 !pINData->inp_lport &&
1273 !pINData->inp_faddr.s_addr &&
1274 !pINData->inp_fport)
1277 /* Fill in structure details */
1278 table->table[table->dwNumEntries].dwLocalAddr =
1279 pINData->inp_laddr.s_addr;
1280 table->table[table->dwNumEntries].dwLocalPort =
1282 table->table[table->dwNumEntries].dwRemoteAddr =
1283 pINData->inp_faddr.s_addr;
1284 table->table[table->dwNumEntries].dwRemotePort =
1286 table->table[table->dwNumEntries].dwState =
1287 TCPStateToMIBState (pTCPData->t_state);
1289 table->dwNumEntries++;
1292 HeapFree (GetProcessHeap (), 0, Buf);
1294 /* get from /proc/net/tcp, no error if can't */
1295 fp = fopen("/proc/net/tcp", "r");
1299 /* skip header line */
1300 ptr = fgets(buf, sizeof(buf), fp);
1301 while (ptr && table->dwNumEntries < maxEntries) {
1302 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1303 ptr = fgets(buf, sizeof(buf), fp);
1307 while (ptr && *ptr && *ptr != ':')
1312 table->table[table->dwNumEntries].dwLocalAddr =
1313 strtoul(ptr, &endPtr, 16);
1318 table->table[table->dwNumEntries].dwLocalPort =
1319 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1323 table->table[table->dwNumEntries].dwRemoteAddr =
1324 strtoul(ptr, &endPtr, 16);
1329 table->table[table->dwNumEntries].dwRemotePort =
1330 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1334 DWORD state = strtoul(ptr, &endPtr, 16);
1336 table->table[table->dwNumEntries].dwState =
1337 TCPStateToMIBState (state);
1340 table->dwNumEntries++;