719 lines
19 KiB
C++
719 lines
19 KiB
C++
/************************************************************************
|
||
|
||
Copyright (c) 2000 - 2000 Microsoft Corporation
|
||
|
||
Module Name :
|
||
|
||
netspeed.cpp
|
||
|
||
Abstract :
|
||
|
||
Main source file for throttle control.
|
||
|
||
Author :
|
||
|
||
Revision History :
|
||
|
||
|
||
---> for small files, we need to feed the file size in to the block calculator,
|
||
because the server-speed estimator will be incorrect if m_BlockSize is 65000
|
||
but the download time is based on a file size of 2002 bytes.
|
||
|
||
***********************************************************************/
|
||
|
||
|
||
#include "stdafx.h"
|
||
#include <malloc.h>
|
||
#include <limits.h>
|
||
|
||
#if !defined(BITS_V12_ON_NT4)
|
||
#include "netspeed.tmh"
|
||
#endif
|
||
|
||
//
|
||
// the maximum % of the perceived bandwidth that BITS will use for itself
|
||
//
|
||
const float MAX_BANDWIDTH_FRACTION = 0.95f;
|
||
|
||
//
|
||
// timer periods in seconds
|
||
//
|
||
const float DEFAULT_BLOCK_INTERVAL = 2.0f;
|
||
const float MIN_BLOCK_INTERVAL = 0.001f;
|
||
const float MAX_BLOCK_INTERVAL = 5.0f;
|
||
|
||
//
|
||
// observed header sizes. request = 250, reply = 300
|
||
//
|
||
#define REQUEST_OVERHEAD 550
|
||
|
||
//
|
||
// smallest block we will pull down
|
||
//
|
||
#define MIN_BLOCK_SIZE 2000
|
||
|
||
//
|
||
// size when we occasionally pull down a block on a full network
|
||
//
|
||
#define BUSY_BLOCK_SIZE 1500
|
||
|
||
//
|
||
// Very small blocks give unreliable speed measurements.
|
||
//
|
||
#define MIN_BLOCK_SIZE_TO_MEASURE 500
|
||
|
||
const NETWORK_RATE CNetworkInterface::DEFAULT_SPEED = 1600.0f;
|
||
|
||
// Work around limitations of the protocol stack
|
||
|
||
const DWORD MAX_BLOCK_SIZE = 2147483648;
|
||
|
||
//------------------------------------------------------------------------
|
||
|
||
//
|
||
// The observed server speed is reported as the average of this many usable samples.
|
||
//
|
||
const float SERVER_SPEED_SAMPLE_COUNT = 3.0F;
|
||
|
||
/*
|
||
|
||
The algorithm used to determine the speed and loading of the network is as follows:
|
||
|
||
1. After contacting the web site with Wininet calls, see whether an HTTP 1.1 "Via" header is present.
|
||
If so, a proxy was used, and we locate the proper net card to talk with the proxy. Otherwise,
|
||
a proxy was not used, and we locate the proper net card to talk with the HTTP server itself.
|
||
|
||
2. Chop time into 1/2-second intervals, and measure the interface's bytes-in and bytes-out count
|
||
three times per interval: first at the beginning, just before a block is downloaded, second at
|
||
the completion of the block, and third at the end of the interval.
|
||
|
||
|
||
*/
|
||
|
||
HRESULT
|
||
CNetworkInterface::TakeSnapshot(
|
||
int StatIndex
|
||
)
|
||
{
|
||
DWORD s;
|
||
ULONG size = 0;
|
||
|
||
//
|
||
// The network speed can be calculated only if all three snapshots succeeded.
|
||
// We keep track of the error status of the current series of snapshots.
|
||
//
|
||
if (StatIndex == BLOCK_START)
|
||
{
|
||
m_SnapshotError = S_OK;
|
||
m_SnapshotsValid = false;
|
||
}
|
||
|
||
m_TempRow.dwIndex = m_InterfaceIndex;
|
||
DWORD dwGetIfEntryError = GetIfEntry( &m_TempRow );
|
||
if ( dwGetIfEntryError )
|
||
{
|
||
LogWarning( "[%d] : GetIfRow(%d) failed %!winerr!", StatIndex, m_InterfaceIndex, dwGetIfEntryError );
|
||
m_SnapshotError = HRESULT_FROM_WIN32( dwGetIfEntryError );
|
||
return m_SnapshotError;
|
||
}
|
||
|
||
QueryPerformanceCounter( &m_Snapshots[ StatIndex ].TimeStamp );
|
||
|
||
m_Snapshots[ StatIndex ].BytesIn = m_TempRow.dwInOctets;
|
||
m_Snapshots[ StatIndex ].BytesOut = m_TempRow.dwOutOctets;
|
||
|
||
LogDl( "[%d] : in=%d, out=%d, timestamp=%d",
|
||
StatIndex,
|
||
m_Snapshots[ StatIndex ].BytesIn,
|
||
m_Snapshots[ StatIndex ].BytesOut,
|
||
m_Snapshots[ StatIndex ].TimeStamp.u.LowPart );
|
||
|
||
if (StatIndex == BLOCK_INTERVAL_END &&
|
||
m_SnapshotError == S_OK)
|
||
{
|
||
m_SnapshotsValid = true;
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
float
|
||
CNetworkInterface::GetTimeDifference(
|
||
int start,
|
||
int finish
|
||
)
|
||
{
|
||
float TotalTime;
|
||
|
||
TotalTime = m_Snapshots[ finish ].TimeStamp.QuadPart - m_Snapshots[ start ].TimeStamp.QuadPart;
|
||
|
||
TotalTime /= g_GlobalInfo->m_PerformanceCounterFrequency.QuadPart; // convert to seconds
|
||
|
||
if (TotalTime <= 0)
|
||
{
|
||
// pretend it was half a tick.
|
||
TotalTime = 1 / float(2 * g_GlobalInfo->m_PerformanceCounterFrequency.QuadPart);
|
||
}
|
||
|
||
return TotalTime;
|
||
}
|
||
|
||
|
||
CNetworkInterface::CNetworkInterface()
|
||
{
|
||
Reset();
|
||
}
|
||
|
||
HRESULT
|
||
CNetworkInterface::SetInterfaceIndex(
|
||
const TCHAR host[]
|
||
)
|
||
{
|
||
DWORD index;
|
||
|
||
HRESULT Hr = FindInterfaceIndex( host, &index );
|
||
if (FAILED(Hr))
|
||
return Hr;
|
||
|
||
if (m_InterfaceIndex != index)
|
||
{
|
||
m_InterfaceIndex = index;
|
||
Reset();
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
void
|
||
CNetworkInterface::Reset()
|
||
{
|
||
m_ServerSpeed = DEFAULT_SPEED;
|
||
m_NetcardSpeed = DEFAULT_SPEED;
|
||
m_PercentFree = 0.5f;
|
||
|
||
m_SnapshotsValid = false;
|
||
m_SnapshotError = E_FAIL;
|
||
m_state = DOWNLOADED_BLOCK;
|
||
}
|
||
|
||
|
||
void
|
||
CNetworkInterface::SetInterfaceSpeed()
|
||
{
|
||
float TotalTime, ratio;
|
||
NETWORK_RATE rate = 0;
|
||
|
||
//
|
||
// Adjust server speed based on block download stats.
|
||
//
|
||
if (m_SnapshotsValid && m_BlockSize)
|
||
{
|
||
float ExpectedTime = m_BlockInterval * m_PercentFree;
|
||
|
||
//
|
||
// Calculate interface speed from the time the last block took.
|
||
//
|
||
TotalTime = GetTimeDifference( BLOCK_START, BLOCK_END );
|
||
|
||
if (ExpectedTime > 0)
|
||
{
|
||
ratio = ExpectedTime / TotalTime;
|
||
|
||
rate = m_ServerSpeed * ratio;
|
||
}
|
||
else
|
||
{
|
||
// either m_PercentFree was zero, or the interval was zero. The ordinary calculation
|
||
// would always produce a ratio of zero and drag down our average speed incorrectly.
|
||
|
||
// use strict bytes per second measure
|
||
rate = m_BlockSize / TotalTime;
|
||
if (rate < m_ServerSpeed)
|
||
{
|
||
rate = m_ServerSpeed;
|
||
}
|
||
}
|
||
|
||
m_ServerSpeed *= (SERVER_SPEED_SAMPLE_COUNT-1) / SERVER_SPEED_SAMPLE_COUNT;
|
||
m_ServerSpeed += (rate / SERVER_SPEED_SAMPLE_COUNT);
|
||
|
||
LogDl("expected interval %f, actual= %f, rate= %!netrate!, avg %!netrate!",
|
||
ExpectedTime, TotalTime, rate, m_ServerSpeed );
|
||
}
|
||
|
||
//
|
||
// Adjust usage and netcard speed based on interval stats.
|
||
//
|
||
if (m_SnapshotsValid)
|
||
{
|
||
float Bytes;
|
||
|
||
Bytes = m_Snapshots[ BLOCK_END ].BytesIn - m_Snapshots[ BLOCK_START ].BytesIn;
|
||
Bytes += m_Snapshots[ BLOCK_END ].BytesOut - m_Snapshots[ BLOCK_START ].BytesOut;
|
||
|
||
ASSERT( Bytes >= 0 );
|
||
|
||
TotalTime = GetTimeDifference( BLOCK_START, BLOCK_END );
|
||
|
||
rate = Bytes/TotalTime;
|
||
|
||
// use whichever estimate is larger
|
||
|
||
if (rate < m_ServerSpeed)
|
||
{
|
||
rate = m_ServerSpeed;
|
||
}
|
||
|
||
if (m_NetcardSpeed == 0)
|
||
{
|
||
m_NetcardSpeed = rate;
|
||
}
|
||
else
|
||
{
|
||
if (rate < m_NetcardSpeed * 0.9f)
|
||
{
|
||
//
|
||
// If the rate drops precipitously, it's probably just a quiet moment on the Net;
|
||
// a strict average would unduly lower our estimated throughput.
|
||
// But reduce the average a little in case it's a long-term slowdown. If so,
|
||
// eventually the average will be lowered enough that the incoming rates are greater
|
||
// than m_NetcardSpeed / 2.
|
||
//
|
||
rate = m_NetcardSpeed * 0.9f;
|
||
}
|
||
|
||
//
|
||
// Keep a running average of the perceived rate.
|
||
//
|
||
m_NetcardSpeed *= (SERVER_SPEED_SAMPLE_COUNT-1) / SERVER_SPEED_SAMPLE_COUNT;
|
||
m_NetcardSpeed += (rate / SERVER_SPEED_SAMPLE_COUNT);
|
||
}
|
||
|
||
LogDl("bandwidth: bytes %f, time %f, rate %f, avg. %f", Bytes, TotalTime, rate, m_NetcardSpeed);
|
||
|
||
//
|
||
// Subtract our usage from the calculated usage. Compare usage to top speed to get free bandwidth.
|
||
//
|
||
Bytes = m_Snapshots[ BLOCK_INTERVAL_END ].BytesIn - m_Snapshots[ BLOCK_START ].BytesIn;
|
||
Bytes += m_Snapshots[ BLOCK_INTERVAL_END ].BytesOut - m_Snapshots[ BLOCK_START ].BytesOut;
|
||
Bytes -= m_BlockSize;
|
||
|
||
if (Bytes < 0)
|
||
{
|
||
Bytes = 0;
|
||
}
|
||
|
||
TotalTime = GetTimeDifference( BLOCK_START, BLOCK_INTERVAL_END );
|
||
|
||
rate = Bytes/TotalTime;
|
||
|
||
m_PercentFree = 1 - (rate / m_NetcardSpeed);
|
||
}
|
||
|
||
LogDl("usage: %f / %f, percent free %f", rate, m_NetcardSpeed, m_PercentFree);
|
||
|
||
if (m_PercentFree < 0)
|
||
{
|
||
m_PercentFree = 0;
|
||
}
|
||
else if (m_PercentFree > MAX_BANDWIDTH_FRACTION) // never monopolize the net
|
||
{
|
||
m_PercentFree = MAX_BANDWIDTH_FRACTION;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CNetworkInterface::BlockSizeFromInterval(
|
||
SECONDS interval
|
||
)
|
||
{
|
||
NETWORK_RATE FreeBandwidth = GetInterfaceSpeed() * GetPercentFree() * interval;
|
||
|
||
if (FreeBandwidth <= REQUEST_OVERHEAD)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
return FreeBandwidth - REQUEST_OVERHEAD;
|
||
}
|
||
|
||
CNetworkInterface::SECONDS
|
||
CNetworkInterface::IntervalFromBlockSize(
|
||
DWORD BlockSize
|
||
)
|
||
{
|
||
NETWORK_RATE FreeBandwidth = GetInterfaceSpeed() * GetPercentFree();
|
||
|
||
BlockSize += REQUEST_OVERHEAD;
|
||
|
||
if (BlockSize / MAX_BLOCK_INTERVAL > FreeBandwidth )
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
return BlockSize / FreeBandwidth;
|
||
}
|
||
|
||
void
|
||
CNetworkInterface::CalculateIntervalAndBlockSize(
|
||
UINT64 MaxBlockSize
|
||
)
|
||
{
|
||
MaxBlockSize = min( MaxBlockSize, MAX_BLOCK_SIZE );
|
||
|
||
if (MaxBlockSize == 0)
|
||
{
|
||
m_BlockInterval = 0;
|
||
m_BlockSize = 0;
|
||
|
||
SetTimerInterval( m_BlockInterval );
|
||
LogDl( "block %d bytes, interval %f seconds", m_BlockSize, m_BlockInterval );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Calculate new block size from the average interface speed.
|
||
//
|
||
DWORD OldState = m_state;
|
||
|
||
m_BlockInterval = DEFAULT_BLOCK_INTERVAL;
|
||
m_BlockSize = BlockSizeFromInterval( m_BlockInterval );
|
||
|
||
if (m_BlockSize > MaxBlockSize)
|
||
{
|
||
m_BlockSize = MaxBlockSize;
|
||
m_BlockInterval = IntervalFromBlockSize( m_BlockSize );
|
||
|
||
ASSERT( m_BlockInterval > 0 );
|
||
}
|
||
else if (m_BlockSize < MIN_BLOCK_SIZE)
|
||
{
|
||
m_BlockSize = min( MIN_BLOCK_SIZE, MaxBlockSize );
|
||
m_BlockInterval = IntervalFromBlockSize( m_BlockSize );
|
||
}
|
||
|
||
if (m_BlockInterval < 0)
|
||
{
|
||
m_BlockSize = 0;
|
||
}
|
||
|
||
//
|
||
// choose the new block download state.
|
||
//
|
||
if (m_BlockSize > 0)
|
||
{
|
||
m_state = DOWNLOADED_BLOCK;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// The first time m_BlockSize is set to zero, retain the default interval.
|
||
// If blocksize is zero twice in a row, expand to MAX_BLOCK_INTERVAL.
|
||
// Then force a small download.
|
||
//
|
||
switch (OldState)
|
||
{
|
||
case DOWNLOADED_BLOCK:
|
||
{
|
||
m_BlockInterval = DEFAULT_BLOCK_INTERVAL;
|
||
m_state = SKIPPED_ONE_BLOCK;
|
||
break;
|
||
}
|
||
|
||
case SKIPPED_ONE_BLOCK:
|
||
{
|
||
m_BlockInterval = MAX_BLOCK_INTERVAL;
|
||
m_state = SKIPPED_TWO_BLOCKS;
|
||
break;
|
||
}
|
||
|
||
case SKIPPED_TWO_BLOCKS:
|
||
{
|
||
m_BlockSize = min( BUSY_BLOCK_SIZE, MaxBlockSize);
|
||
m_BlockInterval = MAX_BLOCK_INTERVAL;
|
||
m_state = DOWNLOADED_BLOCK;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
ASSERT( 0 );
|
||
}
|
||
}
|
||
|
||
SetTimerInterval( m_BlockInterval );
|
||
|
||
LogDl( "block %d bytes, interval %f seconds", m_BlockSize, m_BlockInterval );
|
||
|
||
ASSERT( m_BlockSize <= MaxBlockSize );
|
||
}
|
||
|
||
BOOL
|
||
CNetworkInterface::SetTimerInterval(
|
||
SECONDS interval
|
||
)
|
||
{
|
||
DWORD msec = interval*1000;
|
||
|
||
if (msec <= 0)
|
||
{
|
||
msec = MIN_BLOCK_INTERVAL;
|
||
}
|
||
|
||
LogDl( "%d milliseconds", msec );
|
||
|
||
if (FALSE == m_Timer.Start( msec ))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
HRESULT
|
||
CNetworkInterface::FindInterfaceIndex(
|
||
const TCHAR host[],
|
||
DWORD * pIndex
|
||
)
|
||
{
|
||
//related to finding statistics
|
||
/* Use GetBestInterface with some IP address to get the index. Double check that this index
|
||
* occurs in the output of the IP Address table and look it up in the results of GetIfTable.
|
||
*/
|
||
|
||
#define AOL_ADAPTER _T("AOL Adapter")
|
||
#define AOL_DIALUP_ADAPTER _T("AOL Dial-Up Adapter")
|
||
|
||
BOOL bFound = FALSE;
|
||
BOOL bAOL = FALSE;
|
||
|
||
unsigned i;
|
||
DWORD dwAddr;
|
||
|
||
ULONG HostAddress;
|
||
struct sockaddr_in dest;
|
||
|
||
DWORD dwIndex = -1;
|
||
static TCHAR szIntfName[512];
|
||
|
||
*pIndex = -1;
|
||
|
||
try
|
||
{
|
||
//
|
||
// Translate the host name into a SOCKADDR.
|
||
//
|
||
|
||
unsigned length = 3 * lstrlen(host);
|
||
|
||
CAutoStringA AsciiHost ( new char[ length ]);
|
||
|
||
if (! WideCharToMultiByte( CP_ACP,
|
||
0, // no flags
|
||
host,
|
||
-1, // use strlen
|
||
AsciiHost.get(),
|
||
length, // use strlen
|
||
NULL, // no default char
|
||
NULL // no default char
|
||
))
|
||
{
|
||
DWORD dwError = GetLastError();
|
||
LogError( "Unicode conversion failed %!winerr!", dwError );
|
||
return HRESULT_FROM_WIN32( dwError );
|
||
}
|
||
|
||
HostAddress = inet_addr( AsciiHost.get() );
|
||
if (HostAddress == -1)
|
||
{
|
||
struct hostent *pHostEntry = gethostbyname( AsciiHost.get() );
|
||
|
||
if (pHostEntry == 0)
|
||
{
|
||
DWORD dwError = WSAGetLastError();
|
||
LogError( "failed to find host '%s': %!winerr!", AsciiHost.get(), dwError );
|
||
return HRESULT_FROM_WIN32( dwError );
|
||
}
|
||
|
||
HostAddress = *(unsigned long *)pHostEntry->h_addr;
|
||
}
|
||
}
|
||
catch ( ComError err )
|
||
{
|
||
LogError( "exception 0x%x finding server IP address", err.Error() );
|
||
return err.Error();
|
||
}
|
||
|
||
//for remote addr
|
||
dest.sin_addr.s_addr = HostAddress;
|
||
dest.sin_family = AF_INET;
|
||
dest.sin_port = 80;
|
||
|
||
DWORD dwGetBestInterfaceError = GetBestInterface(dest.sin_addr.s_addr, &dwIndex);
|
||
|
||
if (dwGetBestInterfaceError != NO_ERROR)
|
||
{
|
||
LogError( "GetBestInterface failed with error %!winerr!, might be Win95", dwGetBestInterfaceError);
|
||
|
||
//manually parse the routing table
|
||
|
||
ULONG size = 0;
|
||
DWORD dwIpForwardError = GetIpForwardTable(NULL, &size, FALSE);
|
||
if (dwIpForwardError != ERROR_INSUFFICIENT_BUFFER)
|
||
{
|
||
LogError( "sizing GetIpForwardTable failed %!winerr!", dwIpForwardError );
|
||
return HRESULT_FROM_WIN32( dwIpForwardError );
|
||
}
|
||
|
||
|
||
auto_ptr<MIB_IPFORWARDTABLE> pIpFwdTable((PMIB_IPFORWARDTABLE)new char[size]);
|
||
if ( !pIpFwdTable.get() )
|
||
{
|
||
LogError( "out of memory getting %d bytes", size);
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
|
||
dwIpForwardError = GetIpForwardTable(pIpFwdTable.get(), &size, TRUE);
|
||
|
||
if (dwIpForwardError == NO_ERROR) //sort by dest addr
|
||
{
|
||
//perform bitwise AND of dest address with netmask and see if it matches network dest
|
||
//todo check for multiple matches and then take longest mask
|
||
for (i=0; i < pIpFwdTable->dwNumEntries; i++)
|
||
{
|
||
if ((dest.sin_addr.s_addr & pIpFwdTable->table[i].dwForwardMask) == pIpFwdTable->table[i].dwForwardDest)
|
||
{
|
||
dwIndex = pIpFwdTable->table[i].dwForwardIfIndex;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (dwIndex == -1)
|
||
{
|
||
// no match
|
||
return HRESULT_FROM_WIN32( ERROR_NETWORK_UNREACHABLE );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LogError( "GetIpForwardTable failed with error %!winerr!, exiting", dwIpForwardError );
|
||
return HRESULT_FROM_WIN32( dwIpForwardError );
|
||
}
|
||
}
|
||
|
||
//
|
||
// At this point dwIndex should be correct.
|
||
//
|
||
ASSERT( dwIndex != -1 );
|
||
|
||
#if DBG
|
||
try
|
||
{
|
||
//
|
||
// Discover the local IP address for the correct interface.
|
||
//
|
||
ULONG size = 0;
|
||
DWORD dwGetIpAddr = GetIpAddrTable(NULL, &size, FALSE);
|
||
if (dwGetIpAddr != ERROR_INSUFFICIENT_BUFFER)
|
||
{
|
||
LogError( "GetIpAddrTable #1 returned %!winerr!", dwGetIpAddr );
|
||
return HRESULT_FROM_WIN32( dwGetIpAddr );
|
||
}
|
||
|
||
auto_ptr<MIB_IPADDRTABLE> pAddrTable( (PMIB_IPADDRTABLE) new char[size] );
|
||
|
||
dwGetIpAddr = GetIpAddrTable(pAddrTable.get(), &size, TRUE);
|
||
if (dwGetIpAddr != NO_ERROR)
|
||
{
|
||
LogError( "GetIpAddrTable #2 returned %!winerr!", dwGetIpAddr );
|
||
return HRESULT_FROM_WIN32( dwGetIpAddr );
|
||
}
|
||
|
||
for (i=0; i < pAddrTable->dwNumEntries; i++)
|
||
{
|
||
if (dwIndex == pAddrTable->table[i].dwIndex)
|
||
{
|
||
in_addr address;
|
||
|
||
address.s_addr = pAddrTable->table[i].dwAddr;
|
||
|
||
LogDl( "Throttling on interface with IP address - %s", inet_ntoa( address ));
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i >= pAddrTable->dwNumEntries)
|
||
{
|
||
LogWarning( "can't find interface with index %d in the IP address table", dwIndex );
|
||
}
|
||
}
|
||
catch ( ComError err )
|
||
{
|
||
LogWarning("unable to print the local IP address due to exception %x", err.Error() );
|
||
}
|
||
#endif // DBG
|
||
|
||
//
|
||
// See if the adapter in question is the AOL adapter. If so, use the AOL dial-up adapter instead.
|
||
//
|
||
|
||
static MIB_IFROW s_TempRow;
|
||
s_TempRow.dwIndex = dwIndex;
|
||
|
||
DWORD dwEntryError = GetIfEntry( &s_TempRow );
|
||
if ( NO_ERROR != dwEntryError )
|
||
{
|
||
LogError( "GetIfEntry(%d) returned %!winerr!", dwIndex, dwEntryError );
|
||
return HRESULT_FROM_WIN32( dwEntryError );
|
||
}
|
||
|
||
if (lstrcmp( LPCWSTR(s_TempRow.bDescr), AOL_ADAPTER) == 0)
|
||
{
|
||
LogWarning( "found AOL adapter, searching for dial-up adapter...");
|
||
|
||
dwIndex = -1;
|
||
|
||
ULONG size = 0;
|
||
DWORD dwGetIfTableError = GetIfTable( NULL, &size, FALSE );
|
||
|
||
if (dwGetIfTableError != ERROR_INSUFFICIENT_BUFFER)
|
||
{
|
||
LogError( "GetIfTable #2 returned %!winerr!", dwGetIfTableError );
|
||
return HRESULT_FROM_WIN32( dwGetIfTableError );
|
||
}
|
||
|
||
auto_ptr<MIB_IFTABLE> pIfTable( (PMIB_IFTABLE) new char[size] );
|
||
if ( !pIfTable.get() )
|
||
{
|
||
LogError( "out of memory getting %d bytes", size);
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
|
||
dwGetIfTableError = GetIfTable( pIfTable.get(), &size, FALSE );
|
||
if ( NO_ERROR != dwGetIfTableError )
|
||
{
|
||
LogError( "GetIfTable #2 returned %!winerr!", dwGetIfTableError );
|
||
return HRESULT_FROM_WIN32( dwGetIfTableError );
|
||
}
|
||
|
||
for (i=0; i < pIfTable->dwNumEntries; ++i)
|
||
{
|
||
if (lstrcmp( LPCWSTR(pIfTable->table[i].bDescr), AOL_DIALUP_ADAPTER) == 0)
|
||
{
|
||
dwIndex = pIfTable->table[i].dwIndex;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
ASSERT( dwIndex != -1 );
|
||
|
||
*pIndex = dwIndex;
|
||
|
||
LogDl( "using interface index %d", dwIndex );
|
||
return S_OK;
|
||
}
|
||
|