mirror of
https://github.com/transmission/transmission.git
synced 2025-12-24 20:35:36 +00:00
Merge io branch into trunk
This commit is contained in:
@@ -55,8 +55,8 @@ static int bindPort = TR_DEFAULT_PORT;
|
||||
static int uploadLimit = 20;
|
||||
static int downloadLimit = -1;
|
||||
static char * torrentPath = NULL;
|
||||
static volatile char mustDie = 0;
|
||||
static int natTraversal = 0;
|
||||
static tr_torrent_t * tor;
|
||||
|
||||
static char * finishCall = NULL;
|
||||
|
||||
@@ -67,7 +67,6 @@ int main( int argc, char ** argv )
|
||||
{
|
||||
int i, error, nat;
|
||||
tr_handle_t * h;
|
||||
tr_torrent_t * tor;
|
||||
tr_stat_t * s;
|
||||
|
||||
printf( "Transmission %s (%d) - http://transmission.m0k.org/\n\n",
|
||||
@@ -189,7 +188,7 @@ int main( int argc, char ** argv )
|
||||
tr_torrentSetFolder( tor, "." );
|
||||
tr_torrentStart( tor );
|
||||
|
||||
while( !mustDie )
|
||||
for( ;; )
|
||||
{
|
||||
char string[80];
|
||||
int chars = 0;
|
||||
@@ -199,7 +198,11 @@ int main( int argc, char ** argv )
|
||||
|
||||
s = tr_torrentStat( tor );
|
||||
|
||||
if( s->status & TR_STATUS_CHECK )
|
||||
if( s->status & TR_STATUS_PAUSE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if( s->status & TR_STATUS_CHECK )
|
||||
{
|
||||
chars = snprintf( string, 80,
|
||||
"Checking files... %.2f %%", 100.0 * s->progress );
|
||||
@@ -224,9 +227,9 @@ int main( int argc, char ** argv )
|
||||
string[79] = '\0';
|
||||
fprintf( stderr, "\r%s", string );
|
||||
|
||||
if( s->error & TR_ETRACKER )
|
||||
if( s->error )
|
||||
{
|
||||
fprintf( stderr, "\n%s\n", s->trackerError );
|
||||
fprintf( stderr, "\n%s\n", s->errorString );
|
||||
}
|
||||
else if( verboseLevel > 0 )
|
||||
{
|
||||
@@ -240,18 +243,14 @@ int main( int argc, char ** argv )
|
||||
}
|
||||
fprintf( stderr, "\n" );
|
||||
|
||||
/* Try for 5 seconds to notify the tracker that we are leaving
|
||||
and to delete any port mappings for nat traversal */
|
||||
tr_torrentStop( tor );
|
||||
/* Try for 5 seconds to delete any port mappings for nat traversal */
|
||||
tr_natTraversalDisable( h );
|
||||
for( i = 0; i < 10; i++ )
|
||||
{
|
||||
s = tr_torrentStat( tor );
|
||||
nat = tr_natTraversalStatus( h );
|
||||
if( s->status & TR_STATUS_PAUSE && TR_NAT_TRAVERSAL_DISABLED == nat )
|
||||
if( TR_NAT_TRAVERSAL_DISABLED == nat )
|
||||
{
|
||||
/* The 'stopped' tracker message was sent
|
||||
and port mappings were deleted */
|
||||
/* Port mappings were deleted */
|
||||
break;
|
||||
}
|
||||
usleep( 500000 );
|
||||
@@ -337,7 +336,7 @@ static void sigHandler( int signal )
|
||||
switch( signal )
|
||||
{
|
||||
case SIGINT:
|
||||
mustDie = 1;
|
||||
tr_torrentStop( tor );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -426,7 +426,7 @@ enum {
|
||||
GtkWidget *
|
||||
makewind_list(struct cbdata *data, GObject **sizehack) {
|
||||
GType types[] = {
|
||||
/* info->name, info->totalSize, status, error, trackerError, */
|
||||
/* info->name, info->totalSize, status, error, errorString, */
|
||||
G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING,
|
||||
/* progress, rateDownload, rateUpload, eta, peersTotal, */
|
||||
G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT,
|
||||
@@ -730,7 +730,7 @@ dfname(GtkTreeViewColumn *col SHUTUP, GtkCellRenderer *rend,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if(TR_NOERROR != err) {
|
||||
if(TR_OK != err) {
|
||||
gtk_tree_model_get(model, iter, MC_TERR, &terr, -1);
|
||||
bottom = g_strconcat(_("Error: "), terr, NULL);
|
||||
g_free(terr);
|
||||
@@ -807,7 +807,7 @@ updatemodel(gpointer gdata) {
|
||||
/* XXX find out if setting the same data emits changed signal */
|
||||
gtk_list_store_set(GTK_LIST_STORE(data->model), &iter, MC_NAME, in->name,
|
||||
MC_SIZE, in->totalSize, MC_STAT, st->status, MC_ERR, st->error,
|
||||
MC_TERR, st->trackerError, MC_PROG, st->progress,
|
||||
MC_TERR, st->errorString, MC_PROG, st->progress,
|
||||
MC_DRATE, st->rateDownload, MC_URATE, st->rateUpload, MC_ETA, st->eta,
|
||||
MC_PEERS, st->peersTotal, MC_UPEERS, st->peersUploading,
|
||||
MC_DPEERS, st->peersDownloading, MC_DOWN, st->downloaded,
|
||||
|
||||
@@ -85,6 +85,22 @@ uint64_t tr_cpLeftBytes( tr_completion_t * cp )
|
||||
}
|
||||
|
||||
/* Pieces */
|
||||
int tr_cpPieceHasAllBlocks( tr_completion_t * cp, int piece )
|
||||
{
|
||||
tr_torrent_t * tor = cp->tor;
|
||||
int startBlock = tr_pieceStartBlock( piece );
|
||||
int endBlock = startBlock + tr_pieceCountBlocks( piece );
|
||||
int i;
|
||||
|
||||
for( i = startBlock; i < endBlock; i++ )
|
||||
{
|
||||
if( !tr_bitfieldHas( cp->blockBitfield, i ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int tr_cpPieceIsComplete( tr_completion_t * cp, int piece )
|
||||
{
|
||||
return tr_bitfieldHas( cp->pieceBitfield, piece );
|
||||
@@ -110,6 +126,21 @@ void tr_cpPieceAdd( tr_completion_t * cp, int piece )
|
||||
tr_bitfieldAdd( cp->pieceBitfield, piece );
|
||||
}
|
||||
|
||||
void tr_cpPieceRem( tr_completion_t * cp, int piece )
|
||||
{
|
||||
tr_torrent_t * tor = cp->tor;
|
||||
int startBlock, endBlock, i;
|
||||
|
||||
startBlock = tr_pieceStartBlock( piece );
|
||||
endBlock = startBlock + tr_pieceCountBlocks( piece );
|
||||
for( i = startBlock; i < endBlock; i++ )
|
||||
{
|
||||
tr_cpBlockRem( cp, i );
|
||||
}
|
||||
|
||||
tr_bitfieldRem( cp->pieceBitfield, piece );
|
||||
}
|
||||
|
||||
/* Blocks */
|
||||
void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
|
||||
{
|
||||
|
||||
@@ -45,9 +45,11 @@ static inline int tr_cpIsSeeding( tr_completion_t * cp )
|
||||
uint64_t tr_cpLeftBytes( tr_completion_t * );
|
||||
|
||||
/* Pieces */
|
||||
int tr_cpPieceHasAllBlocks( tr_completion_t *, int piece );
|
||||
int tr_cpPieceIsComplete( tr_completion_t *, int piece );
|
||||
uint8_t * tr_cpPieceBitfield( tr_completion_t * );
|
||||
void tr_cpPieceAdd( tr_completion_t *, int piece );
|
||||
void tr_cpPieceRem( tr_completion_t *, int piece );
|
||||
|
||||
/* Blocks */
|
||||
void tr_cpDownloaderAdd( tr_completion_t *, int block );
|
||||
|
||||
@@ -87,11 +87,9 @@ static int fastResumeMTimes( tr_io_t * io, int * tab )
|
||||
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
|
||||
if( stat( path, &sb ) )
|
||||
{
|
||||
tr_err( "Could not stat '%s'", path );
|
||||
free( path );
|
||||
return 1;
|
||||
tab[i] = 0xFFFFFFFF;
|
||||
}
|
||||
if( ( sb.st_mode & S_IFMT ) == S_IFREG )
|
||||
else if( !S_ISREG( sb.st_mode ) )
|
||||
{
|
||||
#ifdef SYS_DARWIN
|
||||
tab[i] = ( sb.st_mtimespec.tv_sec & 0x7FFFFFFF );
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
|
||||
typedef struct tr_openFile_s
|
||||
{
|
||||
char path[MAX_PATH_LENGTH];
|
||||
char folder[MAX_PATH_LENGTH];
|
||||
char name[MAX_PATH_LENGTH];
|
||||
int file;
|
||||
int write;
|
||||
|
||||
#define STATUS_INVALID 1
|
||||
#define STATUS_UNUSED 2
|
||||
@@ -46,6 +48,7 @@ typedef struct tr_openFile_s
|
||||
struct tr_fd_s
|
||||
{
|
||||
tr_lock_t lock;
|
||||
tr_cond_t cond;
|
||||
|
||||
int reserved;
|
||||
|
||||
@@ -55,6 +58,15 @@ struct tr_fd_s
|
||||
tr_openFile_t open[TR_MAX_OPEN_FILES];
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Local prototypes
|
||||
**********************************************************************/
|
||||
static int ErrorFromErrno();
|
||||
static int OpenFile( tr_fd_t * f, int i, char * folder, char * name,
|
||||
int write );
|
||||
static void CloseFile( tr_fd_t * f, int i );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdInit
|
||||
**********************************************************************/
|
||||
@@ -65,8 +77,9 @@ tr_fd_t * tr_fdInit()
|
||||
|
||||
f = calloc( sizeof( tr_fd_t ), 1 );
|
||||
|
||||
/* Init lock */
|
||||
/* Init lock and cond */
|
||||
tr_lockInit( &f->lock );
|
||||
tr_condInit( &f->cond );
|
||||
|
||||
/* Detect the maximum number of open files or sockets */
|
||||
for( i = 0; i < 4096; i++ )
|
||||
@@ -101,9 +114,9 @@ tr_fd_t * tr_fdInit()
|
||||
/***********************************************************************
|
||||
* tr_fdFileOpen
|
||||
**********************************************************************/
|
||||
int tr_fdFileOpen( tr_fd_t * f, char * path )
|
||||
int tr_fdFileOpen( tr_fd_t * f, char * folder, char * name, int write )
|
||||
{
|
||||
int i, winner;
|
||||
int i, winner, ret;
|
||||
uint64_t date;
|
||||
|
||||
tr_lockLock( &f->lock );
|
||||
@@ -111,21 +124,29 @@ int tr_fdFileOpen( tr_fd_t * f, char * path )
|
||||
/* Is it already open? */
|
||||
for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
|
||||
{
|
||||
if( f->open[i].status > STATUS_INVALID &&
|
||||
!strcmp( path, f->open[i].path ) )
|
||||
if( f->open[i].status & STATUS_INVALID ||
|
||||
strcmp( folder, f->open[i].folder ) ||
|
||||
strcmp( name, f->open[i].name ) )
|
||||
{
|
||||
if( f->open[i].status & STATUS_CLOSING )
|
||||
{
|
||||
/* Wait until the file is closed */
|
||||
tr_lockUnlock( &f->lock );
|
||||
tr_wait( 10 );
|
||||
tr_lockLock( &f->lock );
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
winner = i;
|
||||
goto done;
|
||||
continue;
|
||||
}
|
||||
if( f->open[i].status & STATUS_CLOSING )
|
||||
{
|
||||
/* File is being closed by another thread, wait until
|
||||
* it's done before we reopen it */
|
||||
tr_condWait( &f->cond, &f->lock );
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
if( f->open[i].write < write )
|
||||
{
|
||||
/* File is open read-only and needs to be closed then
|
||||
* re-opened read-write */
|
||||
CloseFile( f, i );
|
||||
continue;
|
||||
}
|
||||
winner = i;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Can we open one more file? */
|
||||
@@ -138,9 +159,9 @@ int tr_fdFileOpen( tr_fd_t * f, char * path )
|
||||
}
|
||||
}
|
||||
|
||||
/* All slots taken - close the oldest currently unused file */
|
||||
for( ;; )
|
||||
{
|
||||
/* Close the oldest currently unused file */
|
||||
date = tr_date() + 1;
|
||||
winner = -1;
|
||||
|
||||
@@ -159,27 +180,23 @@ int tr_fdFileOpen( tr_fd_t * f, char * path )
|
||||
|
||||
if( winner >= 0 )
|
||||
{
|
||||
/* Close the file: we mark it as closing then release the
|
||||
lock while doing so, because close may take same time
|
||||
and we don't want to block other threads */
|
||||
tr_dbg( "Closing %s", f->open[winner].path );
|
||||
f->open[winner].status = STATUS_CLOSING;
|
||||
tr_lockUnlock( &f->lock );
|
||||
close( f->open[winner].file );
|
||||
tr_lockLock( &f->lock );
|
||||
CloseFile( f, winner );
|
||||
goto open;
|
||||
}
|
||||
|
||||
/* All used! Wait a bit and try again */
|
||||
tr_lockUnlock( &f->lock );
|
||||
tr_wait( 10 );
|
||||
tr_lockLock( &f->lock );
|
||||
tr_condWait( &f->cond, &f->lock );
|
||||
}
|
||||
|
||||
open:
|
||||
tr_dbg( "Opening %s", path );
|
||||
snprintf( f->open[winner].path, MAX_PATH_LENGTH, "%s", path );
|
||||
f->open[winner].file = open( path, O_RDWR, 0 );
|
||||
if( ( ret = OpenFile( f, winner, folder, name, write ) ) )
|
||||
{
|
||||
tr_lockUnlock( &f->lock );
|
||||
return ret;
|
||||
}
|
||||
snprintf( f->open[winner].folder, MAX_PATH_LENGTH, "%s", folder );
|
||||
snprintf( f->open[winner].name, MAX_PATH_LENGTH, "%s", name );
|
||||
f->open[winner].write = write;
|
||||
|
||||
done:
|
||||
f->open[winner].status = STATUS_USED;
|
||||
@@ -206,37 +223,38 @@ void tr_fdFileRelease( tr_fd_t * f, int file )
|
||||
}
|
||||
}
|
||||
|
||||
tr_condSignal( &f->cond );
|
||||
tr_lockUnlock( &f->lock );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdFileClose
|
||||
**********************************************************************/
|
||||
void tr_fdFileClose( tr_fd_t * f, char * path )
|
||||
void tr_fdFileClose( tr_fd_t * f, char * folder, char * name )
|
||||
{
|
||||
int i;
|
||||
|
||||
tr_lockLock( &f->lock );
|
||||
|
||||
/* Is it already open? */
|
||||
for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
|
||||
{
|
||||
if( f->open[i].status & STATUS_INVALID )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !strcmp( path, f->open[i].path ) )
|
||||
if( !strcmp( folder, f->open[i].folder ) &&
|
||||
!strcmp( name, f->open[i].name ) )
|
||||
{
|
||||
tr_dbg( "Closing %s", path );
|
||||
close( f->open[i].file );
|
||||
f->open[i].status = STATUS_INVALID;
|
||||
break;
|
||||
CloseFile( f, i );
|
||||
}
|
||||
}
|
||||
|
||||
tr_lockUnlock( &f->lock );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdSocketWillCreate
|
||||
**********************************************************************/
|
||||
int tr_fdSocketWillCreate( tr_fd_t * f, int reserved )
|
||||
{
|
||||
int ret;
|
||||
@@ -273,6 +291,9 @@ int tr_fdSocketWillCreate( tr_fd_t * f, int reserved )
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdSocketClosed
|
||||
**********************************************************************/
|
||||
void tr_fdSocketClosed( tr_fd_t * f, int reserved )
|
||||
{
|
||||
tr_lockLock( &f->lock );
|
||||
@@ -289,9 +310,130 @@ void tr_fdSocketClosed( tr_fd_t * f, int reserved )
|
||||
tr_lockUnlock( &f->lock );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdClose
|
||||
**********************************************************************/
|
||||
void tr_fdClose( tr_fd_t * f )
|
||||
{
|
||||
tr_lockClose( &f->lock );
|
||||
tr_condClose( &f->cond );
|
||||
free( f );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Local functions
|
||||
**********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
* ErrorFromErrno
|
||||
**********************************************************************/
|
||||
static int ErrorFromErrno()
|
||||
{
|
||||
if( errno == EACCES || errno == EROFS )
|
||||
return TR_ERROR_IO_PERMISSIONS;
|
||||
return TR_ERROR_IO_OTHER;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CheckFolder
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
static int OpenFile( tr_fd_t * f, int i, char * folder, char * name,
|
||||
int write )
|
||||
{
|
||||
tr_openFile_t * file = &f->open[i];
|
||||
struct stat sb;
|
||||
char * path;
|
||||
|
||||
tr_dbg( "Opening %s in %s (%d)", name, folder, write );
|
||||
|
||||
/* Make sure the parent folder exists */
|
||||
if( stat( folder, &sb ) || !S_ISDIR( sb.st_mode ) )
|
||||
{
|
||||
return TR_ERROR_IO_PARENT;
|
||||
}
|
||||
|
||||
asprintf( &path, "%s/%s", folder, name );
|
||||
|
||||
/* Create subfolders, if any */
|
||||
if( write )
|
||||
{
|
||||
char * p = path + strlen( folder ) + 1;
|
||||
char * s;
|
||||
|
||||
while( ( s = strchr( p, '/' ) ) )
|
||||
{
|
||||
*s = '\0';
|
||||
if( stat( path, &sb ) )
|
||||
{
|
||||
if( mkdir( path, 0777 ) )
|
||||
{
|
||||
free( path );
|
||||
return ErrorFromErrno();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !S_ISDIR( sb.st_mode ) )
|
||||
{
|
||||
free( path );
|
||||
return TR_ERROR_IO_OTHER;
|
||||
}
|
||||
}
|
||||
*s = '/';
|
||||
p = s + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try to really open the file */
|
||||
file->file = open( path, write ? ( O_RDWR | O_CREAT ) : O_RDONLY, 0666 );
|
||||
free( path );
|
||||
|
||||
if( file->file < 0 )
|
||||
{
|
||||
int ret = ErrorFromErrno();
|
||||
tr_err( "Could not open %s in %s (%d, %d)", name, folder, write, ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CloseFile
|
||||
***********************************************************************
|
||||
* We first mark it as closing then release the lock while doing so,
|
||||
* because close() may take same time and we don't want to block other
|
||||
* threads.
|
||||
**********************************************************************/
|
||||
static void CloseFile( tr_fd_t * f, int i )
|
||||
{
|
||||
tr_openFile_t * file = &f->open[i];
|
||||
|
||||
/* If it's already being closed by another thread, just wait till
|
||||
* it is done */
|
||||
while( file->status & STATUS_CLOSING )
|
||||
{
|
||||
tr_condWait( &f->cond, &f->lock );
|
||||
}
|
||||
if( file->status & STATUS_INVALID )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Nobody is closing it already, so let's do it */
|
||||
if( file->status & STATUS_USED )
|
||||
{
|
||||
tr_err( "CloseFile: closing a file that's being used!" );
|
||||
}
|
||||
tr_dbg( "Closing %s in %s (%d)", file->name, file->folder, file->write );
|
||||
file->status = STATUS_CLOSING;
|
||||
tr_lockUnlock( &f->lock );
|
||||
close( file->file );
|
||||
tr_lockLock( &f->lock );
|
||||
file->status = STATUS_INVALID;
|
||||
tr_condSignal( &f->cond );
|
||||
}
|
||||
|
||||
|
||||
@@ -24,13 +24,59 @@
|
||||
|
||||
typedef struct tr_fd_s tr_fd_t;
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdInit
|
||||
***********************************************************************
|
||||
* Detect the maximum number of open files and initializes things.
|
||||
**********************************************************************/
|
||||
tr_fd_t * tr_fdInit();
|
||||
|
||||
int tr_fdFileOpen ( tr_fd_t *, char * );
|
||||
void tr_fdFileRelease ( tr_fd_t *, int );
|
||||
void tr_fdFileClose ( tr_fd_t *, char * );
|
||||
/***********************************************************************
|
||||
* tr_fdFileOpen
|
||||
***********************************************************************
|
||||
* If it isn't open already, tries to open the file 'name' in the
|
||||
* directory 'folder'. If 'name' itself contains '/'s, required
|
||||
* subfolders are created. The file is open read-write if 'write' is 1
|
||||
* (created if necessary), read-only if 0.
|
||||
* Returns the file descriptor if successful, otherwise returns
|
||||
* one of the TR_ERROR_IO_*.
|
||||
**********************************************************************/
|
||||
int tr_fdFileOpen( tr_fd_t *, char * folder, char * name, int write );
|
||||
|
||||
int tr_fdSocketWillCreate ( tr_fd_t *, int );
|
||||
void tr_fdSocketClosed ( tr_fd_t *, int );
|
||||
/***********************************************************************
|
||||
* tr_fdFileRelease
|
||||
***********************************************************************
|
||||
* Indicates that the file whose descriptor is 'file' is unused at the
|
||||
* moment and can safely be closed.
|
||||
**********************************************************************/
|
||||
void tr_fdFileRelease( tr_fd_t *, int file );
|
||||
|
||||
void tr_fdClose ( tr_fd_t * );
|
||||
/***********************************************************************
|
||||
* tr_fdFileClose
|
||||
***********************************************************************
|
||||
* If the file 'name' in directory 'folder' was open, closes it,
|
||||
* flushing data on disk.
|
||||
**********************************************************************/
|
||||
void tr_fdFileClose( tr_fd_t *, char * folder, char * name );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdSocketWillCreate
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
int tr_fdSocketWillCreate( tr_fd_t *, int );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdSocketClosed
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_fdSocketClosed( tr_fd_t *, int );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* tr_fdClose
|
||||
***********************************************************************
|
||||
* Frees resources allocated by tr_fdInit.
|
||||
**********************************************************************/
|
||||
void tr_fdClose( tr_fd_t * );
|
||||
|
||||
@@ -560,11 +560,11 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
||||
case HTTP_STATE_RESOLVE:
|
||||
switch( tr_netResolvePulse( http->resolve, &addr ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
return TR_WAIT;
|
||||
case TR_ERROR:
|
||||
case TR_NET_WAIT:
|
||||
return TR_NET_WAIT;
|
||||
case TR_NET_ERROR:
|
||||
goto err;
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
tr_netResolveClose( http->resolve );
|
||||
http->resolve = NULL;
|
||||
http->sock = tr_netOpenTCP( addr, htons( http->port ) );
|
||||
@@ -575,11 +575,11 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
||||
case HTTP_STATE_CONNECT:
|
||||
switch( sendrequest( http ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
return TR_WAIT;
|
||||
case TR_ERROR:
|
||||
case TR_NET_WAIT:
|
||||
return TR_NET_WAIT;
|
||||
case TR_NET_ERROR:
|
||||
goto err;
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
http->state = HTTP_STATE_RECEIVE;
|
||||
}
|
||||
/* fallthrough */
|
||||
@@ -587,11 +587,11 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
||||
case HTTP_STATE_RECEIVE:
|
||||
switch( receiveresponse( http ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
return TR_WAIT;
|
||||
case TR_ERROR:
|
||||
case TR_NET_WAIT:
|
||||
return TR_NET_WAIT;
|
||||
case TR_NET_ERROR:
|
||||
goto err;
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
goto ok;
|
||||
}
|
||||
break;
|
||||
@@ -603,11 +603,11 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
||||
goto err;
|
||||
}
|
||||
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
|
||||
err:
|
||||
http->state = HTTP_STATE_ERROR;
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
|
||||
ok:
|
||||
http->state = HTTP_STATE_DONE;
|
||||
@@ -619,7 +619,7 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
||||
{
|
||||
*len = http->header.used;
|
||||
}
|
||||
return TR_OK;
|
||||
return TR_NET_OK;
|
||||
}
|
||||
|
||||
static tr_tristate_t
|
||||
@@ -635,7 +635,7 @@ sendrequest( tr_http_t * http )
|
||||
|
||||
if( 0 > http->sock || tr_date() > http->date + HTTP_TIMEOUT )
|
||||
{
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
|
||||
buf = ( 0 < http->header.used ? &http->header : &http->body );
|
||||
@@ -644,11 +644,11 @@ sendrequest( tr_http_t * http )
|
||||
ret = tr_netSend( http->sock, (uint8_t *) buf->buf, buf->used );
|
||||
if( ret & TR_NET_CLOSE )
|
||||
{
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
else if( ret & TR_NET_BLOCK )
|
||||
{
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
buf->used = 0;
|
||||
buf = &http->body;
|
||||
@@ -659,7 +659,7 @@ sendrequest( tr_http_t * http )
|
||||
http->body.size = 0;
|
||||
http->date = 0;
|
||||
|
||||
return TR_OK;
|
||||
return TR_NET_OK;
|
||||
}
|
||||
|
||||
static tr_tristate_t
|
||||
@@ -682,7 +682,7 @@ receiveresponse( tr_http_t * http )
|
||||
http->header.size + HTTP_BUFSIZE );
|
||||
if( NULL == newbuf )
|
||||
{
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
http->header.buf = newbuf;
|
||||
http->header.size += HTTP_BUFSIZE;
|
||||
@@ -694,7 +694,7 @@ receiveresponse( tr_http_t * http )
|
||||
if( ret & TR_NET_CLOSE )
|
||||
{
|
||||
checklength( http );
|
||||
return TR_OK;
|
||||
return TR_NET_OK;
|
||||
}
|
||||
else if( ret & TR_NET_BLOCK )
|
||||
{
|
||||
@@ -708,15 +708,15 @@ receiveresponse( tr_http_t * http )
|
||||
|
||||
if( before < http->header.used && checklength( http ) )
|
||||
{
|
||||
return TR_OK;
|
||||
return TR_NET_OK;
|
||||
}
|
||||
|
||||
if( tr_date() > HTTP_TIMEOUT + http->date )
|
||||
{
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -46,7 +46,6 @@ struct tr_io_s
|
||||
/***********************************************************************
|
||||
* Local prototypes
|
||||
**********************************************************************/
|
||||
static int createFiles( tr_io_t * );
|
||||
static int checkFiles( tr_io_t * );
|
||||
static void closeFiles( tr_io_t * );
|
||||
static int readOrWriteBytes( tr_io_t *, uint64_t, int, uint8_t *, int );
|
||||
@@ -95,7 +94,7 @@ tr_io_t * tr_ioInit( tr_torrent_t * tor )
|
||||
io = malloc( sizeof( tr_io_t ) );
|
||||
io->tor = tor;
|
||||
|
||||
if( createFiles( io ) || checkFiles( io ) )
|
||||
if( checkFiles( io ) )
|
||||
{
|
||||
free( io );
|
||||
return NULL;
|
||||
@@ -106,14 +105,12 @@ tr_io_t * tr_ioInit( tr_torrent_t * tor )
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioRead
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
int tr_ioRead( tr_io_t * io, int index, int begin, int length,
|
||||
uint8_t * buf )
|
||||
{
|
||||
uint64_t offset;
|
||||
tr_info_t * inf = &io->tor->info;
|
||||
uint64_t offset;
|
||||
|
||||
offset = (uint64_t) io->pieceSlot[index] *
|
||||
(uint64_t) inf->pieceSize + (uint64_t) begin;
|
||||
@@ -123,20 +120,12 @@ int tr_ioRead( tr_io_t * io, int index, int begin, int length,
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioWrite
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
||||
uint8_t * buf )
|
||||
{
|
||||
tr_torrent_t * tor = io->tor;
|
||||
tr_info_t * inf = &io->tor->info;
|
||||
uint64_t offset;
|
||||
int i, hashFailed;
|
||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||
uint8_t * pieceBuf;
|
||||
int pieceSize;
|
||||
int startBlock, endBlock;
|
||||
|
||||
if( io->pieceSlot[index] < 0 )
|
||||
{
|
||||
@@ -148,27 +137,36 @@ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
||||
offset = (uint64_t) io->pieceSlot[index] *
|
||||
(uint64_t) inf->pieceSize + (uint64_t) begin;
|
||||
|
||||
if( writeBytes( io, offset, length, buf ) )
|
||||
return writeBytes( io, offset, length, buf );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioHash
|
||||
**********************************************************************/
|
||||
int tr_ioHash( tr_io_t * io, int index )
|
||||
{
|
||||
tr_torrent_t * tor = io->tor;
|
||||
tr_info_t * inf = &io->tor->info;
|
||||
int pieceSize;
|
||||
uint8_t * pieceBuf;
|
||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||
int hashFailed;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if( !tr_cpPieceIsComplete( tor->completion, index ) )
|
||||
{
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
startBlock = tr_pieceStartBlock( index );
|
||||
endBlock = startBlock + tr_pieceCountBlocks( index );
|
||||
for( i = startBlock; i < endBlock; i++ )
|
||||
{
|
||||
if( !tr_cpBlockIsComplete( tor->completion, i ) )
|
||||
{
|
||||
/* The piece is not complete */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The piece is complete, check the hash */
|
||||
pieceSize = tr_pieceSize( index );
|
||||
pieceBuf = malloc( pieceSize );
|
||||
readBytes( io, (uint64_t) io->pieceSlot[index] *
|
||||
(uint64_t) inf->pieceSize, pieceSize, pieceBuf );
|
||||
if( ( ret = readBytes( io, (uint64_t) io->pieceSlot[index] *
|
||||
(uint64_t) inf->pieceSize, pieceSize, pieceBuf ) ) )
|
||||
{
|
||||
free( pieceBuf );
|
||||
return ret;
|
||||
}
|
||||
SHA1( pieceBuf, pieceSize, hash );
|
||||
free( pieceBuf );
|
||||
|
||||
@@ -177,12 +175,7 @@ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
||||
{
|
||||
tr_inf( "Piece %d (slot %d): hash FAILED", index,
|
||||
io->pieceSlot[index] );
|
||||
|
||||
/* We will need to reload the whole piece */
|
||||
for( i = startBlock; i < endBlock; i++ )
|
||||
{
|
||||
tr_cpBlockRem( tor->completion, i );
|
||||
}
|
||||
tr_cpPieceRem( tor->completion, index );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -200,88 +193,25 @@ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tr_ioClose( tr_io_t * io )
|
||||
/***********************************************************************
|
||||
* tr_ioSync
|
||||
**********************************************************************/
|
||||
void tr_ioSync( tr_io_t * io )
|
||||
{
|
||||
closeFiles( io );
|
||||
|
||||
fastResumeSave( io );
|
||||
|
||||
free( io->pieceSlot );
|
||||
free( io->slotPiece );
|
||||
free( io );
|
||||
}
|
||||
|
||||
void tr_ioSaveResume( tr_io_t * io )
|
||||
{
|
||||
fastResumeSave( io );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* createFiles
|
||||
***********************************************************************
|
||||
* Make sure the existing folders/files have correct types and
|
||||
* permissions, and create missing folders and files
|
||||
* tr_ioClose
|
||||
**********************************************************************/
|
||||
static int createFiles( tr_io_t * io )
|
||||
void tr_ioClose( tr_io_t * io )
|
||||
{
|
||||
tr_torrent_t * tor = io->tor;
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_ioSync( io );
|
||||
|
||||
int i;
|
||||
char * path, * p;
|
||||
struct stat sb;
|
||||
int file;
|
||||
|
||||
tr_dbg( "Creating files..." );
|
||||
|
||||
for( i = 0; i < inf->fileCount; i++ )
|
||||
{
|
||||
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
|
||||
|
||||
/* Create folders */
|
||||
if( NULL != ( p = strrchr( path, '/' ) ) )
|
||||
{
|
||||
*p = '\0';
|
||||
if( tr_mkdir( path ) )
|
||||
{
|
||||
free( path );
|
||||
return 1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
/* Empty folders use a dummy "" file, skip those */
|
||||
if( p == &path[strlen( path ) - 1] )
|
||||
{
|
||||
free( path );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( stat( path, &sb ) )
|
||||
{
|
||||
/* File doesn't exist yet */
|
||||
if( ( file = open( path, O_WRONLY|O_CREAT|O_TRUNC, 0666 ) ) < 0 )
|
||||
{
|
||||
tr_err( "Could not create `%s' (%s)", path,
|
||||
strerror( errno ) );
|
||||
free( path );
|
||||
return 1;
|
||||
}
|
||||
close( file );
|
||||
}
|
||||
else if( ( sb.st_mode & S_IFMT ) != S_IFREG )
|
||||
{
|
||||
/* Node exists but isn't a file */
|
||||
/* XXX this should be reported to the frontend somehow */
|
||||
tr_err( "Remove %s, it's in the way.", path );
|
||||
free( path );
|
||||
return 1;
|
||||
}
|
||||
|
||||
free( path );
|
||||
}
|
||||
|
||||
return 0;
|
||||
free( io->pieceSlot );
|
||||
free( io->slotPiece );
|
||||
free( io );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -369,13 +299,11 @@ static void closeFiles( tr_io_t * io )
|
||||
tr_info_t * inf = &tor->info;
|
||||
|
||||
int i;
|
||||
char * path;
|
||||
|
||||
for( i = 0; i < inf->fileCount; i++ )
|
||||
{
|
||||
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
|
||||
tr_fdFileClose( tor->fdlimit, path );
|
||||
free( path );
|
||||
tr_fdFileClose( tor->fdlimit, tor->destination,
|
||||
inf->files[i].name );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,9 +323,9 @@ static int readOrWriteBytes( tr_io_t * io, uint64_t offset, int size,
|
||||
int begin = offset % inf->pieceSize;
|
||||
int i;
|
||||
size_t cur;
|
||||
char * path;
|
||||
int file;
|
||||
iofunc readOrWrite = isWrite ? (iofunc) write : (iofunc) read;
|
||||
int ret = 0;
|
||||
|
||||
/* Release the torrent lock so the UI can still update itself if
|
||||
this blocks for a while */
|
||||
@@ -407,7 +335,8 @@ static int readOrWriteBytes( tr_io_t * io, uint64_t offset, int size,
|
||||
if( tr_pieceSize( piece ) < begin + size )
|
||||
{
|
||||
tr_err( "readOrWriteBytes: trying to write more than a piece" );
|
||||
goto fail;
|
||||
ret = TR_ERROR_ASSERT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Find which file we shall start reading/writing in */
|
||||
@@ -425,7 +354,8 @@ static int readOrWriteBytes( tr_io_t * io, uint64_t offset, int size,
|
||||
/* Should not happen */
|
||||
tr_err( "readOrWriteBytes: offset out of range (%"PRIu64", %d, %d)",
|
||||
offset, size, isWrite );
|
||||
goto fail;
|
||||
ret = TR_ERROR_ASSERT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while( size > 0 )
|
||||
@@ -442,30 +372,32 @@ static int readOrWriteBytes( tr_io_t * io, uint64_t offset, int size,
|
||||
|
||||
if( cur > 0 )
|
||||
{
|
||||
/* Now let's get a stream on the file... */
|
||||
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
|
||||
file = tr_fdFileOpen( tor->fdlimit, path );
|
||||
/* Now let's get a descriptor on the file... */
|
||||
file = tr_fdFileOpen( tor->fdlimit, tor->destination,
|
||||
inf->files[i].name, isWrite );
|
||||
if( file < 0 )
|
||||
{
|
||||
tr_err( "readOrWriteBytes: could not open file '%s'", path );
|
||||
free( path );
|
||||
goto fail;
|
||||
ret = file;
|
||||
goto cleanup;
|
||||
}
|
||||
free( path );
|
||||
|
||||
/* seek to the right offset... */
|
||||
if( lseek( file, offset, SEEK_SET ) < 0 )
|
||||
{
|
||||
goto fail;
|
||||
tr_fdFileRelease( tor->fdlimit, file );
|
||||
ret = TR_ERROR_IO_OTHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* do what we are here to do... */
|
||||
if( readOrWrite( file, buf, cur ) != cur )
|
||||
{
|
||||
goto fail;
|
||||
tr_fdFileRelease( tor->fdlimit, file );
|
||||
ret = TR_ERROR_IO_OTHER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* and close the stream. */
|
||||
/* and release the descriptor. */
|
||||
tr_fdFileRelease( tor->fdlimit, file );
|
||||
}
|
||||
|
||||
@@ -476,12 +408,9 @@ static int readOrWriteBytes( tr_io_t * io, uint64_t offset, int size,
|
||||
buf += cur;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
tr_lockLock( &tor->lock );
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
tr_lockLock( &tor->lock );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
@@ -30,9 +30,33 @@ typedef struct tr_io_s tr_io_t;
|
||||
void tr_ioLoadResume ( tr_torrent_t * );
|
||||
|
||||
tr_io_t * tr_ioInit ( tr_torrent_t * );
|
||||
int tr_ioRead ( tr_io_t *, int, int, int, uint8_t * );
|
||||
int tr_ioWrite ( tr_io_t *, int, int, int, uint8_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioRead, tr_ioWrite
|
||||
***********************************************************************
|
||||
* Reads or writes the block specified by the piece index, the offset in
|
||||
* that piece and the size of the block. Returns 0 if successful,
|
||||
* TR_ERROR_ASSERT if the parameters are incorrect, one of the
|
||||
* TR_ERROR_IO_* otherwise.
|
||||
**********************************************************************/
|
||||
int tr_ioRead ( tr_io_t *, int index, int begin, int len, uint8_t * );
|
||||
int tr_ioWrite ( tr_io_t *, int index, int begin, int len, uint8_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioHash
|
||||
***********************************************************************
|
||||
* Hashes the specified piece and updates the completion accordingly.
|
||||
**********************************************************************/
|
||||
int tr_ioHash ( tr_io_t *, int piece );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioSync
|
||||
***********************************************************************
|
||||
* Flush all data on disc by closing all files, and update the cache
|
||||
* file.
|
||||
**********************************************************************/
|
||||
void tr_ioSync( tr_io_t * );
|
||||
|
||||
void tr_ioClose ( tr_io_t * );
|
||||
void tr_ioSaveResume ( tr_io_t * );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -119,7 +119,7 @@ static inline void tr_htonl( uint32_t a, uint8_t * p )
|
||||
|
||||
typedef struct tr_completion_s tr_completion_t;
|
||||
|
||||
typedef enum { TR_OK, TR_ERROR, TR_WAIT } tr_tristate_t;
|
||||
typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t;
|
||||
|
||||
#include "platform.h"
|
||||
#include "bencode.h"
|
||||
@@ -150,7 +150,7 @@ struct tr_torrent_s
|
||||
|
||||
int status;
|
||||
int error;
|
||||
char trackerError[128];
|
||||
char errorString[128];
|
||||
int finished;
|
||||
|
||||
char * id;
|
||||
|
||||
@@ -331,7 +331,7 @@ tr_natpmpPulse( tr_natpmp_t * pmp )
|
||||
{
|
||||
switch( pulsereq( pmp->req, &pmp->renew ) )
|
||||
{
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
if( pmp->req->nobodyhome )
|
||||
{
|
||||
pmp->state = PMP_STATE_NOBODYHOME;
|
||||
@@ -353,7 +353,7 @@ tr_natpmpPulse( tr_natpmp_t * pmp )
|
||||
}
|
||||
killreq( &pmp->req );
|
||||
break;
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
pmp->mappedport = pmp->req->port;
|
||||
killreq( &pmp->req );
|
||||
pmp->state = PMP_STATE_MAPPED;
|
||||
@@ -361,7 +361,7 @@ tr_natpmpPulse( tr_natpmp_t * pmp )
|
||||
pmp->mappedport);
|
||||
tr_inf( "nat-pmp mapped port %i", pmp->mappedport );
|
||||
break;
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -383,7 +383,7 @@ tr_natpmpPulse( tr_natpmp_t * pmp )
|
||||
{
|
||||
switch( pulsereq( pmp->req, &pmp->renew ) )
|
||||
{
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
if( pmp->req->nobodyhome )
|
||||
{
|
||||
pmp->state = PMP_STATE_NOBODYHOME;
|
||||
@@ -402,7 +402,7 @@ tr_natpmpPulse( tr_natpmp_t * pmp )
|
||||
}
|
||||
killreq( &pmp->req );
|
||||
break;
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
tr_dbg( "nat-pmp state del -> idle with port %i",
|
||||
pmp->req->port);
|
||||
tr_inf( "nat-pmp unmapped port %i", pmp->req->port );
|
||||
@@ -410,7 +410,7 @@ tr_natpmpPulse( tr_natpmp_t * pmp )
|
||||
killreq( &pmp->req );
|
||||
pmp->state = PMP_STATE_IDLE;
|
||||
break;
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -541,14 +541,14 @@ pulsereq( tr_natpmp_req_t * req, uint64_t * renew )
|
||||
{
|
||||
tr_dbg( "nat-pmp request timed out" );
|
||||
req->nobodyhome = 1;
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
|
||||
if( now >= req->retry )
|
||||
{
|
||||
if( sendrequest( req->adding, req->fd, req->port ) )
|
||||
{
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
req->delay *= 2;
|
||||
req->timeout = now + req->delay;
|
||||
@@ -557,7 +557,7 @@ pulsereq( tr_natpmp_req_t * req, uint64_t * renew )
|
||||
res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin );
|
||||
if( TR_NET_BLOCK & res )
|
||||
{
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
else if( TR_NET_CLOSE & res )
|
||||
{
|
||||
@@ -570,7 +570,7 @@ pulsereq( tr_natpmp_req_t * req, uint64_t * renew )
|
||||
{
|
||||
tr_inf( "error reading nat-pmp response (%s)", strerror( errno ) );
|
||||
}
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
|
||||
tr_dbg( "nat-pmp read %i byte response", res );
|
||||
@@ -635,7 +635,7 @@ mcastpulse( tr_natpmp_t * pmp )
|
||||
return;
|
||||
}
|
||||
|
||||
if( TR_OK == readrequest( buf, res, 0, -1, &pmp->uptime, &pmp->renew, NULL ) &&
|
||||
if( TR_NET_OK == readrequest( buf, res, 0, -1, &pmp->uptime, &pmp->renew, NULL ) &&
|
||||
PMP_STATE_NOBODYHOME == pmp->state )
|
||||
{
|
||||
tr_dbg( "nat-pmp state notfound -> idle" );
|
||||
@@ -700,7 +700,7 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
if( 4 > len )
|
||||
{
|
||||
tr_err( "read truncated %i byte nat-pmp response packet", len );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
version = buf[0];
|
||||
opcode = buf[1];
|
||||
@@ -710,19 +710,19 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
if( !PMP_OPCODE_IS_RESPONSE( opcode ) )
|
||||
{
|
||||
tr_dbg( "nat-pmp ignoring request packet" );
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
opcode = PMP_OPCODE_FROM_RESPONSE( opcode );
|
||||
|
||||
if( PMP_VERSION != version )
|
||||
{
|
||||
tr_err( "bad nat-pmp version %hhu", buf[0] );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
if( wantedopcode != opcode )
|
||||
{
|
||||
tr_err( "bad nat-pmp opcode %hhu", opcode );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
switch( rescode )
|
||||
{
|
||||
@@ -738,13 +738,13 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
/* fallthrough */
|
||||
default:
|
||||
tr_err( "bad nat-pmp result code %hu", rescode );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
|
||||
if( 8 > len )
|
||||
{
|
||||
tr_err( "read truncated %i byte nat-pmp response packet", len );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
seconds = PMP_FROMBUF32( buf + 4 );
|
||||
|
||||
@@ -753,7 +753,7 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
*renew = 0;
|
||||
tr_inf( "detected nat-pmp device reset" );
|
||||
/* XXX should reset retry counter here */
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
|
||||
if( 0 <= port )
|
||||
@@ -762,7 +762,7 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
if( 16 > len )
|
||||
{
|
||||
tr_err( "read truncated %i byte nat-pmp response packet", len );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
privport = PMP_FROMBUF16( buf + 8 );
|
||||
pubport = PMP_FROMBUF16( buf + 10 );
|
||||
@@ -773,7 +773,7 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
/* private port doesn't match, ignore it */
|
||||
tr_dbg( "nat-pmp ignoring message for port %i, expected port %i",
|
||||
privport, port );
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
|
||||
if( adding )
|
||||
@@ -782,12 +782,12 @@ readrequest( uint8_t * buf, int len, int adding, int port,
|
||||
{
|
||||
*tmpfail = 1;
|
||||
/* XXX should just start announcing the pub port we're given */
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
tr_dbg( "nat-pmp set renew to half of %u", lifetime );
|
||||
*renew = tr_date() + ( lifetime / 2 * 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
return TR_OK;
|
||||
return TR_NET_OK;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ tr_resolve_t * tr_netResolveInit( const char * address )
|
||||
tr_resolve_t * r;
|
||||
|
||||
r = malloc( sizeof( tr_resolve_t ) );
|
||||
r->status = TR_WAIT;
|
||||
r->status = TR_NET_WAIT;
|
||||
r->address = strdup( address );
|
||||
r->refcount = 2;
|
||||
r->next = NULL;
|
||||
@@ -131,7 +131,7 @@ tr_tristate_t tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
|
||||
|
||||
tr_lockLock( &resolveLock );
|
||||
ret = r->status;
|
||||
if( ret == TR_OK )
|
||||
if( ret == TR_NET_OK )
|
||||
{
|
||||
*addr = r->addr;
|
||||
}
|
||||
@@ -201,11 +201,11 @@ static void resolveFunc( void * arg UNUSED )
|
||||
if( host )
|
||||
{
|
||||
memcpy( &r->addr, host->h_addr, host->h_length );
|
||||
r->status = TR_OK;
|
||||
r->status = TR_NET_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
r->status = TR_ERROR;
|
||||
r->status = TR_NET_ERROR;
|
||||
}
|
||||
|
||||
resolveQueue = r->next;
|
||||
|
||||
@@ -289,7 +289,7 @@ int tr_peerRead( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
if( ret & TR_NET_CLOSE )
|
||||
{
|
||||
peer_dbg( "connection closed" );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
else if( ret & TR_NET_BLOCK )
|
||||
{
|
||||
@@ -301,16 +301,16 @@ int tr_peerRead( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
{
|
||||
tr_rcTransferred( peer->download, ret );
|
||||
tr_rcTransferred( tor->download, ret );
|
||||
if( parseBuf( tor, peer ) )
|
||||
if( ( ret = parseBuf( tor, peer ) ) )
|
||||
{
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( parseBufHeader( peer ) )
|
||||
if( ( ret = parseBufHeader( peer ) ) )
|
||||
{
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,7 +358,7 @@ uint8_t * tr_peerHash( tr_peer_t * peer )
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_peerPulse( tr_torrent_t * tor )
|
||||
int tr_peerPulse( tr_torrent_t * tor )
|
||||
{
|
||||
int i, ret, size;
|
||||
uint8_t * p;
|
||||
@@ -381,7 +381,7 @@ void tr_peerPulse( tr_torrent_t * tor )
|
||||
|
||||
if( tor->status & TR_STATUS_STOPPING )
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shuffle peers */
|
||||
@@ -404,10 +404,11 @@ void tr_peerPulse( tr_torrent_t * tor )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( tr_peerRead( tor, tor->peers[i] ) )
|
||||
{
|
||||
ret = tr_peerRead( tor, tor->peers[i] );
|
||||
if( ret & TR_ERROR_IO_MASK )
|
||||
return ret;
|
||||
if( ret )
|
||||
goto dropPeer;
|
||||
}
|
||||
|
||||
if( peer->status < PEER_STATUS_CONNECTED )
|
||||
{
|
||||
@@ -497,6 +498,7 @@ writeEnd:
|
||||
dropPeer:
|
||||
tr_peerRem( tor, i );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
@@ -38,7 +38,7 @@ int tr_peerRead ( tr_torrent_t *, tr_peer_t * );
|
||||
uint64_t tr_peerDate ( tr_peer_t * );
|
||||
uint8_t * tr_peerId ( tr_peer_t * );
|
||||
uint8_t * tr_peerHash ( tr_peer_t * );
|
||||
void tr_peerPulse ( tr_torrent_t * );
|
||||
int tr_peerPulse ( tr_torrent_t * );
|
||||
int tr_peerIsConnected ( tr_peer_t * );
|
||||
int tr_peerIsIncoming ( tr_peer_t * );
|
||||
int tr_peerIsUploading ( tr_peer_t * );
|
||||
|
||||
@@ -254,15 +254,7 @@ static void sendRequest( tr_torrent_t * tor, tr_peer_t * peer, int block )
|
||||
r->index = block / ( inf->pieceSize / tor->blockSize );
|
||||
r->begin = ( block % ( inf->pieceSize / tor->blockSize ) ) *
|
||||
tor->blockSize;
|
||||
r->length = tor->blockSize;
|
||||
if( block == tor->blockCount - 1 )
|
||||
{
|
||||
int lastSize = inf->totalSize % tor->blockSize;
|
||||
if( lastSize )
|
||||
{
|
||||
r->length = lastSize;
|
||||
}
|
||||
}
|
||||
r->length = tr_blockSize( block );
|
||||
(peer->inRequestCount)++;
|
||||
|
||||
/* Build the "ask" message */
|
||||
|
||||
@@ -40,7 +40,7 @@ static inline int parseChoke( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
if( len != 1 )
|
||||
{
|
||||
peer_dbg( "GET %schoke, invalid", choking ? "" : "un" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
peer_dbg( "GET %schoke", choking ? "" : "un" );
|
||||
@@ -58,7 +58,7 @@ static inline int parseChoke( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
peer->inRequestCount = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -72,14 +72,14 @@ static inline int parseInterested( tr_peer_t * peer, int len,
|
||||
if( len != 1 )
|
||||
{
|
||||
peer_dbg( "GET %sinterested, invalid", interested ? "" : "un" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
peer_dbg( "GET %sinterested", interested ? "" : "un" );
|
||||
|
||||
peer->peerInterested = interested;
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -95,7 +95,7 @@ static inline int parseHave( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
if( len != 5 )
|
||||
{
|
||||
peer_dbg( "GET have, invalid" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
TR_NTOHL( p, piece );
|
||||
@@ -116,7 +116,7 @@ static inline int parseHave( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
|
||||
tr_rcTransferred( tor->swarmspeed, tor->info.pieceSize );
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static inline int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
@@ -131,7 +131,7 @@ static inline int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
if( len != 1 + bitfieldSize )
|
||||
{
|
||||
peer_dbg( "GET bitfield, wrong size" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
/* Make sure the spare bits are unset */
|
||||
@@ -146,7 +146,7 @@ static inline int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
if( lastByte )
|
||||
{
|
||||
peer_dbg( "GET bitfield, spare bits set" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ static inline int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
|
||||
updateInterest( tor, peer );
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static inline int parseRequest( tr_peer_t * peer, uint8_t * p, int len )
|
||||
@@ -181,14 +181,14 @@ static inline int parseRequest( tr_peer_t * peer, uint8_t * p, int len )
|
||||
if( len != 13 )
|
||||
{
|
||||
peer_dbg( "GET request, invalid" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
if( peer->amChoking )
|
||||
{
|
||||
/* Didn't he get it? */
|
||||
sendChoke( peer, 1 );
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
TR_NTOHL( p, index );
|
||||
@@ -203,13 +203,13 @@ static inline int parseRequest( tr_peer_t * peer, uint8_t * p, int len )
|
||||
if( length > 16384 )
|
||||
{
|
||||
/* Sorry mate */
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
if( peer->outRequestCount >= MAX_REQUEST_COUNT )
|
||||
{
|
||||
tr_err( "Too many requests" );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
r = &peer->outRequests[peer->outRequestCount];
|
||||
@@ -219,124 +219,122 @@ static inline int parseRequest( tr_peer_t * peer, uint8_t * p, int len )
|
||||
|
||||
(peer->outRequestCount)++;
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static inline void updateRequests( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
int index, int begin )
|
||||
{
|
||||
tr_request_t * r;
|
||||
int i, j;
|
||||
|
||||
/* Find this block in the requests list */
|
||||
for( i = 0; i < peer->inRequestCount; i++ )
|
||||
{
|
||||
r = &peer->inRequests[i];
|
||||
if( index == r->index && begin == r->begin )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Usually i should be 0, but some clients don't handle multiple
|
||||
request well and drop previous requests */
|
||||
if( i < peer->inRequestCount )
|
||||
{
|
||||
if( i > 0 )
|
||||
{
|
||||
peer_dbg( "not expecting this block yet (%d requests dropped)", i );
|
||||
}
|
||||
i++;
|
||||
for( j = 0; j < i; j++ )
|
||||
{
|
||||
r = &peer->inRequests[j];
|
||||
tr_cpDownloaderRem( tor->completion,
|
||||
tr_block( r->index, r->begin ) );
|
||||
}
|
||||
peer->inRequestCount -= i;
|
||||
memmove( &peer->inRequests[0], &peer->inRequests[i],
|
||||
peer->inRequestCount * sizeof( tr_request_t ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not in the list. Probably because of a cancel that arrived
|
||||
too late */
|
||||
}
|
||||
}
|
||||
|
||||
static inline int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
int index, begin, block, i, j;
|
||||
tr_request_t * r;
|
||||
int index, begin, block, i, ret;
|
||||
|
||||
TR_NTOHL( p, index );
|
||||
TR_NTOHL( &p[4], begin );
|
||||
block = tr_block( index, begin );
|
||||
|
||||
peer_dbg( "GET piece %d/%d (%d bytes)",
|
||||
index, begin, len - 9 );
|
||||
|
||||
if( peer->inRequestCount < 1 )
|
||||
updateRequests( tor, peer, index, begin );
|
||||
tor->downloadedCur += len;
|
||||
|
||||
/* Sanity checks */
|
||||
if( len - 9 != tr_blockSize( block ) )
|
||||
{
|
||||
/* Our "cancel" was probably late */
|
||||
peer_dbg( "not expecting a block" );
|
||||
return 0;
|
||||
peer_dbg( "wrong size (expecting %d)", tr_blockSize( block ) );
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
r = &peer->inRequests[0];
|
||||
if( index != r->index || begin != r->begin )
|
||||
{
|
||||
int suckyClient;
|
||||
|
||||
/* Either our "cancel" was late, or this is a sucky
|
||||
client that cannot deal with multiple requests */
|
||||
suckyClient = 0;
|
||||
for( i = 0; i < peer->inRequestCount; i++ )
|
||||
{
|
||||
r = &peer->inRequests[i];
|
||||
|
||||
if( index != r->index || begin != r->begin )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Sucky client, he dropped the previous requests */
|
||||
peer_dbg( "block was expected later" );
|
||||
for( j = 0; j < i; j++ )
|
||||
{
|
||||
r = &peer->inRequests[j];
|
||||
tr_cpDownloaderRem( tor->completion,
|
||||
tr_block(r->index,r->begin) );
|
||||
}
|
||||
suckyClient = 1;
|
||||
peer->inRequestCount -= i;
|
||||
memmove( &peer->inRequests[0], &peer->inRequests[i],
|
||||
peer->inRequestCount * sizeof( tr_request_t ) );
|
||||
r = &peer->inRequests[0];
|
||||
break;
|
||||
}
|
||||
|
||||
if( !suckyClient )
|
||||
{
|
||||
r = &peer->inRequests[0];
|
||||
peer_dbg( "wrong block (expecting %d/%d)",
|
||||
r->index, r->begin );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( len - 9 != r->length )
|
||||
{
|
||||
peer_dbg( "wrong size (expecting %d)", r->length );
|
||||
return 1;
|
||||
}
|
||||
|
||||
tor->downloadedCur += r->length;
|
||||
|
||||
block = tr_block( r->index, r->begin );
|
||||
if( tr_cpBlockIsComplete( tor->completion, block ) )
|
||||
{
|
||||
peer_dbg( "have this block already" );
|
||||
(peer->inRequestCount)--;
|
||||
memmove( &peer->inRequests[0], &peer->inRequests[1],
|
||||
peer->inRequestCount * sizeof( tr_request_t ) );
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
/* set blame/credit for this piece */
|
||||
/* Set blame/credit for this piece */
|
||||
if( !peer->blamefield )
|
||||
{
|
||||
peer->blamefield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
|
||||
}
|
||||
tr_bitfieldAdd( peer->blamefield, index );
|
||||
|
||||
/* Write to disk */
|
||||
if( ( ret = tr_ioWrite( tor->io, index, begin, len - 9, &p[8] ) ) )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
tr_cpBlockAdd( tor->completion, block );
|
||||
tr_ioWrite( tor->io, index, begin, len - 9, &p[8] );
|
||||
tr_cpDownloaderRem( tor->completion, block );
|
||||
|
||||
sendCancel( tor, block );
|
||||
|
||||
if( tr_cpPieceIsComplete( tor->completion, index ) )
|
||||
if( !tr_cpPieceHasAllBlocks( tor->completion, index ) )
|
||||
{
|
||||
tr_peer_t * otherPeer;
|
||||
|
||||
for( i = 0; i < tor->peerCount; i++ )
|
||||
{
|
||||
otherPeer = tor->peers[i];
|
||||
|
||||
if( otherPeer->status < PEER_STATUS_CONNECTED )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sendHave( otherPeer, index );
|
||||
updateInterest( tor, otherPeer );
|
||||
}
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
(peer->inRequestCount)--;
|
||||
memmove( &peer->inRequests[0], &peer->inRequests[1],
|
||||
peer->inRequestCount * sizeof( tr_request_t ) );
|
||||
/* Piece is complete, check it */
|
||||
if( ( ret = tr_ioHash( tor->io, index ) ) )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
if( !tr_cpPieceIsComplete( tor->completion, index ) )
|
||||
{
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Hash OK */
|
||||
for( i = 0; i < tor->peerCount; i++ )
|
||||
{
|
||||
tr_peer_t * otherPeer;
|
||||
otherPeer = tor->peers[i];
|
||||
|
||||
if( otherPeer->status < PEER_STATUS_CONNECTED )
|
||||
continue;
|
||||
|
||||
sendHave( otherPeer, index );
|
||||
updateInterest( tor, otherPeer );
|
||||
}
|
||||
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static inline int parseCancel( tr_peer_t * peer, uint8_t * p, int len )
|
||||
@@ -348,7 +346,7 @@ static inline int parseCancel( tr_peer_t * peer, uint8_t * p, int len )
|
||||
if( len != 13 )
|
||||
{
|
||||
peer_dbg( "GET cancel, invalid" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
TR_NTOHL( p, index );
|
||||
@@ -371,7 +369,7 @@ static inline int parseCancel( tr_peer_t * peer, uint8_t * p, int len )
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static inline int parsePort( tr_peer_t * peer, uint8_t * p, int len )
|
||||
@@ -381,13 +379,13 @@ static inline int parsePort( tr_peer_t * peer, uint8_t * p, int len )
|
||||
if( len != 3 )
|
||||
{
|
||||
peer_dbg( "GET port, invalid" );
|
||||
return 1;
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
|
||||
port = *( (in_port_t *) p );
|
||||
peer_dbg( "GET port %d", ntohs( port ) );
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
@@ -423,7 +421,7 @@ static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
}
|
||||
|
||||
peer_dbg( "Unknown message '%d'", id );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
static inline int parseBufHeader( tr_peer_t * peer )
|
||||
@@ -432,7 +430,7 @@ static inline int parseBufHeader( tr_peer_t * peer )
|
||||
|
||||
if( 4 > peer->pos )
|
||||
{
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
if( p[0] != 19 || memcmp( &p[1], "Bit", 3 ) )
|
||||
@@ -441,19 +439,19 @@ static inline int parseBufHeader( tr_peer_t * peer )
|
||||
already */
|
||||
peer_dbg( "GET handshake, invalid" );
|
||||
tr_netSend( peer->socket, (uint8_t *) "Nice try...\r\n", 13 );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
if( peer->pos < 68 )
|
||||
{
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
if( memcmp( &p[4], "Torrent protocol", 16 ) )
|
||||
{
|
||||
peer_dbg( "GET handshake, invalid" );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static uint8_t * parseBufHash( tr_peer_t * peer )
|
||||
@@ -476,12 +474,13 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
int len;
|
||||
uint8_t * p = peer->buf;
|
||||
uint8_t * end = &p[peer->pos];
|
||||
int ret;
|
||||
|
||||
if( peer->banned )
|
||||
{
|
||||
/* Don't even parse, we only stay connected */
|
||||
peer->pos = 0;
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
while( peer->pos >= 4 )
|
||||
@@ -490,9 +489,9 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
{
|
||||
char * client;
|
||||
|
||||
if( parseBufHeader( peer ) )
|
||||
if( ( ret = parseBufHeader( peer ) ) )
|
||||
{
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if( peer->pos < 68 )
|
||||
@@ -503,14 +502,14 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
if( memcmp( &p[28], inf->hash, 20 ) )
|
||||
{
|
||||
peer_dbg( "GET handshake, wrong torrent hash" );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
if( !memcmp( &p[48], tor->id, 20 ) )
|
||||
{
|
||||
/* We are connected to ourselves... */
|
||||
peer_dbg( "GET handshake, that is us" );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
peer->status = PEER_STATUS_CONNECTED;
|
||||
@@ -527,7 +526,7 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
if( !peerCmp( peer, tor->peers[i] ) )
|
||||
{
|
||||
peer_dbg( "GET handshake, duplicate" );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +547,7 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
{
|
||||
/* This should never happen. Drop that peer */
|
||||
peer_dbg( "message too large (%d bytes)", len );
|
||||
return 1;
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
if( !len )
|
||||
@@ -569,9 +568,9 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
/* Remaining data after this message */
|
||||
peer->pos -= 4 + len;
|
||||
|
||||
if( parseMessage( tor, peer, p, len ) )
|
||||
if( ( ret = parseMessage( tor, peer, p, len ) ) )
|
||||
{
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
p += len;
|
||||
@@ -579,5 +578,5 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
|
||||
memmove( peer->buf, p, peer->pos );
|
||||
|
||||
return 0;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
@@ -232,6 +232,56 @@ void tr_lockClose( tr_lock_t * l )
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void tr_condInit( tr_cond_t * c )
|
||||
{
|
||||
#ifdef SYS_BEOS
|
||||
*c = -1;
|
||||
#else
|
||||
pthread_cond_init( c, NULL );
|
||||
#endif
|
||||
}
|
||||
|
||||
void tr_condWait( tr_cond_t * c, tr_lock_t * l )
|
||||
{
|
||||
#ifdef SYS_BEOS
|
||||
*c = find_thread( NULL );
|
||||
release_sem( *l );
|
||||
suspend_thread( *c );
|
||||
acquire_sem( *l );
|
||||
*c = -1;
|
||||
#else
|
||||
pthread_cond_wait( c, l );
|
||||
#endif
|
||||
}
|
||||
|
||||
void tr_condSignal( tr_cond_t * c )
|
||||
{
|
||||
#ifdef SYS_BEOS
|
||||
while( *c != -1 )
|
||||
{
|
||||
thread_info info;
|
||||
get_thread_info( *c, &info );
|
||||
if( info.state == B_THREAD_SUSPENDED )
|
||||
{
|
||||
resume_thread( *c );
|
||||
break;
|
||||
}
|
||||
snooze( 5000 );
|
||||
}
|
||||
#else
|
||||
pthread_cond_signal( c );
|
||||
#endif
|
||||
}
|
||||
|
||||
void tr_condClose( tr_cond_t * c )
|
||||
{
|
||||
#ifndef SYS_BEOS
|
||||
pthread_cond_destroy( c );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined( BSD )
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
#include <kernel/OS.h>
|
||||
typedef thread_id tr_thread_t;
|
||||
typedef sem_id tr_lock_t;
|
||||
typedef int tr_cond_t;
|
||||
#else
|
||||
#include <pthread.h>
|
||||
typedef pthread_t tr_thread_t;
|
||||
typedef pthread_mutex_t tr_lock_t;
|
||||
typedef pthread_cond_t tr_cond_t;
|
||||
#endif
|
||||
|
||||
char * tr_getCacheDirectory();
|
||||
@@ -60,6 +62,11 @@ static inline void tr_lockUnlock( tr_lock_t * l )
|
||||
#endif
|
||||
}
|
||||
|
||||
void tr_condInit( tr_cond_t * );
|
||||
void tr_condWait( tr_cond_t *, tr_lock_t * );
|
||||
void tr_condSignal( tr_cond_t * );
|
||||
void tr_condClose( tr_cond_t * );
|
||||
|
||||
int
|
||||
tr_getDefaultRoute( struct in_addr * addr );
|
||||
|
||||
|
||||
@@ -434,10 +434,10 @@ void tr_trackerAnnouncePulse( tr_tracker_t * tc, int manual )
|
||||
{
|
||||
switch( tr_httpPulse( tc->http, &data, &len ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
break;
|
||||
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
killHttp( &tc->http, tor->fdlimit );
|
||||
tc->dateTry = tr_date();
|
||||
|
||||
@@ -453,7 +453,7 @@ void tr_trackerAnnouncePulse( tr_tracker_t * tc, int manual )
|
||||
|
||||
break;
|
||||
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
readAnswer( tc, data, len );
|
||||
killHttp( &tc->http, tor->fdlimit );
|
||||
|
||||
@@ -504,15 +504,15 @@ void tr_trackerAnnouncePulse( tr_tracker_t * tc, int manual )
|
||||
{
|
||||
switch( tr_httpPulse( tc->httpScrape, &data, &len ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
break;
|
||||
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
killHttp( &tc->httpScrape, tor->fdlimit );
|
||||
tc->lastScrapeFailed = 1;
|
||||
break;
|
||||
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
readScrapeAnswer( tc, data, len );
|
||||
killHttp( &tc->httpScrape, tor->fdlimit );
|
||||
break;
|
||||
@@ -731,8 +731,8 @@ static void readAnswer( tr_tracker_t * tc, const char * data, int len )
|
||||
if( ( bePeers = tr_bencDictFind( &beAll, "failure reason" ) ) )
|
||||
{
|
||||
tr_err( "Tracker: Error - %s", bePeers->val.s.s );
|
||||
tor->error |= TR_ETRACKER;
|
||||
snprintf( tor->trackerError, sizeof( tor->trackerError ),
|
||||
tor->error = TR_ERROR_TC_ERROR;
|
||||
snprintf( tor->errorString, sizeof( tor->errorString ),
|
||||
"%s", bePeers->val.s.s );
|
||||
tc->lastError = 1;
|
||||
tc->allUnreachIfError = 0;
|
||||
@@ -742,15 +742,15 @@ static void readAnswer( tr_tracker_t * tc, const char * data, int len )
|
||||
else if( ( bePeers = tr_bencDictFind( &beAll, "warning message" ) ) )
|
||||
{
|
||||
tr_err( "Tracker: Warning - %s", bePeers->val.s.s );
|
||||
snprintf( tor->trackerError, sizeof( tor->trackerError ),
|
||||
tor->error = TR_ERROR_TC_WARNING;
|
||||
snprintf( tor->errorString, sizeof( tor->errorString ),
|
||||
"%s", bePeers->val.s.s );
|
||||
}
|
||||
else
|
||||
else if( tor->error & TR_ERROR_TC_MASK )
|
||||
{
|
||||
tor->trackerError[0] = '\0';
|
||||
tor->error = TR_OK;
|
||||
}
|
||||
|
||||
tor->error &= ~TR_ETRACKER;
|
||||
tc->lastError = 0;
|
||||
tc->allUnreachIfError = 0;
|
||||
|
||||
@@ -1128,13 +1128,13 @@ int tr_trackerScrape( tr_torrent_t * tor, int * s, int * l, int * d )
|
||||
{
|
||||
switch( tr_httpPulse( http, &data, &len ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
break;
|
||||
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
goto scrapeDone;
|
||||
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
readScrapeAnswer( tc, data, len );
|
||||
goto scrapeDone;
|
||||
}
|
||||
|
||||
@@ -379,6 +379,7 @@ void tr_torrentStart( tr_torrent_t * tor )
|
||||
tor->uploadedCur = 0;
|
||||
|
||||
tor->status = TR_STATUS_CHECK;
|
||||
tor->error = TR_OK;
|
||||
tor->tracker = tr_trackerInit( tor );
|
||||
|
||||
tor->date = tr_date();
|
||||
@@ -386,15 +387,20 @@ void tr_torrentStart( tr_torrent_t * tor )
|
||||
tr_threadCreate( &tor->thread, downloadLoop, tor );
|
||||
}
|
||||
|
||||
void tr_torrentStop( tr_torrent_t * tor )
|
||||
static void torrentStop( tr_torrent_t * tor )
|
||||
{
|
||||
tr_lockLock( &tor->lock );
|
||||
tr_trackerStopped( tor->tracker );
|
||||
tr_rcReset( tor->download );
|
||||
tr_rcReset( tor->upload );
|
||||
tr_rcReset( tor->swarmspeed );
|
||||
tor->status = TR_STATUS_STOPPING;
|
||||
tor->stopDate = tr_date();
|
||||
}
|
||||
|
||||
void tr_torrentStop( tr_torrent_t * tor )
|
||||
{
|
||||
tr_lockLock( &tor->lock );
|
||||
torrentStop( tor );
|
||||
tr_lockUnlock( &tor->lock );
|
||||
}
|
||||
|
||||
@@ -484,8 +490,8 @@ tr_stat_t * tr_torrentStat( tr_torrent_t * tor )
|
||||
|
||||
s->status = tor->status;
|
||||
s->error = tor->error;
|
||||
memcpy( s->trackerError, tor->trackerError,
|
||||
sizeof( s->trackerError ) );
|
||||
memcpy( s->errorString, tor->errorString,
|
||||
sizeof( s->errorString ) );
|
||||
|
||||
tc = tor->tracker;
|
||||
s->cannotConnect = tr_trackerCannotConnect( tc );
|
||||
@@ -755,6 +761,7 @@ static void downloadLoop( void * _tor )
|
||||
{
|
||||
tr_torrent_t * tor = _tor;
|
||||
uint64_t date1, date2;
|
||||
int ret;
|
||||
|
||||
tr_dbg( "Thread started" );
|
||||
|
||||
@@ -783,15 +790,18 @@ static void downloadLoop( void * _tor )
|
||||
tor->status = TR_STATUS_SEED;
|
||||
tor->finished = 1;
|
||||
tr_trackerCompleted( tor->tracker );
|
||||
tr_ioSaveResume( tor->io );
|
||||
#ifndef __AMIGAOS4__
|
||||
sync(); /* KLUDGE: all files should be closed and
|
||||
re-opened in read-only mode instead */
|
||||
#endif
|
||||
tr_ioSync( tor->io );
|
||||
}
|
||||
|
||||
/* Receive/send messages */
|
||||
tr_peerPulse( tor );
|
||||
if( ( ret = tr_peerPulse( tor ) ) )
|
||||
{
|
||||
tr_err( "Fatal error, stopping download (%d)", ret );
|
||||
torrentStop( tor );
|
||||
tor->error = ret;
|
||||
snprintf( tor->errorString, sizeof( tor->errorString ),
|
||||
"%s", tr_errorString( ret ) );
|
||||
}
|
||||
|
||||
/* Try to get new peers or to send a message to the tracker */
|
||||
tr_trackerPulse( tor->tracker );
|
||||
|
||||
@@ -50,7 +50,23 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define TR_DEFAULT_PORT 9090
|
||||
#define TR_NOERROR 0
|
||||
|
||||
/***********************************************************************
|
||||
* Error codes
|
||||
**********************************************************************/
|
||||
/* General errors */
|
||||
#define TR_OK 0x00000000
|
||||
#define TR_ERROR 0x81000000
|
||||
#define TR_ERROR_ASSERT 0x82000000
|
||||
/* I/O errors */
|
||||
#define TR_ERROR_IO_MASK 0x0000000F
|
||||
#define TR_ERROR_IO_PARENT 0x80000001
|
||||
#define TR_ERROR_IO_PERMISSIONS 0x80000002
|
||||
#define TR_ERROR_IO_OTHER 0x80000008
|
||||
/* Misc */
|
||||
#define TR_ERROR_TC_MASK 0x000000F0
|
||||
#define TR_ERROR_TC_ERROR 0x80000010
|
||||
#define TR_ERROR_TC_WARNING 0x80000020
|
||||
|
||||
/***********************************************************************
|
||||
* tr_init
|
||||
@@ -370,10 +386,8 @@ struct tr_stat_s
|
||||
#define TR_STATUS_INACTIVE (TR_STATUS_STOPPING|TR_STATUS_STOPPED|TR_STATUS_PAUSE)
|
||||
int status;
|
||||
|
||||
#define TR_ETRACKER 1
|
||||
#define TR_EINOUT 2
|
||||
int error;
|
||||
char trackerError[128];
|
||||
char errorString[128];
|
||||
int cannotConnect;
|
||||
|
||||
const char * trackerAddress;
|
||||
|
||||
@@ -453,11 +453,11 @@ watchSSDP( tr_upnp_device_t ** devices, int fd )
|
||||
len = sizeof( buf );
|
||||
switch( recvSSDP( fd, buf, &len ) )
|
||||
{
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
return ret;
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
return 1;
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
ret = 1;
|
||||
if( parseSSDP( buf, len, hdr ) &&
|
||||
NULL != hdr[OFF_LOC].data &&
|
||||
@@ -475,22 +475,22 @@ recvSSDP( int fd, char * buf, int * len )
|
||||
{
|
||||
if( 0 > fd )
|
||||
{
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
|
||||
*len = tr_netRecv( fd, ( uint8_t * ) buf, *len );
|
||||
if( TR_NET_BLOCK & *len )
|
||||
{
|
||||
return TR_WAIT;
|
||||
return TR_NET_WAIT;
|
||||
}
|
||||
else if( TR_NET_CLOSE & *len )
|
||||
{
|
||||
tr_err( "Could not receive SSDP message (%s)", strerror( errno ) );
|
||||
return TR_ERROR;
|
||||
return TR_NET_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TR_OK;
|
||||
return TR_NET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -955,7 +955,7 @@ devicePulseHttp( tr_upnp_device_t * dev, tr_fd_t * fdlimit,
|
||||
|
||||
switch( tr_httpPulse( dev->http, &headers, &hlen ) )
|
||||
{
|
||||
case TR_OK:
|
||||
case TR_NET_OK:
|
||||
code = tr_httpResponseCode( headers, hlen );
|
||||
if( SOAP_METHOD_NOT_ALLOWED == code && !dev->soapretry )
|
||||
{
|
||||
@@ -967,7 +967,7 @@ devicePulseHttp( tr_upnp_device_t * dev, tr_fd_t * fdlimit,
|
||||
*body = tr_httpParse( headers, hlen, NULL );
|
||||
*len = ( NULL == body ? 0 : hlen - ( *body - headers ) );
|
||||
return code;
|
||||
case TR_ERROR:
|
||||
case TR_NET_ERROR:
|
||||
killHttp( fdlimit, &dev->http );
|
||||
if( dev->soapretry )
|
||||
{
|
||||
@@ -981,7 +981,7 @@ devicePulseHttp( tr_upnp_device_t * dev, tr_fd_t * fdlimit,
|
||||
dev->soapretry = 1;
|
||||
}
|
||||
break;
|
||||
case TR_WAIT:
|
||||
case TR_NET_WAIT:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,3 +334,25 @@ tr_dupstr( const char * base, int len )
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
tr_errorString( int code )
|
||||
{
|
||||
switch( code )
|
||||
{
|
||||
case TR_OK:
|
||||
return "No error";
|
||||
case TR_ERROR:
|
||||
return "Generic error";
|
||||
case TR_ERROR_ASSERT:
|
||||
return "Assert error";
|
||||
case TR_ERROR_IO_PARENT:
|
||||
return "Download folder does not exist";
|
||||
case TR_ERROR_IO_PERMISSIONS:
|
||||
return "Unsufficient permissions";
|
||||
case TR_ERROR_IO_OTHER:
|
||||
return "Generic I/O error";
|
||||
}
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ int tr_vsprintf( char **, int *, int *, const char *, va_list, va_list );
|
||||
**********************************************************************/
|
||||
char * tr_dupstr( const char * base, int len );
|
||||
|
||||
char * tr_errorString( int code );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_date
|
||||
***********************************************************************
|
||||
|
||||
@@ -377,7 +377,7 @@ static uint32_t kRed = BE(0xFF6450FF), //255, 100, 80
|
||||
break;
|
||||
}
|
||||
|
||||
if (fStat->error & TR_ETRACKER)
|
||||
if (fStat->error)
|
||||
{
|
||||
[fStatusString setString: [NSLocalizedString(@"Error: ", "Torrent -> status string") stringByAppendingString:
|
||||
[self errorMessage]]];
|
||||
@@ -927,12 +927,12 @@ static uint32_t kRed = BE(0xFF6450FF), //255, 100, 80
|
||||
|
||||
- (BOOL) isError
|
||||
{
|
||||
return fStat->error & TR_ETRACKER;
|
||||
return fStat->error;
|
||||
}
|
||||
|
||||
- (NSString *) errorMessage
|
||||
{
|
||||
[NSString stringWithUTF8String: fStat->trackerError];
|
||||
[NSString stringWithUTF8String: fStat->errorString];
|
||||
}
|
||||
|
||||
- (BOOL) justFinished
|
||||
|
||||
Reference in New Issue
Block a user