|
|
/************************************************************************
Copyright (c) 2000 - 2000 Microsoft Corporation
Module Name :
progressivedl.h
Abstract :
Main header file for downloader.
Author :
Revision History :
***********************************************************************/
#pragma once
#define MIN(a, b) (a>b ? b:a)
#define MAX(a, b) (a>b ? a:b)
#define MAX_REPLY_DATA (2 * INTERNET_MAX_URL_LENGTH)
#define E_RETRY HRESULT_FROM_WIN32( ERROR_RETRY )
#define BG_E_HEADER_NOT_FOUND HRESULT_FROM_WIN32( ERROR_HTTP_HEADER_NOT_FOUND )
//
// valid in HTTP 1.1, but not defined in the Windows-XP version of wininet.h
//
#define HTTP_STATUS_RANGE_NOT_SATISFIABLE 416
//----------------------------------------------------------------------
typedef HRESULT (*QMCALLBACK)(DWORD, DWORD, LPBYTE, DWORD);
#define MAX_VIA_HEADER_LENGTH 300
#define FILE_DATA_BUFFER_LEN 63000
extern BYTE g_FileDataBuffer[];
//--------------------------------------------
struct URL_INFO { HINTERNET hInternet; HINTERNET hConnect;
FILETIME UrlModificationTime; FILETIME FileCreationTime; UINT64 FileSize; DWORD dwFlags;
bool bHttp11; bool bRange; bool fProxy;
//
// Most of these could be stack variables, but they are too big.
//
TCHAR HostName[INTERNET_MAX_URL_LENGTH + 1];
// host-relative URL
//
TCHAR UrlPath[INTERNET_MAX_URL_LENGTH + 1];
INTERNET_PORT Port;
// a copy of <UrlPath> with range information appended as parameters
//
TCHAR BlockUrl[INTERNET_MAX_URL_LENGTH + 1];
TCHAR UserName[UNLEN + 1]; TCHAR Password[UNLEN + 1];
PROXY_SETTINGS_CONTAINER * ProxySettings;
CAutoString ProxyHost;
TCHAR ViaHeader[ MAX_VIA_HEADER_LENGTH + 1];
const CCredentialsContainer * Credentials;
//--------
URL_INFO( LPCTSTR a_Url, const PROXY_SETTINGS * a_ProxySettings, const CCredentialsContainer * a_Credentials, LPCTSTR HostId = NULL );
~URL_INFO();
void Cleanup();
QMErrInfo Connect();
void Disconnect();
BOOL GetProxyUsage( HINTERNET hRequest, QMErrInfo *pQMErrInfo );
};
//---------------------------------------------
class CUploadJob;
class CJobManager;
class ITransferCallback { public:
virtual bool DownloaderProgress( UINT64 BytesTransferred, UINT64 BytesTotal ) = 0;
virtual bool PollAbort() = 0;
virtual bool UploaderProgress( UINT64 BytesTransferred ) = 0;
};
class Downloader { public:
virtual HRESULT Download( LPCTSTR szURL, LPCTSTR szDest, UINT64 Offset, ITransferCallback *CallBack, QMErrInfo *pErrInfo, HANDLE hToken, BOOL bThrottle, const PROXY_SETTINGS * pProxySettings, // optional
const CCredentialsContainer * Credentials, const StringHandle HostId = StringHandle() // optional
) = 0;
virtual HRESULT GetRemoteFileInformation( HANDLE hToken, LPCTSTR szURL, UINT64 * pFileSize, FILETIME *pFileTime, QMErrInfo *pErrInfo, const PROXY_SETTINGS * pProxySettings, //optional
const CCredentialsContainer * Credentials, // optional
const StringHandle HostId = StringHandle() // optional
) = 0;
virtual ~Downloader() {}
protected:
};
HRESULT CreateHttpDownloader( Downloader **ppDownloader, QMErrInfo *pErrInfo ); void DeleteHttpDownloader( Downloader * pDownloader );
extern DWORD g_dwDownloadThread; extern HWND ghPDWnd;
//
// conversion factor to go from time in milliseconds to time in 100-nanoseconds.
//
#define ONE_MSEC_IN_100_NSEC (10 * 1000)
class CPeriodicTimer { public:
CPeriodicTimer( LPSECURITY_ATTRIBUTES Security = NULL, BOOL ManualReset = FALSE, LPCTSTR Name = NULL ) { m_handle = CreateWaitableTimer( Security, ManualReset, Name ); if (!m_handle) { ThrowLastError(); } }
~CPeriodicTimer() { if (m_handle) { CloseHandle( m_handle ); } }
BOOL Start( LONG Period, BOOL fResume = FALSE, PTIMERAPCROUTINE fn = NULL, LPVOID arg = NULL ) { LARGE_INTEGER Time;
//
// negative values are relative; positive values are absolute.
// The period is in milliseconds, but the start time is in units of 100-nanoseconds,
//
Time.QuadPart = -1 * Period * ONE_MSEC_IN_100_NSEC;
return SetWaitableTimer( m_handle, &Time, Period, fn, arg, fResume ); }
BOOL Stop() { return CancelWaitableTimer( m_handle ); }
BOOL Wait( LONG msec = INFINITE ) { if (WAIT_OBJECT_0 != WaitForSingleObject( m_handle, msec )) { return FALSE; }
return TRUE; }
private:
HANDLE m_handle; };
//
// Network rate is in bytes per second.
//
typedef float NETWORK_RATE;
class CNetworkInterface { public:
//
// snapshot indices
//
enum { BLOCK_START = 0, BLOCK_END, BLOCK_INTERVAL_END, BLOCK_COUNT };
typedef float SECONDS;
//
// public interface
//
CNetworkInterface();
void Reset();
void SetInterfaceSpeed();
HRESULT TakeSnapshot( int SnapshotIndex );
HRESULT SetInterfaceIndex( const TCHAR host[] );
BOOL SetTimerInterval( SECONDS interval );
NETWORK_RATE GetInterfaceSpeed() { return m_ServerSpeed; }
float GetPercentFree() { return m_PercentFree; }
void ResetInterface() { m_InterfaceIndex = -1; }
void Wait() { m_Timer.Wait(); } void StopTimer() { m_Timer.Stop(); }
void CalculateIntervalAndBlockSize( UINT64 MaxBlockSize );
DWORD m_BlockSize;
SECONDS m_BlockInterval;
private:
static const NETWORK_RATE DEFAULT_SPEED;
struct NET_SNAPSHOT { LARGE_INTEGER TimeStamp; UINT BytesIn; UINT BytesOut; };
//
// index of the interface that Wininet would use to talk to the server.
//
DWORD m_InterfaceIndex;
//
// the "start" and "end" pictures of network activity.
//
NET_SNAPSHOT m_Snapshots[BLOCK_COUNT];
//
// the apparent speed of the connection to our server
//
NETWORK_RATE m_ServerSpeed;
//
// The local interface's apparent speed
//
NETWORK_RATE m_NetcardSpeed;
//
//
//
float m_PercentFree;
//
// Error value from previous snapshots in the current series {BLOCK_START, BLOCK_END, INTERVAL_END}.
//
HRESULT m_SnapshotError;
//
// true if all three snapshots in the current series are valid.
// If so, then it is safe to calculate network speed and server speed.
//
bool m_SnapshotsValid;
MIB_IFROW m_TempRow;
//
// The download thread sends only one packet per timer notification.
// This is the timer.
//
CPeriodicTimer m_Timer;
enum DOWNLOAD_STATE { DOWNLOADED_BLOCK = 0x55, SKIPPED_ONE_BLOCK, SKIPPED_TWO_BLOCKS };
enum DOWNLOAD_STATE m_state;
static HRESULT FindInterfaceIndex( const TCHAR host[], DWORD * pIndex );
float GetTimeDifference( int start, int finish );
//throttle related
DWORD BlockSizeFromInterval( SECONDS interval );
SECONDS IntervalFromBlockSize( DWORD BlockSize );
};
/////////////////////////////////////////////////////////////////////////////
// CProgressiveDL
//
class CProgressiveDL : public Downloader { public: CProgressiveDL( QMErrInfo *pErrInfo ); ~CProgressiveDL();
// pure virtual method from class Downloader
virtual HRESULT Download( LPCTSTR szURL, LPCTSTR szDest, UINT64 Offset, ITransferCallback * CallBack, QMErrInfo *pErrInfo, HANDLE hToken, BOOL bThrottle, const PROXY_SETTINGS *pProxySettings, const CCredentialsContainer * Credentials, const StringHandle HostId = StringHandle() );
virtual HRESULT GetRemoteFileInformation( HANDLE hToken, LPCTSTR szURL, UINT64 * pFileSize, FILETIME *pFileTime, QMErrInfo *pErrInfo, const PROXY_SETTINGS * pProxySettings, const CCredentialsContainer * Credentials, const StringHandle HostId = StringHandle() );
// other methods
private:
//download related
BOOL OpenLocalDownloadFile( LPCTSTR Path, UINT64 Offset, UINT64 Size, FILETIME UrlModificationTime );
BOOL CloseLocalFile();
BOOL WriteBlockToCache(LPBYTE lpBuffer, DWORD dwRead);
BOOL SetFileTimes();
HRESULT DownloadFile( HANDLE hToken, const PROXY_SETTINGS * ProxySettings, const CCredentialsContainer * Credentials, LPCTSTR Url, LPCWSTR Path, UINT64 Offset, StringHandle HostId );
HRESULT GetNextBlock( ); BOOL DownloadBlock( void * Buffer, DWORD * pdwRead);
HRESULT OpenConnection(); void CloseHandles();
BOOL IsAbortRequested() { return m_Callbacks->PollAbort(); }
BOOL IsFileComplete() { if (m_CurrentOffset == m_wupdinfo->FileSize) { return TRUE; }
return FALSE; }
void ClearError();
void SetError( ERROR_SOURCE Source, ERROR_STYLE Style, UINT64 Code, char * comment = 0 );
BOOL IsErrorSet() {
// If the file was aborted, the error wont
// be set.
if (QM_FILE_ABORTED == m_pQMInfo->result) { return TRUE; }
if (QM_SERVER_FILE_CHANGED == m_pQMInfo->result ) { return TRUE; }
if (m_pQMInfo->Style != 0) { return TRUE; }
return FALSE; }
BOOL GetRemoteResourceInformation( URL_INFO * Info, QMErrInfo * pQMErrInfo );
//
// These are static so they they don't mess with member data accidentally
//
static bool DoesErrorIndicateNoISAPI( DWORD dwHttpError );
HRESULT CreateBlockUrl( LPTSTR lpszNewUrl, DWORD Length);
HRESULT StartEncodedRangeRequest( DWORD Length );
HRESULT StartRangeRequest( DWORD Length );
//--------------------------------------------------------------------
HANDLE m_hFile;
//download related
URL_INFO * m_wupdinfo;
UINT64 m_CurrentOffset;
HINTERNET m_hOpenRequest;
QMErrInfo *m_pQMInfo;
ITransferCallback * m_Callbacks;
BOOL m_bThrottle;
HRESULT DownloadForegroundFile();
public:
//
// Tracks network statistics.
//
CNetworkInterface m_Network;
};
extern CACHED_AUTOPROXY * g_ProxyCache;
HRESULT SendRequest( HINTERNET hRequest, URL_INFO * Info );
HRESULT SetRequestCredentials( HINTERNET hRequest, const CCredentialsContainer & Container );
HRESULT SetRequestProxy( HINTERNET hRequest, PROXY_SETTINGS_CONTAINER * ProxySettings );
HRESULT OpenHttpRequest( LPCTSTR Verb, LPCTSTR Protocol, URL_INFO & Info, HINTERNET * phRequest );
URL_INFO * ConnectToUrl( LPCTSTR Url, const PROXY_SETTINGS * ProxySettings, const CCredentialsContainer * Credentials, LPCTSTR HostId, QMErrInfo * pErrInfo );
HRESULT GetRequestHeader( HINTERNET hRequest, DWORD HeaderIndex, LPCWSTR HeaderName, CAutoString & Destination, size_t MaxChars );
HRESULT GetResponseVersion( HINTERNET hRequest, unsigned * MajorVersion, unsigned * MinorVersion );
HRESULT AddRangeHeader( HINTERNET hRequest, UINT64 Start, UINT64 End );
HRESULT AddIf_Unmodified_SinceHeader( HINTERNET hRequest, const FILETIME &Time );
|