windows-nt/Source/XPSP1/NT/admin/services/drizzle/newjob/downloader.h
2020-09-26 16:20:57 +08:00

642 lines
13 KiB
C++

/************************************************************************
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
);