Merge io branch into trunk

This commit is contained in:
Eric Petit
2007-01-14 12:00:21 +00:00
parent 58a8bdedf0
commit e5e6a8b5df
26 changed files with 701 additions and 432 deletions

View File

@@ -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:

View File

@@ -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,

View File

@@ -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 )
{

View File

@@ -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 );

View File

@@ -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 );

View File

@@ -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 );
}

View File

@@ -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 * );

View File

@@ -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

View File

@@ -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;
}
/***********************************************************************

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}
/***********************************************************************

View File

@@ -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 * );

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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 );

View File

@@ -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;
}

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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";
}

View File

@@ -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
***********************************************************************

View File

@@ -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