Leaked source code of windows server 2003
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.

1109 lines
26 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. MPCUpload.cpp
  5. Abstract:
  6. This file contains the implementation of the CMPCUpload class, which is
  7. used as the entry point into the Upload Library.
  8. Revision History:
  9. Davide Massarenti (Dmassare) 04/15/99
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. #include <Sddl.h>
  14. ////////////////////////////////////////////////////////////////////////////////
  15. static const WCHAR l_ConfigFile [] = L"%WINDIR%\\PCHEALTH\\UPLOADLB\\CONFIG\\CONFIG.XML";
  16. static const WCHAR l_DirectoryFile[] = L"upload_library.db";
  17. static const DWORD l_dwVersion = 0x03004C55; // UL 03
  18. static const DATE l_SecondsInDay = (86400.0);
  19. ////////////////////////////////////////////////////////////////////////////////
  20. MPC::CComObjectGlobalNoLock<CMPCUpload> g_Root;
  21. ////////////////////////////////////////////////////////////////////////////////
  22. CMPCUpload::CMPCUpload()
  23. {
  24. __ULT_FUNC_ENTRY( "CMPCUpload::CMPCUpload" );
  25. //
  26. // Seed the random-number generator with current time so that
  27. // the numbers will be different every time we run.
  28. //
  29. srand( ::GetTickCount() );
  30. m_dwLastJobID = rand(); // DWORD m_dwLastJobID
  31. // List m_lstActiveJobs
  32. // CMPCTransportAgent m_mpctaThread;
  33. m_fDirty = false; // mutable bool m_fDirty
  34. m_fPassivated = false; // mutable bool m_fPassivated;
  35. (void)MPC::_MPC_Module.RegisterCallback( this, (void (CMPCUpload::*)())Passivate );
  36. }
  37. CMPCUpload::~CMPCUpload()
  38. {
  39. MPC::_MPC_Module.UnregisterCallback( this );
  40. Passivate();
  41. }
  42. ////////////////////////////////////////
  43. HRESULT CMPCUpload::Init()
  44. {
  45. __ULT_FUNC_ENTRY( "CMPCUpload::Init" );
  46. HRESULT hr;
  47. MPC::wstring str( l_ConfigFile ); MPC::SubstituteEnvVariables( str );
  48. bool fLoaded;
  49. MPC::SmartLock<_ThreadModel> lock( this );
  50. //
  51. // Load configuration.
  52. //
  53. g_Config.Load( str, fLoaded );
  54. //
  55. // Initialize Transport Agent
  56. //
  57. __MPC_EXIT_IF_METHOD_FAILS(hr, m_mpctaThread.LinkToSystem( this ));
  58. //
  59. // Load queue from disk.
  60. //
  61. if(FAILED(hr = InitFromDisk()))
  62. {
  63. //
  64. // If, for any reason, loading failed, discard all the jobs and recreate a clean database...
  65. //
  66. CleanUp();
  67. m_fDirty = true;
  68. }
  69. //
  70. // Remove objects marked as DON'T QUEUE.
  71. //
  72. __MPC_EXIT_IF_METHOD_FAILS(hr, RemoveNonQueueableJob( false ) );
  73. //
  74. // Remove entry from Task Scheduler
  75. //
  76. (void)Handle_TaskScheduler( false );
  77. hr = S_OK;
  78. __ULT_FUNC_CLEANUP;
  79. __ULT_FUNC_EXIT(hr);
  80. }
  81. void CMPCUpload::Passivate()
  82. {
  83. __ULT_FUNC_ENTRY( "CMPCUpload::Passivate" );
  84. MPC::SmartLock<_ThreadModel> lock( NULL );
  85. //
  86. // Stop the worker thread before starting the cleanup.
  87. //
  88. m_mpctaThread.Thread_Wait();
  89. lock = this; // Get the lock.
  90. if(m_fPassivated == false)
  91. {
  92. //
  93. // Remove objects marked as DON'T QUEUE.
  94. //
  95. (void)RemoveNonQueueableJob( false );
  96. //
  97. // See if we need to reschedule ourself.
  98. //
  99. {
  100. bool fNeedTS = false;
  101. Iter it;
  102. //
  103. // Search for active jobs.
  104. //
  105. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  106. {
  107. CMPCUploadJob* mpcujJob = *it;
  108. UL_STATUS ulStatus;
  109. (void)mpcujJob->get_Status( &ulStatus );
  110. switch(ulStatus)
  111. {
  112. case UL_ACTIVE :
  113. case UL_TRANSMITTING:
  114. case UL_ABORTED : fNeedTS = true; break;
  115. }
  116. }
  117. if(fNeedTS)
  118. {
  119. (void)Handle_TaskScheduler( true );
  120. }
  121. }
  122. CleanUp();
  123. m_fPassivated = true;
  124. }
  125. }
  126. void CMPCUpload::CleanUp()
  127. {
  128. __ULT_FUNC_ENTRY( "CMPCUpload::CleanUp" );
  129. IterConst it;
  130. //
  131. // Release all the jobs.
  132. //
  133. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  134. {
  135. CMPCUploadJob* mpcujJob = *it;
  136. mpcujJob->Unlink();
  137. mpcujJob->Release();
  138. }
  139. m_lstActiveJobs.clear();
  140. }
  141. /////////////////////////////////////////////////////////////////////////////
  142. HRESULT CMPCUpload::CreateChild( /*[in/out]*/ CMPCUploadJob*& mpcujJob )
  143. {
  144. __ULT_FUNC_ENTRY( "CMPCUpload::CreateChild" );
  145. HRESULT hr;
  146. CMPCUploadJob_Object* newobj;
  147. MPC::SmartLock<_ThreadModel> lock( this );
  148. mpcujJob = NULL;
  149. __MPC_EXIT_IF_METHOD_FAILS(hr, newobj->CreateInstance( &newobj )); newobj->AddRef();
  150. newobj->LinkToSystem( this );
  151. m_lstActiveJobs.push_back( mpcujJob = newobj );
  152. hr = S_OK;
  153. __ULT_FUNC_CLEANUP;
  154. __ULT_FUNC_EXIT(hr);
  155. }
  156. HRESULT CMPCUpload::ReleaseChild( /*[in/out]*/ CMPCUploadJob*& mpcujJob )
  157. {
  158. __ULT_FUNC_ENTRY( "CMPCUpload::ReleaseChild" );
  159. MPC::SmartLock<_ThreadModel> lock( this );
  160. if(mpcujJob)
  161. {
  162. m_lstActiveJobs.remove( mpcujJob );
  163. mpcujJob->Unlink ();
  164. mpcujJob->Release();
  165. mpcujJob = NULL;
  166. }
  167. __ULT_FUNC_EXIT(S_OK);
  168. }
  169. HRESULT CMPCUpload::WrapChild( /*[in]*/ CMPCUploadJob* mpcujJob, /*[out]*/ IMPCUploadJob* *pVal )
  170. {
  171. __ULT_FUNC_ENTRY( "CMPCUpload::WrapChild" );
  172. HRESULT hr;
  173. CComPtr<CMPCUploadJobWrapper> wrap;
  174. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &wrap ));
  175. __MPC_EXIT_IF_METHOD_FAILS(hr, wrap->Init( mpcujJob ));
  176. __MPC_EXIT_IF_METHOD_FAILS(hr, wrap.QueryInterface( pVal ));
  177. hr = S_OK;
  178. __ULT_FUNC_CLEANUP;
  179. __ULT_FUNC_EXIT(hr);
  180. }
  181. /////////////////////////////////////////////////////////////////////////////
  182. bool CMPCUpload::CanContinue()
  183. {
  184. __ULT_FUNC_ENTRY( "CMPCUpload::CanContinue" );
  185. bool fRes = false;
  186. DWORD dwMode = 0;
  187. IterConst it;
  188. MPC::SmartLock<_ThreadModel> lock( this );
  189. //
  190. // If no connection is available, there's no reason to continue.
  191. //
  192. if(::InternetGetConnectedState( &dwMode, 0 ) == TRUE)
  193. {
  194. //
  195. // Search for at least one pending job.
  196. //
  197. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  198. {
  199. CMPCUploadJob* mpcujJob = *it;
  200. UL_STATUS usStatus;
  201. (void)mpcujJob->get_Status( &usStatus );
  202. switch(usStatus)
  203. {
  204. case UL_ACTIVE :
  205. case UL_TRANSMITTING:
  206. case UL_ABORTED :
  207. // This job can be executed, so we can continue.
  208. fRes = true; __ULT_FUNC_LEAVE;
  209. }
  210. }
  211. }
  212. __ULT_FUNC_CLEANUP;
  213. __ULT_FUNC_EXIT(fRes);
  214. }
  215. /////////////////////////////////////////////////////////////////////////////
  216. HRESULT CMPCUpload::InitFromDisk()
  217. {
  218. __ULT_FUNC_ENTRY( "CMPCUpload::InitFromDisk" );
  219. HRESULT hr;
  220. HANDLE hFile = NULL;
  221. MPC::wstring str;
  222. MPC::wstring str_bak;
  223. str = g_Config.get_QueueLocation(); str.append( l_DirectoryFile );
  224. str_bak = str + L"_backup";
  225. //
  226. // First of all, try to open the backup file, if present.
  227. //
  228. hFile = ::CreateFileW( str_bak.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  229. if(hFile == INVALID_HANDLE_VALUE)
  230. {
  231. //
  232. // No backup present, so open the real file.
  233. //
  234. hFile = ::CreateFileW( str.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  235. }
  236. else
  237. {
  238. //
  239. // backup present, so delete the corrupted .db file.
  240. //
  241. (void)MPC::DeleteFile( str );
  242. }
  243. if(hFile == INVALID_HANDLE_VALUE)
  244. {
  245. hFile = NULL; // For cleanup.
  246. DWORD dwRes = ::GetLastError();
  247. if(dwRes != ERROR_FILE_NOT_FOUND)
  248. {
  249. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, dwRes );
  250. }
  251. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  252. }
  253. //
  254. // Load the real data from storage.
  255. //
  256. __MPC_EXIT_IF_METHOD_FAILS(hr, Load( MPC::Serializer_File( hFile ) ));
  257. hr = S_OK;
  258. __ULT_FUNC_CLEANUP;
  259. if(hFile) ::CloseHandle( hFile );
  260. //
  261. // "RescheduleJobs" should be executed after the file is closed...
  262. //
  263. if(SUCCEEDED(hr))
  264. {
  265. hr = RescheduleJobs( true );
  266. }
  267. __ULT_FUNC_EXIT(hr);
  268. }
  269. HRESULT CMPCUpload::UpdateToDisk()
  270. {
  271. __ULT_FUNC_ENTRY( "CMPCUpload::UpdateToDisk" );
  272. HRESULT hr;
  273. HANDLE hFile = NULL;
  274. MPC::wstring str;
  275. MPC::wstring str_bak;
  276. str = g_Config.get_QueueLocation(); str.append( l_DirectoryFile );
  277. str_bak = str + L"_backup";
  278. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( str ) );
  279. //
  280. // First of all, remove any old backup.
  281. //
  282. (void)MPC::DeleteFile( str_bak );
  283. //
  284. // Then, make a backup of current file.
  285. //
  286. (void)MPC::MoveFile( str, str_bak );
  287. //
  288. // Create the new file.
  289. //
  290. __MPC_EXIT_IF_INVALID_HANDLE__CLEAN(hr, hFile, ::CreateFileW( str.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ));
  291. __MPC_EXIT_IF_METHOD_FAILS(hr, Save( MPC::Serializer_File( hFile ) ));
  292. //
  293. // Remove the backup.
  294. //
  295. (void)MPC::DeleteFile( str_bak );
  296. hr = S_OK;
  297. __ULT_FUNC_CLEANUP;
  298. if(hFile)
  299. {
  300. ::FlushFileBuffers( hFile );
  301. ::CloseHandle ( hFile );
  302. }
  303. __ULT_FUNC_EXIT(hr);
  304. }
  305. /////////////////////////////////////////////////////////////////////////////
  306. HRESULT CMPCUpload::TriggerRescheduleJobs()
  307. {
  308. __ULT_FUNC_ENTRY( "CMPCUpload::TriggerRescheduleJobs" );
  309. HRESULT hr;
  310. //
  311. // Signal the Transport Agent.
  312. //
  313. m_mpctaThread.Thread_Signal();
  314. hr = S_OK;
  315. __ULT_FUNC_EXIT(hr);
  316. }
  317. HRESULT CMPCUpload::RemoveNonQueueableJob( /*[in]*/ bool fSignal )
  318. {
  319. __ULT_FUNC_ENTRY( "CMPCUpload::RemoveNonQueueableJob" );
  320. HRESULT hr;
  321. SYSTEMTIME stTime;
  322. DATE dTime;
  323. Iter it;
  324. MPC::SmartLock<_ThreadModel> lock( this );
  325. //
  326. // Search for jobs which need to be updated.
  327. //
  328. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end();)
  329. {
  330. CMPCUploadJob* mpcujJob = *it;
  331. VARIANT_BOOL fPersistToDisk;
  332. (void)mpcujJob->get_PersistToDisk( &fPersistToDisk );
  333. if(fPersistToDisk == VARIANT_FALSE)
  334. {
  335. bool fSuccess;
  336. (void)mpcujJob->put_Status( UL_DELETED );
  337. __MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->CanRelease( fSuccess ));
  338. if(fSuccess)
  339. {
  340. //
  341. // Remove from the system.
  342. //
  343. ReleaseChild( mpcujJob );
  344. m_fDirty = true;
  345. it = m_lstActiveJobs.begin(); // Iterator is no longer valid, start from the beginning.
  346. continue;
  347. }
  348. }
  349. it++;
  350. }
  351. //
  352. // Save if needed.
  353. //
  354. if(IsDirty())
  355. {
  356. __MPC_EXIT_IF_METHOD_FAILS(hr, UpdateToDisk());
  357. }
  358. //
  359. // Signal the Transport Agent.
  360. //
  361. if(fSignal) m_mpctaThread.Thread_Signal();
  362. hr = S_OK;
  363. __ULT_FUNC_CLEANUP;
  364. __ULT_FUNC_EXIT(hr);
  365. }
  366. HRESULT CMPCUpload::RescheduleJobs( /*[in]*/ bool fSignal, /*[out]*/ DWORD *pdwWait )
  367. {
  368. __ULT_FUNC_ENTRY( "CMPCUpload::RescheduleJobs" );
  369. HRESULT hr;
  370. MPC::SmartLock<_ThreadModel> lock( this );
  371. CMPCUploadJob* mpcujFirstJob = NULL;
  372. DATE dTime = MPC::GetLocalTime();
  373. DWORD dwWait = INFINITE;
  374. Iter it;
  375. //
  376. // Search for jobs which need to be updated.
  377. //
  378. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end();)
  379. {
  380. CMPCUploadJob* mpcujJob = *it;
  381. UL_STATUS usStatus; (void)mpcujJob->get_Status ( &usStatus );
  382. DATE dCompleteTime; (void)mpcujJob->get_CompleteTime ( &dCompleteTime );
  383. DATE dExpirationTime; (void)mpcujJob->get_ExpirationTime( &dExpirationTime );
  384. DWORD dwRetryInterval; (void)mpcujJob->get_RetryInterval ( &dwRetryInterval );
  385. //
  386. // If the job has an expiration date and it has passed, remove it.
  387. //
  388. if(dExpirationTime && dTime >= dExpirationTime)
  389. {
  390. (void)mpcujJob->put_Status( usStatus = UL_DELETED );
  391. }
  392. //
  393. // Check if the job is ready for transmission.
  394. //
  395. switch(usStatus)
  396. {
  397. case UL_ACTIVE :
  398. case UL_TRANSMITTING:
  399. case UL_ABORTED :
  400. //
  401. // Pick the higher priority job.
  402. //
  403. if(mpcujFirstJob == NULL || *mpcujFirstJob < *mpcujJob) mpcujFirstJob = mpcujJob;
  404. break;
  405. }
  406. //
  407. // If the job is marked as ABORTED and a certain amount of time is elapsed, retry to send.
  408. //
  409. if(usStatus == UL_ABORTED)
  410. {
  411. DATE dDiff = (dCompleteTime + (dwRetryInterval / l_SecondsInDay)) - dTime;
  412. if(dDiff > 0)
  413. {
  414. if(dwWait > dDiff * l_SecondsInDay)
  415. {
  416. dwWait = dDiff * l_SecondsInDay;
  417. }
  418. }
  419. else
  420. {
  421. (void)mpcujJob->put_Status( usStatus = UL_ACTIVE );
  422. }
  423. }
  424. //
  425. // If the job is marked as DELETED, remove it.
  426. //
  427. if(usStatus == UL_DELETED)
  428. {
  429. bool fSuccess;
  430. __MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->CanRelease( fSuccess ));
  431. if(fSuccess)
  432. {
  433. //
  434. // Remove from the system.
  435. //
  436. m_lstActiveJobs.remove( mpcujJob );
  437. mpcujJob->Unlink ();
  438. mpcujJob->Release();
  439. m_fDirty = true;
  440. it = m_lstActiveJobs.begin(); // Iterator is no longer valid, start from the beginning.
  441. continue;
  442. }
  443. }
  444. it++;
  445. }
  446. //
  447. // If the best job is ready, set the wait delay to zero.
  448. //
  449. if(mpcujFirstJob)
  450. {
  451. UL_STATUS usStatus; (void)mpcujFirstJob->get_Status( &usStatus );
  452. if(usStatus == UL_ACTIVE ||
  453. usStatus == UL_TRANSMITTING )
  454. {
  455. dwWait = 0;
  456. }
  457. }
  458. //
  459. // Save if needed.
  460. //
  461. if(IsDirty())
  462. {
  463. __MPC_EXIT_IF_METHOD_FAILS(hr, UpdateToDisk());
  464. }
  465. //
  466. // Signal the Transport Agent.
  467. //
  468. if(fSignal) m_mpctaThread.Thread_Signal();
  469. hr = S_OK;
  470. __ULT_FUNC_CLEANUP;
  471. if(pdwWait) *pdwWait = dwWait;
  472. __ULT_FUNC_EXIT(hr);
  473. }
  474. HRESULT CMPCUpload::GetFirstJob( /*[out]*/ CMPCUploadJob*& mpcujJob ,
  475. /*[out]*/ bool& fFound )
  476. {
  477. __ULT_FUNC_ENTRY( "CMPCUpload::GetFirstJob" );
  478. HRESULT hr;
  479. UL_STATUS usStatus;
  480. IterConst it;
  481. MPC::SmartLock<_ThreadModel> lock( this );
  482. mpcujJob = NULL;
  483. fFound = false;
  484. //
  485. // Rebuild the queue.
  486. //
  487. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  488. {
  489. CMPCUploadJob* mpcujJob2 = *it;
  490. (void)mpcujJob2->get_Status( &usStatus );
  491. //
  492. // Check if the job is ready for transmission.
  493. //
  494. switch(usStatus)
  495. {
  496. case UL_ACTIVE :
  497. case UL_TRANSMITTING:
  498. case UL_ABORTED :
  499. //
  500. // Pick the higher priority job.
  501. //
  502. if(mpcujJob == NULL || *mpcujJob < *mpcujJob2) mpcujJob = mpcujJob2;
  503. break;
  504. }
  505. }
  506. if(mpcujJob)
  507. {
  508. (void)mpcujJob->get_Status( &usStatus );
  509. if(usStatus != UL_ABORTED)
  510. {
  511. mpcujJob->AddRef();
  512. fFound = true;
  513. }
  514. else
  515. {
  516. mpcujJob = NULL;
  517. }
  518. }
  519. hr = S_OK;
  520. __ULT_FUNC_EXIT(hr);
  521. }
  522. HRESULT CMPCUpload::GetJobByName( /*[out]*/ CMPCUploadJob*& mpcujJob ,
  523. /*[out]*/ bool& fFound ,
  524. /*[in] */ BSTR bstrName )
  525. {
  526. __ULT_FUNC_ENTRY( "CMPCUpload::GetJobByName" );
  527. HRESULT hr;
  528. IterConst it;
  529. MPC::wstring szName = SAFEBSTR( bstrName );
  530. MPC::SmartLock<_ThreadModel> lock( this );
  531. mpcujJob = NULL;
  532. fFound = false;
  533. //
  534. // Rebuild the queue.
  535. //
  536. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  537. {
  538. CMPCUploadJob* mpcujJob2 = *it;
  539. CComBSTR bstrName2;
  540. MPC::wstring szName2;
  541. (void)mpcujJob2->get_JobID( &bstrName2 );
  542. szName2 = SAFEBSTR( bstrName2 );
  543. if(szName == szName2)
  544. {
  545. mpcujJob2->AddRef();
  546. mpcujJob = mpcujJob2;
  547. fFound = true;
  548. break;
  549. }
  550. }
  551. hr = S_OK;
  552. __ULT_FUNC_EXIT(hr);
  553. }
  554. /////////////////////////////////////////////////////////////////////////////
  555. HRESULT CMPCUpload::CalculateQueueSize( /*[out]*/ DWORD& dwSize )
  556. {
  557. __ULT_FUNC_ENTRY( "CMPCUpload::CalculateQueueSize" );
  558. HRESULT hr;
  559. MPC::SmartLock<_ThreadModel> lock( this );
  560. dwSize = 0;
  561. {
  562. MPC::wstring szQueue = g_Config.get_QueueLocation();
  563. WIN32_FILE_ATTRIBUTE_DATA wfadInfo;
  564. MPC::FileSystemObject fso( szQueue.c_str() );
  565. MPC::FileSystemObject::List lst;
  566. MPC::FileSystemObject::Iter it;
  567. __MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFiles( lst ));
  568. for(it = lst.begin(); it != lst.end(); it++)
  569. {
  570. DWORD dwFileSize;
  571. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->get_FileSize( dwFileSize ));
  572. dwSize += dwFileSize;
  573. }
  574. }
  575. hr = S_OK;
  576. __ULT_FUNC_CLEANUP;
  577. __ULT_FUNC_EXIT(hr);
  578. }
  579. //////////////////////////////////////////////////////////////////////
  580. // Persistence
  581. //////////////////////////////////////////////////////////////////////
  582. bool CMPCUpload::IsDirty()
  583. {
  584. __ULT_FUNC_ENTRY( "CMPCUpload::IsDirty" );
  585. bool fRes = true; // Default result.
  586. IterConst it;
  587. MPC::SmartLock<_ThreadModel> lock( this );
  588. if(m_fDirty == true) __ULT_FUNC_LEAVE;
  589. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  590. {
  591. CMPCUploadJob* mpcujJob = *it;
  592. if(mpcujJob->IsDirty() == true) __ULT_FUNC_LEAVE;
  593. }
  594. fRes = false;
  595. __ULT_FUNC_CLEANUP;
  596. __ULT_FUNC_EXIT(fRes);
  597. }
  598. HRESULT CMPCUpload::Load( /*[in]*/ MPC::Serializer& streamIn )
  599. {
  600. __ULT_FUNC_ENTRY( "CMPCUpload::Load" );
  601. HRESULT hr;
  602. DWORD dwVer;
  603. CMPCUploadJob* mpcujJob = NULL;
  604. MPC::SmartLock<_ThreadModel> lock( this );
  605. CleanUp();
  606. //
  607. // Version doesn't match, so force a rewrite and exit.
  608. //
  609. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> dwVer);
  610. if(dwVer != l_dwVersion)
  611. {
  612. m_fDirty = true;
  613. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  614. }
  615. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dwLastJobID);
  616. m_lstActiveJobs.clear();
  617. while(1)
  618. {
  619. HRESULT hr2;
  620. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateChild( mpcujJob ));
  621. if(FAILED(hr2 = mpcujJob->Load( streamIn )))
  622. {
  623. if(hr2 != HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ))
  624. {
  625. __MPC_SET_ERROR_AND_EXIT(hr, hr2);
  626. }
  627. break;
  628. }
  629. mpcujJob = NULL;
  630. }
  631. m_fDirty = false;
  632. hr = S_OK;
  633. __ULT_FUNC_CLEANUP;
  634. ReleaseChild( mpcujJob );
  635. __ULT_FUNC_EXIT(hr);
  636. }
  637. HRESULT CMPCUpload::Save( /*[in]*/ MPC::Serializer& streamOut )
  638. {
  639. __ULT_FUNC_ENTRY( "CMPCUpload::Save" );
  640. HRESULT hr;
  641. IterConst it;
  642. MPC::SmartLock<_ThreadModel> lock( this );
  643. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << l_dwVersion );
  644. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dwLastJobID);
  645. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  646. {
  647. CMPCUploadJob* mpcujJob = *it;
  648. __MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->Save( streamOut ));
  649. }
  650. m_fDirty = false;
  651. __ULT_FUNC_CLEANUP;
  652. __ULT_FUNC_EXIT(hr);
  653. }
  654. //////////////////////////////////////////////////////////////////////
  655. // Enumerator
  656. //////////////////////////////////////////////////////////////////////
  657. STDMETHODIMP CMPCUpload::get__NewEnum( /*[out]*/ IUnknown* *pVal )
  658. {
  659. __ULT_FUNC_ENTRY( "CMPCUpload::get__NewEnum" );
  660. HRESULT hr;
  661. Iter it;
  662. CComPtr<CMPCUploadEnum> pEnum;
  663. MPC::SmartLock<_ThreadModel> lock( this );
  664. __MPC_PARAMCHECK_BEGIN(hr)
  665. __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
  666. __MPC_PARAMCHECK_END();
  667. //
  668. // Create the Enumerator and fill it with jobs.
  669. //
  670. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pEnum ));
  671. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  672. {
  673. CComBSTR bstrUser;
  674. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->get_Creator( &bstrUser ));
  675. if(SUCCEEDED(MPC::CheckCallerAgainstPrincipal( /*fImpersonate*/true, bstrUser, MPC::IDENTITY_SYSTEM | MPC::IDENTITY_ADMIN | MPC::IDENTITY_ADMINS )))
  676. {
  677. CComPtr<IMPCUploadJob> job;
  678. __MPC_EXIT_IF_METHOD_FAILS(hr, WrapChild( *it, &job ));
  679. __MPC_EXIT_IF_METHOD_FAILS(hr, pEnum->AddItem( job ));
  680. }
  681. }
  682. __MPC_EXIT_IF_METHOD_FAILS(hr, pEnum->QueryInterface( IID_IEnumVARIANT, (void**)pVal ));
  683. hr = S_OK;
  684. __ULT_FUNC_CLEANUP;
  685. __ULT_FUNC_EXIT(hr);
  686. }
  687. STDMETHODIMP CMPCUpload::Item( /*[in]*/ long index, /*[out]*/ IMPCUploadJob* *pVal )
  688. {
  689. __ULT_FUNC_ENTRY( "CMPCUpload::Item" );
  690. HRESULT hr;
  691. IterConst it;
  692. MPC::SmartLock<_ThreadModel> lock( this );
  693. __MPC_PARAMCHECK_BEGIN(hr)
  694. __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
  695. __MPC_PARAMCHECK_END();
  696. //
  697. // Look for the N-th job.
  698. //
  699. for(it = m_lstActiveJobs.begin(); it != m_lstActiveJobs.end(); it++)
  700. {
  701. if(index-- == 0)
  702. {
  703. (*pVal = *it)->AddRef();
  704. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  705. }
  706. }
  707. hr = E_INVALIDARG;
  708. __ULT_FUNC_CLEANUP;
  709. __ULT_FUNC_EXIT(hr);
  710. }
  711. STDMETHODIMP CMPCUpload::get_Count( /*[out]*/ long *pVal )
  712. {
  713. __ULT_FUNC_ENTRY( "CMPCUpload::get_Count" );
  714. if(pVal == NULL) __ULT_FUNC_EXIT(E_POINTER);
  715. MPC::SmartLock<_ThreadModel> lock( this );
  716. *pVal = m_lstActiveJobs.size();
  717. __ULT_FUNC_EXIT(S_OK);
  718. }
  719. STDMETHODIMP CMPCUpload::CreateJob( /*[out]*/ IMPCUploadJob* *pVal )
  720. {
  721. __ULT_FUNC_ENTRY( "CMPCUpload::CreateJob" );
  722. HRESULT hr;
  723. CMPCUploadJob* mpcujJob = NULL;
  724. DWORD dwSize;
  725. MPC::SmartLock<_ThreadModel> lock( this );
  726. __MPC_PARAMCHECK_BEGIN(hr)
  727. __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
  728. __MPC_PARAMCHECK_END();
  729. //
  730. // Check quota limits.
  731. //
  732. __MPC_EXIT_IF_METHOD_FAILS(hr, CalculateQueueSize( dwSize ));
  733. if(dwSize > g_Config.get_QueueSize())
  734. {
  735. __MPC_SET_ERROR_AND_EXIT(hr, E_UPLOADLIBRARY_CLIENT_QUOTA_EXCEEDED);
  736. }
  737. //
  738. // Create a new job and link it to the system.
  739. //
  740. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateChild( mpcujJob ));
  741. //
  742. // Assign a unique ID to the job.
  743. //
  744. while(1)
  745. {
  746. WCHAR rgBuf[64];
  747. swprintf( rgBuf, L"INNER_%08x", m_dwLastJobID );
  748. __MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->SetSequence( m_dwLastJobID++ ));
  749. if(SUCCEEDED(hr = mpcujJob->put_JobID( CComBSTR( rgBuf ) ))) break;
  750. if(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
  751. {
  752. //
  753. // Some other error, bailing out...
  754. //
  755. __MPC_FUNC_LEAVE;
  756. }
  757. }
  758. //
  759. // Find out the ID of the caller.
  760. //
  761. {
  762. CComBSTR bstrUser;
  763. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetCallerPrincipal( /*fImpersonate*/true, bstrUser ));
  764. __MPC_EXIT_IF_METHOD_FAILS(hr, mpcujJob->put_Creator( bstrUser ));
  765. }
  766. //
  767. // Get the proxy settings from the caller...
  768. //
  769. (void)mpcujJob->GetProxySettings();
  770. //
  771. // Cast it to an IMPCUploadJob.
  772. //
  773. __MPC_EXIT_IF_METHOD_FAILS(hr, WrapChild( mpcujJob, pVal ));
  774. mpcujJob = NULL;
  775. m_fDirty = true;
  776. //
  777. // Reschedule jobs, so the status of the queue will be updated to disk.
  778. //
  779. __MPC_EXIT_IF_METHOD_FAILS(hr, RescheduleJobs( true ));
  780. hr = S_OK;
  781. __ULT_FUNC_CLEANUP;
  782. ReleaseChild( mpcujJob );
  783. __ULT_FUNC_EXIT(hr);
  784. }