/* * Copyright (C) 2003,2006 Juan Lang * Copyright (C) 2007 TransGaming Technologies Inc. * Copyright (C) 2009 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #include #include #include #ifdef HAVE_ALIAS_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_SOCKETVAR_H #include #endif #ifdef HAVE_SYS_TIMEOUT_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN_SYSTM_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_NET_IF_DL_H #include #endif #ifdef HAVE_NET_IF_TYPES_H #include #endif #ifdef HAVE_NET_ROUTE_H #include #endif #ifdef HAVE_NET_IF_ARP_H #include #endif #ifdef HAVE_NETINET_IF_ETHER_H #include #endif #ifdef HAVE_NETINET_IF_INARP_H #include #endif #ifdef HAVE_NETINET_IP_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_NETINET_IP_VAR_H #include #endif #ifdef HAVE_NETINET_TCP_FSM_H #include #endif #ifdef HAVE_NETINET_IN_PCB_H #include #endif #ifdef HAVE_NETINET_TCP_TIMER_H #include #endif #ifdef HAVE_NETINET_TCP_VAR_H #include #endif #ifdef HAVE_NETINET_IP_ICMP_H #include #endif #ifdef HAVE_NETINET_ICMP_VAR_H #include #endif #ifdef HAVE_NETINET_UDP_H #include #endif #ifdef HAVE_NETINET_UDP_VAR_H #include #endif #ifdef HAVE_SYS_PROTOSW_H #include #endif #ifdef HAVE_SYS_SYSCTL_H #include #endif #ifdef HAVE_KSTAT_H #include #endif #ifndef ROUNDUP #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #endif #ifndef ADVANCE #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len)) #endif #include "windef.h" #include "winbase.h" #include "iprtrmib.h" #include "ifenum.h" #include "ipstats.h" #include "wine/debug.h" #ifndef HAVE_NETINET_TCP_FSM_H #define TCPS_ESTABLISHED 1 #define TCPS_SYN_SENT 2 #define TCPS_SYN_RECEIVED 3 #define TCPS_FIN_WAIT_1 4 #define TCPS_FIN_WAIT_2 5 #define TCPS_TIME_WAIT 6 #define TCPS_CLOSED 7 #define TCPS_CLOSE_WAIT 8 #define TCPS_LAST_ACK 9 #define TCPS_LISTEN 10 #define TCPS_CLOSING 11 #endif #ifndef RTF_MULTICAST #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */ #endif #ifndef RTF_LLINFO #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */ #endif WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); #ifdef HAVE_LIBKSTAT static DWORD kstat_get_ui32( kstat_t *ksp, const char *name ) { unsigned int i; kstat_named_t *data = ksp->ks_data; for (i = 0; i < ksp->ks_ndata; i++) if (!strcmp( data[i].name, name )) return data[i].value.ui32; return 0; } #endif DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry) { DWORD ret = ERROR_NOT_SUPPORTED; if (!name || !entry) return ERROR_INVALID_PARAMETER; #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/dev", "r"))) { DWORD skip; char buf[512], *ptr; int nameLen = strlen(name); while ((ptr = fgets(buf, sizeof(buf), fp))) { while (*ptr && isspace(*ptr)) ptr++; if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':') { ptr += nameLen + 1; sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u", &entry->dwInOctets, &entry->dwInUcastPkts, &entry->dwInErrors, &entry->dwInDiscards, &skip, &skip, &skip, &entry->dwInNUcastPkts, &entry->dwOutOctets, &entry->dwOutUcastPkts, &entry->dwOutErrors, &entry->dwOutDiscards ); break; } } fclose(fp); ret = NO_ERROR; } } #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST) { int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) size_t needed; char *buf = NULL, *end; struct if_msghdr *ifm; struct if_data ifdata; if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1) { ERR ("failed to get size of iflist\n"); goto done; } buf = HeapAlloc (GetProcessHeap (), 0, needed); if (!buf) { ret = ERROR_OUTOFMEMORY; goto done; } if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1) { ERR ("failed to get iflist\n"); goto done; } for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen) { ifm = (struct if_msghdr *) buf; if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER) { ifdata = ifm->ifm_data; entry->dwMtu = ifdata.ifi_mtu; entry->dwSpeed = ifdata.ifi_baudrate; entry->dwInOctets = ifdata.ifi_ibytes; entry->dwInErrors = ifdata.ifi_ierrors; entry->dwInDiscards = ifdata.ifi_iqdrops; entry->dwInUcastPkts = ifdata.ifi_ipackets; entry->dwInNUcastPkts = ifdata.ifi_imcasts; entry->dwOutOctets = ifdata.ifi_obytes; entry->dwOutUcastPkts = ifdata.ifi_opackets; entry->dwOutErrors = ifdata.ifi_oerrors; ret = NO_ERROR; break; } } done: HeapFree (GetProcessHeap (), 0, buf); } #else FIXME( "unimplemented\n" ); #endif return ret; } /****************************************************************** * GetIcmpStatistics (IPHLPAPI.@) * * Get the ICMP statistics for the local computer. * * PARAMS * stats [Out] buffer for ICMP statistics * * RETURNS * Success: NO_ERROR * Failure: error code from winerror.h */ DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats) { DWORD ret = ERROR_NOT_SUPPORTED; if (!stats) return ERROR_INVALID_PARAMETER; memset( stats, 0, sizeof(MIB_ICMP) ); #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/snmp", "r"))) { static const char hdr[] = "Icmp:"; char buf[512], *ptr; while ((ptr = fgets(buf, sizeof(buf), fp))) { if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue; /* last line was a header, get another */ if (!(ptr = fgets(buf, sizeof(buf), fp))) break; if (!strncasecmp(buf, hdr, sizeof(hdr) - 1)) { ptr += sizeof(hdr); sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", &stats->stats.icmpInStats.dwMsgs, &stats->stats.icmpInStats.dwErrors, &stats->stats.icmpInStats.dwDestUnreachs, &stats->stats.icmpInStats.dwTimeExcds, &stats->stats.icmpInStats.dwParmProbs, &stats->stats.icmpInStats.dwSrcQuenchs, &stats->stats.icmpInStats.dwRedirects, &stats->stats.icmpInStats.dwEchoReps, &stats->stats.icmpInStats.dwTimestamps, &stats->stats.icmpInStats.dwTimestampReps, &stats->stats.icmpInStats.dwAddrMasks, &stats->stats.icmpInStats.dwAddrMaskReps, &stats->stats.icmpOutStats.dwMsgs, &stats->stats.icmpOutStats.dwErrors, &stats->stats.icmpOutStats.dwDestUnreachs, &stats->stats.icmpOutStats.dwTimeExcds, &stats->stats.icmpOutStats.dwParmProbs, &stats->stats.icmpOutStats.dwSrcQuenchs, &stats->stats.icmpOutStats.dwRedirects, &stats->stats.icmpOutStats.dwEchoReps, &stats->stats.icmpOutStats.dwTimestamps, &stats->stats.icmpOutStats.dwTimestampReps, &stats->stats.icmpOutStats.dwAddrMasks, &stats->stats.icmpOutStats.dwAddrMaskReps ); break; } } fclose(fp); ret = NO_ERROR; } } #elif defined(HAVE_LIBKSTAT) { static char ip[] = "ip", icmp[] = "icmp"; kstat_ctl_t *kc; kstat_t *ksp; if ((kc = kstat_open()) && (ksp = kstat_lookup( kc, ip, 0, icmp )) && kstat_read( kc, ksp, NULL ) != -1 && ksp->ks_type == KSTAT_TYPE_NAMED) { stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" ); stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" ); stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" ); stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" ); stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" ); stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" ); stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" ); stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" ); stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" ); stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" ); stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" ); stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" ); stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" ); stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" ); stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" ); stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" ); stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" ); stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" ); stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" ); stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" ); stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" ); stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" ); stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" ); stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" ); stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" ); stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" ); ret = NO_ERROR; } if (kc) kstat_close( kc ); } #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) { int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) struct icmpstat icmp_stat; size_t needed = sizeof(icmp_stat); int i; if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1) { /*in stats */ stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen; for(i = 0; i <= ICMP_MAXTYPE; i++) stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i]; stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen; stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH]; stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED]; stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB]; stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH]; stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT]; stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO]; stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY]; stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP]; stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY]; stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ]; stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY]; #ifdef HAVE_ICPS_OUTHIST /* out stats */ stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp; for(i = 0; i <= ICMP_MAXTYPE; i++) stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i]; stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp; stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH]; stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED]; stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB]; stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH]; stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT]; stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO]; stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY]; stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP]; stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY]; stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ]; stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY]; #endif /* ICPS_OUTHIST */ ret = NO_ERROR; } } #else /* ICMPCTL_STATS */ FIXME( "unimplemented\n" ); #endif return ret; } /****************************************************************** * GetIpStatistics (IPHLPAPI.@) * * Get the IP statistics for the local computer. * * PARAMS * stats [Out] buffer for IP statistics * * RETURNS * Success: NO_ERROR * Failure: error code from winerror.h */ DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats) { DWORD ret = ERROR_NOT_SUPPORTED; MIB_IPFORWARDTABLE *fwd_table; if (!stats) return ERROR_INVALID_PARAMETER; memset( stats, 0, sizeof(*stats) ); stats->dwNumIf = stats->dwNumAddr = getNumInterfaces(); if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 )) { stats->dwNumRoutes = fwd_table->dwNumEntries; HeapFree( GetProcessHeap(), 0, fwd_table ); } #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/snmp", "r"))) { static const char hdr[] = "Ip:"; char buf[512], *ptr; while ((ptr = fgets(buf, sizeof(buf), fp))) { if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue; /* last line was a header, get another */ if (!(ptr = fgets(buf, sizeof(buf), fp))) break; if (!strncasecmp(buf, hdr, sizeof(hdr) - 1)) { ptr += sizeof(hdr); sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", &stats->dwForwarding, &stats->dwDefaultTTL, &stats->dwInReceives, &stats->dwInHdrErrors, &stats->dwInAddrErrors, &stats->dwForwDatagrams, &stats->dwInUnknownProtos, &stats->dwInDiscards, &stats->dwInDelivers, &stats->dwOutRequests, &stats->dwOutDiscards, &stats->dwOutNoRoutes, &stats->dwReasmTimeout, &stats->dwReasmReqds, &stats->dwReasmOks, &stats->dwReasmFails, &stats->dwFragOks, &stats->dwFragFails, &stats->dwFragCreates ); /* hmm, no routingDiscards */ break; } } fclose(fp); ret = NO_ERROR; } } #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) { int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) int ip_ttl, ip_forwarding; struct ipstat ip_stat; size_t needed; needed = sizeof(ip_stat); if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1) { ERR ("failed to get ipstat\n"); return ERROR_NOT_SUPPORTED; } needed = sizeof(ip_ttl); if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1) { ERR ("failed to get ip Default TTL\n"); return ERROR_NOT_SUPPORTED; } needed = sizeof(ip_forwarding); if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1) { ERR ("failed to get ip forwarding\n"); return ERROR_NOT_SUPPORTED; } stats->dwForwarding = ip_forwarding; stats->dwDefaultTTL = ip_ttl; stats->dwInDelivers = ip_stat.ips_delivered; stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen; stats->dwInAddrErrors = ip_stat.ips_cantforward; stats->dwInReceives = ip_stat.ips_total; stats->dwForwDatagrams = ip_stat.ips_forward; stats->dwInUnknownProtos = ip_stat.ips_noproto; stats->dwInDiscards = ip_stat.ips_fragdropped; stats->dwOutDiscards = ip_stat.ips_odropped; stats->dwReasmOks = ip_stat.ips_reassembled; stats->dwFragOks = ip_stat.ips_fragmented; stats->dwFragFails = ip_stat.ips_cantfrag; stats->dwReasmTimeout = ip_stat.ips_fragtimeout; stats->dwOutNoRoutes = ip_stat.ips_noroute; stats->dwOutRequests = ip_stat.ips_localout; stats->dwReasmReqds = ip_stat.ips_fragments; ret = NO_ERROR; } #else FIXME( "unimplemented\n" ); #endif return ret; } /****************************************************************** * GetTcpStatistics (IPHLPAPI.@) * * Get the TCP statistics for the local computer. * * PARAMS * stats [Out] buffer for TCP statistics * * RETURNS * Success: NO_ERROR * Failure: error code from winerror.h */ DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats) { DWORD ret = ERROR_NOT_SUPPORTED; if (!stats) return ERROR_INVALID_PARAMETER; memset( stats, 0, sizeof(*stats) ); #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/snmp", "r"))) { static const char hdr[] = "Tcp:"; MIB_TCPTABLE *tcp_table; char buf[512], *ptr; while ((ptr = fgets(buf, sizeof(buf), fp))) { if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue; /* last line was a header, get another */ if (!(ptr = fgets(buf, sizeof(buf), fp))) break; if (!strncasecmp(buf, hdr, sizeof(hdr) - 1)) { ptr += sizeof(hdr); sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u", &stats->dwRtoAlgorithm, &stats->dwRtoMin, &stats->dwRtoMax, &stats->dwMaxConn, &stats->dwActiveOpens, &stats->dwPassiveOpens, &stats->dwAttemptFails, &stats->dwEstabResets, &stats->dwCurrEstab, &stats->dwInSegs, &stats->dwOutSegs, &stats->dwRetransSegs, &stats->dwInErrs, &stats->dwOutRsts ); break; } } if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 )) { stats->dwNumConns = tcp_table->dwNumEntries; HeapFree( GetProcessHeap(), 0, tcp_table ); } fclose(fp); ret = NO_ERROR; } } #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) { #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */ #define TCPTV_MIN 2 #define TCPTV_REXMTMAX 128 #endif int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) #define hz 1000 struct tcpstat tcp_stat; size_t needed = sizeof(tcp_stat); if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1) { stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ; stats->dwRtoMin = TCPTV_MIN; stats->dwRtoMax = TCPTV_REXMTMAX; stats->dwMaxConn = -1; stats->dwActiveOpens = tcp_stat.tcps_connattempt; stats->dwPassiveOpens = tcp_stat.tcps_accepts; stats->dwAttemptFails = tcp_stat.tcps_conndrops; stats->dwEstabResets = tcp_stat.tcps_drops; stats->dwCurrEstab = 0; stats->dwInSegs = tcp_stat.tcps_rcvtotal; stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack; stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack; stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort; stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed; stats->dwNumConns = tcp_stat.tcps_connects; ret = NO_ERROR; } else ERR ("failed to get tcpstat\n"); } #else FIXME( "unimplemented\n" ); #endif return ret; } /****************************************************************** * GetUdpStatistics (IPHLPAPI.@) * * Get the UDP statistics for the local computer. * * PARAMS * stats [Out] buffer for UDP statistics * * RETURNS * Success: NO_ERROR * Failure: error code from winerror.h */ DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats) { DWORD ret = ERROR_NOT_SUPPORTED; if (!stats) return ERROR_INVALID_PARAMETER; memset( stats, 0, sizeof(*stats) ); #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/snmp", "r"))) { static const char hdr[] = "Udp:"; char buf[512], *ptr; while ((ptr = fgets(buf, sizeof(buf), fp))) { if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue; /* last line was a header, get another */ if (!(ptr = fgets(buf, sizeof(buf), fp))) break; if (!strncasecmp(buf, hdr, sizeof(hdr) - 1)) { ptr += sizeof(hdr); sscanf( ptr, "%u %u %u %u %u", &stats->dwInDatagrams, &stats->dwNoPorts, &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs ); break; } } fclose(fp); ret = NO_ERROR; } } #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) { int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) struct udpstat udp_stat; MIB_UDPTABLE *udp_table; size_t needed = sizeof(udp_stat); if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1) { stats->dwInDatagrams = udp_stat.udps_ipackets; stats->dwOutDatagrams = udp_stat.udps_opackets; stats->dwNoPorts = udp_stat.udps_noport; stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen; if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 )) { stats->dwNumAddrs = udp_table->dwNumEntries; HeapFree( GetProcessHeap(), 0, udp_table ); } ret = NO_ERROR; } else ERR ("failed to get udpstat\n"); } #else FIXME( "unimplemented\n" ); #endif return ret; } static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table, DWORD *count, const MIB_IPFORWARDROW *row ) { if (table->dwNumEntries >= *count) { MIB_IPFORWARDTABLE *new_table; DWORD new_count = table->dwNumEntries * 2; if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] )))) { HeapFree( heap, 0, table ); return NULL; } *count = new_count; table = new_table; } memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) ); return table; } static int compare_ipforward_rows(const void *a, const void *b) { const MIB_IPFORWARDROW *rowA = a; const MIB_IPFORWARDROW *rowB = b; int ret; if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret; if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret; if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret; return rowA->dwForwardNextHop - rowB->dwForwardNextHop; } /****************************************************************** * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@) * * Get the route table. * Like GetIpForwardTable(), but allocate the returned table from heap. * * PARAMS * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is * allocated and returned. * bOrder [In] whether to sort the table * heap [In] heap from which the table is allocated * flags [In] flags to HeapAlloc * * RETURNS * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes * on failure, NO_ERROR on success. */ DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags) { MIB_IPFORWARDTABLE *table; MIB_IPFORWARDROW row; DWORD ret = NO_ERROR, count = 16; TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags); if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER; if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] )))) return ERROR_OUTOFMEMORY; table->dwNumEntries = 0; #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/route", "r"))) { char buf[512], *ptr; DWORD flags; /* skip header line */ ptr = fgets(buf, sizeof(buf), fp); while ((ptr = fgets(buf, sizeof(buf), fp))) { memset( &row, 0, sizeof(row) ); while (!isspace(*ptr)) ptr++; *ptr++ = 0; if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR) continue; row.dwForwardDest = strtoul(ptr, &ptr, 16); row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16); flags = strtoul(ptr + 1, &ptr, 16); if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID; else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT; strtoul(ptr + 1, &ptr, 16); /* refcount, skip */ strtoul(ptr + 1, &ptr, 16); /* use, skip */ row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16); row.dwForwardMask = strtoul(ptr + 1, &ptr, 16); /* FIXME: other protos might be appropriate, e.g. the default * route is typically set with MIB_IPPROTO_NETMGMT instead */ row.dwForwardProto = MIB_IPPROTO_LOCAL; if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break; } fclose(fp); } else ret = ERROR_NOT_SUPPORTED; } #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) { int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0}; size_t needed; char *buf = NULL, *lim, *next, *addrPtr; struct rt_msghdr *rtm; if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) { ERR ("sysctl 1 failed!\n"); ret = ERROR_NOT_SUPPORTED; goto done; } buf = HeapAlloc (GetProcessHeap (), 0, needed); if (!buf) { ret = ERROR_OUTOFMEMORY; goto done; } if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { ret = ERROR_NOT_SUPPORTED; goto done; } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { int i; rtm = (struct rt_msghdr *)next; if (rtm->rtm_type != RTM_GET) { WARN ("Got unexpected message type 0x%x!\n", rtm->rtm_type); continue; } /* Ignore all entries except for gateway routes which aren't multicast */ if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST)) continue; memset( &row, 0, sizeof(row) ); row.dwForwardIfIndex = rtm->rtm_index; row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount; row.dwForwardProto = MIB_IPPROTO_LOCAL; addrPtr = (char *)(rtm + 1); for (i = 1; i; i <<= 1) { struct sockaddr *sa; DWORD addr; if (!(i & rtm->rtm_addrs)) continue; sa = (struct sockaddr *)addrPtr; ADVANCE (addrPtr, sa); /* default routes are encoded by length-zero sockaddr */ if (sa->sa_len == 0) addr = 0; else if (sa->sa_family != AF_INET) { WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family); addr = 0; } else { struct sockaddr_in *sin = (struct sockaddr_in *)sa; addr = sin->sin_addr.s_addr; } switch (i) { case RTA_DST: row.dwForwardDest = addr; break; case RTA_GATEWAY: row.dwForwardNextHop = addr; break; case RTA_NETMASK: row.dwForwardMask = addr; break; default: WARN ("Unexpected address type 0x%x\n", i); } } if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break; } done: HeapFree( GetProcessHeap (), 0, buf ); } #else FIXME( "not implemented\n" ); ret = ERROR_NOT_SUPPORTED; #endif if (!table) return ERROR_OUTOFMEMORY; if (!ret) { if (bOrder && table->dwNumEntries) qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows ); *ppIpForwardTable = table; } else HeapFree( heap, flags, table ); TRACE( "returning ret %u table %p\n", ret, table ); return ret; } static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table, DWORD *count, const MIB_IPNETROW *row ) { if (table->dwNumEntries >= *count) { MIB_IPNETTABLE *new_table; DWORD new_count = table->dwNumEntries * 2; if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] )))) { HeapFree( heap, 0, table ); return NULL; } *count = new_count; table = new_table; } memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) ); return table; } static int compare_ipnet_rows(const void *a, const void *b) { const MIB_IPNETROW *rowA = a; const MIB_IPNETROW *rowB = b; return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr); } /****************************************************************** * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@) * * Get the IP-to-physical address mapping table. * Like GetIpNetTable(), but allocate the returned table from heap. * * PARAMS * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is * allocated and returned. * bOrder [In] whether to sort the table * heap [In] heap from which the table is allocated * flags [In] flags to HeapAlloc * * RETURNS * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes * on failure, NO_ERROR on success. */ DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder, HANDLE heap, DWORD flags) { MIB_IPNETTABLE *table; MIB_IPNETROW row; DWORD ret = NO_ERROR, count = 16; TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags); if (!ppIpNetTable) return ERROR_INVALID_PARAMETER; if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] )))) return ERROR_OUTOFMEMORY; table->dwNumEntries = 0; #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/arp", "r"))) { char buf[512], *ptr; DWORD flags; /* skip header line */ ptr = fgets(buf, sizeof(buf), fp); while ((ptr = fgets(buf, sizeof(buf), fp))) { memset( &row, 0, sizeof(row) ); row.dwAddr = inet_addr(ptr); while (*ptr && !isspace(*ptr)) ptr++; strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */ flags = strtoul(ptr + 1, &ptr, 16); #ifdef ATF_COM if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC; else #endif #ifdef ATF_PERM if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC; else #endif row.dwType = MIB_IPNET_TYPE_OTHER; while (*ptr && isspace(*ptr)) ptr++; while (*ptr && !isspace(*ptr)) { row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16); if (*ptr) ptr++; } while (*ptr && isspace(*ptr)) ptr++; while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */ while (*ptr && isspace(*ptr)) ptr++; getInterfaceIndexByName(ptr, &row.dwIndex); if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break; } fclose(fp); } else ret = ERROR_NOT_SUPPORTED; } #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) { int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) size_t needed; char *buf = NULL, *lim, *next; struct rt_msghdr *rtm; struct sockaddr_inarp *sinarp; struct sockaddr_dl *sdl; if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1) { ERR ("failed to get arp table\n"); ret = ERROR_NOT_SUPPORTED; goto done; } buf = HeapAlloc (GetProcessHeap (), 0, needed); if (!buf) { ret = ERROR_OUTOFMEMORY; goto done; } if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1) { ret = ERROR_NOT_SUPPORTED; goto done; } lim = buf + needed; next = buf; while(next < lim) { rtm = (struct rt_msghdr *)next; sinarp=(struct sockaddr_inarp *)(rtm + 1); sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len)); if(sdl->sdl_alen) /* arp entry */ { memset( &row, 0, sizeof(row) ); row.dwAddr = sinarp->sin_addr.s_addr; row.dwIndex = sdl->sdl_index; row.dwPhysAddrLen = min( 8, sdl->sdl_alen ); memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen ); if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC; else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER; else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC; else row.dwType = MIB_IPNET_TYPE_INVALID; if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break; } next += rtm->rtm_msglen; } done: HeapFree( GetProcessHeap (), 0, buf ); } #else FIXME( "not implemented\n" ); ret = ERROR_NOT_SUPPORTED; #endif if (!table) return ERROR_OUTOFMEMORY; if (!ret) { if (bOrder && table->dwNumEntries) qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows ); *ppIpNetTable = table; } else HeapFree( heap, flags, table ); TRACE( "returning ret %u table %p\n", ret, table ); return ret; } static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table, DWORD *count, const MIB_UDPROW *row ) { if (table->dwNumEntries >= *count) { MIB_UDPTABLE *new_table; DWORD new_count = table->dwNumEntries * 2; if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] )))) { HeapFree( heap, 0, table ); return NULL; } *count = new_count; table = new_table; } memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) ); return table; } static int compare_udp_rows(const void *a, const void *b) { const MIB_UDPROW *rowA = a; const MIB_UDPROW *rowB = b; int ret; if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret; return rowA->dwLocalPort - rowB->dwLocalPort; } /****************************************************************** * AllocateAndGetUdpTableFromStack (IPHLPAPI.@) * * Get the UDP listener table. * Like GetUdpTable(), but allocate the returned table from heap. * * PARAMS * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is * allocated and returned. * bOrder [In] whether to sort the table * heap [In] heap from which the table is allocated * flags [In] flags to HeapAlloc * * RETURNS * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable() * returns otherwise. */ DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder, HANDLE heap, DWORD flags) { MIB_UDPTABLE *table; MIB_UDPROW row; DWORD ret = NO_ERROR, count = 16; TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags); if (!ppUdpTable) return ERROR_INVALID_PARAMETER; if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] )))) return ERROR_OUTOFMEMORY; table->dwNumEntries = 0; #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/udp", "r"))) { char buf[512], *ptr; DWORD dummy; /* skip header line */ ptr = fgets(buf, sizeof(buf), fp); while ((ptr = fgets(buf, sizeof(buf), fp))) { if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3) continue; row.dwLocalPort = htons( row.dwLocalPort ); if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break; } fclose(fp); } else ret = ERROR_NOT_SUPPORTED; } #else FIXME( "not implemented\n" ); ret = ERROR_NOT_SUPPORTED; #endif if (!table) return ERROR_OUTOFMEMORY; if (!ret) { if (bOrder && table->dwNumEntries) qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows ); *ppUdpTable = table; } else HeapFree( heap, flags, table ); TRACE( "returning ret %u table %p\n", ret, table ); return ret; } static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table, DWORD *count, const MIB_TCPROW *row ) { if (table->dwNumEntries >= *count) { MIB_TCPTABLE *new_table; DWORD new_count = table->dwNumEntries * 2; if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] )))) { HeapFree( heap, 0, table ); return NULL; } *count = new_count; table = new_table; } memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) ); return table; } /* Why not a lookup table? Because the TCPS_* constants are different on different platforms */ static DWORD TCPStateToMIBState (int state) { switch (state) { case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB; case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT; case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD; case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1; case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2; case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT; case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT; case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK; case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN; case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING; default: case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED; } } static int compare_tcp_rows(const void *a, const void *b) { const MIB_TCPROW *rowA = a; const MIB_TCPROW *rowB = b; int ret; if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret; if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) - ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret; if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret; return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort); } /****************************************************************** * AllocateAndGetTcpTableFromStack (IPHLPAPI.@) * * Get the TCP connection table. * Like GetTcpTable(), but allocate the returned table from heap. * * PARAMS * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is * allocated and returned. * bOrder [In] whether to sort the table * heap [In] heap from which the table is allocated * flags [In] flags to HeapAlloc * * RETURNS * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable() * returns otherwise. */ DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder, HANDLE heap, DWORD flags) { MIB_TCPTABLE *table; MIB_TCPROW row; DWORD ret = NO_ERROR, count = 16; TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags); if (!ppTcpTable) return ERROR_INVALID_PARAMETER; if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] )))) return ERROR_OUTOFMEMORY; table->dwNumEntries = 0; #ifdef __linux__ { FILE *fp; if ((fp = fopen("/proc/net/tcp", "r"))) { char buf[512], *ptr; DWORD dummy; /* skip header line */ ptr = fgets(buf, sizeof(buf), fp); while ((ptr = fgets(buf, sizeof(buf), fp))) { if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6) continue; row.dwLocalPort = htons( row.dwLocalPort ); row.dwRemotePort = htons( row.dwRemotePort ); row.dwState = TCPStateToMIBState( row.dwState ); if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break; } fclose( fp ); } else ret = ERROR_NOT_SUPPORTED; } #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN) { size_t Len = 0; char *Buf = NULL; struct xinpgen *pXIG, *pOrigXIG; if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0) { ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n"); ret = ERROR_NOT_SUPPORTED; goto done; } Buf = HeapAlloc (GetProcessHeap (), 0, Len); if (!Buf) { ret = ERROR_OUTOFMEMORY; goto done; } if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0) { ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n"); ret = ERROR_NOT_SUPPORTED; goto done; } /* Might be nothing here; first entry is just a header it seems */ if (Len <= sizeof (struct xinpgen)) goto done; pOrigXIG = (struct xinpgen *)Buf; pXIG = pOrigXIG; for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len); pXIG->xig_len > sizeof (struct xinpgen); pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len)) { struct tcpcb *pTCPData = NULL; struct inpcb *pINData; struct xsocket *pSockData; pTCPData = &((struct xtcpcb *)pXIG)->xt_tp; pINData = &((struct xtcpcb *)pXIG)->xt_inp; pSockData = &((struct xtcpcb *)pXIG)->xt_socket; /* Ignore sockets for other protocols */ if (pSockData->xso_protocol != IPPROTO_TCP) continue; /* Ignore PCBs that were freed while generating the data */ if (pINData->inp_gencnt > pOrigXIG->xig_gen) continue; /* we're only interested in IPv4 addresses */ if (!(pINData->inp_vflag & INP_IPV4) || (pINData->inp_vflag & INP_IPV6)) continue; /* If all 0's, skip it */ if (!pINData->inp_laddr.s_addr && !pINData->inp_lport && !pINData->inp_faddr.s_addr && !pINData->inp_fport) continue; /* Fill in structure details */ row.dwLocalAddr = pINData->inp_laddr.s_addr; row.dwLocalPort = pINData->inp_lport; row.dwRemoteAddr = pINData->inp_faddr.s_addr; row.dwRemotePort = pINData->inp_fport; row.dwState = TCPStateToMIBState (pTCPData->t_state); if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break; } done: HeapFree (GetProcessHeap (), 0, Buf); } #else FIXME( "not implemented\n" ); ret = ERROR_NOT_SUPPORTED; #endif if (!table) return ERROR_OUTOFMEMORY; if (!ret) { if (bOrder && table->dwNumEntries) qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows ); *ppTcpTable = table; } else HeapFree( heap, flags, table ); TRACE( "returning ret %u table %p\n", ret, table ); return ret; }