Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

796 lines
18 KiB

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
precomp.h
Abstract:
Main header for BITS server extensions
--*/
#define INITGUID
#include<nt.h>
#include<ntrtl.h>
#include<nturtl.h>
#include <windows.h>
#include <httpfilt.h>
#include <httpext.h>
#include <objbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <iadmw.h>
#include <iiscnfg.h>
#include <shlwapi.h>
#include <winsock2.h>
#include <iphlpapi.h>
#ifdef USE_WININET
#include <wininet.h>
#else
#include "winhttp.h"
#include "inethttp.h"
#endif
#include <activeds.h>
#include <bitsmsg.h>
#include "resource.h"
#include <strsafe.h>
#if defined(DBG)
// check build
#define BITS_MUST_SUCCEED( expr ) ASSERT( expr )
#else
// free build
#define BITS_MUST_SUCCEED( expr ) ( expr )
#endif
const UINT32 LOG_INFO = 0x1;
const UINT32 LOG_WARNING = 0x2;
const UINT32 LOG_ERROR = 0x4;
const UINT32 LOG_CALLBEGIN = 0x8;
const UINT32 LOG_CALLEND = 0x10;
#if defined(DBG)
const UINT32 DEFAULT_LOG_FLAGS = LOG_INFO | LOG_WARNING | LOG_ERROR | LOG_CALLBEGIN | LOG_CALLEND;
#else
const UINT32 DEFAULT_LOG_FLAGS = 0;
#endif
const UINT32 DEFAULT_LOG_SIZE = 20;
// LogSetings path under HKEY_LOCAL_MACHINE
const char * const LOG_SETTINGS_PATH = "SOFTWARE\\Microsoft\\BITSServer";
// Values
// (REG_EXPAND_SZ). Contains the full path of the log file name
const char * const LOG_FILENAME_VALUE = "LogFileName";
// (REG_DWORD) Contains the log flags
const char * const LOG_FLAGS_VALUE = "LogFlags";
// (REG_DWORD) Contains the log size in MB
const char * const LOG_SIZE_VALUE = "LogSize";
extern UINT32 g_LogFlags;
HRESULT LogInit();
void LogClose();
void LogInternal( UINT32 LogFlags, char *Format, va_list arglist );
void inline Log( UINT32 LogFlags, char *Format, ... )
{
if ( !( g_LogFlags & LogFlags ) )
return;
va_list arglist;
va_start( arglist, Format );
LogInternal( LogFlags, Format, arglist );
}
const char *LookupHTTPStatusCodeText( DWORD HttpCode );
class ServerException
{
public:
ServerException() :
m_Code( 0 ),
m_HttpCode( 0 ),
m_Context( 0 )
{
}
ServerException( HRESULT Code, DWORD HttpCode = 0, DWORD Context = 0x5 ) :
m_Code( Code ),
m_HttpCode( HttpCode ? HttpCode : MapStatus( Code ) ),
m_Context( Context )
{
}
HRESULT GetCode() const
{
return m_Code;
}
DWORD GetHttpCode() const
{
return m_HttpCode;
}
DWORD GetContext() const
{
return m_Context;
}
void SendErrorResponse( EXTENSION_CONTROL_BLOCK * ExtensionControlBlock ) const;
DWORD MapStatus( HRESULT Hr ) const;
private:
HRESULT m_Code;
DWORD m_HttpCode;
DWORD m_Context;
};
class CharStringRoutines
{
public:
static int strcmp( const char *str1, const char *str2 )
{
return ::strcmp( str1, str2 );
}
static HRESULT StringCchCopy( char *str1, size_t cchDest, const char *str2 )
{
return ::StringCchCopyA( str1, cchDest, str2 );
}
static size_t strlen( const char *str )
{
return ::strlen( str );
}
static void* ConvertToInternal( SIZE_T Pad, const char *String, SIZE_T & Size )
{
Size = ::strlen( String );
char *Ret = new char[ Pad + Size + 1 ];
::StringCchCopyA( Ret + Pad, Size + 1, String );
return (void*)Ret;
}
static void* ConvertToInternal( SIZE_T Pad, const WCHAR *String, SIZE_T & Size )
{
int Alloc =
WideCharToMultiByte(
CP_THREAD_ACP, // code page
0, // performance and mapping flags
String, // wide-character string
-1, // number of chars in string
NULL, // buffer for new string
0, // size of buffer
NULL, // default for unmappable chars
NULL // set when default char used
);
if ( !Alloc )
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
char *Ret = new char[ Pad + Alloc ];
int Actual =
WideCharToMultiByte(
CP_THREAD_ACP, // code page
0, // performance and mapping flags
String, // wide-character string
-1, // number of chars in string
Ret + Pad, // buffer for new string
Alloc, // size of buffer
NULL, // default for unmappable chars
NULL // set when default char used
);
if ( !Actual )
{
HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
delete[] Ret;
throw ServerException( Hr );
}
Size = Actual - 1;
return Ret;
}
};
class WCHARStringRoutines
{
public:
static int strcmp( const WCHAR *str1, const WCHAR *str2 )
{
return ::wcscmp( str1, str2 );
}
static HRESULT StringCchCopy( WCHAR *str1, size_t cchDest, const WCHAR *str2 )
{
return ::StringCchCopyW( str1, cchDest, str2 );
}
static size_t strlen( const wchar_t *str )
{
return ::wcslen( str );
}
static void* ConvertToInternal( SIZE_T Pad, const WCHAR *String, SIZE_T & Size )
{
Size = ::wcslen( String );
char *Ret = new char[ Pad + ( ( Size + 1 ) * sizeof(WCHAR) ) ];
::StringCchCopyW( (WCHAR*)(Ret + Pad), Size + 1, String );
return (void*)Ret;
}
static void* ConvertToInternal( SIZE_T Pad, const char *String, SIZE_T & Size )
{
int Alloc =
MultiByteToWideChar(
CP_THREAD_ACP, // code page
0, // character-type options
String, // string to map
-1, // number of bytes in string
NULL, // wide-character buffer
0 // size of buffer
);
if ( !Alloc )
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
char *Ret = new char[ Pad + ( Alloc * sizeof(WCHAR) ) ];
int Actual =
MultiByteToWideChar(
CP_THREAD_ACP, // code page
0, // character-type options
String, // string to map
-1, // number of bytes in string
(WCHAR*)( Ret + Pad ), // wide-character buffer
Alloc // size of buffer
);
if ( !Actual )
{
HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
delete[] Ret;
throw ServerException( Hr );
}
Size = Actual - 1;
return Ret;
}
};
template<class T, class CONV>
class StringHandleTemplate : private CONV
{
struct StringData
{
SIZE_T m_Count;
long m_Refs;
};
struct EmptyStringData
{
StringData m_StringData;
T m_Data;
};
static EmptyStringData s_EmptyString;
StringData *m_Value;
void NewString( const char *String, bool ReplaceExisting = false );
void NewString( const WCHAR *String, bool ReplaceExisting = false );
StringData * RefIt() const
{
InterlockedIncrement( &m_Value->m_Refs );
return m_Value;
}
void FreeIt()
{
if ( InterlockedDecrement( &m_Value->m_Refs ) == 0 )
delete[] (char*)m_Value;
}
// Create String by concating 2 strings
StringHandleTemplate( const StringData *LeftValue, const T *RightValue, SIZE_T RightSize );
public:
StringHandleTemplate()
{
NewString( (T*)NULL );
}
StringHandleTemplate( const char *String )
{
NewString( String );
}
StringHandleTemplate( const WCHAR *String )
{
NewString( String );
}
StringHandleTemplate( const StringHandleTemplate & Other ) :
m_Value( Other.RefIt() )
{
}
~StringHandleTemplate()
{
FreeIt();
}
void SetStringSize()
{
m_Value->m_Count = strlen( (T*)(m_Value + 1) );
}
T *AllocBuffer( SIZE_T Size );
StringHandleTemplate & operator=( const StringHandleTemplate & r )
{
FreeIt();
m_Value = r.RefIt();
return *this;
}
StringHandleTemplate & operator=( const T * r )
{
NewString( r, true );
return *this;
}
SIZE_T Size() const
{
return m_Value->m_Count;
}
operator const T*() const
{
return (const T*)(m_Value + 1);
}
bool operator <( const StringHandleTemplate & r ) const
{
if ( m_Value == r.m_Value)
return false;
return (strcmp( (const T*)*this, (const T*)r ) < 0);
}
StringHandleTemplate operator+( const StringHandleTemplate & r ) const
{
return StringHandleTemplate( m_Value, (T*)(r.m_Value+1), r.m_Value->m_Count );
}
StringHandleTemplate operator+( const T * p ) const
{
static const T EmptyChar = '\0';
if ( !p )
return StringHandleTemplate( m_Value, &EmptyChar, 0 );
return StringHandleTemplate( m_Value, p, strlen(p) );
}
StringHandleTemplate & operator+=( const StringHandleTemplate & r )
{
return (*this = (*this + r ) );
}
StringHandleTemplate & operator+=( const T * p )
{
return (*this = (*this + p ) );
}
};
template<class T,class CONV>
void
StringHandleTemplate<T,CONV>::NewString( const char *String, bool ReplaceExisting )
{
if ( !String )
{
InterlockedIncrement( &s_EmptyString.m_StringData.m_Refs );
StringData* Value = (StringData*)&s_EmptyString;
if ( ReplaceExisting )
FreeIt();
m_Value = Value;
return;
}
SIZE_T Size;
StringData* Value = (StringData*)ConvertToInternal( sizeof(StringData), String, Size );
Value->m_Count = Size;
Value->m_Refs = 1;
if ( ReplaceExisting )
FreeIt();
m_Value = Value;
}
template<class T,class CONV>
void
StringHandleTemplate<T,CONV>::NewString( const WCHAR *String, bool ReplaceExisting )
{
if ( !String )
{
InterlockedIncrement( &s_EmptyString.m_StringData.m_Refs );
StringData* Value = (StringData*)&s_EmptyString;
if ( ReplaceExisting )
FreeIt();
m_Value = Value;
return;
}
SIZE_T Size;
StringData* Value = (StringData*)ConvertToInternal( sizeof(StringData), String, Size );
Value->m_Count = Size;
Value->m_Refs = 1;
if ( ReplaceExisting )
FreeIt();
m_Value = Value;
}
// Create String by concating 2 strings
template<class T,class CONV>
StringHandleTemplate<T,CONV>::StringHandleTemplate( const StringData *LeftValue, const T *RightValue, SIZE_T RightSize )
{
SIZE_T Size = LeftValue->m_Count + RightSize;
m_Value = (StringData*)new char[ sizeof(StringData) + (Size*sizeof(T)) + sizeof(T) ];
m_Value->m_Count = Size;
m_Value->m_Refs = 1;
T *DestData = (T*)( m_Value + 1 );
memcpy( DestData, (T*)(LeftValue + 1), sizeof(T) * LeftValue->m_Count );
memcpy( DestData + LeftValue->m_Count, RightValue, sizeof( T ) * RightSize );
DestData[ Size ] = 0;
}
template<class T,class CONV>
T *
StringHandleTemplate<T,CONV>::AllocBuffer( SIZE_T Size )
{
StringData *Data = (StringData*)new T[sizeof(StringData)+(Size*sizeof(T))+sizeof(T)];
Data->m_Count = 0;
Data->m_Refs = 1;
T *String = (T*)(Data + 1);
String[0] = '\0';
FreeIt(); // Free old string
m_Value = Data;
// Whoever fills in the string needs to call SetStringSize
return String;
}
template<class T,class CONV>
StringHandleTemplate<T,CONV>::EmptyStringData StringHandleTemplate<T,CONV>::s_EmptyString =
{
0, 1, L'\0' // Initialize with 1 ref so it is never deleted
};
typedef StringHandleTemplate<char, CharStringRoutines> StringHandleA;
typedef StringHandleTemplate<WCHAR, WCHARStringRoutines> StringHandleW;
typedef StringHandleA StringHandle;
inline UINT64 FILETIMEToUINT64( const FILETIME & FileTime )
{
ULARGE_INTEGER LargeInteger;
LargeInteger.HighPart = FileTime.dwHighDateTime;
LargeInteger.LowPart = FileTime.dwLowDateTime;
return LargeInteger.QuadPart;
}
inline FILETIME UINT64ToFILETIME( UINT64 Int64Value )
{
ULARGE_INTEGER LargeInteger;
LargeInteger.QuadPart = Int64Value;
FILETIME FileTime;
FileTime.dwHighDateTime = LargeInteger.HighPart;
FileTime.dwLowDateTime = LargeInteger.LowPart;
return FileTime;
}
// API thunks
UINT64 BITSGetFileSize(
HANDLE Handle );
UINT64 BITSSetFilePointer(
HANDLE Handle,
INT64 Distance,
DWORD MoveMethod );
DWORD
BITSWriteFile(
HANDLE Handle,
LPCVOID Buffer,
DWORD NumberOfBytesToWrite);
void
BITSCreateDirectory(
LPCTSTR DirectoryName
);
void
BITSRenameFile(
LPCTSTR ExistingName,
LPCTSTR NewName );
void
BITSDeleteFile(
LPCTSTR FileName );
GUID
BITSCreateGuid();
GUID
BITSGuidFromString( const char *String );
StringHandle
BITSStringFromGuid(
GUID Guid );
StringHandle
BITSUnicodeToStringHandle( const WCHAR *pStr );
StringHandle
BITSUrlCombine(
const char *Base,
const char *Relative,
DWORD dwFlags );
StringHandle
BITSUrlCanonicalize(
const char *URL,
DWORD dwFlags );
void
BITSSetCurrentThreadToken(
HANDLE hToken );
// Metadata wrappers
StringHandle
GetMetaDataString(
IMSAdminBase *IISAdminBase,
METADATA_HANDLE Handle,
LPCWSTR Path,
DWORD dwIdentifier,
LPCSTR DefaultValue );
DWORD
GetMetaDataDWORD(
IMSAdminBase *IISAdminBase,
METADATA_HANDLE Handle,
LPCWSTR Path,
DWORD dwIdentifier,
DWORD DefaultValue );
class WorkStringBufferA
{
char *Data;
public:
WorkStringBufferA( SIZE_T Size )
{
Data = new char[Size];
}
WorkStringBufferA( const char* String )
{
size_t BufferSize = strlen(String) + 1;
Data = new char[ BufferSize ];
memcpy( Data, String, BufferSize );
}
~WorkStringBufferA()
{
delete[] Data;
}
char *GetBuffer()
{
return Data;
}
};
class WorkStringBufferW
{
WCHAR *Data;
public:
WorkStringBufferW( SIZE_T Size )
{
Data = new WCHAR[Size];
}
WorkStringBufferW( const WCHAR* String )
{
size_t BufferSize = wcslen(String) + 1;
Data = new WCHAR[ BufferSize ];
memcpy( Data, String, BufferSize * sizeof( WCHAR ) );
}
~WorkStringBufferW()
{
delete[] Data;
}
WCHAR *GetBuffer()
{
return Data;
}
};
typedef WorkStringBufferA WorkStringBuffer;
const char * const BITS_CONNECTIONS_NAME_WITH_SLASH="BITS-Connections\\";
const char * const BITS_CONNECTIONS_NAME="BITS-Connections";
const UINT64 NanoSec100PerSec = 10000000; //no of 100 nanosecs per sec
const DWORD WorkerRunInterval = 1000 * 60 /*secs*/ * 60 /*mins*/ * 12; /* hours */ /* twice a day */
const UINT64 CleanupThreshold = NanoSec100PerSec * 60 /*secs*/ * 60 /*mins*/ * 24 /* hours */ * 3; // 3 days
//
// Configuration manager
//
#include "bitssrvcfg.h"
class ConfigurationManager;
class VDirConfig
{
friend ConfigurationManager;
LONG m_Refs;
FILETIME m_LastLookup;
public:
StringHandle m_Path;
StringHandle m_PhysicalPath;
StringHandle m_ConnectionsDir;
DWORD m_NoProgressTimeout;
UINT64 m_MaxFileSize;
BITS_SERVER_NOTIFICATION_TYPE m_NotificationType;
StringHandle m_NotificationURL;
bool m_UploadEnabled;
StringHandle m_HostId;
DWORD m_HostIdFallbackTimeout;
DWORD m_ExecutePermissions;
VDirConfig(
StringHandle Path,
IMSAdminBase *AdminBase );
void AddRef()
{
InterlockedIncrement( &m_Refs );
}
void Release()
{
if (!InterlockedDecrement( &m_Refs ))
delete this;
}
};
class MapCacheEntry
{
friend ConfigurationManager;
FILETIME m_LastLookup;
public:
StringHandle m_InstanceMetabasePath;
StringHandle m_URL;
VDirConfig *m_Config;
MapCacheEntry(
StringHandle InstanceMetabasePath,
StringHandle URL,
VDirConfig * Config ) :
m_InstanceMetabasePath( InstanceMetabasePath ),
m_URL( URL ),
m_Config( Config )
{
m_Config->AddRef();
GetSystemTimeAsFileTime( &m_LastLookup );
}
~MapCacheEntry()
{
m_Config->Release();
}
};
class ConfigurationManager
{
public:
ConfigurationManager();
~ConfigurationManager();
VDirConfig* GetConfig( StringHandle InstanceMetabasePath, StringHandle URL );
static const PATH_CACHE_ENTRIES = 10;
static const MAP_CACHE_ENTRIES = 10;
private:
IMSAdminBase *m_IISAdminBase;
CRITICAL_SECTION m_CacheCS;
DWORD m_ChangeNumber;
VDirConfig *m_PathCacheEntries[ PATH_CACHE_ENTRIES ];
MapCacheEntry *m_MapCacheEntries[ MAP_CACHE_ENTRIES ];
void FlushCache();
bool HandleCacheConsistency();
// L2 cache
VDirConfig* Lookup( StringHandle Path );
void Insert( VDirConfig *NewConfig );
VDirConfig* GetVDirConfig( StringHandle Path );
// L1 cache
VDirConfig* Lookup( StringHandle InstanceMetabasePath,
StringHandle URL );
VDirConfig* Insert( StringHandle InstanceMetabasePath,
StringHandle URL,
StringHandle Path );
StringHandle GetVDirPath( StringHandle InstanceMetabasePath,
StringHandle URL );
};
extern ConfigurationManager *g_ConfigMan;
extern HMODULE g_hinst;
extern PropertyIDManager *g_PropertyMan;