1 /* Copyright (C) 2003,2006 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 * This file implements statistics getting using the /proc filesystem exported
18 * by Linux, and maybe other OSes.
22 #include "wine/port.h"
23 #include "wine/debug.h"
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 #include <sys/socket.h>
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
42 #ifdef HAVE_NET_ROUTE_H
43 #include <net/route.h>
45 #ifdef HAVE_NET_IF_ARP_H
46 #include <net/if_arp.h>
48 #ifdef HAVE_NETINET_TCP_H
49 #include <netinet/tcp.h>
51 #ifdef HAVE_NETINET_TCP_FSM_H
52 #include <netinet/tcp_fsm.h>
55 #ifdef HAVE_SYS_SYSCTL_H
56 #include <sys/sysctl.h>
60 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
61 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
70 #define TCPS_ESTABLISHED 1
71 #define TCPS_SYN_SENT 2
72 #define TCPS_SYN_RECEIVED 3
73 #define TCPS_FIN_WAIT_1 4
74 #define TCPS_FIN_WAIT_2 5
75 #define TCPS_TIME_WAIT 6
77 #define TCPS_CLOSE_WAIT 8
78 #define TCPS_LAST_ACK 9
79 #define TCPS_LISTEN 10
80 #define TCPS_CLOSING 11
83 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
85 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
90 return ERROR_INVALID_PARAMETER;
92 return ERROR_INVALID_PARAMETER;
94 /* get interface stats from /proc/net/dev, no error if can't
95 no inUnknownProtos, outNUcastPkts, outQLen */
96 fp = fopen("/proc/net/dev", "r");
98 char buf[512] = { 0 }, *ptr;
99 int nameLen = strlen(name), nameFound = 0;
102 ptr = fgets(buf, sizeof(buf), fp);
103 while (ptr && !nameFound) {
104 while (*ptr && isspace(*ptr))
106 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
109 ptr = fgets(buf, sizeof(buf), fp);
116 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
120 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
124 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
128 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
132 strtoul(ptr, &endPtr, 10); /* skip */
136 strtoul(ptr, &endPtr, 10); /* skip */
140 strtoul(ptr, &endPtr, 10); /* skip */
144 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
148 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
152 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
156 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
160 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
167 ERR ("unimplemented!\n");
172 DWORD getICMPStats(MIB_ICMP *stats)
177 return ERROR_INVALID_PARAMETER;
179 memset(stats, 0, sizeof(MIB_ICMP));
180 /* get most of these stats from /proc/net/snmp, no error if can't */
181 fp = fopen("/proc/net/snmp", "r");
183 static const char hdr[] = "Icmp:";
184 char buf[512] = { 0 }, *ptr;
187 ptr = fgets(buf, sizeof(buf), fp);
188 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
190 /* last line was a header, get another */
191 ptr = fgets(buf, sizeof(buf), fp);
192 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
197 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
201 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
205 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
209 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
213 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
217 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
221 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
225 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
229 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
233 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
237 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
241 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
245 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
249 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
253 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
257 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
261 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
265 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
269 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
273 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
277 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
281 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
285 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
289 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
297 ERR ("unimplemented!\n");
302 DWORD getIPStats(PMIB_IPSTATS stats)
307 return ERROR_INVALID_PARAMETER;
309 memset(stats, 0, sizeof(MIB_IPSTATS));
310 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
311 stats->dwNumRoutes = getNumRoutes();
313 /* get most of these stats from /proc/net/snmp, no error if can't */
314 fp = fopen("/proc/net/snmp", "r");
316 static const char hdr[] = "Ip:";
317 char buf[512] = { 0 }, *ptr;
320 ptr = fgets(buf, sizeof(buf), fp);
321 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
323 /* last line was a header, get another */
324 ptr = fgets(buf, sizeof(buf), fp);
325 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
330 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
334 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
338 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
342 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
346 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
350 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
354 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
358 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
362 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
366 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
370 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
374 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
378 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
382 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
386 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
390 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
394 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
398 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
402 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
405 /* hmm, no routingDiscards */
411 ERR ("unimplemented!\n");
416 DWORD getTCPStats(MIB_TCPSTATS *stats)
421 return ERROR_INVALID_PARAMETER;
423 memset(stats, 0, sizeof(MIB_TCPSTATS));
425 /* get from /proc/net/snmp, no error if can't */
426 fp = fopen("/proc/net/snmp", "r");
428 static const char hdr[] = "Tcp:";
429 char buf[512] = { 0 }, *ptr;
433 ptr = fgets(buf, sizeof(buf), fp);
434 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
436 /* last line was a header, get another */
437 ptr = fgets(buf, sizeof(buf), fp);
438 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
443 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
447 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
451 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
455 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
459 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
463 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
467 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
471 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
475 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
479 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
483 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
487 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
491 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
495 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
498 stats->dwNumConns = getNumTcpEntries();
504 ERR ("unimplemented!\n");
509 DWORD getUDPStats(MIB_UDPSTATS *stats)
514 return ERROR_INVALID_PARAMETER;
516 memset(stats, 0, sizeof(MIB_UDPSTATS));
518 /* get from /proc/net/snmp, no error if can't */
519 fp = fopen("/proc/net/snmp", "r");
521 static const char hdr[] = "Udp:";
522 char buf[512] = { 0 }, *ptr;
526 ptr = fgets(buf, sizeof(buf), fp);
527 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
529 /* last line was a header, get another */
530 ptr = fgets(buf, sizeof(buf), fp);
531 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
536 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
540 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
544 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
548 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
552 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
560 ERR ("unimplemented!\n");
565 static DWORD getNumWithOneHeader(const char *filename)
570 fp = fopen(filename, "r");
572 char buf[512] = { 0 }, *ptr;
575 ptr = fgets(buf, sizeof(buf), fp);
578 ptr = fgets(buf, sizeof(buf), fp);
586 ERR ("Unable to open '%s' to count entries!\n", filename);
591 DWORD getNumRoutes(void)
593 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
594 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
596 char *buf, *lim, *next;
597 struct rt_msghdr *rtm;
598 DWORD RouteCount = 0;
600 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
602 ERR ("sysctl 1 failed!\n");
606 buf = HeapAlloc (GetProcessHeap (), 0, needed);
609 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
611 ERR ("sysctl 2 failed!\n");
612 HeapFree (GetProcessHeap (), 0, buf);
617 for (next = buf; next < lim; next += rtm->rtm_msglen)
619 rtm = (struct rt_msghdr *)next;
621 if (rtm->rtm_type != RTM_GET)
623 WARN ("Got unexpected message type 0x%x!\n",
628 /* Ignore all entries except for gateway routes which aren't
630 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
636 HeapFree (GetProcessHeap (), 0, buf);
639 return getNumWithOneHeader("/proc/net/route");
643 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
648 if (!ppIpForwardTable)
649 ret = ERROR_INVALID_PARAMETER;
651 DWORD numRoutes = getNumRoutes();
652 PMIB_IPFORWARDTABLE table = HeapAlloc(heap, flags,
653 sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) * sizeof(MIB_IPFORWARDROW));
656 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
657 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
659 char *buf, *lim, *next, *addrPtr;
660 struct rt_msghdr *rtm;
662 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
664 ERR ("sysctl 1 failed!\n");
665 HeapFree (GetProcessHeap (), 0, table);
669 buf = HeapAlloc (GetProcessHeap (), 0, needed);
672 HeapFree (GetProcessHeap (), 0, table);
673 return ERROR_OUTOFMEMORY;
676 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
678 ERR ("sysctl 2 failed!\n");
679 HeapFree (GetProcessHeap (), 0, table);
680 HeapFree (GetProcessHeap (), 0, buf);
684 *ppIpForwardTable = table;
685 table->dwNumEntries = 0;
688 for (next = buf; next < lim; next += rtm->rtm_msglen)
692 rtm = (struct rt_msghdr *)next;
694 if (rtm->rtm_type != RTM_GET)
696 WARN ("Got unexpected message type 0x%x!\n",
701 /* Ignore all entries except for gateway routes which aren't
703 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
704 (rtm->rtm_flags & RTF_MULTICAST))
707 memset (&table->table[table->dwNumEntries], 0,
708 sizeof (MIB_IPFORWARDROW));
709 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
710 table->table[table->dwNumEntries].dwForwardType =
711 MIB_IPROUTE_TYPE_INDIRECT;
712 table->table[table->dwNumEntries].dwForwardMetric1 =
713 rtm->rtm_rmx.rmx_hopcount;
714 table->table[table->dwNumEntries].dwForwardProto =
717 addrPtr = (char *)(rtm + 1);
719 for (i = 1; i; i <<= 1)
724 if (!(i & rtm->rtm_addrs))
727 sa = (struct sockaddr *)addrPtr;
728 ADVANCE (addrPtr, sa);
730 /* default routes are encoded by length-zero sockaddr */
733 else if (sa->sa_family != AF_INET)
735 ERR ("Received unsupported sockaddr family 0x%x\n",
741 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
743 addr = sin->sin_addr.s_addr;
749 table->table[table->dwNumEntries].dwForwardDest = addr;
753 table->table[table->dwNumEntries].dwForwardNextHop = addr;
757 table->table[table->dwNumEntries].dwForwardMask = addr;
761 ERR ("Unexpected address type 0x%x\n", i);
765 table->dwNumEntries++;
768 HeapFree (GetProcessHeap (), 0, buf);
774 *ppIpForwardTable = table;
775 table->dwNumEntries = 0;
776 /* get from /proc/net/route, no error if can't */
777 fp = fopen("/proc/net/route", "r");
779 char buf[512] = { 0 }, *ptr;
781 /* skip header line */
782 ptr = fgets(buf, sizeof(buf), fp);
783 while (ptr && table->dwNumEntries < numRoutes) {
784 memset(&table->table[table->dwNumEntries], 0,
785 sizeof(MIB_IPFORWARDROW));
786 ptr = fgets(buf, sizeof(buf), fp);
790 while (!isspace(*ptr))
794 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
797 table->table[table->dwNumEntries].dwForwardIfIndex = index;
799 table->table[table->dwNumEntries].dwForwardDest =
800 strtoul(ptr, &endPtr, 16);
804 table->table[table->dwNumEntries].dwForwardNextHop =
805 strtoul(ptr, &endPtr, 16);
809 DWORD flags = strtoul(ptr, &endPtr, 16);
811 if (!(flags & RTF_UP))
812 table->table[table->dwNumEntries].dwForwardType =
813 MIB_IPROUTE_TYPE_INVALID;
814 else if (flags & RTF_GATEWAY)
815 table->table[table->dwNumEntries].dwForwardType =
816 MIB_IPROUTE_TYPE_INDIRECT;
818 table->table[table->dwNumEntries].dwForwardType =
819 MIB_IPROUTE_TYPE_DIRECT;
823 strtoul(ptr, &endPtr, 16); /* refcount, skip */
827 strtoul(ptr, &endPtr, 16); /* use, skip */
831 table->table[table->dwNumEntries].dwForwardMetric1 =
832 strtoul(ptr, &endPtr, 16);
836 table->table[table->dwNumEntries].dwForwardMask =
837 strtoul(ptr, &endPtr, 16);
840 /* FIXME: other protos might be appropriate, e.g. the default
841 * route is typically set with MIB_IPPROTO_NETMGMT instead */
842 table->table[table->dwNumEntries].dwForwardProto =
844 table->dwNumEntries++;
852 ERR ("unimplemented!\n");
853 return ERROR_INVALID_PARAMETER;
858 ret = ERROR_OUTOFMEMORY;
863 DWORD getNumArpEntries(void)
865 return getNumWithOneHeader("/proc/net/arp");
868 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
872 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
873 ERR ("unimplemented!\n");
874 return ERROR_INVALID_PARAMETER;
878 ret = ERROR_INVALID_PARAMETER;
880 DWORD numEntries = getNumArpEntries();
881 PMIB_IPNETTABLE table = HeapAlloc(heap, flags,
882 sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
888 *ppIpNetTable = table;
889 table->dwNumEntries = 0;
890 /* get from /proc/net/arp, no error if can't */
891 fp = fopen("/proc/net/arp", "r");
893 char buf[512] = { 0 }, *ptr;
895 /* skip header line */
896 ptr = fgets(buf, sizeof(buf), fp);
897 while (ptr && table->dwNumEntries < numEntries) {
898 ptr = fgets(buf, sizeof(buf), fp);
902 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
903 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
904 while (ptr && *ptr && !isspace(*ptr))
908 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
912 DWORD flags = strtoul(ptr, &endPtr, 16);
916 table->table[table->dwNumEntries].dwType =
917 MIB_IPNET_TYPE_DYNAMIC;
921 if (flags & ATF_PERM)
922 table->table[table->dwNumEntries].dwType =
923 MIB_IPNET_TYPE_STATIC;
926 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
930 while (ptr && *ptr && isspace(*ptr))
932 while (ptr && *ptr && !isspace(*ptr)) {
933 DWORD byte = strtoul(ptr, &endPtr, 16);
935 if (endPtr && *endPtr) {
937 table->table[table->dwNumEntries].bPhysAddr[
938 table->table[table->dwNumEntries].dwPhysAddrLen++] =
944 strtoul(ptr, &endPtr, 16); /* mask (skip) */
947 getInterfaceIndexByName(ptr,
948 &table->table[table->dwNumEntries].dwIndex);
949 table->dwNumEntries++;
956 ret = ERROR_OUTOFMEMORY;
961 DWORD getNumUdpEntries(void)
963 return getNumWithOneHeader("/proc/net/udp");
966 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
970 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
971 ERR ("unimplemented!\n");
972 return ERROR_INVALID_PARAMETER;
976 ret = ERROR_INVALID_PARAMETER;
978 DWORD numEntries = getNumUdpEntries();
979 PMIB_UDPTABLE table = HeapAlloc(heap, flags,
980 sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
987 table->dwNumEntries = 0;
988 /* get from /proc/net/udp, no error if can't */
989 fp = fopen("/proc/net/udp", "r");
991 char buf[512] = { 0 }, *ptr;
993 /* skip header line */
994 ptr = fgets(buf, sizeof(buf), fp);
995 while (ptr && table->dwNumEntries < numEntries) {
996 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
997 ptr = fgets(buf, sizeof(buf), fp);
1002 strtoul(ptr, &endPtr, 16); /* skip */
1007 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1013 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1017 table->dwNumEntries++;
1024 ret = ERROR_OUTOFMEMORY;
1029 DWORD getNumTcpEntries(void)
1031 return getNumWithOneHeader("/proc/net/tcp");
1034 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags)
1038 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1039 ERR ("unimplemented!\n");
1040 return ERROR_INVALID_PARAMETER;
1044 ret = ERROR_INVALID_PARAMETER;
1046 DWORD numEntries = getNumTcpEntries();
1047 PMIB_TCPTABLE table = HeapAlloc(heap, flags,
1048 sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW));
1054 *ppTcpTable = table;
1055 table->dwNumEntries = 0;
1056 /* get from /proc/net/tcp, no error if can't */
1057 fp = fopen("/proc/net/tcp", "r");
1059 char buf[512] = { 0 }, *ptr;
1061 /* skip header line */
1062 ptr = fgets(buf, sizeof(buf), fp);
1063 while (ptr && table->dwNumEntries < numEntries) {
1064 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1065 ptr = fgets(buf, sizeof(buf), fp);
1069 while (ptr && *ptr && *ptr != ':')
1074 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1080 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1085 table->table[table->dwNumEntries].dwRemoteAddr = strtoul(ptr,
1091 table->table[table->dwNumEntries].dwRemotePort = strtoul(ptr,
1096 DWORD state = strtoul(ptr, &endPtr, 16);
1100 case TCPS_ESTABLISHED:
1101 table->table[table->dwNumEntries].dwState =
1102 MIB_TCP_STATE_ESTAB;
1105 table->table[table->dwNumEntries].dwState =
1106 MIB_TCP_STATE_SYN_SENT;
1108 case TCPS_SYN_RECEIVED:
1109 table->table[table->dwNumEntries].dwState =
1110 MIB_TCP_STATE_SYN_RCVD;
1112 case TCPS_FIN_WAIT_1:
1113 table->table[table->dwNumEntries].dwState =
1114 MIB_TCP_STATE_FIN_WAIT1;
1116 case TCPS_FIN_WAIT_2:
1117 table->table[table->dwNumEntries].dwState =
1118 MIB_TCP_STATE_FIN_WAIT2;
1120 case TCPS_TIME_WAIT:
1121 table->table[table->dwNumEntries].dwState =
1122 MIB_TCP_STATE_TIME_WAIT;
1125 table->table[table->dwNumEntries].dwState =
1126 MIB_TCP_STATE_CLOSED;
1128 case TCPS_CLOSE_WAIT:
1129 table->table[table->dwNumEntries].dwState =
1130 MIB_TCP_STATE_CLOSE_WAIT;
1133 table->table[table->dwNumEntries].dwState =
1134 MIB_TCP_STATE_LAST_ACK;
1137 table->table[table->dwNumEntries].dwState =
1138 MIB_TCP_STATE_LISTEN;
1141 table->table[table->dwNumEntries].dwState =
1142 MIB_TCP_STATE_CLOSING;
1147 table->dwNumEntries++;
1154 ret = ERROR_OUTOFMEMORY;