1069 lines
29 KiB
C++
1069 lines
29 KiB
C++
/******************************************************************************
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
Client.cpp
|
|
|
|
Abstract:
|
|
This file contains the implementation of the MPCClient class,
|
|
that describes a client's state.
|
|
|
|
Revision History:
|
|
Davide Massarenti (Dmassare) 04/20/99
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#define BUFFER_SIZE_FILECOPY (512)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Construction/Destruction
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::MPCClient
|
|
//
|
|
// Parameters : MPCServer* mpcsServer: callback for getting information about the current request.
|
|
// const Sig& sigID : a reference to the ID for this client.
|
|
//
|
|
// Synopsis : Initializes the MPCClient object with the ID of a client.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
MPCClient::MPCClient( /*[in]*/ MPCServer* mpcsServer ,
|
|
/*[in]*/ const Sig& sigID )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::MPCClient");
|
|
|
|
m_mpcsServer = mpcsServer; // MPCServer* m_mpcsServer;
|
|
// MPC::wstring m_szFile;
|
|
//
|
|
m_sigID = sigID; // Sig m_sigID;
|
|
// List m_lstActiveSessions;
|
|
// SYSTEMTIME m_stLastUsed;
|
|
m_dwLastSession = 0; // DWORD m_dwLastSession;
|
|
//
|
|
m_fDirty = false; // mutable bool m_fDirty;
|
|
m_hfFile = NULL; // mutable HANDLE m_hfFile;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::MPCClient
|
|
//
|
|
// Parameters : MPCServer* mpcsServer : callback for getting information about the current request.
|
|
// const MPC::wstring& szFile : the file holding the DB.
|
|
//
|
|
// Synopsis : Initializes the MPCClient object suppling the filename of the DB of a client.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
MPCClient::MPCClient( /*[in]*/ MPCServer* mpcsServer ,
|
|
/*[in]*/ const MPC::wstring& szFile )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::MPCClient");
|
|
|
|
MPC::wstring::size_type iPos;
|
|
|
|
m_mpcsServer = mpcsServer; // MPCServer* m_mpcsServer;
|
|
m_szFile = szFile; // MPC::wstring m_szFile;
|
|
//
|
|
// Sig m_sigID;
|
|
// List m_lstActiveSessions;
|
|
// SYSTEMTIME m_stLastUsed;
|
|
m_dwLastSession = 0; // DWORD m_dwLastSession;
|
|
//
|
|
m_fDirty = false; // mutable bool m_fDirty;
|
|
m_hfFile = NULL; // mutable HANDLE m_hfFile;
|
|
|
|
|
|
if((iPos = szFile.find( CLIENT_CONST__DB_EXTENSION, 0 )) != MPC::wstring::npos)
|
|
{
|
|
m_szFile = MPC::wstring( &szFile[0], &szFile[iPos] );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::~MPCClient
|
|
//
|
|
// Synopsis : Before destructing the object, ensures its state is updated
|
|
// to disk.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
MPCClient::~MPCClient()
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::~MPCClient");
|
|
|
|
if(m_hfFile)
|
|
{
|
|
(void)SyncToDisk();
|
|
|
|
::CloseHandle( m_hfFile ); m_hfFile = NULL;
|
|
}
|
|
}
|
|
|
|
MPCServer* MPCClient::GetServer() { return m_mpcsServer; }
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Persistence
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::IsDirty
|
|
//
|
|
// Return : bool : 'true' is the object is out-of-sync with the disk.
|
|
//
|
|
// Synopsis : Checks if the object needs to be written to disk.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
bool MPCClient::IsDirty() const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::IsDirty");
|
|
|
|
bool fRes = true; // Default result.
|
|
|
|
|
|
if(m_fDirty)
|
|
{
|
|
__ULT_FUNC_LEAVE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Recursively check the 'Dirty' state of each session.
|
|
//
|
|
for(IterConst it = m_lstActiveSessions.begin(); it != m_lstActiveSessions.end(); it++)
|
|
{
|
|
if(it->IsDirty()) __ULT_FUNC_LEAVE;
|
|
}
|
|
}
|
|
|
|
fRes = false;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(fRes);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::Load
|
|
//
|
|
// Parameters : MPC::Serializer& in : the stream used to initialize the object.
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Loads the state of this object from the stream.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::Load( /*[in]*/ MPC::Serializer& streamIn )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::Load");
|
|
|
|
HRESULT hr;
|
|
DWORD dwVer;
|
|
Sig sigID;
|
|
MPCSession mpcsSession(this);
|
|
|
|
|
|
//
|
|
// Clean up the previous state of the object.
|
|
//
|
|
m_lstActiveSessions.clear();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> dwVer);
|
|
|
|
if(dwVer != c_dwVersion)
|
|
{
|
|
m_fDirty = true; // Force rewrite...
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> sigID );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_stLastUsed );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dwLastSession);
|
|
|
|
if(m_szFile.length())
|
|
{
|
|
//
|
|
// In case of direct access (m_szFile != ""), initialize the sigID from disk.
|
|
//
|
|
m_sigID = sigID;
|
|
}
|
|
else if(m_sigID == sigID)
|
|
{
|
|
//
|
|
// IDs match...
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// IDs don't match, fail.
|
|
//
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
|
|
//
|
|
// While it's successful to read MPCSession objects from the stream,
|
|
// keep adding them to the list of active sessions.
|
|
//
|
|
while(SUCCEEDED(mpcsSession.Load( streamIn )))
|
|
{
|
|
m_lstActiveSessions.push_back( mpcsSession );
|
|
}
|
|
|
|
m_fDirty = false;
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::Save
|
|
//
|
|
// Parameters : MPC::Serializer& out : the stream used to persist the state of the object.
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Saves the state of this object to the stream.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::Save( /*[in]*/ MPC::Serializer& streamOut ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::Save");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << c_dwVersion );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_sigID );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_stLastUsed );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dwLastSession);
|
|
|
|
//
|
|
// Recursively save each session.
|
|
//
|
|
{
|
|
for(IterConst it = m_lstActiveSessions.begin(); it != m_lstActiveSessions.end(); it++)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, it->Save( streamOut ));
|
|
}
|
|
}
|
|
|
|
m_fDirty = false;
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Operators
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
bool MPCClient::operator==( /*[in]*/ const UploadLibrary::Signature& rhs )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::operator==");
|
|
|
|
|
|
bool fRes = (m_sigID == rhs);
|
|
|
|
|
|
__ULT_FUNC_EXIT(fRes);
|
|
}
|
|
|
|
bool MPCClient::Find( /*[in] */ const MPC::wstring& szJobID ,
|
|
/*[out]*/ Iter& it )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::Find");
|
|
|
|
bool fRes;
|
|
|
|
|
|
it = std::find( m_lstActiveSessions.begin(), m_lstActiveSessions.end(), szJobID );
|
|
|
|
fRes = (it != m_lstActiveSessions.end());
|
|
|
|
|
|
__ULT_FUNC_EXIT(fRes);
|
|
}
|
|
|
|
void MPCClient::Erase( /*[in]*/ Iter& it )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::Erase");
|
|
|
|
|
|
m_lstActiveSessions.erase( it );
|
|
m_fDirty = true;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Methods
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::GetInstance
|
|
//
|
|
// Parameters : CISAPIistance*& isapiInstance : instance of this request.
|
|
// bool& fFound : true if instance exists.
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Locates the configuration settings for the server
|
|
// associated with this client.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::GetInstance( /*[out]*/ CISAPIinstance*& isapiInstance ,
|
|
/*[out]*/ bool& fFound ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::GetInstance");
|
|
|
|
HRESULT hr;
|
|
|
|
isapiInstance = m_mpcsServer->getInstance();
|
|
fFound = (isapiInstance != NULL);
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::GetInstance
|
|
//
|
|
// Parameters : MPC::wstring& szURL : variable where to store the server name.
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Returns the URL associated with this client.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::GetInstance( /*[out]*/ MPC::wstring& szURL ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::GetInstance");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
m_mpcsServer->getURL( szURL );
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::IDtoPath
|
|
//
|
|
// Parameters : MPC::wstring& szStr : output buffer for the path.
|
|
//
|
|
// Synopsis : Hashing algorithm, to transform from the client ID to the
|
|
// temporary queue location.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::IDtoPath( /*[out]*/ MPC::wstring& szStr ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::IDtoPath");
|
|
|
|
HRESULT hr;
|
|
WCHAR rgBuf1[4*2+1];
|
|
WCHAR rgBuf2[2*2+1];
|
|
WCHAR rgBuf3[2*2+1];
|
|
WCHAR rgBuf4[8*2+1];
|
|
|
|
|
|
swprintf( rgBuf1, L"%08lx", m_sigID.guidMachineID.Data1 );
|
|
swprintf( rgBuf2, L"%04x" , (int)m_sigID.guidMachineID.Data2 );
|
|
swprintf( rgBuf3, L"%04x" , (int)m_sigID.guidMachineID.Data3 );
|
|
|
|
for(int i=0; i<8; i++)
|
|
{
|
|
swprintf( &rgBuf4[i*2], L"%02x", (int)m_sigID.guidMachineID.Data4[i] );
|
|
}
|
|
|
|
//
|
|
// Debug Format: XXYYYZZZ-AAAA-BBBB-CCCCCCCC
|
|
//
|
|
szStr.append( L"\\" );
|
|
szStr.append( rgBuf1 );
|
|
szStr.append( L"-" );
|
|
szStr.append( rgBuf2 );
|
|
szStr.append( L"-" );
|
|
szStr.append( rgBuf3 );
|
|
szStr.append( L"-" );
|
|
szStr.append( rgBuf4 );
|
|
|
|
//
|
|
// Format: XX\YYY\ZZZ\AAAA-BBBB-CCCCCCCC
|
|
//
|
|
/*
|
|
szStr.append( &rgBuf1[0], &rgBuf1[2] );
|
|
szStr.append( L"\\" );
|
|
szStr.append( &rgBuf1[2], &rgBuf1[5] );
|
|
szStr.append( L"\\" );
|
|
szStr.append( &rgBuf1[5], &rgBuf1[8] );
|
|
szStr.append( L"\\" );
|
|
szStr.append( rgBuf2 );
|
|
szStr.append( L"-" );
|
|
szStr.append( rgBuf3 );
|
|
szStr.append( L"-" );
|
|
szStr.append( rgBuf4 );
|
|
*/
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::BuildClientPath
|
|
//
|
|
// Parameters : MPC::wstring& szPath : output buffer for the path.
|
|
//
|
|
// Synopsis : Returns in 'szPath' the location of this client's data.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::BuildClientPath( /*[out]*/ MPC::wstring& szPath ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::BuildClientPath");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
if(m_szFile.length())
|
|
{
|
|
szPath = m_szFile;
|
|
}
|
|
else
|
|
{
|
|
CISAPIinstance* isapiInstance;
|
|
bool fFound;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, GetInstance( isapiInstance, fFound ));
|
|
if(fFound == false)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
else
|
|
{
|
|
CISAPIinstance::PathIter itBegin;
|
|
CISAPIinstance::PathIter itEnd;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, isapiInstance->GetLocations( itBegin, itEnd ));
|
|
|
|
if(itBegin == itEnd)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
szPath = *itBegin; IDtoPath( szPath );
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::GetFileName
|
|
//
|
|
// Parameters : MPC::wstring& szFile : output buffer for the path.
|
|
//
|
|
// Synopsis : Returns the filename of the directory file.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::GetFileName( /*[out]*/ MPC::wstring& szFile ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::GetFileName");
|
|
|
|
//
|
|
// The filename for the Directory File is "<ID>.db"
|
|
//
|
|
BuildClientPath( szFile );
|
|
|
|
szFile.append( CLIENT_CONST__DB_EXTENSION );
|
|
|
|
|
|
__ULT_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::GetFileSize
|
|
//
|
|
// Parameters : DWORD& dwSize : size of the Directory File.
|
|
//
|
|
// Synopsis : Returns the size of the directory file, if opened.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::GetFileSize( /*[out]*/ DWORD& dwSize ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::GetFileSize");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
if(m_hfFile)
|
|
{
|
|
BY_HANDLE_FILE_INFORMATION info;
|
|
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::GetFileInformationByHandle( m_hfFile, &info ));
|
|
|
|
dwSize = info.nFileSizeLow;
|
|
}
|
|
else
|
|
{
|
|
__MPC_SET_WIN32_ERROR_AND_EXIT( hr, ERROR_INVALID_HANDLE );
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::FormatID
|
|
//
|
|
// Parameters : MPC::wstring& szID : output buffer for the ID.
|
|
//
|
|
// Synopsis : Returns a textual representation of the client ID.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::FormatID( /*[out]*/ MPC::wstring& szID ) const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::FormatID");
|
|
|
|
HRESULT hr;
|
|
CComBSTR bstrSig;
|
|
|
|
bstrSig = m_sigID.guidMachineID;
|
|
szID = bstrSig;
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::CheckSignature
|
|
//
|
|
// Return : bool : 'true' on success.
|
|
//
|
|
// Synopsis : Validates the ID of this client, to ensure it's not a fake.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
bool MPCClient::CheckSignature() const
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::CheckSignature");
|
|
|
|
bool fRes = true;
|
|
|
|
__ULT_FUNC_EXIT(fRes);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::OpenStorage
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Opens the Directory File for this client, trying to
|
|
// lock it for exclusive usage.
|
|
// The file is kept open until this object is deleted.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::OpenStorage( /*[in]*/ bool fCheckFreeSpace )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::OpenStorage");
|
|
|
|
HRESULT hr;
|
|
MPC::wstring szFile;
|
|
bool fLocked = false;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, GetFileName( szFile ));
|
|
|
|
//
|
|
// If requested, make sure there's enough free space before opening the file.
|
|
//
|
|
if(fCheckFreeSpace)
|
|
{
|
|
bool fEnough;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::Util_CheckDiskSpace( szFile, DISKSPACE_SAFETYMARGIN, fEnough ));
|
|
if(fEnough == false)
|
|
{
|
|
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_DISK_FULL );
|
|
}
|
|
}
|
|
|
|
|
|
if(m_hfFile == NULL)
|
|
{
|
|
|
|
// Ensure the directory exists.
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( szFile ) );
|
|
|
|
m_hfFile = ::CreateFileW( szFile.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
|
if(m_hfFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
m_hfFile = NULL;
|
|
|
|
DWORD dwRes = ::GetLastError();
|
|
if(dwRes == ERROR_SHARING_VIOLATION)
|
|
{
|
|
fLocked = true;
|
|
}
|
|
|
|
__MPC_SET_WIN32_ERROR_AND_EXIT( hr, dwRes );
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
MPC::wstring szURL; m_mpcsServer->getURL( szURL );
|
|
MPC::wstring szID; (void)FormatID ( szID );
|
|
|
|
if(fLocked)
|
|
{
|
|
(void)g_NTEvents.LogEvent( EVENTLOG_INFORMATION_TYPE, PCHUL_WARN_COLLISION,
|
|
szURL .c_str(), // %1 = SERVER
|
|
szID .c_str(), // %2 = CLIENT
|
|
szFile.c_str(), // %3 = FILE
|
|
NULL );
|
|
}
|
|
else
|
|
{
|
|
(void)g_NTEvents.LogEvent( EVENTLOG_ERROR_TYPE, PCHUL_ERR_CLIENT_DB,
|
|
szURL .c_str(), // %1 = SERVER
|
|
szID .c_str(), // %2 = CLIENT
|
|
szFile.c_str(), // %3 = FILE
|
|
NULL );
|
|
}
|
|
}
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::InitFromDisk
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Opens the Directory File (if not already opened) and reads
|
|
// the state of the client from disk.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::InitFromDisk( /*[in]*/ bool fCheckFreeSpace )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::InitFromDisk");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, OpenStorage( fCheckFreeSpace ));
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Load( MPC::Serializer_File( m_hfFile ) ));
|
|
|
|
|
|
//
|
|
// Now check that all the files exist.
|
|
//
|
|
{
|
|
Iter it = m_lstActiveSessions.begin();
|
|
while(it != m_lstActiveSessions.end())
|
|
{
|
|
bool fPassed;
|
|
HRESULT hr2 = it->Validate( true, fPassed );
|
|
|
|
if(FAILED(hr2) || fPassed == false)
|
|
{
|
|
m_lstActiveSessions.erase( it ); // Remove session.
|
|
m_fDirty = true;
|
|
|
|
it = m_lstActiveSessions.begin(); // Iterator corrupted, restart from beginning.
|
|
}
|
|
else
|
|
{
|
|
it++;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
//
|
|
// If the file is not correctly loaded, try to recreate it.
|
|
//
|
|
if(hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ))
|
|
{
|
|
hr = SaveToDisk();
|
|
}
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::SaveToDisk
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Opens the Directory File (if not already opened) and writes
|
|
// the state of the client to disk.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::SaveToDisk()
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::SaveToDisk");
|
|
|
|
HRESULT hr;
|
|
DWORD dwRes;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, OpenStorage( false ));
|
|
|
|
|
|
//
|
|
// Move to the beginning of the file and truncate it.
|
|
//
|
|
__MPC_EXIT_IF_CALL_RETURNS_THISVALUE(hr, ::SetFilePointer( m_hfFile, 0, NULL, FILE_BEGIN ), INVALID_SET_FILE_POINTER);
|
|
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::SetEndOfFile( m_hfFile ));
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Save( MPC::Serializer_File( m_hfFile ) ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::SyncToDisk
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : If the Directory File has been read and modified, update it to disk.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::SyncToDisk()
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::SyncToDisk");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
if(m_hfFile && IsDirty())
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, SaveToDisk());
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::GetSessions
|
|
//
|
|
// Parameters : Iter& itBegin : first session.
|
|
// Iter& itEnd : end session marker.
|
|
//
|
|
// Return : HRESULT : S_OK on success, failed otherwise.
|
|
//
|
|
// Synopsis : Returns two iterators to access the sessions.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::GetSessions( /*[out]*/ Iter& itBegin ,
|
|
/*[out]*/ Iter& itEnd )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::GetSessions");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
itBegin = m_lstActiveSessions.begin();
|
|
itEnd = m_lstActiveSessions.end ();
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::NewSession
|
|
//
|
|
// Parameters : UploadLibrary::ClientRequest_OpenSession& req :
|
|
// holds the information for the new session about to create.
|
|
//
|
|
// Return : MPCClient::Iter : an iterator pointing to the new session.
|
|
//
|
|
// Synopsis : Based on the values of 'req', creates a new session.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
MPCClient::Iter MPCClient::NewSession( /*[in]*/ UploadLibrary::ClientRequest_OpenSession& crosReq )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::NewSession");
|
|
|
|
MPCClient::Iter it;
|
|
MPCSession mpcsNewSession( this, crosReq, m_dwLastSession++ );
|
|
|
|
it = m_lstActiveSessions.insert( m_lstActiveSessions.end(), mpcsNewSession );
|
|
|
|
::GetSystemTime( &m_stLastUsed );
|
|
m_fDirty = true;
|
|
|
|
|
|
__ULT_FUNC_EXIT(it);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method Name : MPCClient::AppendData
|
|
//
|
|
// Parameters : UploadLibrary::ClientRequest_OpenSession& req : holds the information for the new session about to create.
|
|
//
|
|
// Return : MPCClient::Iter : an iterator pointing to the new session.
|
|
//
|
|
// Synopsis : Based on the values of 'req', creates a new session.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MPCClient::AppendData( /*[in]*/ MPCSession& mpcsSession ,
|
|
/*[in]*/ MPC::Serializer& streamConn ,
|
|
/*[in]*/ DWORD dwSize )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::AppendData");
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcsSession.AppendData( streamConn, dwSize ));
|
|
|
|
::GetSystemTime( &m_stLastUsed );
|
|
m_fDirty = true;
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT MPCClient::CheckQuotas( /*[in] */ MPCSession& mpcsSession ,
|
|
/*[out]*/ bool& fServerBusy ,
|
|
/*[out]*/ bool& fAccessDenied,
|
|
/*[out]*/ bool& fExceeded )
|
|
{
|
|
__ULT_FUNC_ENTRY("MPCClient::CheckQuotas");
|
|
|
|
HRESULT hr;
|
|
DWORD dwError = 0;
|
|
DWORD dwJobsPerDay = 0;
|
|
DWORD dwBytesPerDay = 0;
|
|
DWORD dwJobSize = 0;
|
|
DWORD dwMaxJobsPerDay;
|
|
DWORD dwMaxBytesPerDay;
|
|
DWORD dwMaxJobSize;
|
|
DWORD fProcessingMode;
|
|
CISAPIprovider* isapiProvider;
|
|
IterConst it;
|
|
bool fFound;
|
|
|
|
|
|
fServerBusy = false;
|
|
fAccessDenied = false;
|
|
fExceeded = false;
|
|
|
|
|
|
//
|
|
// If the related provider doesn't exist, validation fails.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcsSession.GetProvider( isapiProvider, fFound ));
|
|
if(fFound == false)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, isapiProvider->get_MaxJobSize ( dwMaxJobSize ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, isapiProvider->get_MaxJobsPerDay ( dwMaxJobsPerDay ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, isapiProvider->get_MaxBytesPerDay( dwMaxBytesPerDay ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, isapiProvider->get_ProcessingMode( fProcessingMode ));
|
|
|
|
if(fProcessingMode != 0)
|
|
{
|
|
fServerBusy = true;
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
mpcsSession.get_TotalSize( dwJobSize );
|
|
|
|
//
|
|
// Find inactive sessions.
|
|
//
|
|
{
|
|
double dblNow = MPC::GetSystemTime();
|
|
|
|
for(it = m_lstActiveSessions.begin(); it != m_lstActiveSessions.end(); it++)
|
|
{
|
|
double dblLastModified;
|
|
|
|
it->get_LastModified( dblLastModified );
|
|
|
|
if(dblNow - dblLastModified < 1.0) // Within 24 hours.
|
|
{
|
|
DWORD dwTotalSize; it->get_TotalSize( dwTotalSize );
|
|
|
|
dwJobsPerDay += 1;
|
|
dwBytesPerDay += dwTotalSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(dwMaxJobSize && dwMaxJobSize < dwJobSize)
|
|
{
|
|
dwError = PCHUL_INFO_QUOTA_JOB_SIZE;
|
|
fAccessDenied = true;
|
|
}
|
|
|
|
if(dwMaxJobsPerDay && dwMaxJobsPerDay < dwJobsPerDay)
|
|
{
|
|
dwError = PCHUL_INFO_QUOTA_DAILY_JOBS;
|
|
fExceeded = true;
|
|
}
|
|
|
|
if(dwMaxBytesPerDay && dwMaxBytesPerDay < dwBytesPerDay)
|
|
{
|
|
dwError = PCHUL_INFO_QUOTA_DAILY_BYTES;
|
|
fExceeded = true;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if enough free space is available.
|
|
//
|
|
{
|
|
MPC::wstring szFile;
|
|
bool fEnough;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, GetFileName( szFile ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::Util_CheckDiskSpace( szFile, DISKSPACE_SAFETYMARGIN, fEnough ));
|
|
if(fEnough == false)
|
|
{
|
|
dwError = PCHUL_INFO_QUOTA_DAILY_BYTES;
|
|
fExceeded = true;
|
|
}
|
|
}
|
|
|
|
|
|
if(dwError != 0)
|
|
{
|
|
//
|
|
// Quota limits exceeded.
|
|
//
|
|
MPC::wstring szURL; m_mpcsServer->getURL ( szURL );
|
|
MPC::wstring szID; (void)FormatID ( szID );
|
|
MPC::wstring szName; (void)isapiProvider->get_Name( szName );
|
|
|
|
(void)g_NTEvents.LogEvent( EVENTLOG_INFORMATION_TYPE, dwError,
|
|
szURL .c_str(), // %1 = SERVER
|
|
szID .c_str(), // %2 = CLIENT
|
|
szName.c_str(), // %3 = PROVIDER
|
|
NULL );
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__ULT_FUNC_CLEANUP;
|
|
|
|
__ULT_FUNC_EXIT(hr);
|
|
}
|