888 lines
23 KiB
C++
888 lines
23 KiB
C++
|
/******************************************************************************
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
Server.cpp
|
||
|
|
||
|
Abstract:
|
||
|
This file contains the implementation of the MPCServer class,
|
||
|
that controls the overall interaction between client and server.
|
||
|
|
||
|
Revision History:
|
||
|
Davide Massarenti (Dmassare) 04/20/99
|
||
|
created
|
||
|
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// Construction/Destruction
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
MPCServer::MPCServer( /*[in]*/ MPCHttpContext* hcCallback, /*[in]*/ LPCWSTR szURL, /*[in]*/ LPCWSTR szUser )
|
||
|
: m_SelfCOM ( this ),
|
||
|
m_crClientRequest ( 0 ),
|
||
|
m_srServerResponse( UPLOAD_LIBRARY_PROTOCOL_VERSION_SRV ) // Prepare default response protocol.
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::MPCServer");
|
||
|
|
||
|
bool fFound;
|
||
|
|
||
|
m_szURL = SAFEWSTR( szURL ); // MPC::wstring m_szURL;
|
||
|
m_szUser = SAFEWSTR( szUser ); // MPC::wstring m_szUser;
|
||
|
m_isapiInstance = NULL; // CISAPIinstance* m_isapiInstance;
|
||
|
m_flLogHandle = NULL; // MPC::FileLog* m_flLogHandle;
|
||
|
//
|
||
|
m_hcCallback = hcCallback; // MPCHttpContext* m_hcCallback;
|
||
|
m_mpccClient = NULL; // MPCClient* m_mpccClient;
|
||
|
//
|
||
|
// UploadLibrary::ClientRequest m_crClientRequest;
|
||
|
// UploadLibrary::ServerResponse m_srServerResponse;
|
||
|
//
|
||
|
// MPC::Serializer_Memory m_streamResponseData;
|
||
|
// MPCServerCOMWrapper m_SelfCOM;
|
||
|
m_Session = NULL; // MPCSession* m_Session;
|
||
|
m_customProvider = NULL; // IULProvider* m_customProvider;
|
||
|
m_fTerminated = false; // bool m_fTerminated;
|
||
|
|
||
|
|
||
|
if(SUCCEEDED(::Config_GetInstance( m_szURL, m_isapiInstance, fFound )))
|
||
|
{
|
||
|
if(fFound)
|
||
|
{
|
||
|
m_isapiInstance->get_LogHandle( m_flLogHandle );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MPCServer::~MPCServer()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::~MPCServer");
|
||
|
|
||
|
|
||
|
ReleaseClient();
|
||
|
}
|
||
|
|
||
|
IULServer* MPCServer::COM() { return &m_SelfCOM; }
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// Methods.
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void MPCServer::getURL ( MPC::wstring& szURL ) { szURL = m_szURL ; }
|
||
|
void MPCServer::getUser( MPC::wstring& szUser ) { szUser = m_szUser; }
|
||
|
|
||
|
CISAPIinstance* MPCServer::getInstance() { return m_isapiInstance; }
|
||
|
MPC::FileLog* MPCServer::getFileLog () { return m_flLogHandle ; }
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT MPCServer::Process( BOOL& fKeepAlive )
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::Process");
|
||
|
|
||
|
MPC::Serializer& streamConn = MPCSerializerHttp( m_hcCallback );
|
||
|
HRESULT hr;
|
||
|
|
||
|
m_fKeepAlive = TRUE;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
if(m_hcCallback->m_Debug_FIXED_POINTER_ERROR)
|
||
|
{
|
||
|
m_srServerResponse.dwPosition = m_hcCallback->m_Debug_FIXED_POINTER_ERROR_pos;
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_SKIPPED, TRUE );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Enforce maximum request size.
|
||
|
//
|
||
|
{
|
||
|
DWORD dwMaximumPacketSize;
|
||
|
DWORD dwCount;
|
||
|
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::Config_GetMaximumPacketSize( m_szURL, dwMaximumPacketSize ));
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hcCallback->GetRequestSize( dwCount ));
|
||
|
|
||
|
if(dwCount > dwMaximumPacketSize)
|
||
|
{
|
||
|
WCHAR rgSize[16]; swprintf( rgSize, L"%d", dwCount );
|
||
|
|
||
|
(void)g_NTEvents.LogEvent( EVENTLOG_WARNING_TYPE, PCHUL_WARN_PACKET_SIZE,
|
||
|
m_szURL.c_str(), // %1 = SERVER
|
||
|
rgSize , // %2 = SIZE
|
||
|
NULL );
|
||
|
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"ERROR | Received a packet too large: %ld, limit %ld", dwCount, dwMaximumPacketSize );
|
||
|
}
|
||
|
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BAD_REQUEST );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Read request.
|
||
|
//
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamConn >> m_crClientRequest);
|
||
|
|
||
|
if(m_srServerResponse.MatchVersion( m_crClientRequest ) == false)
|
||
|
{
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"ERROR | Received an invalid packet: SIG:%08lx VER:%08lx", m_crClientRequest.rhProlog.dwSignature, m_crClientRequest.rhProlog.dwVersion );
|
||
|
}
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BAD_REQUEST );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
if(FAILED(hr = GrabClient()))
|
||
|
{
|
||
|
//
|
||
|
// If another process is handling the file, reply with warning BUSY.
|
||
|
//
|
||
|
if(hr == HRESULT_FROM_WIN32( ERROR_SHARING_VIOLATION ))
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BUSY );
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
__ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
|
||
|
if(m_crClientRequest.dwCommand == UploadLibrary::UL_COMMAND_OPENSESSION)
|
||
|
{
|
||
|
hr = HandleCommand_OpenSession ( streamConn );
|
||
|
}
|
||
|
else if(m_crClientRequest.dwCommand == UploadLibrary::UL_COMMAND_WRITESESSION)
|
||
|
{
|
||
|
hr = HandleCommand_WriteSession( streamConn );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BAD_REQUEST );
|
||
|
}
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
__ULT_TRACE_ERROR( UPLOADLIBID, "Upload Server raised an exception. Gracefully exiting..." );
|
||
|
|
||
|
MPC::wstring szID;
|
||
|
|
||
|
if(m_mpccClient)
|
||
|
{
|
||
|
(void)m_mpccClient->FormatID( szID );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szID = L"<UNKNOWN>";
|
||
|
}
|
||
|
|
||
|
(void)g_NTEvents.LogEvent( EVENTLOG_ERROR_TYPE, PCHUL_ERR_EXCEPTION,
|
||
|
m_szURL.c_str(), // %1 = SERVER
|
||
|
szID .c_str(), // %2 = CLIENT
|
||
|
NULL );
|
||
|
|
||
|
//
|
||
|
// Something ugly happened, reply with SERVER_BUSY...
|
||
|
//
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BUSY );
|
||
|
}
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
|
||
|
if(hr != S_FALSE &&
|
||
|
hr != E_PENDING )
|
||
|
{
|
||
|
MPC::Serializer_Memory streamRes;
|
||
|
|
||
|
streamRes << m_srServerResponse;
|
||
|
|
||
|
m_hcCallback->Write( streamRes .GetData(), streamRes .GetSize() );
|
||
|
m_hcCallback->Write( m_streamResponseData.GetData(), m_streamResponseData.GetSize() );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Never return a real failure!
|
||
|
//
|
||
|
if(hr != E_PENDING) hr = S_OK;
|
||
|
|
||
|
ReleaseClient();
|
||
|
|
||
|
fKeepAlive = m_fKeepAlive;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// Helpers.
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT MPCServer::GrabClient()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::GrabClient");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
if(m_mpccClient)
|
||
|
{
|
||
|
if(*m_mpccClient == m_crClientRequest.sigClient)
|
||
|
{
|
||
|
//
|
||
|
// It's for the same client, dont' do anything...
|
||
|
//
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ReleaseClient());
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get instance's settings and create client object.
|
||
|
//
|
||
|
m_mpccClient = new MPCClient( this, m_crClientRequest.sigClient );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check authenticity of ID.
|
||
|
//
|
||
|
if(m_mpccClient->CheckSignature() == false)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_DENIED );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(FAILED(hr = m_mpccClient->InitFromDisk( true )))
|
||
|
{
|
||
|
if(hr == HRESULT_FROM_WIN32( ERROR_DISK_FULL ))
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_QUOTA_EXCEEDED );
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
__ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT MPCServer::ReleaseClient()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::ReleaseClient");
|
||
|
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
(void)CustomProvider_Release();
|
||
|
|
||
|
|
||
|
if(m_mpccClient)
|
||
|
{
|
||
|
hr = m_mpccClient->SyncToDisk();
|
||
|
|
||
|
delete m_mpccClient; m_mpccClient = NULL;
|
||
|
|
||
|
if(FAILED(hr)) __ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT MPCServer::HandleCommand_OpenSession( /*[in] */ MPC::Serializer& streamConn )
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::HandleCommand_OpenSession");
|
||
|
|
||
|
UploadLibrary::ClientRequest_OpenSession crosReq( 0 );
|
||
|
MPCClient::Iter it;
|
||
|
HRESULT hr;
|
||
|
bool fServerBusy;
|
||
|
bool fAccessDenied;
|
||
|
bool fExceeded;
|
||
|
|
||
|
crosReq.crHeader = m_crClientRequest;
|
||
|
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamConn >> crosReq );
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if(m_hcCallback->m_Debug_NO_RESPONSE_TO_OPEN)
|
||
|
{
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
||
|
}
|
||
|
|
||
|
if(m_hcCallback->m_Debug_RESPONSE_TO_OPEN)
|
||
|
{
|
||
|
m_srServerResponse.dwPosition = m_hcCallback->m_Debug_RESPONSE_TO_OPEN_position;
|
||
|
m_srServerResponse.rhProlog.dwVersion = m_hcCallback->m_Debug_RESPONSE_TO_OPEN_protocol;
|
||
|
|
||
|
SetResponse( m_hcCallback->m_Debug_RESPONSE_TO_OPEN_response );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Reject any request whose length is zero.
|
||
|
//
|
||
|
if(crosReq.dwSize == 0 ||
|
||
|
crosReq.dwSizeOriginal == 0 )
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BAD_REQUEST );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(m_mpccClient->Find( crosReq.szJobID, it ))
|
||
|
{
|
||
|
if(it->get_Committed() == true)
|
||
|
{
|
||
|
if(it->MatchRequest( crosReq ) == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_COMMITTED, TRUE );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_EXISTS );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_SKIPPED, TRUE );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bool fPassed;
|
||
|
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"PROGRESS | Created new session: '%s' (%s)", crosReq.szJobID.c_str(), crosReq.szProviderID.c_str() );
|
||
|
}
|
||
|
|
||
|
|
||
|
it = m_mpccClient->NewSession( crosReq );
|
||
|
|
||
|
if(SUCCEEDED(hr = it->Validate( false, fPassed )) && fPassed)
|
||
|
{
|
||
|
if(SUCCEEDED(hr = m_mpccClient->CheckQuotas( *it, fServerBusy, fAccessDenied, fExceeded )))
|
||
|
{
|
||
|
if(fServerBusy == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BUSY );
|
||
|
}
|
||
|
else if(fAccessDenied == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_DENIED );
|
||
|
}
|
||
|
else if(fExceeded == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_QUOTA_EXCEEDED );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_SUCCESS, TRUE );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(FAILED(hr) ||
|
||
|
fPassed == false ||
|
||
|
fExceeded == true )
|
||
|
{
|
||
|
m_mpccClient->Erase( it );
|
||
|
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CustomProvider_Create( *it ));
|
||
|
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CustomProvider_ValidateClient());
|
||
|
if(m_fTerminated) __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
|
||
|
|
||
|
it->get_CurrentSize( m_srServerResponse.dwPosition );
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT MPCServer::HandleCommand_WriteSession( /*[in] */ MPC::Serializer& streamConn )
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::HandleCommand_WriteSession");
|
||
|
|
||
|
HRESULT hr;
|
||
|
UploadLibrary::ClientRequest_WriteSession crwsReq( 0 );
|
||
|
MPCClient::Iter it;
|
||
|
DWORD dwCurrentSize;
|
||
|
DWORD dwTotalSize;
|
||
|
bool fServerBusy;
|
||
|
bool fAccessDenied;
|
||
|
bool fExceeded;
|
||
|
bool fAvailable;
|
||
|
|
||
|
|
||
|
crwsReq.crHeader = m_crClientRequest;
|
||
|
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamConn >> crwsReq);
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if(m_hcCallback->m_Debug_NO_RESPONSE_TO_WRITE)
|
||
|
{
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
||
|
}
|
||
|
|
||
|
if(m_hcCallback->m_Debug_RESPONSE_TO_WRITE)
|
||
|
{
|
||
|
m_srServerResponse.dwPosition = m_hcCallback->m_Debug_RESPONSE_TO_WRITE_position;
|
||
|
m_srServerResponse.rhProlog.dwVersion = m_hcCallback->m_Debug_RESPONSE_TO_WRITE_protocol;
|
||
|
|
||
|
SetResponse( m_hcCallback->m_Debug_RESPONSE_TO_WRITE_response );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// Session couldn't be found, reply with error NOTACTIVE.
|
||
|
//
|
||
|
if(m_mpccClient->Find( crwsReq.szJobID, it ) == false)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_NOTACTIVE );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CustomProvider_Create( *it ));
|
||
|
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CustomProvider_ValidateClient());
|
||
|
if(m_fTerminated) __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
|
||
|
|
||
|
if(SUCCEEDED(hr = m_mpccClient->CheckQuotas( *it, fServerBusy, fAccessDenied, fExceeded )))
|
||
|
{
|
||
|
if(fServerBusy == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BUSY );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
if(fAccessDenied == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_DENIED );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
if(fExceeded == true)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_QUOTA_EXCEEDED );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Session has already being finished, reply with warning COMMITTED.
|
||
|
//
|
||
|
if(it->get_Committed())
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_COMMITTED, TRUE );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if(m_hcCallback->m_Debug_RANDOM_POINTER_ERROR)
|
||
|
{
|
||
|
double pick = (double)rand() / (double)RAND_MAX;
|
||
|
|
||
|
m_srServerResponse.dwPosition = m_hcCallback->m_Debug_RANDOM_POINTER_ERROR_pos_low +
|
||
|
(m_hcCallback->m_Debug_RANDOM_POINTER_ERROR_pos_high - m_hcCallback->m_Debug_RANDOM_POINTER_ERROR_pos_low) * pick;
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_SKIPPED, TRUE );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
it->get_CurrentSize( dwCurrentSize );
|
||
|
it->get_TotalSize ( dwTotalSize );
|
||
|
|
||
|
//
|
||
|
// If request offset and file size don't match, reply with warning SKIPPED.
|
||
|
//
|
||
|
if(dwCurrentSize != crwsReq.dwOffset)
|
||
|
{
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"WARN | Resync the client to %ld", dwCurrentSize );
|
||
|
}
|
||
|
|
||
|
m_srServerResponse.dwPosition = dwCurrentSize;
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_SKIPPED, TRUE );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Trim request size (don't overwrite past the declared file size).
|
||
|
//
|
||
|
crwsReq.dwSize = min( dwTotalSize - dwCurrentSize, crwsReq.dwSize );
|
||
|
|
||
|
//
|
||
|
// If data is not all available, wait.
|
||
|
//
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hcCallback->CheckDataAvailable( crwsReq.dwSize, fAvailable ));
|
||
|
if(fAvailable == false)
|
||
|
{
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, E_PENDING);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"PROGRESS | Writing chunk: %ld bytes at %ld", crwsReq.dwSize, crwsReq.dwOffset );
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Try to add the chunk to the file. If it fails due to low free disk space, reply with QUOTA_EXCEEDED.
|
||
|
//
|
||
|
{
|
||
|
MPC::Serializer_Text streamText( streamConn );
|
||
|
MPC::Serializer* pstream = UploadLibrary::SelectStream( streamConn, streamText );
|
||
|
|
||
|
if(FAILED(hr = m_mpccClient->AppendData( *it, *pstream, crwsReq.dwSize )))
|
||
|
{
|
||
|
if(hr == HRESULT_FROM_WIN32( ERROR_DISK_FULL ))
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_QUOTA_EXCEEDED );
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
__ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CustomProvider_DataAvailable());
|
||
|
if(m_fTerminated) __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check for end of transmission.
|
||
|
//
|
||
|
it->get_CurrentSize( dwCurrentSize );
|
||
|
if(dwCurrentSize >= dwTotalSize)
|
||
|
{
|
||
|
bool fMatch;
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, it->CompareCRC( fMatch ));
|
||
|
|
||
|
if(fMatch == false)
|
||
|
{
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"WARN | Wrong CRC, restarting..." );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The CRC is wrong, so remove the session completely...
|
||
|
//
|
||
|
(void)it->RemoveFile();
|
||
|
|
||
|
m_mpccClient->Erase( it );
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_BADCRC );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(m_flLogHandle)
|
||
|
{
|
||
|
m_flLogHandle->LogRecord( L"PROGRESS | Transfer complete" );
|
||
|
}
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CustomProvider_TransferComplete());
|
||
|
if(m_fTerminated) __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_SUCCESS, TRUE );
|
||
|
}
|
||
|
|
||
|
it->get_CurrentSize( m_srServerResponse.dwPosition );
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
void MPCServer::SetResponse( /*[in]*/ DWORD fResponse, /*[in]*/ BOOL fKeepAlive )
|
||
|
{
|
||
|
m_srServerResponse.fResponse = fResponse;
|
||
|
m_fKeepAlive = fKeepAlive;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT MPCServer::CustomProvider_Create( /*[in]*/ MPCSession& mpcsSession )
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::CustomProvider_Create");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
if(m_customProvider == NULL)
|
||
|
{
|
||
|
CISAPIprovider* isapiProvider;
|
||
|
bool fFound;
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, mpcsSession.GetProvider( isapiProvider, fFound ));
|
||
|
if(fFound)
|
||
|
{
|
||
|
MPC::wstring szProviderGUID;
|
||
|
CLSID guid;
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, isapiProvider->get_ProviderGUID( szProviderGUID ));
|
||
|
|
||
|
if(szProviderGUID.size() && SUCCEEDED(::CLSIDFromString( (LPOLESTR)szProviderGUID.c_str(), &guid )))
|
||
|
{
|
||
|
hr = ::CoCreateInstance( guid, NULL, CLSCTX_INPROC_SERVER, IID_IULProvider, (void**)&m_customProvider );
|
||
|
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
m_customProvider = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_Session = &mpcsSession;
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT MPCServer::CustomProvider_ValidateClient()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::CustomProvider_ValidateClient");
|
||
|
|
||
|
HRESULT hr;
|
||
|
bool fMatch;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Before doing anything, check client identity.
|
||
|
//
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_Session->CheckUser( m_szUser, fMatch ))
|
||
|
if(fMatch == false)
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_NOT_AUTHORIZED );
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
||
|
}
|
||
|
|
||
|
if(m_customProvider)
|
||
|
{
|
||
|
hr = m_customProvider->ValidateClient( COM(), m_Session->COM() );
|
||
|
|
||
|
if(FAILED(hr) && hr != E_NOTIMPL) __ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT MPCServer::CustomProvider_DataAvailable()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::CustomProvider_DataAvailable");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
if(m_customProvider)
|
||
|
{
|
||
|
hr = m_customProvider->DataAvailable( COM(), m_Session->COM() );
|
||
|
|
||
|
if(FAILED(hr) && hr != E_NOTIMPL) __ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT MPCServer::CustomProvider_TransferComplete()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::CustomProvider_TransferComplete");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set the commit flag, but only move the file if we don't have a custom provider.
|
||
|
//
|
||
|
if(FAILED(hr = m_Session->put_Committed( true, m_customProvider ? false : true )))
|
||
|
{
|
||
|
if(hr == HRESULT_FROM_WIN32( ERROR_DISK_FULL ))
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_QUOTA_EXCEEDED );
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
__ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_COMMITTED, TRUE );
|
||
|
|
||
|
|
||
|
if(m_customProvider)
|
||
|
{
|
||
|
hr = m_customProvider->TransferComplete( COM(), m_Session->COM() );
|
||
|
|
||
|
if(FAILED(hr) && hr != E_NOTIMPL) __ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT MPCServer::CustomProvider_SetResponse( /*[in]*/ IStream* data )
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::CustomProvider_SetResponse");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set the commit flag, but only move the file if we don't have a custom provider.
|
||
|
//
|
||
|
if(FAILED(hr = m_Session->put_Committed( true, m_customProvider ? false : true )))
|
||
|
{
|
||
|
if(hr == HRESULT_FROM_WIN32( ERROR_DISK_FULL ))
|
||
|
{
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_QUOTA_EXCEEDED );
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
__ULT_FUNC_LEAVE;
|
||
|
}
|
||
|
|
||
|
|
||
|
SetResponse( UploadLibrary::UL_RESPONSE_COMMITTED, TRUE );
|
||
|
|
||
|
|
||
|
if(data)
|
||
|
{
|
||
|
BYTE buf[512];
|
||
|
DWORD dwRead;
|
||
|
|
||
|
while(1)
|
||
|
{
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, data->Read( buf, sizeof(buf), &dwRead ));
|
||
|
|
||
|
if(dwRead == 0) break;
|
||
|
|
||
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_streamResponseData.write( buf, dwRead ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_CLEANUP;
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT MPCServer::CustomProvider_Release()
|
||
|
{
|
||
|
__ULT_FUNC_ENTRY("MPCServer::CustomProvider_Release");
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
|
||
|
if(m_customProvider)
|
||
|
{
|
||
|
if(m_fTerminated)
|
||
|
{
|
||
|
if(m_Session) m_Session->RemoveFile();
|
||
|
}
|
||
|
|
||
|
m_customProvider->Release();
|
||
|
m_customProvider = NULL;
|
||
|
}
|
||
|
|
||
|
m_Session = NULL;
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__ULT_FUNC_EXIT(hr);
|
||
|
}
|