reactos/dll/win32/iphlpapi/ipstats_reactos.c

663 lines
18 KiB
C
Raw Normal View History

/* Copyright (C) 2003 Art Yerkes
* A reimplementation of ifenum.c by Juan Lang
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* This file is implemented on the IOCTL_TCP_QUERY_INFORMATION_EX ioctl on
* tcpip.sys
*/
#include "iphlpapi_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
#ifndef TCPS_ESTABLISHED
# define TCPS_ESTABLISHED TCP_ESTABLISHED
#endif
#ifndef TCPS_SYN_SENT
# define TCPS_SYN_SENT TCP_SYN_SENT
#endif
#ifndef TCPS_SYN_RECEIVED
# define TCPS_SYN_RECEIVED TCP_SYN_RECV
#endif
#ifndef TCPS_FIN_WAIT_1
# define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
#endif
#ifndef TCPS_FIN_WAIT_2
# define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
#endif
#ifndef TCPS_TIME_WAIT
# define TCPS_TIME_WAIT TCP_TIME_WAIT
#endif
#ifndef TCPS_CLOSED
# define TCPS_CLOSED TCP_CLOSE
#endif
#ifndef TCPS_CLOSE_WAIT
# define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
#endif
#ifndef TCPS_LAST_ACK
# define TCPS_LAST_ACK TCP_LAST_ACK
#endif
#ifndef TCPS_LISTEN
# define TCPS_LISTEN TCP_LISTEN
#endif
#ifndef TCPS_CLOSING
# define TCPS_CLOSING TCP_CLOSING
#endif
BOOL isIpEntity( HANDLE tcpFile, TDIEntityID *ent ) {
return (ent->tei_entity == CL_NL_ENTITY ||
ent->tei_entity == CO_NL_ENTITY);
}
NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
DWORD numEntities = 0;
DWORD numRoutes = 0;
TDIEntityID *entitySet = 0;
NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
int i;
if( !NT_SUCCESS(status) )
return status;
for( i = 0; i < numEntities; i++ ) {
if( isIpEntity( tcpFile, &entitySet[i] ) ) {
TRACE("Entity %d is an IP Entity\n", i);
if( numRoutes == index ) break;
else numRoutes++;
}
}
if( numRoutes == index && i < numEntities ) {
TRACE("Index %d is entity #%d - %04x:%08x\n", index, i,
entitySet[i].tei_entity, entitySet[i].tei_instance );
memcpy( ent, &entitySet[i], sizeof(*ent) );
tdiFreeThingSet( entitySet );
return STATUS_SUCCESS;
} else {
tdiFreeThingSet( entitySet );
return STATUS_UNSUCCESSFUL;
}
}
NTSTATUS tdiGetMibForIpEntity
( HANDLE tcpFile, TDIEntityID *ent, IPSNMPInfo *entry ) {
TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
NTSTATUS status = STATUS_SUCCESS;
DWORD returnSize;
memset( entry, 0, sizeof( *entry ) );
TRACE("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n",
(DWORD)tcpFile, ent->tei_instance);
req.ID.toi_class = INFO_CLASS_PROTOCOL;
req.ID.toi_type = INFO_TYPE_PROVIDER;
req.ID.toi_id = IP_MIB_STATS_ID;
req.ID.toi_entity = *ent;
status = DeviceIoControl( tcpFile,
IOCTL_TCP_QUERY_INFORMATION_EX,
&req,
sizeof(req),
entry,
sizeof(*entry),
&returnSize,
NULL );
TRACE("TdiGetMibForIpEntity() => {\n"
" ipsi_forwarding ............ %d\n"
" ipsi_defaultttl ............ %d\n"
" ipsi_inreceives ............ %d\n"
" ipsi_indelivers ............ %d\n"
" ipsi_outrequests ........... %d\n"
" ipsi_routingdiscards ....... %d\n"
" ipsi_outdiscards ........... %d\n"
" ipsi_outnoroutes ........... %d\n"
" ipsi_numif ................. %d\n"
" ipsi_numaddr ............... %d\n"
" ipsi_numroutes ............. %d\n"
"} status %08x\n",
entry->ipsi_forwarding,
entry->ipsi_defaultttl,
entry->ipsi_inreceives,
entry->ipsi_indelivers,
entry->ipsi_outrequests,
entry->ipsi_routingdiscards,
entry->ipsi_outdiscards,
entry->ipsi_outnoroutes,
entry->ipsi_numif,
entry->ipsi_numaddr,
entry->ipsi_numroutes,
status);
return status;
}
NTSTATUS tdiGetRoutesForIpEntity
( HANDLE tcpFile, TDIEntityID *ent, IPRouteEntry **routes, PDWORD numRoutes ) {
NTSTATUS status = STATUS_SUCCESS;
TRACE("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
(DWORD)tcpFile, ent->tei_instance);
status = tdiGetSetOfThings( tcpFile,
INFO_CLASS_PROTOCOL,
INFO_TYPE_PROVIDER,
IP_MIB_ARPTABLE_ENTRY_ID,
CL_NL_ENTITY,
ent->tei_instance,
0,
sizeof(IPRouteEntry),
(PVOID *)routes,
numRoutes);
return status;
}
NTSTATUS tdiGetIpAddrsForIpEntity
( HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs, PDWORD numAddrs ) {
NTSTATUS status;
TRACE("TdiGetIpAddrsForIpEntity(tcpFile %x,entityId %x)\n",
(DWORD)tcpFile, ent->tei_instance);
status = tdiGetSetOfThings( tcpFile,
INFO_CLASS_PROTOCOL,
INFO_TYPE_PROVIDER,
IP_MIB_ADDRTABLE_ENTRY_ID,
CL_NL_ENTITY,
ent->tei_instance,
0,
sizeof(IPAddrEntry),
(PVOID *)addrs,
numAddrs );
return status;
}
DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
{
if (!name)
return ERROR_INVALID_PARAMETER;
if (!entry)
return ERROR_INVALID_PARAMETER;
return NO_ERROR;
}
DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry)
{
return ERROR_INVALID_PARAMETER;
}
DWORD getICMPStats(MIB_ICMP *stats)
{
FILE *fp;
if (!stats)
return ERROR_INVALID_PARAMETER;
memset(stats, 0, sizeof(MIB_ICMP));
/* get most of these stats from /proc/net/snmp, no error if can't */
fp = fopen("/proc/net/snmp", "r");
if (fp) {
const char hdr[] = "Icmp:";
char buf[512] = { 0 }, *ptr;
do {
ptr = fgets(buf, sizeof(buf), fp);
} while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
if (ptr) {
/* last line was a header, get another */
ptr = fgets(buf, sizeof(buf), fp);
if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
char *endPtr;
ptr += sizeof(hdr);
if (ptr && *ptr) {
stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
if (ptr && *ptr) {
stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
ptr = endPtr;
}
}
}
fclose(fp);
}
return NO_ERROR;
}
DWORD getIPStats(PMIB_IPSTATS stats, DWORD family)
{
if (!stats)
return ERROR_INVALID_PARAMETER;
return NO_ERROR;
}
DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family)
{
if (!stats)
return ERROR_INVALID_PARAMETER;
return NO_ERROR;
}
DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family)
{
if (!stats)
return ERROR_INVALID_PARAMETER;
return NO_ERROR;
}
static DWORD getNumWithOneHeader(const char *filename)
{
return 0;
}
DWORD getNumRoutes(void)
{
DWORD numEntities, numRoutes = 0;
TDIEntityID *entitySet;
HANDLE tcpFile;
int i;
NTSTATUS status;
TRACE("called.\n");
status = openTcpFile( &tcpFile, FILE_READ_DATA );
if( !NT_SUCCESS(status) ) {
TRACE("failure: %08x\n", (int)status );
return 0;
}
status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
if( !NT_SUCCESS(status) ) {
TRACE("failure: %08x\n", (int)status );
closeTcpFile( tcpFile );
return 0;
}
for( i = 0; i < numEntities; i++ ) {
if( isIpEntity( tcpFile, &entitySet[i] ) ) {
IPSNMPInfo isnmp;
memset( &isnmp, 0, sizeof( isnmp ) );
status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp );
if( !NT_SUCCESS(status) ) {
WARN("tdiGetMibForIpEntity failed for i = %d", i);
numRoutes = 0;
break;
}
numRoutes += isnmp.ipsi_numroutes;
}
}
TRACE("numRoutes: %d\n", (int)numRoutes);
tdiFreeThingSet( entitySet );
closeTcpFile( tcpFile );
return numRoutes;
}
VOID HexDump( PCHAR Data, DWORD Len ) {
int i;
for( i = 0; i < Len; i++ ) {
if( !(i & 0xf) ) {
if( i ) fprintf(stderr,"\n");
fprintf(stderr,"%08x:", i);
}
fprintf( stderr, " %02x", Data[i] & 0xff );
}
fprintf(stderr,"\n");
}
RouteTable *getRouteTable(void)
{
RouteTable *out_route_table;
DWORD numRoutes = getNumRoutes(), routesAdded = 0;
TDIEntityID ent;
HANDLE tcpFile;
NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
int i;
if( !NT_SUCCESS(status) )
return 0;
TRACE("GETTING ROUTE TABLE\n");
out_route_table = HeapAlloc( GetProcessHeap(), 0,
sizeof(RouteTable) +
(sizeof(RouteEntry) * (numRoutes - 1)) );
if (!out_route_table) {
closeTcpFile(tcpFile);
return NULL;
}
out_route_table->numRoutes = numRoutes;
for( i = 0; routesAdded < out_route_table->numRoutes; i++ ) {
int j;
IPRouteEntry *route_set;
getNthIpEntity( tcpFile, i, &ent );
tdiGetRoutesForIpEntity( tcpFile, &ent, &route_set, &numRoutes );
if( !route_set ) {
closeTcpFile( tcpFile );
HeapFree( GetProcessHeap(), 0, out_route_table );
return 0;
}
TRACE( "%d routes in instance %d\n", numRoutes, i );
#if 0
HexDump( route_set,
sizeof( IPRouteEntry ) *
snmpInfo.ipsi_numroutes );
#endif
for( j = 0; j < numRoutes; j++ ) {
int routeNum = j + routesAdded;
out_route_table->routes[routeNum].dest =
route_set[j].ire_dest;
out_route_table->routes[routeNum].mask =
route_set[j].ire_mask;
out_route_table->routes[routeNum].gateway =
route_set[j].ire_gw;
out_route_table->routes[routeNum].ifIndex =
route_set[j].ire_index;
out_route_table->routes[routeNum].metric =
route_set[j].ire_metric1;
}
if( route_set ) tdiFreeThingSet( route_set );
routesAdded += numRoutes;
}
closeTcpFile( tcpFile );
TRACE("Return: %08x, %08x\n", status, out_route_table);
return out_route_table;
}
DWORD getNumArpEntries(void)
{
DWORD numEntities;
TDIEntityID *entitySet = NULL;
HANDLE tcpFile;
int i, totalNumber = 0;
NTSTATUS status;
PMIB_IPNETROW IpArpTable = NULL;
DWORD returnSize;
TRACE("called.\n");
status = openTcpFile( &tcpFile, FILE_READ_DATA );
if( !NT_SUCCESS(status) ) {
TRACE("failure: %08x\n", (int)status );
return 0;
}
status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
for( i = 0; i < numEntities; i++ ) {
if( isInterface( &entitySet[i] ) &&
hasArp( tcpFile, &entitySet[i] ) ) {
status = tdiGetSetOfThings( tcpFile,
INFO_CLASS_PROTOCOL,
INFO_TYPE_PROVIDER,
IP_MIB_ARPTABLE_ENTRY_ID,
AT_ENTITY,
entitySet[i].tei_instance,
0,
sizeof(MIB_IPNETROW),
(PVOID *)&IpArpTable,
&returnSize );
if( status == STATUS_SUCCESS ) totalNumber += returnSize;
if( IpArpTable ) {
tdiFreeThingSet( IpArpTable );
IpArpTable = NULL;
}
}
}
closeTcpFile( tcpFile );
if( IpArpTable ) tdiFreeThingSet( IpArpTable );
if( entitySet ) tdiFreeThingSet( entitySet );
return totalNumber;
}
PMIB_IPNETTABLE getArpTable(void)
{
DWORD numEntities, returnSize;
TDIEntityID *entitySet;
HANDLE tcpFile;
int i, totalNumber, TmpIdx, CurrIdx = 0;
NTSTATUS status;
PMIB_IPNETTABLE IpArpTable = NULL;
PMIB_IPNETROW AdapterArpTable = NULL;
TRACE("called.\n");
totalNumber = getNumArpEntries();
status = openTcpFile( &tcpFile, FILE_READ_DATA );
if( !NT_SUCCESS(status) ) {
TRACE("failure: %08x\n", (int)status );
return 0;
}
IpArpTable = HeapAlloc
( GetProcessHeap(), 0,
sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber) );
if (!IpArpTable) {
closeTcpFile(tcpFile);
return NULL;
}
status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
for( i = 0; i < numEntities; i++ ) {
if( isInterface( &entitySet[i] ) &&
hasArp( tcpFile, &entitySet[i] ) ) {
status = tdiGetSetOfThings( tcpFile,
INFO_CLASS_PROTOCOL,
INFO_TYPE_PROVIDER,
IP_MIB_ARPTABLE_ENTRY_ID,
AT_ENTITY,
entitySet[i].tei_instance,
0,
sizeof(MIB_IPNETROW),
(PVOID *)&AdapterArpTable,
&returnSize );
if( status == STATUS_SUCCESS ) {
for( TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++ )
IpArpTable->table[CurrIdx] = AdapterArpTable[TmpIdx];
tdiFreeThingSet( AdapterArpTable );
}
}
}
closeTcpFile( tcpFile );
tdiFreeThingSet( entitySet );
IpArpTable->dwNumEntries = CurrIdx;
return IpArpTable;
}
DWORD getNumUdpEntries(void)
{
return getNumWithOneHeader("/proc/net/udp");
}
PMIB_UDPTABLE getUdpTable(void)
{
DWORD numEntries = getNumUdpEntries();
PMIB_UDPTABLE ret;
ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
(numEntries - 1) * sizeof(MIB_UDPROW));
if (ret) {
FILE *fp;
/* get from /proc/net/udp, no error if can't */
fp = fopen("/proc/net/udp", "r");
if (fp) {
char buf[512] = { 0 }, *ptr;
/* skip header line */
ptr = fgets(buf, sizeof(buf), fp);
while (ptr && ret->dwNumEntries < numEntries) {
ptr = fgets(buf, sizeof(buf), fp);
if (ptr) {
char *endPtr;
if (ptr && *ptr) {
strtoul(ptr, &endPtr, 16); /* skip */
ptr = endPtr;
}
if (ptr && *ptr) {
ptr++;
ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
16);
ptr = endPtr;
}
if (ptr && *ptr) {
ptr++;
ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
16);
ptr = endPtr;
}
ret->dwNumEntries++;
}
}
fclose(fp);
}
}
return ret;
}
DWORD getNumTcpEntries(void)
{
return getNumWithOneHeader("/proc/net/tcp");
}
PMIB_TCPTABLE getTcpTable(void)
{
return 0;
}