2008-07-23 18:01:59 -04:00
/*
* libretroshare / src / ft : ftcontroller . cc
*
* File Transfer for RetroShare .
*
* Copyright 2008 by Robert Fernie .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " retroshare@lunamutt.com " .
*
*/
2009-06-11 17:41:42 -04:00
/*
2008-07-23 18:01:59 -04:00
* ftController
*
* Top level download controller .
*
* inherits configuration ( save downloading files )
* inherits pqiMonitor ( knows which peers are online ) .
* inherits CacheTransfer ( transfers cache files too )
* inherits RsThread ( to control transfers )
*
*/
2008-08-09 13:03:24 -04:00
# include "ft/ftcontroller.h"
# include "ft/ftfilecreator.h"
# include "ft/fttransfermodule.h"
# include "ft/ftsearch.h"
# include "ft/ftdatamultiplex.h"
2008-11-09 17:17:20 -05:00
# include "ft/ftextralist.h"
2008-08-09 13:03:24 -04:00
2009-05-26 17:42:45 -04:00
# include "turtle/p3turtle.h"
2008-08-09 13:03:24 -04:00
# include "util/rsdir.h"
2008-07-23 18:01:59 -04:00
2008-08-09 13:03:24 -04:00
# include "pqi/p3connmgr.h"
2009-03-19 08:49:11 -04:00
# include "pqi/pqinotify.h"
2008-07-23 18:01:59 -04:00
2008-11-15 15:00:29 -05:00
# include "serialiser/rsconfigitems.h"
2009-05-11 10:30:53 -04:00
# include <stdio.h>
2008-08-09 13:03:24 -04:00
2008-12-07 09:53:57 -05:00
/******
* # define CONTROL_DEBUG 1
* * * * */
2008-08-09 13:03:24 -04:00
2009-12-10 17:55:27 -05:00
static const uint32_t SAVE_TRANSFERS_DELAY = 30 ; // save transfer progress every 30 seconds.
2008-08-17 11:23:11 -04:00
ftFileControl : : ftFileControl ( )
2009-06-11 17:41:42 -04:00
: mTransfer ( NULL ) , mCreator ( NULL ) ,
2008-08-17 11:23:11 -04:00
mState ( 0 ) , mSize ( 0 ) , mFlags ( 0 )
{
return ;
}
2009-06-11 17:41:42 -04:00
ftFileControl : : ftFileControl ( std : : string fname ,
std : : string tmppath , std : : string dest ,
uint64_t size , std : : string hash , uint32_t flags ,
2008-10-29 16:58:23 -04:00
ftFileCreator * fc , ftTransferModule * tm , uint32_t cb )
: mName ( fname ) , mCurrentPath ( tmppath ) , mDestination ( dest ) ,
mTransfer ( tm ) , mCreator ( fc ) , mState ( 0 ) , mHash ( hash ) ,
2009-05-06 16:48:32 -04:00
mSize ( size ) , mFlags ( flags ) , mDoCallback ( false ) , mCallbackCode ( cb )
2008-08-17 11:23:11 -04:00
{
2008-10-29 16:58:23 -04:00
if ( cb )
mDoCallback = true ;
2008-08-17 11:23:11 -04:00
return ;
}
2008-08-09 13:03:24 -04:00
ftController : : ftController ( CacheStrapper * cs , ftDataMultiplex * dm , std : : string configDir )
2009-07-12 09:22:31 -04:00
: CacheTransfer ( cs ) , p3Config ( CONFIG_TYPE_FT_CONTROL ) , mDataplex ( dm ) , mFtActive ( false ) ,
2009-12-10 17:55:27 -05:00
mTurtle ( NULL ) , mShareDownloadDir ( true ) , last_save_time ( 0 )
2008-07-23 18:01:59 -04:00
{
2008-08-09 13:03:24 -04:00
/* TODO */
2008-07-23 18:01:59 -04:00
}
2009-05-26 17:42:45 -04:00
void ftController : : setTurtleRouter ( p3turtle * pt )
{
mTurtle = pt ;
}
2008-11-09 17:17:20 -05:00
void ftController : : setFtSearchNExtra ( ftSearch * search , ftExtraList * list )
2008-08-09 13:03:24 -04:00
{
mSearch = search ;
2008-11-09 17:17:20 -05:00
mExtraList = list ;
2008-08-09 13:03:24 -04:00
}
2008-07-23 18:01:59 -04:00
2009-11-18 18:02:37 -05:00
bool ftController : : getFileChunksDetails ( const std : : string & hash , FileChunksInfo & info )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
std : : map < std : : string , ftFileControl > : : iterator it = mDownloads . find ( hash ) ;
if ( it = = mDownloads . end ( ) )
return false ;
it - > second . mCreator - > getChunkMap ( info ) ;
return true ;
}
2009-05-26 17:42:45 -04:00
void ftController : : addFileSource ( const std : : string & hash , const std : : string & peer_id )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
std : : map < std : : string , ftFileControl > : : iterator it ;
std : : map < std : : string , ftFileControl > currentDownloads = * ( & mDownloads ) ;
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController: Adding source " < < peer_id < < " to current download hash= " < < hash ;
# endif
for ( it = currentDownloads . begin ( ) ; it ! = currentDownloads . end ( ) ; it + + )
if ( it - > first = = hash )
{
it - > second . mTransfer - > addFileSource ( peer_id ) ;
// setPeerState(it->second.mTransfer, peer_id, rate, mConnMgr->isOnline(peer_id));
# ifdef CONTROL_DEBUG
std : : cerr < < " ... added. " < < std : : endl ;
# endif
return ;
}
# ifdef CONTROL_DEBUG
std : : cerr < < " ... not added: hash not found. " < < std : : endl ;
# endif
}
2009-06-03 14:47:14 -04:00
void ftController : : removeFileSource ( const std : : string & hash , const std : : string & peer_id )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
std : : map < std : : string , ftFileControl > : : iterator it ;
std : : map < std : : string , ftFileControl > currentDownloads = * ( & mDownloads ) ;
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController: Adding source " < < peer_id < < " to current download hash= " < < hash ;
# endif
for ( it = currentDownloads . begin ( ) ; it ! = currentDownloads . end ( ) ; it + + )
if ( it - > first = = hash )
{
it - > second . mTransfer - > removeFileSource ( peer_id ) ;
2009-05-26 17:42:45 -04:00
2009-06-03 14:47:14 -04:00
// setPeerState(it->second.mTransfer, peer_id, rate, mConnMgr->isOnline(peer_id));
# ifdef CONTROL_DEBUG
std : : cerr < < " ... added. " < < std : : endl ;
# endif
return ;
}
# ifdef CONTROL_DEBUG
std : : cerr < < " ... not added: hash not found. " < < std : : endl ;
# endif
}
2008-08-09 13:03:24 -04:00
void ftController : : run ( )
2008-07-23 18:01:59 -04:00
{
2008-08-17 11:23:11 -04:00
2009-05-06 16:48:32 -04:00
/* check the queues */
2008-08-21 17:30:59 -04:00
while ( 1 )
2008-08-17 11:23:11 -04:00
{
2008-08-25 16:03:39 -04:00
# ifdef WIN32
Sleep ( 1000 ) ;
# else
2008-08-21 17:30:59 -04:00
sleep ( 1 ) ;
2008-08-25 16:03:39 -04:00
# endif
2008-08-21 17:30:59 -04:00
2008-11-02 06:38:11 -05:00
# ifdef CONTROL_DEBUG
2009-05-06 16:48:32 -04:00
std : : cerr < < " ftController::run() " ;
std : : cerr < < std : : endl ;
2008-11-02 06:38:11 -05:00
# endif
2008-11-20 19:10:59 -05:00
bool doPending = false ;
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
doPending = ( mFtActive ) & & ( ! mFtPendingDone ) ;
}
2009-12-10 17:55:27 -05:00
time_t now = time ( NULL ) ;
if ( now - last_save_time > SAVE_TRANSFERS_DELAY )
{
IndicateConfigChanged ( ) ;
last_save_time = now ;
}
2008-11-20 19:10:59 -05:00
if ( doPending )
{
if ( ! handleAPendingRequest ( ) )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
mFtPendingDone = true ;
}
}
2008-08-17 11:23:11 -04:00
2008-08-21 17:30:59 -04:00
/* tick the transferModules */
2008-10-29 16:58:23 -04:00
std : : list < std : : string > done ;
std : : list < std : : string > : : iterator it ;
2008-08-21 17:30:59 -04:00
{
2008-10-29 16:58:23 -04:00
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2009-01-24 10:22:08 -05:00
std : : map < std : : string , ftFileControl > : : iterator it ;
2009-05-06 16:48:32 -04:00
std : : map < std : : string , ftFileControl > currentDownloads = * ( & mDownloads ) ;
for ( it = currentDownloads . begin ( ) ; it ! = currentDownloads . end ( ) ; it + + )
2008-10-29 16:58:23 -04:00
{
2008-12-07 09:53:57 -05:00
# ifdef CONTROL_DEBUG
2009-01-24 10:22:08 -05:00
std : : cerr < < " \t Ticking: " < < it - > first ;
2008-08-21 17:30:59 -04:00
std : : cerr < < std : : endl ;
2008-12-07 09:53:57 -05:00
# endif
2009-01-24 10:22:08 -05:00
2009-06-11 17:41:42 -04:00
if ( it - > second . mTransfer )
2009-05-26 17:42:45 -04:00
{
# ifdef CONTROL_DEBUG
std : : cerr < < " \t Ticking mTransfer: " < < ( void * ) it - > second . mTransfer ;
std : : cerr < < std : : endl ;
# endif
( it - > second . mTransfer ) - > tick ( ) ;
2009-05-06 16:48:32 -04:00
2009-05-26 17:42:45 -04:00
//check if a cache file is downloaded, if the case, timeout the transfer after TIMOUT_CACHE_FILE_TRANSFER
if ( ( it - > second ) . mFlags & RS_FILE_HINTS_CACHE ) {
2009-05-06 16:48:32 -04:00
# ifdef CONTROL_DEBUG
2009-05-26 17:42:45 -04:00
std : : cerr < < " ftController::run() cache transfer found. age of this tranfer is : " < < ( int ) ( time ( NULL ) - ( it - > second ) . mCreateTime ) ;
std : : cerr < < std : : endl ;
2009-05-06 16:48:32 -04:00
# endif
2009-05-26 17:42:45 -04:00
if ( ( time ( NULL ) - ( it - > second ) . mCreateTime ) > TIMOUT_CACHE_FILE_TRANSFER ) {
2009-05-06 16:48:32 -04:00
# ifdef CONTROL_DEBUG
2009-05-26 17:42:45 -04:00
std : : cerr < < " ftController::run() cache transfer to old. Cancelling transfer. Hash : " < < ( it - > second ) . mHash < < " , time= " < < ( it - > second ) . mCreateTime < < " , now = " < < time ( NULL ) ;
std : : cerr < < std : : endl ;
2009-05-06 16:48:32 -04:00
# endif
2009-05-26 17:42:45 -04:00
this - > FileCancel ( ( it - > second ) . mHash ) ;
}
2009-05-06 16:48:32 -04:00
}
}
2009-05-26 17:42:45 -04:00
# ifdef CONTROL_DEBUG
else
std : : cerr < < " No mTransfer for this hash. " < < std : : endl ;
# endif
2008-10-29 16:58:23 -04:00
}
2008-08-21 17:30:59 -04:00
}
2008-10-29 16:58:23 -04:00
2009-06-11 17:41:42 -04:00
RsStackMutex stack2 ( doneMutex ) ;
2008-10-29 16:58:23 -04:00
for ( it = mDone . begin ( ) ; it ! = mDone . end ( ) ; it + + )
{
completeFile ( * it ) ;
}
mDone . clear ( ) ;
2008-08-17 11:23:11 -04:00
}
2008-10-29 16:58:23 -04:00
2008-07-23 18:01:59 -04:00
}
/* Called every 10 seconds or so */
void ftController : : checkDownloadQueue ( )
{
2009-01-24 10:22:08 -05:00
/* */
2008-07-23 18:01:59 -04:00
}
2008-10-29 16:58:23 -04:00
bool ftController : : FlagFileComplete ( std : : string hash )
2008-07-23 18:01:59 -04:00
{
2009-06-11 17:41:42 -04:00
RsStackMutex stack2 ( doneMutex ) ;
2008-10-29 16:58:23 -04:00
mDone . push_back ( hash ) ;
2008-08-09 13:03:24 -04:00
2009-12-14 13:10:20 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController:FlagFileComplete( " < < hash < < " ) " ;
std : : cerr < < std : : endl ;
# endif
2008-08-09 13:03:24 -04:00
2008-10-29 16:58:23 -04:00
return true ;
}
2009-03-19 08:49:11 -04:00
bool ftController : : moveFile ( const std : : string & source , const std : : string & dest )
{
// First try a rename
//
if ( 0 = = rename ( source . c_str ( ) , dest . c_str ( ) ) )
{
2009-12-14 13:10:20 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::completeFile() renaming to: " ;
std : : cerr < < dest ;
std : : cerr < < std : : endl ;
# endif
2009-03-19 08:49:11 -04:00
return true ;
}
2009-12-14 13:10:20 -05:00
# ifdef CONTROL_DEBUG
2009-03-19 08:49:11 -04:00
std : : cerr < < " ftController::completeFile() FAILED mv to: " ;
std : : cerr < < dest ;
std : : cerr < < std : : endl ;
std : : cerr < < " trying copy " < < std : : endl ;
2009-12-14 13:10:20 -05:00
# endif
2009-06-11 17:41:42 -04:00
// We could not rename, probably because we're dealing with different file systems.
2009-03-19 08:49:11 -04:00
// Let's copy then.
std : : string error ;
static const int BUFF_SIZE = 10485760 ; // 10 MB buffer to speed things up.
void * buffer = malloc ( BUFF_SIZE ) ;
2009-03-23 10:45:51 -04:00
FILE * in = fopen ( source . c_str ( ) , " rb " ) ;
2009-03-19 08:49:11 -04:00
if ( in = = NULL )
{
getPqiNotify ( ) - > AddSysMessage ( 0 , RS_SYS_WARNING , " File copy error " , " Error while copying file " + dest + " \n Cannot open input file " + source ) ;
return false ;
}
2009-03-23 10:45:51 -04:00
FILE * out = fopen ( dest . c_str ( ) , " wb " ) ;
2009-03-19 08:49:11 -04:00
if ( out = = NULL )
{
getPqiNotify ( ) - > AddSysMessage ( 0 , RS_SYS_WARNING , " File copy error " , " Error while copying file " + dest + " \n Check for disk full, or write permission ? \n Original file kept under the name " + source ) ;
return false ;
}
size_t s = 0 ;
size_t T = 0 ;
while ( ( s = fread ( buffer , 1 , BUFF_SIZE , in ) ) > 0 )
{
size_t t = fwrite ( buffer , 1 , s , out ) ;
T + = t ;
if ( t ! = s )
{
getPqiNotify ( ) - > AddSysMessage ( 0 , RS_SYS_WARNING , " File copy error " , " Error while copying file " + dest + " \n Is your disc full ? \n Original file kept under the name " + source ) ;
return false ;
}
}
fclose ( in ) ;
fclose ( out ) ;
// copy was successfull, let's delete the original
std : : cerr < < " deleting original file " < < source < < std : : endl ;
free ( buffer ) ;
if ( 0 = = remove ( source . c_str ( ) ) )
return true ;
else
{
getPqiNotify ( ) - > AddSysMessage ( 0 , RS_SYS_WARNING , " File erase error " , " Error while removing hash file " + dest + " \n Read-only file system ? " ) ;
return false ;
}
}
2008-10-29 16:58:23 -04:00
bool ftController : : completeFile ( std : : string hash )
{
2008-11-09 17:17:20 -05:00
/* variables... so we can drop mutex later */
std : : string path ;
uint64_t size = 0 ;
uint32_t state = 0 ;
uint32_t period = 0 ;
uint32_t flags = 0 ;
bool doCallback = false ;
uint32_t callbackCode = 0 ;
2009-06-11 17:41:42 -04:00
{
2009-02-12 07:47:57 -05:00
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-10-29 16:58:23 -04:00
2009-12-14 13:10:34 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController:completeFile( " < < hash < < " ) " ;
2008-10-29 16:58:23 -04:00
std : : cerr < < std : : endl ;
2009-12-14 13:10:34 -05:00
# endif
2009-02-12 07:47:57 -05:00
std : : map < std : : string , ftFileControl > : : iterator it ;
it = mDownloads . find ( hash ) ;
if ( it = = mDownloads . end ( ) )
{
2009-12-14 13:10:34 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController:completeFile( " < < hash < < " ) " ;
2009-02-12 07:47:57 -05:00
std : : cerr < < " Not Found! " ;
std : : cerr < < std : : endl ;
2009-12-14 13:10:34 -05:00
# endif
return false ;
2009-02-12 07:47:57 -05:00
}
2008-10-29 16:58:23 -04:00
2009-02-12 07:47:57 -05:00
/* check if finished */
if ( ! ( it - > second ) . mCreator - > finished ( ) )
{
/* not done! */
2009-12-14 13:10:34 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController:completeFile( " < < hash < < " ) " ;
2009-02-12 07:47:57 -05:00
std : : cerr < < " Transfer Not Done " ;
std : : cerr < < std : : endl ;
2008-10-29 16:58:23 -04:00
2009-02-12 07:47:57 -05:00
std : : cerr < < " FileSize: " ;
std : : cerr < < ( it - > second ) . mCreator - > getFileSize ( ) ;
std : : cerr < < " and Recvd: " ;
std : : cerr < < ( it - > second ) . mCreator - > getRecvd ( ) ;
2009-12-14 13:10:34 -05:00
# endif
2009-02-12 07:47:57 -05:00
return false ;
}
2008-07-23 18:01:59 -04:00
2008-10-29 16:58:23 -04:00
2009-02-12 07:47:57 -05:00
ftFileControl * fc = & ( it - > second ) ;
2008-07-23 18:01:59 -04:00
2009-06-11 17:41:42 -04:00
// (csoler) I've postponed this to the end of the block because deleting the
// element from the map calls the destructor of fc->mTransfer, which
2009-02-12 07:47:57 -05:00
// makes fc to point to nothing and causes random behavior/crashes.
//
// mDataplex->removeTransferModule(fc->mTransfer->hash());
//
/* done - cleanup */
2008-10-29 16:58:23 -04:00
2009-02-12 07:47:57 -05:00
// (csoler) I'm copying this because "delete fc->mTransfer" deletes the hash string!
2009-06-11 17:41:42 -04:00
std : : string hash_to_suppress ( fc - > mTransfer - > hash ( ) ) ;
2008-07-23 18:01:59 -04:00
2009-02-12 07:47:57 -05:00
if ( fc - > mTransfer )
{
delete fc - > mTransfer ;
fc - > mTransfer = NULL ;
}
2008-07-23 18:01:59 -04:00
2009-02-12 07:47:57 -05:00
if ( fc - > mCreator )
{
delete fc - > mCreator ;
fc - > mCreator = NULL ;
}
fc - > mState = ftFileControl : : COMPLETED ;
2009-04-06 15:41:40 -04:00
// I don't know how the size can be zero, but believe me, this happens,
// and it causes an error on linux because then the file may not even exist.
//
2009-06-11 17:41:42 -04:00
if ( fc - > mSize > 0 & & moveFile ( fc - > mCurrentPath , fc - > mDestination ) )
2009-02-12 07:47:57 -05:00
fc - > mCurrentPath = fc - > mDestination ;
else
fc - > mState = ftFileControl : : ERROR_COMPLETION ;
2008-10-29 16:58:23 -04:00
2009-02-12 07:47:57 -05:00
/* switch map */
2009-06-11 17:41:42 -04:00
if ( fc - > mFlags & RS_FILE_HINTS_CACHE ) /* clean up completed cache files automatically */
2009-02-12 07:47:57 -05:00
{
mCompleted [ fc - > mHash ] = * fc ;
}
2008-11-09 17:17:20 -05:00
2009-02-12 07:47:57 -05:00
/* for extralist additions */
path = fc - > mDestination ;
//hash = fc->mHash;
size = fc - > mSize ;
state = fc - > mState ;
period = 30 * 24 * 3600 ; /* 30 days */
flags = 0 ;
2008-11-09 17:17:20 -05:00
2009-04-06 15:41:40 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " CompleteFile(): size = " < < size < < std : : endl ;
# endif
2009-02-12 07:47:57 -05:00
doCallback = fc - > mDoCallback ;
callbackCode = fc - > mCallbackCode ;
2008-11-09 17:17:20 -05:00
2009-02-12 07:47:57 -05:00
mDataplex - > removeTransferModule ( hash_to_suppress ) ;
mDownloads . erase ( it ) ;
2009-06-14 15:34:22 -04:00
mTurtle - > stopMonitoringFileTunnels ( hash_to_suppress ) ;
2009-02-12 07:47:57 -05:00
} /******* UNLOCKED ********/
2008-11-09 17:17:20 -05:00
/******************** NO Mutex from Now ********************
* cos Callback can end up back in this class .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-10-29 16:58:23 -04:00
/* If it has a callback - do it now */
2008-11-09 17:17:20 -05:00
if ( doCallback )
2008-10-29 16:58:23 -04:00
{
2008-11-04 18:12:53 -05:00
# ifdef CONTROL_DEBUG
2008-11-29 17:03:36 -05:00
std : : cerr < < " ftController::completeFile() doing Callback, callbackCode: " < < callbackCode ;
2008-11-04 18:12:53 -05:00
std : : cerr < < std : : endl ;
# endif
2008-11-09 17:17:20 -05:00
switch ( callbackCode )
2008-10-29 16:58:23 -04:00
{
case CB_CODE_CACHE :
/* callback */
2008-11-09 17:17:20 -05:00
if ( state = = ftFileControl : : COMPLETED )
2008-10-29 16:58:23 -04:00
{
2008-11-04 18:12:53 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::completeFile() doing Callback : Success " ;
std : : cerr < < std : : endl ;
# endif
2009-06-11 17:41:42 -04:00
2008-11-09 17:17:20 -05:00
CompletedCache ( hash ) ;
2008-10-29 16:58:23 -04:00
}
else
{
2008-11-04 18:12:53 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::completeFile() Cache Callback : Failed " ;
std : : cerr < < std : : endl ;
# endif
2008-11-09 17:17:20 -05:00
FailedCache ( hash ) ;
2008-10-29 16:58:23 -04:00
}
2008-11-09 17:17:20 -05:00
break ;
case CB_CODE_EXTRA :
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::completeFile() adding to ExtraList " ;
std : : cerr < < std : : endl ;
# endif
mExtraList - > addExtraFile ( path , hash , size , period , flags ) ;
2008-10-29 16:58:23 -04:00
break ;
case CB_CODE_MEDIA :
2008-11-04 18:12:53 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::completeFile() NULL MEDIA callback " ;
std : : cerr < < std : : endl ;
# endif
2008-10-29 16:58:23 -04:00
break ;
}
}
2008-11-04 18:12:53 -05:00
else
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::completeFile() No callback " ;
std : : cerr < < std : : endl ;
# endif
}
2009-06-11 17:41:42 -04:00
2008-11-15 15:00:29 -05:00
IndicateConfigChanged ( ) ; /* completed transfer -> save */
2008-07-23 18:01:59 -04:00
return true ;
2008-08-09 13:03:24 -04:00
2008-07-23 18:01:59 -04:00
}
/***************************************************************/
/********************** Controller Access **********************/
/***************************************************************/
2008-11-18 20:12:21 -05:00
const uint32_t FT_CNTRL_STANDARD_RATE = 1024 * 1024 ;
const uint32_t FT_CNTRL_SLOW_RATE = 10 * 1024 ;
2008-11-04 18:12:53 -05:00
2008-11-20 19:10:59 -05:00
bool ftController : : activate ( )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
mFtActive = true ;
mFtPendingDone = false ;
return true ;
}
2009-08-10 15:01:27 -04:00
bool ftController : : isActiveAndNoPending ( )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
return ( mFtActive & & mFtPendingDone ) ;
}
2008-11-20 19:10:59 -05:00
bool ftController : : handleAPendingRequest ( )
{
ftPendingRequest req ;
2009-12-10 17:55:27 -05:00
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-11-20 19:10:59 -05:00
2009-12-10 17:55:27 -05:00
if ( mPendingRequests . size ( ) < 1 )
{
return false ;
}
req = mPendingRequests . front ( ) ;
mPendingRequests . pop_front ( ) ;
2008-11-20 19:10:59 -05:00
}
2009-12-10 17:55:27 -05:00
2008-11-20 19:10:59 -05:00
FileRequest ( req . mName , req . mHash , req . mSize , req . mDest , req . mFlags , req . mSrcIds ) ;
2009-12-10 17:55:27 -05:00
{
// See whether there is a pendign chunk map recorded for this hash.
//
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
std : : map < std : : string , RsFileTransfer * > : : iterator it ( mPendingChunkMaps . find ( req . mHash ) ) ;
if ( it ! = mPendingChunkMaps . end ( ) )
{
RsFileTransfer * rsft = it - > second ;
std : : map < std : : string , ftFileControl > : : iterator fit = mDownloads . find ( rsft - > file . hash ) ;
if ( ( fit = = mDownloads . end ( ) | | ( fit - > second ) . mCreator = = NULL ) )
{
// This should never happen, because the last call to FileRequest must have created the fileCreator!!
//
std : : cerr < < " ftController::loadList(): Error: could not find hash " < < rsft - > file . hash < < " in mDownloads list ! " < < std : : endl ;
}
else
( fit - > second ) . mCreator - > loadAvailabilityMap ( rsft - > chunk_map , rsft - > chunk_size , rsft - > chunk_number , rsft - > chunk_strategy ) ;
delete rsft ;
mPendingChunkMaps . erase ( it ) ;
}
}
2008-11-20 19:10:59 -05:00
}
2009-06-11 17:41:42 -04:00
bool ftController : : FileRequest ( std : : string fname , std : : string hash ,
uint64_t size , std : : string dest , uint32_t flags ,
2008-08-09 13:03:24 -04:00
std : : list < std : : string > & srcIds )
2008-07-23 18:01:59 -04:00
{
2008-11-20 19:10:59 -05:00
/* If file transfer is not enabled ....
* save request for later . This will also
2009-06-11 17:41:42 -04:00
* mean that we will have to copy local files ,
2008-11-20 19:10:59 -05:00
* or have a callback which says : local file .
*/
2009-06-11 17:41:42 -04:00
{
2009-02-12 07:47:57 -05:00
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
if ( ! mFtActive )
{
/* store in pending queue */
ftPendingRequest req ( fname , hash , size , dest , flags , srcIds ) ;
mPendingRequests . push_back ( req ) ;
return true ;
}
2008-11-20 19:10:59 -05:00
}
2008-07-23 18:01:59 -04:00
/* check if we have the file */
2008-08-09 13:03:24 -04:00
FileInfo info ;
2008-08-17 11:23:11 -04:00
std : : list < std : : string > : : iterator it ;
2008-11-02 06:38:11 -05:00
std : : list < TransferInfo > : : iterator pit ;
2008-07-23 18:01:59 -04:00
2008-08-17 11:23:11 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest( " < < fname < < " , " ;
std : : cerr < < hash < < " , " < < size < < " , " < < dest < < " , " ;
std : : cerr < < flags < < " ,< " ;
for ( it = srcIds . begin ( ) ; it ! = srcIds . end ( ) ; it + + )
2008-07-23 18:01:59 -04:00
{
2008-08-17 11:23:11 -04:00
std : : cerr < < * it < < " , " ;
2008-07-23 18:01:59 -04:00
}
2008-08-17 11:23:11 -04:00
std : : cerr < < " >) " ;
std : : cerr < < std : : endl ;
# endif
2008-11-13 18:03:46 -05:00
std : : string ownId = mConnMgr - > getOwnId ( ) ;
2008-11-09 17:17:20 -05:00
uint32_t rate = 0 ;
if ( flags & RS_FILE_HINTS_BACKGROUND )
{
rate = FT_CNTRL_SLOW_RATE ;
}
else
{
rate = FT_CNTRL_STANDARD_RATE ;
}
2009-06-11 17:41:42 -04:00
/* First check if the file is already being downloaded....
2008-11-09 17:17:20 -05:00
* This is important as some guis request duplicate files regularly .
*/
2008-11-15 15:00:29 -05:00
{ RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-11-09 17:17:20 -05:00
std : : map < std : : string , ftFileControl > : : iterator dit ;
dit = mDownloads . find ( hash ) ;
if ( dit ! = mDownloads . end ( ) )
{
/* we already have it! */
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Already Downloading File " ;
std : : cerr < < std : : endl ;
std : : cerr < < " \t No need to download " ;
std : : cerr < < std : : endl ;
# endif
/* but we should add this peer - if they don't exist!
* ( needed for channels ) .
*/
for ( it = srcIds . begin ( ) ; it ! = srcIds . end ( ) ; it + + )
{
uint32_t i , j ;
if ( ( dit - > second ) . mTransfer - > getPeerState ( * it , i , j ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Peer Existing " ;
std : : cerr < < std : : endl ;
# endif
continue ; /* already added peer */
}
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Adding Peer: " < < * it ;
std : : cerr < < std : : endl ;
# endif
2008-11-13 18:03:46 -05:00
( dit - > second ) . mTransfer - > addFileSource ( * it ) ;
2009-06-11 17:41:42 -04:00
setPeerState ( dit - > second . mTransfer , * it ,
2008-11-13 18:03:46 -05:00
rate , mConnMgr - > isOnline ( * it ) ) ;
2008-11-15 15:00:29 -05:00
IndicateConfigChanged ( ) ; /* new peer for transfer -> save */
2008-11-13 18:03:46 -05:00
}
2008-11-09 17:17:20 -05:00
2008-11-13 18:03:46 -05:00
if ( srcIds . size ( ) = = 0 )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() WARNING: No Src Peers " ;
std : : cerr < < std : : endl ;
# endif
2008-11-09 17:17:20 -05:00
}
2008-11-13 18:03:46 -05:00
return true ;
2008-11-09 17:17:20 -05:00
}
2008-11-15 15:00:29 -05:00
} /******* UNLOCKED ********/
2008-11-09 17:17:20 -05:00
2008-10-29 16:58:23 -04:00
bool doCallback = false ;
uint32_t callbackCode = 0 ;
if ( flags & RS_FILE_HINTS_NO_SEARCH )
2008-08-17 11:23:11 -04:00
{
2008-10-29 16:58:23 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Flags for NO_SEARCH " ;
std : : cerr < < std : : endl ;
# endif
2008-08-17 11:23:11 -04:00
/* no search */
2008-10-29 16:58:23 -04:00
if ( flags & RS_FILE_HINTS_CACHE )
{
doCallback = true ;
callbackCode = CB_CODE_CACHE ;
}
2008-11-09 17:17:20 -05:00
else if ( flags & RS_FILE_HINTS_EXTRA )
{
doCallback = true ;
callbackCode = CB_CODE_EXTRA ;
}
2008-08-17 11:23:11 -04:00
}
2009-06-11 17:41:42 -04:00
else
2008-07-23 18:01:59 -04:00
{
2009-06-11 17:41:42 -04:00
if ( mSearch - > search ( hash , size ,
RS_FILE_HINTS_LOCAL |
RS_FILE_HINTS_EXTRA |
2008-08-17 11:23:11 -04:00
RS_FILE_HINTS_SPEC_ONLY , info ) )
{
/* have it already */
/* add in as completed transfer */
2008-10-29 16:58:23 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Matches Local File " ;
std : : cerr < < std : : endl ;
std : : cerr < < " \t No need to download " ;
std : : cerr < < std : : endl ;
# endif
2008-08-17 11:23:11 -04:00
return true ;
}
/* do a source search - for any extra sources */
2009-06-11 17:41:42 -04:00
if ( mSearch - > search ( hash , size ,
2008-08-17 11:23:11 -04:00
RS_FILE_HINTS_REMOTE |
2009-05-26 17:42:45 -04:00
RS_FILE_HINTS_TURTLE |
2008-08-17 11:23:11 -04:00
RS_FILE_HINTS_SPEC_ONLY , info ) )
{
/* do something with results */
2008-10-29 16:58:23 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Found Other Sources " ;
std : : cerr < < std : : endl ;
# endif
/* if the sources don't exist already - add in */
2008-11-02 06:38:11 -05:00
for ( pit = info . peers . begin ( ) ; pit ! = info . peers . end ( ) ; pit + + )
2008-10-29 16:58:23 -04:00
{
2009-12-14 13:10:20 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " \t Source: " < < pit - > peerId ;
2008-10-29 16:58:23 -04:00
std : : cerr < < std : : endl ;
2009-12-14 13:10:20 -05:00
# endif
2008-10-29 16:58:23 -04:00
if ( srcIds . end ( ) = = std : : find (
2008-11-02 06:38:11 -05:00
srcIds . begin ( ) , srcIds . end ( ) , pit - > peerId ) )
2008-10-29 16:58:23 -04:00
{
2008-11-02 06:38:11 -05:00
srcIds . push_back ( pit - > peerId ) ;
2008-10-29 16:58:23 -04:00
2009-12-14 13:10:20 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " \t Adding in: " < < pit - > peerId ;
2008-10-29 16:58:23 -04:00
std : : cerr < < std : : endl ;
2009-12-14 13:10:20 -05:00
# endif
}
2009-06-11 17:41:42 -04:00
}
2008-10-29 16:58:23 -04:00
}
2008-11-09 17:17:20 -05:00
if ( flags & RS_FILE_HINTS_EXTRA )
{
doCallback = true ;
callbackCode = CB_CODE_EXTRA ;
}
else if ( flags & RS_FILE_HINTS_MEDIA )
2008-10-29 16:58:23 -04:00
{
doCallback = true ;
callbackCode = CB_CODE_MEDIA ;
2008-08-17 11:23:11 -04:00
}
2008-07-23 18:01:59 -04:00
}
2008-10-29 16:58:23 -04:00
//std::map<std::string, ftTransferModule *> mTransfers;
//std::map<std::string, ftFileCreator *> mFileCreators;
2008-07-23 18:01:59 -04:00
/* add in new item for download */
2008-11-15 15:00:29 -05:00
std : : string savepath ;
std : : string destination ;
{ RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2009-07-28 11:29:21 -04:00
savepath = mPartialsPath + " / " + hash ;
2008-11-15 15:00:29 -05:00
destination = dest + " / " + fname ;
2008-10-29 16:58:23 -04:00
/* if no destpath - send to download directory */
if ( dest = = " " )
{
destination = mDownloadPath + " / " + fname ;
}
2008-11-15 15:00:29 -05:00
} /******* UNLOCKED ********/
2009-06-11 17:41:42 -04:00
2008-10-22 14:12:58 -04:00
ftFileCreator * fc = new ftFileCreator ( savepath , size , hash , 0 ) ;
2008-09-08 10:04:10 -04:00
ftTransferModule * tm = new ftTransferModule ( fc , mDataplex , this ) ;
2008-07-23 18:01:59 -04:00
/* add into maps */
2009-06-11 17:41:42 -04:00
ftFileControl ftfc ( fname , savepath , destination ,
2008-10-29 16:58:23 -04:00
size , hash , flags , fc , tm , callbackCode ) ;
2009-05-06 16:48:32 -04:00
ftfc . mCreateTime = time ( NULL ) ;
2008-07-23 18:01:59 -04:00
2008-11-13 18:03:46 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileRequest() Created ftFileCreator @: " < < fc ;
std : : cerr < < std : : endl ;
std : : cerr < < " ftController::FileRequest() Created ftTransModule @: " < < tm ;
std : : cerr < < std : : endl ;
2009-05-06 16:48:32 -04:00
std : : cerr < < " ftController::FileRequest() Created ftFileControl. " ;
std : : cerr < < std : : endl ;
2008-11-13 18:03:46 -05:00
# endif
2008-07-23 18:01:59 -04:00
/* add to ClientModule */
2008-08-09 13:03:24 -04:00
mDataplex - > addTransferModule ( tm , fc ) ;
2008-07-23 18:01:59 -04:00
/* now add source peers (and their current state) */
tm - > setFileSources ( srcIds ) ;
/* get current state for transfer module */
for ( it = srcIds . begin ( ) ; it ! = srcIds . end ( ) ; it + + )
{
2008-08-21 17:30:59 -04:00
# ifdef CONTROL_DEBUG
2008-11-13 18:03:46 -05:00
std : : cerr < < " ftController::FileRequest() adding peer: " < < * it ;
std : : cerr < < std : : endl ;
2008-08-17 11:23:11 -04:00
# endif
2008-11-13 18:03:46 -05:00
setPeerState ( tm , * it , rate , mConnMgr - > isOnline ( * it ) ) ;
2008-07-23 18:01:59 -04:00
}
2008-11-15 15:00:29 -05:00
2008-07-23 18:01:59 -04:00
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
mDownloads [ hash ] = ftfc ;
mSlowQueue . push_back ( hash ) ;
2008-11-15 15:00:29 -05:00
IndicateConfigChanged ( ) ; /* completed transfer -> save */
2008-10-29 16:58:23 -04:00
return true ;
2008-08-09 13:03:24 -04:00
}
2009-06-11 17:41:42 -04:00
bool ftController : : setPeerState ( ftTransferModule * tm , std : : string id ,
2008-11-13 18:03:46 -05:00
uint32_t maxrate , bool online )
{
if ( id = = mConnMgr - > getOwnId ( ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::setPeerState() is Self " ;
std : : cerr < < std : : endl ;
# endif
tm - > setPeerState ( id , PQIPEER_IDLE , maxrate ) ;
}
2009-05-26 17:42:45 -04:00
else if ( online | | mTurtle - > isOnline ( id ) )
2008-11-13 18:03:46 -05:00
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::setPeerState() " ;
std : : cerr < < " Peer is Online " ;
std : : cerr < < std : : endl ;
# endif
tm - > setPeerState ( id , PQIPEER_IDLE , maxrate ) ;
}
else
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::setPeerState() " ;
std : : cerr < < " Peer is Offline " ;
std : : cerr < < std : : endl ;
# endif
tm - > setPeerState ( id , PQIPEER_NOT_ONLINE , maxrate ) ;
}
return true ;
}
2009-12-08 17:29:52 -05:00
bool ftController : : setChunkStrategy ( const std : : string & hash , FileChunksInfo : : ChunkStrategy s )
{
std : : map < std : : string , ftFileControl > : : iterator mit ;
mit = mDownloads . find ( hash ) ;
if ( mit = = mDownloads . end ( ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileCancel file is not found in mDownloads " < < std : : endl ;
# endif
return false ;
}
mit - > second . mCreator - > setChunkStrategy ( s ) ;
return true ;
}
2008-11-04 18:12:53 -05:00
2008-08-09 13:03:24 -04:00
bool ftController : : FileCancel ( std : : string hash )
{
2008-09-08 04:44:37 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileCancel " < < std : : endl ;
# endif
/*check if the file in the download map*/
std : : map < std : : string , ftFileControl > : : iterator mit ;
mit = mDownloads . find ( hash ) ;
if ( mit = = mDownloads . end ( ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileCancel file is not found in mDownloads " < < std : : endl ;
# endif
return false ;
}
2008-11-29 17:03:36 -05:00
/* check if finished */
if ( ( mit - > second ) . mCreator - > finished ( ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController:FileCancel( " < < hash < < " ) " ;
std : : cerr < < " Transfer Already finished " ;
std : : cerr < < std : : endl ;
std : : cerr < < " FileSize: " ;
std : : cerr < < ( mit - > second ) . mCreator - > getFileSize ( ) ;
std : : cerr < < " and Recvd: " ;
std : : cerr < < ( mit - > second ) . mCreator - > getRecvd ( ) ;
# endif
return false ;
}
2008-09-08 04:44:37 -04:00
/*find the point to transfer module*/
ftTransferModule * ft = ( mit - > second ) . mTransfer ;
ft - > cancelTransfer ( ) ;
2008-11-29 17:03:36 -05:00
ftFileControl * fc = & ( mit - > second ) ;
mDataplex - > removeTransferModule ( fc - > mTransfer - > hash ( ) ) ;
if ( fc - > mTransfer )
{
delete fc - > mTransfer ;
fc - > mTransfer = NULL ;
}
if ( fc - > mCreator )
{
delete fc - > mCreator ;
fc - > mCreator = NULL ;
}
2008-11-30 16:43:51 -05:00
/* delete the temporary file */
if ( 0 = = remove ( fc - > mCurrentPath . c_str ( ) ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileCancel() remove temporary file " ;
std : : cerr < < fc - > mCurrentPath ;
std : : cerr < < std : : endl ;
# endif
}
else
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileCancel() fail to remove file " ;
std : : cerr < < fc - > mCurrentPath ;
std : : cerr < < std : : endl ;
# endif
}
2008-11-29 17:03:36 -05:00
mDownloads . erase ( mit ) ;
2009-06-14 15:34:22 -04:00
IndicateConfigChanged ( ) ; /* completed transfer -> save */
2008-09-08 04:44:37 -04:00
return true ;
2008-07-23 18:01:59 -04:00
}
2008-08-09 13:03:24 -04:00
bool ftController : : FileControl ( std : : string hash , uint32_t flags )
{
2008-09-08 04:44:37 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileControl( " < < hash < < " , " ;
std : : cerr < < flags < < " ) " < < std : : endl ;
# endif
/*check if the file in the download map*/
std : : map < std : : string , ftFileControl > : : iterator mit ;
mit = mDownloads . find ( hash ) ;
if ( mit = = mDownloads . end ( ) )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileControl file is not found in mDownloads " < < std : : endl ;
# endif
return false ;
}
/*find the point to transfer module*/
ftTransferModule * ft = ( mit - > second ) . mTransfer ;
switch ( flags )
{
case RS_FILE_CTRL_PAUSE :
2008-09-09 09:08:22 -04:00
ft - > pauseTransfer ( ) ;
2008-09-08 04:44:37 -04:00
break ;
case RS_FILE_CTRL_START :
ft - > resumeTransfer ( ) ;
break ;
default :
return false ;
}
return true ;
2008-08-09 13:03:24 -04:00
}
2008-07-23 18:01:59 -04:00
2008-08-09 13:03:24 -04:00
bool ftController : : FileClearCompleted ( )
{
2008-12-04 16:34:19 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::FileClearCompleted() " < < std : : endl ;
# endif
mCompleted . clear ( ) ;
2009-06-11 17:41:42 -04:00
IndicateConfigChanged ( ) ;
2008-08-09 13:03:24 -04:00
return false ;
}
2008-07-23 18:01:59 -04:00
/* get Details of File Transfers */
bool ftController : : FileDownloads ( std : : list < std : : string > & hashs )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
std : : map < std : : string , ftFileControl > : : iterator it ;
for ( it = mDownloads . begin ( ) ; it ! = mDownloads . end ( ) ; it + + )
{
2008-08-09 13:03:24 -04:00
hashs . push_back ( it - > second . mHash ) ;
2008-07-23 18:01:59 -04:00
}
2008-11-09 17:17:20 -05:00
for ( it = mCompleted . begin ( ) ; it ! = mCompleted . end ( ) ; it + + )
{
hashs . push_back ( it - > second . mHash ) ;
}
2008-07-23 18:01:59 -04:00
return true ;
}
/* Directory Handling */
bool ftController : : setDownloadDirectory ( std : : string path )
{
2008-08-29 21:07:24 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::setDownloadDirectory( " < < path < < " ) " ;
std : : cerr < < std : : endl ;
# endif
2008-07-23 18:01:59 -04:00
/* check if it exists */
if ( RsDirUtil : : checkCreateDirectory ( path ) )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
mDownloadPath = path ;
2008-08-29 21:07:24 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::setDownloadDirectory() Okay! " ;
std : : cerr < < std : : endl ;
# endif
2009-06-11 17:41:42 -04:00
IndicateConfigChanged ( ) ;
2008-07-23 18:01:59 -04:00
return true ;
}
2008-08-29 21:07:24 -04:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::setDownloadDirectory() Failed " ;
std : : cerr < < std : : endl ;
# endif
2008-07-23 18:01:59 -04:00
return false ;
}
2008-08-09 13:03:24 -04:00
bool ftController : : setPartialsDirectory ( std : : string path )
2008-07-23 18:01:59 -04:00
{
2008-08-09 13:03:24 -04:00
2008-07-23 18:01:59 -04:00
/* check it is not a subdir of download / shared directories (BAD) - TODO */
2009-06-11 17:41:42 -04:00
{
RsStackMutex stack ( ctrlMutex ) ;
if ( ! path . find ( mDownloadPath ) ) {
return false ;
}
if ( rsFiles ) {
2009-08-04 05:19:32 -04:00
std : : list < SharedDirInfo > : : iterator it ;
std : : list < SharedDirInfo > dirs ;
2009-06-11 17:41:42 -04:00
rsFiles - > getSharedDirectories ( dirs ) ;
for ( it = dirs . begin ( ) ; it ! = dirs . end ( ) ; it + + ) {
2009-08-04 05:19:32 -04:00
if ( ! path . find ( ( * it ) . filename ) ) {
2009-06-11 17:41:42 -04:00
return false ;
}
}
}
}
2008-07-23 18:01:59 -04:00
/* check if it exists */
if ( RsDirUtil : : checkCreateDirectory ( path ) )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-10-29 16:58:23 -04:00
mPartialsPath = path ;
2008-07-23 18:01:59 -04:00
2008-10-29 16:58:23 -04:00
#if 0 /*** FIX ME !!!**************/
2008-07-23 18:01:59 -04:00
/* move all existing files! */
std : : map < std : : string , ftFileControl > : : iterator it ;
for ( it = mDownloads . begin ( ) ; it ! = mDownloads . end ( ) ; it + + )
{
( it - > second ) . mCreator - > changePartialDirectory ( mPartialPath ) ;
}
2008-10-29 16:58:23 -04:00
# endif
2009-06-11 17:41:42 -04:00
IndicateConfigChanged ( ) ;
2008-07-23 18:01:59 -04:00
return true ;
}
2008-08-09 13:03:24 -04:00
2008-07-23 18:01:59 -04:00
return false ;
}
std : : string ftController : : getDownloadDirectory ( )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
return mDownloadPath ;
}
std : : string ftController : : getPartialsDirectory ( )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-10-29 16:58:23 -04:00
return mPartialsPath ;
2008-07-23 18:01:59 -04:00
}
bool ftController : : FileDetails ( std : : string hash , FileInfo & info )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-11-09 17:17:20 -05:00
bool completed = false ;
2008-07-23 18:01:59 -04:00
std : : map < std : : string , ftFileControl > : : iterator it ;
it = mDownloads . find ( hash ) ;
if ( it = = mDownloads . end ( ) )
{
2008-11-09 17:17:20 -05:00
/* search completed files too */
it = mCompleted . find ( hash ) ;
if ( it = = mCompleted . end ( ) )
{
2009-06-11 17:41:42 -04:00
/* Note: mTransfer & mCreator
2008-11-09 17:17:20 -05:00
* are both NULL
*/
return false ;
}
completed = true ;
2008-07-23 18:01:59 -04:00
}
/* extract details */
2008-11-02 06:38:11 -05:00
info . hash = hash ;
info . fname = it - > second . mName ;
2009-05-06 16:48:32 -04:00
info . flags = it - > second . mFlags ;
2008-11-15 15:00:29 -05:00
info . path = RsDirUtil : : removeTopDir ( it - > second . mDestination ) ; /* remove fname */
2008-11-02 06:38:11 -05:00
/* get list of sources from transferModule */
std : : list < std : : string > peerIds ;
std : : list < std : : string > : : iterator pit ;
2008-11-09 17:17:20 -05:00
if ( ! completed )
{
it - > second . mTransfer - > getFileSources ( peerIds ) ;
}
2008-11-02 06:38:11 -05:00
2009-02-12 07:47:57 -05:00
double totalRate = 0 ;
uint32_t tfRate = 0 ;
uint32_t state = 0 ;
2008-11-02 06:38:11 -05:00
bool isDownloading = false ;
bool isSuspended = false ;
for ( pit = peerIds . begin ( ) ; pit ! = peerIds . end ( ) ; pit + + )
{
if ( it - > second . mTransfer - > getPeerState ( * pit , state , tfRate ) )
{
TransferInfo ti ;
switch ( state )
{
case PQIPEER_INIT :
ti . status = FT_STATE_OKAY ;
break ;
case PQIPEER_NOT_ONLINE :
ti . status = FT_STATE_WAITING ;
break ;
case PQIPEER_DOWNLOADING :
isDownloading = true ;
ti . status = FT_STATE_DOWNLOADING ;
break ;
case PQIPEER_IDLE :
ti . status = FT_STATE_OKAY ;
break ;
default :
case PQIPEER_SUSPEND :
isSuspended = true ;
ti . status = FT_STATE_FAILED ;
break ;
}
ti . tfRate = tfRate / 1024.0 ;
ti . peerId = * pit ;
info . peers . push_back ( ti ) ;
totalRate + = tfRate / 1024.0 ;
}
}
2008-11-09 17:17:20 -05:00
if ( ( completed ) | | ( ( it - > second ) . mCreator - > finished ( ) ) )
2008-11-02 06:38:11 -05:00
{
info . downloadStatus = FT_STATE_COMPLETE ;
}
else if ( isDownloading )
{
info . downloadStatus = FT_STATE_DOWNLOADING ;
}
else if ( isSuspended )
{
info . downloadStatus = FT_STATE_FAILED ;
}
2009-06-11 17:41:42 -04:00
else
2008-11-02 06:38:11 -05:00
{
info . downloadStatus = FT_STATE_WAITING ;
}
info . tfRate = totalRate ;
info . size = ( it - > second ) . mSize ;
2008-11-09 17:17:20 -05:00
if ( completed )
{
info . transfered = info . size ;
2008-11-30 12:17:28 -05:00
info . avail = info . transfered ;
2008-11-09 17:17:20 -05:00
}
else
{
info . transfered = ( it - > second ) . mCreator - > getRecvd ( ) ;
2008-11-30 12:17:28 -05:00
info . avail = info . transfered ;
2008-11-09 17:17:20 -05:00
}
2008-07-23 18:01:59 -04:00
return true ;
}
/***************************************************************/
/********************** Controller Access **********************/
/***************************************************************/
/* pqiMonitor callback:
* Used to tell TransferModules new available peers
*/
void ftController : : statusChange ( const std : : list < pqipeer > & plist )
{
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
2008-11-13 18:03:46 -05:00
uint32_t rate = FT_CNTRL_STANDARD_RATE ;
2008-07-23 18:01:59 -04:00
/* add online to all downloads */
std : : map < std : : string , ftFileControl > : : iterator it ;
std : : list < pqipeer > : : const_iterator pit ;
2009-05-26 17:42:45 -04:00
std : : list < pqipeer > vlist ;
mTurtle - > getVirtualPeersList ( vlist ) ;
2008-11-13 18:03:46 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::statusChange() " ;
std : : cerr < < std : : endl ;
# endif
2008-07-23 18:01:59 -04:00
for ( it = mDownloads . begin ( ) ; it ! = mDownloads . end ( ) ; it + + )
{
2008-11-13 18:03:46 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::statusChange() Updating Hash: " ;
std : : cerr < < it - > first ;
std : : cerr < < std : : endl ;
# endif
2008-07-23 18:01:59 -04:00
for ( pit = plist . begin ( ) ; pit ! = plist . end ( ) ; pit + + )
{
2008-11-13 18:03:46 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " Peer: " < < pit - > id ;
# endif
if ( pit - > actions & RS_PEER_CONNECTED )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " is Newly Connected! " ;
std : : cerr < < std : : endl ;
# endif
setPeerState ( it - > second . mTransfer , pit - > id , rate , true ) ;
}
else if ( pit - > actions & RS_PEER_DISCONNECTED )
2008-07-23 18:01:59 -04:00
{
2008-11-13 18:03:46 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " is Just disconnected! " ;
std : : cerr < < std : : endl ;
2009-05-26 17:42:45 -04:00
# endif
setPeerState ( it - > second . mTransfer , pit - > id , rate , false ) ;
}
else
{
# ifdef CONTROL_DEBUG
std : : cerr < < " had something happen to it: " ;
std : : cerr < < pit - > actions ;
std : : cerr < < std : : endl ;
# endif
setPeerState ( it - > second . mTransfer , pit - > id , rate , false ) ;
}
}
2009-06-11 17:41:42 -04:00
2009-05-26 17:42:45 -04:00
// Now also look at turtle virtual peers.
//
for ( pit = vlist . begin ( ) ; pit ! = vlist . end ( ) ; pit + + )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " Peer: " < < pit - > id ;
# endif
if ( pit - > actions & RS_PEER_CONNECTED )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " is Newly Connected! " ;
std : : cerr < < std : : endl ;
# endif
setPeerState ( it - > second . mTransfer , pit - > id , rate , true ) ;
}
else if ( pit - > actions & RS_PEER_DISCONNECTED )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " is Just disconnected! " ;
std : : cerr < < std : : endl ;
2008-11-13 18:03:46 -05:00
# endif
setPeerState ( it - > second . mTransfer , pit - > id , rate , false ) ;
2008-07-23 18:01:59 -04:00
}
2008-11-13 18:03:46 -05:00
else
2008-07-23 18:01:59 -04:00
{
2008-11-13 18:03:46 -05:00
# ifdef CONTROL_DEBUG
std : : cerr < < " had something happen to it: " ;
std : : cerr < < pit - > actions ;
std : : cerr < < std : : endl ;
# endif
setPeerState ( it - > second . mTransfer , pit - > id , rate , false ) ;
2008-07-23 18:01:59 -04:00
}
}
}
2008-08-09 13:03:24 -04:00
}
2008-07-23 18:01:59 -04:00
2008-08-17 11:23:11 -04:00
/* Cache Interface */
bool ftController : : RequestCacheFile ( RsPeerId id , std : : string path , std : : string hash , uint64_t size )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::RequestCacheFile( " < < id < < " , " ;
std : : cerr < < path < < " , " < < hash < < " , " < < size < < " ) " ;
std : : cerr < < std : : endl ;
# endif
/* Request File */
std : : list < std : : string > ids ;
ids . push_back ( id ) ;
2009-12-10 17:55:27 -05:00
FileRequest ( hash , hash , size , path , RS_FILE_HINTS_CACHE | RS_FILE_HINTS_NO_SEARCH , ids ) ;
2008-10-29 16:58:23 -04:00
return true ;
2008-08-17 11:23:11 -04:00
}
bool ftController : : CancelCacheFile ( RsPeerId id , std : : string path , std : : string hash , uint64_t size )
{
# ifdef CONTROL_DEBUG
std : : cerr < < " ftController::CancelCacheFile( " < < id < < " , " ;
std : : cerr < < path < < " , " < < hash < < " , " < < size < < " ) " ;
std : : cerr < < std : : endl ;
# endif
2008-10-29 16:58:23 -04:00
return true ;
2008-08-17 11:23:11 -04:00
}
2008-11-15 15:00:29 -05:00
const std : : string download_dir_ss ( " DOWN_DIR " ) ;
const std : : string partial_dir_ss ( " PART_DIR " ) ;
2009-07-12 09:22:31 -04:00
const std : : string share_dwl_dir ( " SHARE_DWL_DIR " ) ;
2008-11-15 15:00:29 -05:00
/* p3Config Interface */
RsSerialiser * ftController : : setupSerialiser ( )
{
RsSerialiser * rss = new RsSerialiser ( ) ;
/* add in the types we need! */
rss - > addSerialType ( new RsFileConfigSerialiser ( ) ) ;
rss - > addSerialType ( new RsGeneralConfigSerialiser ( ) ) ;
return rss ;
}
std : : list < RsItem * > ftController : : saveList ( bool & cleanup )
{
std : : list < RsItem * > saveData ;
/* it can delete them! */
cleanup = true ;
/* create a key/value set for most of the parameters */
std : : map < std : : string , std : : string > configMap ;
std : : map < std : : string , std : : string > : : iterator mit ;
std : : list < std : : string > : : iterator it ;
/* basic control parameters */
configMap [ download_dir_ss ] = getDownloadDirectory ( ) ;
configMap [ partial_dir_ss ] = getPartialsDirectory ( ) ;
2009-07-12 09:22:31 -04:00
configMap [ share_dwl_dir ] = mShareDownloadDir ? " YES " : " NO " ;
2008-11-15 15:00:29 -05:00
RsConfigKeyValueSet * rskv = new RsConfigKeyValueSet ( ) ;
/* Convert to TLV */
for ( mit = configMap . begin ( ) ; mit ! = configMap . end ( ) ; mit + + )
{
RsTlvKeyValue kv ;
kv . key = mit - > first ;
kv . value = mit - > second ;
rskv - > tlvkvs . pairs . push_back ( kv ) ;
}
/* Add KeyValue to saveList */
saveData . push_back ( rskv ) ;
/* get list of Downloads ....
* strip out Caches / ExtraList / Channels ? ? ? ?
* ( anything with a callback ? )
* - most systems will restart missing files .
*/
/* get Details of File Transfers */
std : : list < std : : string > hashs ;
FileDownloads ( hashs ) ;
for ( it = hashs . begin ( ) ; it ! = hashs . end ( ) ; it + + )
{
/* stack mutex released each loop */
RsStackMutex stack ( ctrlMutex ) ; /******* LOCKED ********/
std : : map < std : : string , ftFileControl > : : iterator fit ;
fit = mDownloads . find ( * it ) ;
if ( fit = = mDownloads . end ( ) )
{
continue ;
}
/* ignore callback ones */
if ( fit - > second . mDoCallback )
{
continue ;
}
if ( ( fit - > second ) . mCreator - > finished ( ) )
{
continue ;
}
/* make RsFileTransfer item for save list */
RsFileTransfer * rft = new RsFileTransfer ( ) ;
/* what data is important? */
rft - > file . name = fit - > second . mName ;
2009-06-11 17:41:42 -04:00
rft - > file . hash = fit - > second . mHash ;
2008-11-15 15:00:29 -05:00
rft - > file . filesize = fit - > second . mSize ;
rft - > file . path = RsDirUtil : : removeTopDir ( fit - > second . mDestination ) ; /* remove fname */
//rft->flags = fit->second.mFlags;
fit - > second . mTransfer - > getFileSources ( rft - > allPeerIds . ids ) ;
2009-12-10 17:55:27 -05:00
fit - > second . mCreator - > storeAvailabilityMap ( rft - > chunk_map , rft - > chunk_size , rft - > chunk_number , rft - > chunk_strategy ) ;
2008-11-15 15:00:29 -05:00
saveData . push_back ( rft ) ;
}
/* list completed! */
return saveData ;
}
bool ftController : : loadList ( std : : list < RsItem * > load )
{
std : : list < RsItem * > : : iterator it ;
std : : list < RsTlvKeyValue > : : iterator kit ;
RsConfigKeyValueSet * rskv ;
RsFileTransfer * rsft ;
2009-06-11 17:41:42 -04:00
# ifdef CONTROL_DEBUG
2008-11-15 15:00:29 -05:00
std : : cerr < < " ftController::loadList() Item Count: " < < load . size ( ) ;
std : : cerr < < std : : endl ;
# endif
for ( it = load . begin ( ) ; it ! = load . end ( ) ; it + + )
{
/* switch on type */
if ( NULL ! = ( rskv = dynamic_cast < RsConfigKeyValueSet * > ( * it ) ) )
{
/* make into map */
std : : map < std : : string , std : : string > configMap ;
for ( kit = rskv - > tlvkvs . pairs . begin ( ) ;
kit ! = rskv - > tlvkvs . pairs . end ( ) ; kit + + )
{
configMap [ kit - > key ] = kit - > value ;
}
loadConfigMap ( configMap ) ;
}
else if ( NULL ! = ( rsft = dynamic_cast < RsFileTransfer * > ( * it ) ) )
{
2009-06-11 17:41:42 -04:00
/* This will get stored on a waiting list - until the
2008-11-20 19:10:59 -05:00
* config files are fully loaded
*/
2009-12-10 17:55:27 -05:00
FileRequest ( rsft - > file . name , rsft - > file . hash , rsft - > file . filesize , rsft - > file . path , 0 , rsft - > allPeerIds . ids ) ;
{
RsStackMutex mtx ( ctrlMutex ) ;
std : : map < std : : string , ftFileControl > : : iterator fit = mDownloads . find ( rsft - > file . hash ) ;
2008-11-20 19:10:59 -05:00
2009-12-10 17:55:27 -05:00
if ( ( fit = = mDownloads . end ( ) | | ( fit - > second ) . mCreator = = NULL ) )
{
std : : cerr < < " ftController::loadList(): Error: could not find hash " < < rsft - > file . hash < < " in mDownloads list ! " < < std : : endl ;
std : : cerr < < " Storing the map in a wait list. " < < std : : endl ;
mPendingChunkMaps [ rsft - > file . hash ] = rsft ;
continue ; // i.e. don't delete the item!
}
else
( fit - > second ) . mCreator - > loadAvailabilityMap ( rsft - > chunk_map , rsft - > chunk_size , rsft - > chunk_number , rsft - > chunk_strategy ) ;
}
2008-11-15 15:00:29 -05:00
}
2008-11-20 19:10:59 -05:00
/* cleanup */
delete ( * it ) ;
2008-11-15 15:00:29 -05:00
}
return true ;
}
bool ftController : : loadConfigMap ( std : : map < std : : string , std : : string > & configMap )
{
std : : map < std : : string , std : : string > : : iterator mit ;
std : : string str_true ( " true " ) ;
std : : string empty ( " " ) ;
std : : string dir = " notempty " ;
if ( configMap . end ( ) ! = ( mit = configMap . find ( download_dir_ss ) ) )
{
setDownloadDirectory ( mit - > second ) ;
}
if ( configMap . end ( ) ! = ( mit = configMap . find ( partial_dir_ss ) ) )
{
2009-06-11 17:41:42 -04:00
setPartialsDirectory ( mit - > second ) ;
2008-11-15 15:00:29 -05:00
}
2009-07-12 09:22:31 -04:00
if ( configMap . end ( ) ! = ( mit = configMap . find ( share_dwl_dir ) ) )
{
if ( mit - > second = = " YES " )
{
setShareDownloadDirectory ( true ) ;
}
else if ( mit - > second = = " NO " )
{
setShareDownloadDirectory ( false ) ;
}
}
2008-11-15 15:00:29 -05:00
return true ;
}
2009-07-12 09:22:31 -04:00
void ftController : : setShareDownloadDirectory ( bool value )
{
mShareDownloadDir = value ;
}
bool ftController : : getShareDownloadDirectory ( )
{
return mShareDownloadDir ;
}