Thread safety improvements. Also, stopping/starting/rechecking/etc. torrents no longer blocks the calling thread. Since this a big commit, it will probably create some short-term pain via new bugs.
This commit is contained in:
parent
21cf51e3f7
commit
7e09d157cd
|
@ -154,7 +154,7 @@ int main( int argc, char ** argv )
|
|||
}
|
||||
|
||||
/* Open and parse torrent file */
|
||||
if( !( tor = tr_torrentInit( h, torrentPath, NULL, 0, &error ) ) )
|
||||
if( !( tor = tr_torrentInit( h, torrentPath, ".", NULL, 0, &error ) ) )
|
||||
{
|
||||
printf( "Failed opening torrent file `%s'\n", torrentPath );
|
||||
tr_close( h );
|
||||
|
@ -227,7 +227,6 @@ int main( int argc, char ** argv )
|
|||
|
||||
tr_natTraversalEnable( h, natTraversal );
|
||||
|
||||
tr_torrentSetFolder( tor, "." );
|
||||
tr_torrentStart( tor );
|
||||
|
||||
for( ;; )
|
||||
|
@ -246,11 +245,7 @@ int main( int argc, char ** argv )
|
|||
|
||||
s = tr_torrentStat( tor );
|
||||
|
||||
if( s->status & TR_STATUS_PAUSE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if( s->status & TR_STATUS_CHECK_WAIT )
|
||||
if( s->status & TR_STATUS_CHECK_WAIT )
|
||||
{
|
||||
chars = snprintf( string, sizeof string,
|
||||
"Waiting to check files... %.2f %%", 100.0 * s->percentDone );
|
||||
|
|
10
gtk/main.c
10
gtk/main.c
|
@ -956,14 +956,8 @@ recheckTorrentForeach (GtkTreeModel * model,
|
|||
gpointer data UNUSED)
|
||||
{
|
||||
TrTorrent * gtor = NULL;
|
||||
int status = 0;
|
||||
tr_torrent_t * tor;
|
||||
gtk_tree_model_get( model, iter, MC_TORRENT, >or, MC_STAT, &status, -1 );
|
||||
tor = tr_torrent_handle( gtor );
|
||||
if( status & TR_STATUS_ACTIVE )
|
||||
tr_torrentStop( tor );
|
||||
tr_torrentRemoveFastResume( tor );
|
||||
tr_torrentStart( tor );
|
||||
gtk_tree_model_get( model, iter, MC_TORRENT, >or, -1 );
|
||||
tr_torrentRecheck( tr_torrent_handle( gtor ) );
|
||||
g_object_unref( G_OBJECT( gtor ) );
|
||||
}
|
||||
|
||||
|
|
126
gtk/tr_core.c
126
gtk/tr_core.c
|
@ -31,9 +31,6 @@
|
|||
#include "bencode.h"
|
||||
#include "transmission.h"
|
||||
|
||||
/* XXX */
|
||||
#define TR_WANT_TORRENT_PRIVATE
|
||||
|
||||
#include "conf.h"
|
||||
#include "tr_core.h"
|
||||
#include "tr_prefs.h"
|
||||
|
@ -55,10 +52,6 @@ tr_core_marshal_data( GClosure * closure, GValue * ret, guint count,
|
|||
const GValue * vals, gpointer hint, gpointer marshal );
|
||||
static void
|
||||
tr_core_dispose( GObject * obj );
|
||||
static int
|
||||
tr_core_check_torrents( TrCore * self );
|
||||
static int
|
||||
tr_core_check_zombies( TrCore * self );
|
||||
static void
|
||||
tr_core_insert( TrCore * self, TrTorrent * tor );
|
||||
static void
|
||||
|
@ -238,7 +231,6 @@ tr_core_init( GTypeInstance * instance, gpointer g_class SHUTUP )
|
|||
|
||||
self->model = GTK_TREE_MODEL( store );
|
||||
self->handle = tr_init( "gtk" );
|
||||
self->zombies = NULL;
|
||||
self->nextid = 1;
|
||||
self->quitting = FALSE;
|
||||
self->disposed = FALSE;
|
||||
|
@ -250,7 +242,6 @@ tr_core_dispose( GObject * obj )
|
|||
TrCore * self = (TrCore *) obj;
|
||||
GObjectClass * parent;
|
||||
GtkTreeIter iter;
|
||||
GList * ii;
|
||||
TrTorrent * tor;
|
||||
|
||||
if( self->disposed )
|
||||
|
@ -273,17 +264,6 @@ tr_core_dispose( GObject * obj )
|
|||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
g_object_unref( self->model );
|
||||
|
||||
/* sever and unref all remaining zombie torrents */
|
||||
if( NULL != self->zombies )
|
||||
{
|
||||
for( ii = g_list_first( self->zombies ); NULL != ii; ii = ii->next )
|
||||
{
|
||||
tr_torrent_sever( ii->data );
|
||||
g_object_unref( ii->data );
|
||||
}
|
||||
g_list_free( self->zombies );
|
||||
}
|
||||
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "core %p dead\n", self );
|
||||
#endif
|
||||
|
@ -322,29 +302,22 @@ void
|
|||
tr_core_shutdown( TrCore * self )
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
TrTorrent * tor;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert( !self->quitting );
|
||||
self->quitting = TRUE;
|
||||
|
||||
/* try to stop all the torrents nicely */
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_stop( tor );
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
if ( gtk_tree_model_get_iter_first( self->model, &iter) ) do {
|
||||
TrTorrent * tor;
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
tr_torrent_sever( tor );
|
||||
g_object_unref( tor );
|
||||
} while( gtk_list_store_remove( GTK_LIST_STORE(self->model), &iter ) );
|
||||
|
||||
/* shut down nat traversal */
|
||||
tr_natTraversalEnable( self->handle, 0 );
|
||||
|
@ -353,78 +326,25 @@ tr_core_shutdown( TrCore * self )
|
|||
gboolean
|
||||
tr_core_quiescent( TrCore * self )
|
||||
{
|
||||
tr_handle_status_t * hstat;
|
||||
const tr_handle_status_t * hstat;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
g_assert( self->quitting );
|
||||
|
||||
if( self->disposed )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( 0 < tr_core_check_torrents( self ) )
|
||||
{
|
||||
if ( tr_torrentCount( self->handle ) != 0 )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hstat = tr_handleStatus( self->handle );
|
||||
|
||||
return TR_NAT_TRAVERSAL_DISABLED == hstat->natTraversalStatus;
|
||||
}
|
||||
|
||||
int
|
||||
tr_core_check_torrents( TrCore * self )
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
tr_stat_t * st;
|
||||
int count;
|
||||
TrTorrent * tor;
|
||||
|
||||
g_assert( !self->disposed && self->quitting );
|
||||
|
||||
count = 0;
|
||||
|
||||
if( gtk_tree_model_get_iter_first( self->model, &iter) )
|
||||
{
|
||||
do
|
||||
{
|
||||
gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
|
||||
st = tr_torrent_stat( tor );
|
||||
if( !( TR_STATUS_PAUSE & st->status ) )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
g_object_unref( tor );
|
||||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
count += tr_core_check_zombies( self );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
tr_core_check_zombies( TrCore * self )
|
||||
{
|
||||
GList * ii, * next;
|
||||
tr_stat_t * st;
|
||||
|
||||
for( ii = g_list_first( self->zombies ); NULL != ii; ii = next )
|
||||
{
|
||||
next = ii->next;
|
||||
st = tr_torrent_stat( ii->data );
|
||||
if( TR_STATUS_PAUSE & st->status )
|
||||
{
|
||||
tr_torrent_sever( ii->data );
|
||||
g_object_unref( ii->data );
|
||||
/* XXX is this safe to do? */
|
||||
self->zombies = g_list_delete_link( self->zombies, ii );
|
||||
}
|
||||
}
|
||||
|
||||
return g_list_length( self->zombies );
|
||||
return gtk_tree_model_iter_n_children( self->model, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -666,29 +586,16 @@ void
|
|||
tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter )
|
||||
{
|
||||
TrTorrent * tor;
|
||||
tr_stat_t * st;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
gtk_tree_model_get( self->model, iter, MC_TORRENT, &tor, -1 );
|
||||
|
||||
gtk_list_store_remove( GTK_LIST_STORE( self->model ), iter );
|
||||
if( TR_FLAG_SAVE & tr_torrent_info( tor )->flags )
|
||||
{
|
||||
tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
|
||||
}
|
||||
|
||||
st = tr_torrent_stat( tor );
|
||||
if( TR_STATUS_ACTIVE & st->status )
|
||||
{
|
||||
tr_torrentStop( tr_torrent_handle( tor ) );
|
||||
self->zombies = g_list_append( self->zombies, tor );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_torrent_sever( tor );
|
||||
g_object_unref( tor );
|
||||
}
|
||||
if( TR_FLAG_SAVE & tr_torrent_info( tor )->flags )
|
||||
tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
|
||||
|
||||
tr_torrent_sever( tor );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -715,7 +622,7 @@ tr_core_update( TrCore * self )
|
|||
{
|
||||
GtkTreeIter iter;
|
||||
TrTorrent * tor;
|
||||
tr_stat_t * st;
|
||||
const tr_stat_t * st;
|
||||
|
||||
TR_IS_CORE( self );
|
||||
|
||||
|
@ -752,11 +659,6 @@ tr_core_update( TrCore * self )
|
|||
}
|
||||
while( gtk_tree_model_iter_next( self->model, &iter ) );
|
||||
}
|
||||
|
||||
if( !self->quitting )
|
||||
{
|
||||
tr_core_check_zombies( self );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -60,7 +60,6 @@ struct _TrCore
|
|||
GObject parent;
|
||||
GtkTreeModel * model;
|
||||
tr_handle_t * handle;
|
||||
GList * zombies;
|
||||
int nextid;
|
||||
gboolean quitting;
|
||||
gboolean disposed;
|
||||
|
|
243
gtk/tr_torrent.c
243
gtk/tr_torrent.c
|
@ -31,9 +31,6 @@
|
|||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
|
||||
/* XXX */
|
||||
#define TR_WANT_TORRENT_PRIVATE
|
||||
|
||||
#include "tr_prefs.h"
|
||||
#include "tr_torrent.h"
|
||||
#include "util.h"
|
||||
|
@ -41,7 +38,6 @@
|
|||
enum {
|
||||
TR_TORRENT_HANDLE = 1,
|
||||
TR_TORRENT_DIR,
|
||||
TR_TORRENT_PAUSED,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -58,8 +54,6 @@ static void
|
|||
tr_torrent_dispose(GObject *obj);
|
||||
static void
|
||||
tr_torrent_set_folder(TrTorrent *tor);
|
||||
static gboolean
|
||||
tr_torrent_paused(TrTorrent *tor);
|
||||
|
||||
static gpointer
|
||||
tracker_boxed_fake_copy( gpointer boxed )
|
||||
|
@ -127,11 +121,6 @@ tr_torrent_class_init(gpointer g_class, gpointer g_class_data SHUTUP) {
|
|||
"Directory to download files to", NULL,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
g_object_class_install_property(gobject_class, TR_TORRENT_DIR, pspec);
|
||||
|
||||
pspec = g_param_spec_boolean("paused", "Paused",
|
||||
"Is the torrent paused or running", TRUE,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property(gobject_class, TR_TORRENT_PAUSED, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -143,6 +132,7 @@ tr_torrent_init(GTypeInstance *instance, gpointer g_class SHUTUP) {
|
|||
#endif
|
||||
|
||||
self->handle = NULL;
|
||||
self->lastStatTime = 0;
|
||||
self->dir = NULL;
|
||||
self->delfile = NULL;
|
||||
self->severed = FALSE;
|
||||
|
@ -174,12 +164,6 @@ tr_torrent_set_property(GObject *object, guint property_id,
|
|||
if(NULL != self->handle && NULL != self->dir)
|
||||
tr_torrent_set_folder(self);
|
||||
break;
|
||||
case TR_TORRENT_PAUSED:
|
||||
g_assert(NULL != self->handle);
|
||||
if(tr_torrent_paused(self) != g_value_get_boolean(value))
|
||||
(g_value_get_boolean(value) ? tr_torrentStop : tr_torrentStart)
|
||||
(self->handle);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
break;
|
||||
|
@ -202,9 +186,6 @@ tr_torrent_get_property(GObject *object, guint property_id,
|
|||
g_value_set_string(value, (NULL != self->dir ? self->dir :
|
||||
tr_torrentGetFolder(self->handle)));
|
||||
break;
|
||||
case TR_TORRENT_PAUSED:
|
||||
g_value_set_boolean(value, tr_torrent_paused(self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
break;
|
||||
|
@ -225,9 +206,7 @@ tr_torrent_dispose(GObject *obj) {
|
|||
#endif
|
||||
|
||||
if( !self->severed )
|
||||
{
|
||||
tr_torrent_sever( self );
|
||||
}
|
||||
|
||||
g_free (self->delfile);
|
||||
g_free (self->dir);
|
||||
|
@ -241,47 +220,39 @@ tr_torrent_sever( TrTorrent * self )
|
|||
{
|
||||
g_return_if_fail (TR_IS_TORRENT( self ));
|
||||
|
||||
if( self->severed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef REFDBG
|
||||
fprintf( stderr, "torrent %p sever\n", self );
|
||||
#endif
|
||||
|
||||
if( NULL == self->handle )
|
||||
if( !self->severed )
|
||||
{
|
||||
self->severed = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !tr_torrent_paused( self ) )
|
||||
{
|
||||
tr_torrentStop( self->handle );
|
||||
if( self->handle )
|
||||
tr_torrentClose( self->handle );
|
||||
}
|
||||
tr_torrentClose( self->handle );
|
||||
self->severed = TRUE;
|
||||
}
|
||||
|
||||
tr_torrent_t *
|
||||
tr_torrent_handle(TrTorrent *tor) {
|
||||
TR_IS_TORRENT(tor);
|
||||
tr_torrent_handle(TrTorrent *tor)
|
||||
{
|
||||
g_assert( TR_IS_TORRENT(tor) );
|
||||
|
||||
if(tor->severed)
|
||||
return NULL;
|
||||
|
||||
return tor->handle;
|
||||
return tor->severed ? NULL : tor->handle;
|
||||
}
|
||||
|
||||
tr_stat_t *
|
||||
tr_torrent_stat(TrTorrent *tor) {
|
||||
TR_IS_TORRENT(tor);
|
||||
const tr_stat_t *
|
||||
tr_torrent_stat(TrTorrent *tor)
|
||||
{
|
||||
const time_t now = time( NULL );
|
||||
|
||||
if(tor->severed)
|
||||
return NULL;
|
||||
g_assert( TR_IS_TORRENT(tor) );
|
||||
|
||||
return tr_torrentStat(tor->handle);
|
||||
if( tor->severed )
|
||||
return NULL;
|
||||
|
||||
if( tor->lastStatTime != now ) {
|
||||
tor->lastStatTime = now;
|
||||
tor->stat = *tr_torrentStat( tor->handle );
|
||||
}
|
||||
|
||||
return &tor->stat;
|
||||
}
|
||||
|
||||
tr_info_t *
|
||||
|
@ -299,12 +270,8 @@ tr_torrent_start( TrTorrent * self )
|
|||
{
|
||||
TR_IS_TORRENT( self );
|
||||
|
||||
if( self->severed || !tr_torrent_paused( self ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tr_torrentStart( self->handle );
|
||||
if( !self->severed )
|
||||
tr_torrentStart( self->handle );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -312,31 +279,19 @@ tr_torrent_stop( TrTorrent * self )
|
|||
{
|
||||
TR_IS_TORRENT( self );
|
||||
|
||||
if( self->severed || tr_torrent_paused( self ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tr_torrentStop( self->handle );
|
||||
if( !self->severed )
|
||||
tr_torrentStop( self->handle );
|
||||
}
|
||||
|
||||
static TrTorrent *
|
||||
maketorrent( tr_torrent_t * handle,
|
||||
const char * dir,
|
||||
gboolean paused )
|
||||
maketorrent( tr_torrent_t * handle )
|
||||
{
|
||||
TrTorrent * tor;
|
||||
|
||||
tr_torrentDisablePex( handle,
|
||||
!tr_prefs_get_bool_with_default( PREF_ID_PEX ) );
|
||||
|
||||
tor = g_object_new( TR_TORRENT_TYPE,
|
||||
"torrent-handle", handle,
|
||||
"download-directory", dir,
|
||||
NULL);
|
||||
g_object_set( tor, "paused", paused, NULL );
|
||||
|
||||
return tor;
|
||||
return g_object_new( TR_TORRENT_TYPE,
|
||||
"torrent-handle", handle,
|
||||
NULL);
|
||||
}
|
||||
|
||||
TrTorrent *
|
||||
|
@ -345,16 +300,19 @@ tr_torrent_new( tr_handle_t * back, const char *torrent, const char *dir,
|
|||
{
|
||||
TrTorrent *ret;
|
||||
tr_torrent_t *handle;
|
||||
int errcode, flag;
|
||||
int errcode, flags;
|
||||
|
||||
g_assert(NULL != dir);
|
||||
|
||||
*err = NULL;
|
||||
|
||||
flag = ( TR_TOR_COPY == act || TR_TOR_MOVE == act ? TR_FLAG_SAVE : 0 );
|
||||
errcode = -1;
|
||||
|
||||
handle = tr_torrentInit( back, torrent, NULL, flag, &errcode );
|
||||
flags = ( TR_TOR_COPY == act || TR_TOR_MOVE == act ? TR_FLAG_SAVE : 0 );
|
||||
if( paused )
|
||||
flags |= TR_FLAG_PAUSED;
|
||||
|
||||
handle = tr_torrentInit( back, torrent, dir, NULL, flags, &errcode );
|
||||
|
||||
if(NULL == handle) {
|
||||
switch(errcode) {
|
||||
|
@ -371,7 +329,7 @@ tr_torrent_new( tr_handle_t * back, const char *torrent, const char *dir,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ret = maketorrent( handle, dir, paused );
|
||||
ret = maketorrent( handle );
|
||||
|
||||
if( TR_TOR_MOVE == act )
|
||||
ret->delfile = g_strdup(torrent);
|
||||
|
@ -385,14 +343,18 @@ tr_torrent_new_with_data( tr_handle_t * back, uint8_t * data, size_t size,
|
|||
{
|
||||
tr_torrent_t * handle;
|
||||
int errcode;
|
||||
int flags;
|
||||
|
||||
g_assert( NULL != dir );
|
||||
|
||||
*err = NULL;
|
||||
|
||||
flags = TR_FLAG_SAVE;
|
||||
if( paused )
|
||||
flags |= TR_FLAG_PAUSED;
|
||||
|
||||
errcode = -1;
|
||||
handle = tr_torrentInitData( back, data, size, NULL, TR_FLAG_SAVE,
|
||||
&errcode );
|
||||
handle = tr_torrentInitData( back, data, size, dir, NULL, flags, &errcode );
|
||||
|
||||
if( NULL == handle )
|
||||
{
|
||||
|
@ -411,7 +373,7 @@ tr_torrent_new_with_data( tr_handle_t * back, uint8_t * data, size_t size,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return maketorrent( handle, dir, paused );
|
||||
return maketorrent( handle );
|
||||
}
|
||||
|
||||
TrTorrent *
|
||||
|
@ -421,6 +383,7 @@ tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
|
|||
TrTorrent * ret;
|
||||
tr_torrent_t * handle;
|
||||
int ii, errcode;
|
||||
int flags;
|
||||
benc_val_t *name, *data;
|
||||
char *torrent, *hash, *dir;
|
||||
gboolean paused = FALSE;
|
||||
|
@ -463,10 +426,14 @@ tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
|
|||
(NULL == torrent && NULL == hash) || NULL == dir)
|
||||
return NULL;
|
||||
|
||||
flags = 0;
|
||||
if( forcedpause )
|
||||
flags |= TR_FLAG_PAUSED;
|
||||
|
||||
if( NULL != hash )
|
||||
handle = tr_torrentInitSaved(back, hash, 0, &errcode);
|
||||
handle = tr_torrentInitSaved(back, hash, dir, flags, &errcode);
|
||||
else
|
||||
handle = tr_torrentInit(back, torrent, NULL, 0, &errcode);
|
||||
handle = tr_torrentInit(back, torrent, dir, NULL, flags, &errcode);
|
||||
|
||||
if(NULL == handle) {
|
||||
torrent = ( NULL == hash ? torrent : hash );
|
||||
|
@ -484,7 +451,7 @@ tr_torrent_new_with_state( tr_handle_t * back, benc_val_t * state,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ret = maketorrent( handle, dir, paused || forcedpause );
|
||||
ret = maketorrent( handle );
|
||||
ret->ul_cap = ul_cap;
|
||||
ret->ul_cap_enabled = ul_cap_enabled;
|
||||
ret->dl_cap = dl_cap;
|
||||
|
@ -526,8 +493,10 @@ tr_torrent_get_state( TrTorrent * tor, benc_val_t * state )
|
|||
}
|
||||
tr_bencInitStr( tr_bencDictAdd( state, "dir" ),
|
||||
tr_torrentGetFolder( tor->handle ), -1, 1 );
|
||||
#if 0
|
||||
tr_bencInitInt( tr_bencDictAdd( state, "paused" ),
|
||||
tr_torrent_paused( tor ) ? 1 : 0 );
|
||||
#endif
|
||||
|
||||
tr_bencInitInt( tr_bencDictAdd( state, "ul-cap-speed" ),
|
||||
tor->ul_cap );
|
||||
|
@ -576,13 +545,6 @@ tr_torrent_set_folder(TrTorrent *tor) {
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tr_torrent_paused(TrTorrent *tor) {
|
||||
tr_stat_t *st = tr_torrentStat(tor->handle);
|
||||
|
||||
return (TR_STATUS_INACTIVE & st->status ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
extern void tr_setUseCustomUpload( tr_torrent_t * tor, int limit );
|
||||
extern void tr_setUseCustomDownload( tr_torrent_t * tor, int limit );
|
||||
|
||||
|
@ -622,7 +584,7 @@ tr_torrent_set_download_cap_enabled ( TrTorrent *gtor, gboolean b ) {
|
|||
|
||||
void
|
||||
tr_torrent_check_seeding_cap ( TrTorrent *gtor) {
|
||||
tr_stat_t * st = tr_torrent_stat( gtor );
|
||||
const tr_stat_t * st = tr_torrent_stat( gtor );
|
||||
if ((gtor->seeding_cap_enabled) && (st->ratio >= gtor->seeding_cap))
|
||||
tr_torrent_stop (gtor);
|
||||
}
|
||||
|
@ -642,62 +604,59 @@ tr_torrent_status_str ( TrTorrent * gtor )
|
|||
{
|
||||
char * top = 0;
|
||||
|
||||
tr_stat_t * st = tr_torrent_stat( gtor );
|
||||
const tr_stat_t * st = tr_torrent_stat( gtor );
|
||||
|
||||
const int tpeers = MAX (st->peersTotal, 0);
|
||||
const int upeers = MAX (st->peersUploading, 0);
|
||||
const int eta = st->eta;
|
||||
const double prog = st->percentDone * 100.0; /* [0...100] */
|
||||
const int status = st->status;
|
||||
|
||||
if( TR_STATUS_CHECK_WAIT & status )
|
||||
switch( st->status )
|
||||
{
|
||||
top = g_strdup_printf( _("Waiting to check existing files (%.1f%%)"), prog );
|
||||
}
|
||||
else if( TR_STATUS_CHECK & status )
|
||||
{
|
||||
top = g_strdup_printf( _("Checking existing files (%.1f%%)"), prog );
|
||||
}
|
||||
else if( TR_STATUS_DOWNLOAD & status )
|
||||
{
|
||||
if( 0 > eta )
|
||||
{
|
||||
top = g_strdup_printf( _("Stalled (%.1f%%)"), prog );
|
||||
}
|
||||
else
|
||||
{
|
||||
char * timestr = readabletime(eta);
|
||||
top = g_strdup_printf( _("Finishing in %s (%.1f%%)"),
|
||||
timestr, prog );
|
||||
g_free(timestr);
|
||||
}
|
||||
}
|
||||
else if( TR_STATUS_SEED & status )
|
||||
{
|
||||
top = g_strdup_printf(
|
||||
ngettext( "Seeding, uploading to %d of %d peer",
|
||||
"Seeding, uploading to %d of %d peers", tpeers ),
|
||||
upeers, tpeers );
|
||||
}
|
||||
else if( TR_STATUS_DONE & status )
|
||||
{
|
||||
top = g_strdup_printf(
|
||||
ngettext( "Uploading to %d of %d peer",
|
||||
"Uploading to %d of %d peers", tpeers ),
|
||||
upeers, tpeers );
|
||||
}
|
||||
else if( TR_STATUS_STOPPING & status )
|
||||
{
|
||||
top = g_strdup( _("Stopping...") );
|
||||
}
|
||||
else if( TR_STATUS_PAUSE & status )
|
||||
{
|
||||
top = g_strdup_printf( _("Stopped (%.1f%%)"), prog );
|
||||
}
|
||||
else
|
||||
{
|
||||
top = g_strdup( "" );
|
||||
g_assert_not_reached();
|
||||
case TR_STATUS_CHECK_WAIT:
|
||||
top = g_strdup_printf( _("Waiting to check existing files (%.1f%%)"), prog );
|
||||
break;
|
||||
|
||||
case TR_STATUS_CHECK:
|
||||
top = g_strdup_printf( _("Checking existing files (%.1f%%)"), prog );
|
||||
break;
|
||||
|
||||
case TR_STATUS_DOWNLOAD:
|
||||
if( eta < 0 )
|
||||
top = g_strdup_printf( _("Stalled (%.1f%%)"), prog );
|
||||
else {
|
||||
char * timestr = readabletime(eta);
|
||||
top = g_strdup_printf( _("Finishing in %s (%.1f%%)"), timestr, prog );
|
||||
g_free(timestr);
|
||||
}
|
||||
break;
|
||||
|
||||
case TR_STATUS_DONE:
|
||||
top = g_strdup_printf(
|
||||
ngettext( "Uploading to %d of %d peer",
|
||||
"Uploading to %d of %d peers", tpeers ),
|
||||
upeers, tpeers );
|
||||
break;
|
||||
|
||||
case TR_STATUS_SEED:
|
||||
top = g_strdup_printf(
|
||||
ngettext( "Seeding, uploading to %d of %d peer",
|
||||
"Seeding, uploading to %d of %d peers", tpeers ),
|
||||
upeers, tpeers );
|
||||
break;
|
||||
|
||||
case TR_STATUS_STOPPING:
|
||||
top = g_strdup( _("Stopping...") );
|
||||
break;
|
||||
|
||||
case TR_STATUS_STOPPED:
|
||||
top = g_strdup( _("Stopped") );
|
||||
break;
|
||||
|
||||
default:
|
||||
top = g_strdup_printf("Unrecognized state: %d", st->status );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return top;
|
||||
|
|
|
@ -58,6 +58,8 @@ struct _TrTorrent {
|
|||
tr_torrent_t *handle;
|
||||
char *dir;
|
||||
char *delfile;
|
||||
tr_stat_t stat;
|
||||
time_t lastStatTime;
|
||||
|
||||
/* FIXME: hm, are these heavyweight enough to deserve their own properties? */
|
||||
gboolean severed;
|
||||
|
@ -80,7 +82,7 @@ tr_torrent_get_type(void);
|
|||
tr_torrent_t *
|
||||
tr_torrent_handle(TrTorrent *tor);
|
||||
|
||||
tr_stat_t *
|
||||
const tr_stat_t *
|
||||
tr_torrent_stat(TrTorrent *tor);
|
||||
|
||||
tr_info_t *
|
||||
|
@ -112,8 +114,6 @@ tr_torrent_set_seeding_cap_ratio ( TrTorrent*, gdouble ratio );
|
|||
void
|
||||
tr_torrent_set_seeding_cap_enabled ( TrTorrent*, gboolean );
|
||||
|
||||
#ifdef TR_WANT_TORRENT_PRIVATE
|
||||
|
||||
TrTorrent *
|
||||
tr_torrent_new( tr_handle_t * handle, const char * path, const char * dir,
|
||||
enum tr_torrent_action act, gboolean paused, char ** err);
|
||||
|
@ -135,6 +135,4 @@ tr_torrent_state_saved(TrTorrent *tor);
|
|||
void
|
||||
tr_torrent_sever( TrTorrent * tor );
|
||||
|
||||
#endif /* TR_WANT_TORRENT_PRIVATE */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -145,7 +145,7 @@ void tr_chokingPulse( tr_choking_t * c )
|
|||
peersTotalCount = 0;
|
||||
for( tor = c->h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_lockLock( &tor->lock );
|
||||
tr_torrentWriterLock( tor );
|
||||
peersTotalCount += tor->peerCount;
|
||||
}
|
||||
|
||||
|
@ -310,9 +310,7 @@ void tr_chokingPulse( tr_choking_t * c )
|
|||
|
||||
/* Unlock all torrents */
|
||||
for( tor = c->h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_lockUnlock( &tor->lock );
|
||||
}
|
||||
tr_torrentWriterUnlock( tor );
|
||||
|
||||
tr_lockUnlock( &c->lock );
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ fastResumeLoadProgress( const tr_torrent_t * tor,
|
|||
tr_time_t * curMTimes = getMTimes( tor, &n );
|
||||
const tr_time_t * oldMTimes = (const tr_time_t *) walk;
|
||||
for( i=0; i<n; ++i ) {
|
||||
if ( !curMTimes[i] || ( curMTimes[i]!=oldMTimes[i] ) ) {
|
||||
if ( curMTimes[i]!=oldMTimes[i] ) {
|
||||
const tr_file_t * file = &tor->info.files[i];
|
||||
tr_dbg( "File '%s' mtimes differ-- flagging pieces [%d..%d] for recheck",
|
||||
file->name, file->firstPiece, file->lastPiece);
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
struct tr_io_s
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
|
||||
tr_bitfield_t * uncheckedPieces;
|
||||
};
|
||||
|
||||
#include "fastresume.h"
|
||||
|
@ -135,10 +133,6 @@ readOrWritePiece ( tr_torrent_t * tor,
|
|||
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
|
||||
assert( buflen <= (size_t) tr_pieceSize( pieceIndex ) );
|
||||
|
||||
/* Release the torrent lock so the UI can still update itself if
|
||||
this blocks for a while */
|
||||
tr_lockUnlock( &tor->lock );
|
||||
|
||||
findFileLocation ( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset );
|
||||
|
||||
while( buflen && !ret )
|
||||
|
@ -158,8 +152,6 @@ readOrWritePiece ( tr_torrent_t * tor,
|
|||
fileOffset = 0;
|
||||
}
|
||||
|
||||
tr_lockLock( &tor->lock );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -217,37 +209,46 @@ checkPiece ( tr_torrent_t * tor, int pieceIndex )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
checkFiles( tr_io_t * io )
|
||||
int
|
||||
tr_ioCheckFiles( tr_torrent_t * tor, int mode )
|
||||
{
|
||||
int i;
|
||||
tr_torrent_t * tor = io->tor;
|
||||
tr_bitfield_t * uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
|
||||
|
||||
tr_bitfieldClear( io->uncheckedPieces );
|
||||
tr_cpReset( tor->completion );
|
||||
|
||||
if( fastResumeLoad( io->tor, io->uncheckedPieces ) )
|
||||
tr_bitfieldAddRange( io->uncheckedPieces, 0, tor->info.pieceCount-1 );
|
||||
tr_bitfieldClear( uncheckedPieces );
|
||||
|
||||
if( !tr_bitfieldIsEmpty( io->uncheckedPieces ) )
|
||||
tr_inf( "Rechecking portions of \"%s\"", tor->info.name );
|
||||
if( (mode==TR_RECHECK_FORCE) || fastResumeLoad( tor, uncheckedPieces ) )
|
||||
tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount-1 );
|
||||
|
||||
if( tr_bitfieldIsEmpty( uncheckedPieces ) ) {
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
if( mode == TR_RECHECK_FAST ) {
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
return TR_ERROR_IO_OTHER;
|
||||
}
|
||||
|
||||
tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
|
||||
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
{
|
||||
if( tor->status & TR_STATUS_STOPPING )
|
||||
break;
|
||||
|
||||
if( !tr_bitfieldHas( io->uncheckedPieces, i ) )
|
||||
if( !tr_bitfieldHas( uncheckedPieces, i ) )
|
||||
continue;
|
||||
|
||||
tr_dbg ( "Checking piece %d because it's not in fast-resume", i );
|
||||
|
||||
if( !checkPiece( tor, i ) )
|
||||
tr_cpPieceAdd( tor->completion, i );
|
||||
else
|
||||
tr_cpPieceRem( tor->completion, i );
|
||||
tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
|
||||
|
||||
tr_bitfieldRem( io->uncheckedPieces, i );
|
||||
tr_bitfieldRem( uncheckedPieces, i );
|
||||
}
|
||||
|
||||
fastResumeSave( tor );
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
/****
|
||||
|
@ -255,49 +256,52 @@ checkFiles( tr_io_t * io )
|
|||
****/
|
||||
|
||||
tr_io_t*
|
||||
tr_ioInit( tr_torrent_t * tor )
|
||||
tr_ioInitFast( tr_torrent_t * tor )
|
||||
{
|
||||
tr_io_t * io = calloc( 1, sizeof( tr_io_t ) );
|
||||
io->uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
|
||||
tr_io_t * io = tr_calloc( 1, sizeof( tr_io_t ) );
|
||||
io->tor = tor;
|
||||
checkFiles( io );
|
||||
|
||||
if( tr_ioCheckFiles( tor, TR_RECHECK_FAST ) )
|
||||
{
|
||||
tr_free( io );
|
||||
io = NULL;
|
||||
}
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tr_ioSync( tr_io_t * io )
|
||||
{
|
||||
int i;
|
||||
const tr_info_t * info = &io->tor->info;
|
||||
if( io != NULL )
|
||||
{
|
||||
int i;
|
||||
const tr_info_t * info = &io->tor->info;
|
||||
|
||||
for( i=0; i<info->fileCount; ++i )
|
||||
tr_fdFileClose( io->tor->destination, info->files[i].name );
|
||||
for( i=0; i<info->fileCount; ++i )
|
||||
tr_fdFileClose( io->tor->destination, info->files[i].name );
|
||||
|
||||
if( tr_bitfieldIsEmpty( io->uncheckedPieces ) )
|
||||
fastResumeSave( io->tor );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_ioClose( tr_io_t * io )
|
||||
{
|
||||
tr_ioSync( io );
|
||||
|
||||
tr_bitfieldFree( io->uncheckedPieces );
|
||||
free( io );
|
||||
if( io != NULL )
|
||||
{
|
||||
tr_ioSync( io );
|
||||
tr_free( io );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* try to load the fast resume file */
|
||||
void
|
||||
int
|
||||
tr_ioLoadResume( tr_torrent_t * tor )
|
||||
{
|
||||
tr_io_t * io = calloc( 1, sizeof( tr_io_t ) );
|
||||
io->uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
|
||||
io->tor = tor;
|
||||
fastResumeLoad( tor, io->uncheckedPieces );
|
||||
tor->ioLoaded = 1;
|
||||
tr_bitfieldFree( io->uncheckedPieces );
|
||||
free( io );
|
||||
return tr_ioCheckFiles ( tor, TR_RECHECK_FAST );
|
||||
}
|
||||
|
||||
void tr_ioRemoveResume( tr_torrent_t * tor )
|
||||
|
|
|
@ -27,10 +27,19 @@
|
|||
|
||||
typedef struct tr_io_s tr_io_t;
|
||||
|
||||
void tr_ioLoadResume ( tr_torrent_t * );
|
||||
void tr_ioRemoveResume( tr_torrent_t * tor );
|
||||
int tr_ioLoadResume ( tr_torrent_t * );
|
||||
void tr_ioRemoveResume( tr_torrent_t * );
|
||||
|
||||
tr_io_t * tr_ioInit ( tr_torrent_t * );
|
||||
|
||||
enum
|
||||
{
|
||||
TR_RECHECK_FAST, /* only try the fast resume, even if it's incomplete */
|
||||
TR_RECHECK_FORCE /* ignore the fast resume data; recheck from disk */
|
||||
};
|
||||
int tr_ioCheckFiles ( tr_torrent_t *, int recheckMode );
|
||||
|
||||
|
||||
tr_io_t * tr_ioInitFast ( tr_torrent_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioRead, tr_ioWrite
|
||||
|
|
|
@ -157,10 +157,28 @@ typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t;
|
|||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
void tr_torrentResetTransferStats( tr_torrent_t * );
|
||||
|
||||
int tr_torrentAddCompact( tr_torrent_t * tor, int from,
|
||||
uint8_t * buf, int count );
|
||||
int tr_torrentAttachPeer( tr_torrent_t * tor, tr_peer_t * peer );
|
||||
|
||||
void tr_torrentSetHasPiece( tr_torrent_t * tor, int pieceIndex, int has );
|
||||
|
||||
void tr_torrentReaderLock ( const tr_torrent_t * );
|
||||
void tr_torrentReaderUnlock ( const tr_torrent_t * );
|
||||
void tr_torrentWriterLock ( tr_torrent_t * );
|
||||
void tr_torrentWriterUnlock ( tr_torrent_t * );
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_RUN_CHECKING = (1<<0), /* checking files' checksums */
|
||||
TR_RUN_RUNNING = (1<<1), /* seeding or leeching */
|
||||
TR_RUN_STOPPING = (1<<2), /* stopping */
|
||||
TR_RUN_STOPPED = (1<<3) /* stopped */
|
||||
}
|
||||
run_status_t;
|
||||
|
||||
struct tr_torrent_s
|
||||
{
|
||||
tr_handle_t * handle;
|
||||
|
@ -172,7 +190,6 @@ struct tr_torrent_s
|
|||
tr_ratecontrol_t * download;
|
||||
tr_ratecontrol_t * swarmspeed;
|
||||
|
||||
int status;
|
||||
int error;
|
||||
char errorString[128];
|
||||
int hasChangedState;
|
||||
|
@ -194,10 +211,12 @@ struct tr_torrent_s
|
|||
|
||||
tr_completion_t * completion;
|
||||
|
||||
volatile char die;
|
||||
volatile char dieFlag;
|
||||
volatile char recheckFlag;
|
||||
run_status_t runStatus;
|
||||
cp_status_t cpStatus;
|
||||
tr_thread_t thread;
|
||||
tr_lock_t lock;
|
||||
tr_cond_t cond;
|
||||
tr_rwlock_t lock;
|
||||
|
||||
tr_tracker_t * tracker;
|
||||
tr_io_t * io;
|
||||
|
@ -219,7 +238,6 @@ struct tr_torrent_s
|
|||
tr_stat_t stats[2];
|
||||
int statCur;
|
||||
|
||||
tr_torrent_t * prev;
|
||||
tr_torrent_t * next;
|
||||
};
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ static const int SWIFT_INITIAL_CREDIT = 64 * 1024; /* 64 KiB */
|
|||
* on largesse by uniformly distributing free credit to
|
||||
* all of our peers. This too helps prevent gridlock.
|
||||
*/
|
||||
static const double SWIFT_LARGESSE = 0.05; /* 5% of our UL */
|
||||
static const double SWIFT_LARGESSE = 0.10; /* 10% of our UL */
|
||||
|
||||
/**
|
||||
* How frequently to extend largesse-based credit
|
||||
|
@ -450,7 +450,7 @@ int tr_peerPulse( tr_peer_t * peer )
|
|||
|
||||
/* Disconnect if seeder and torrent is seeding */
|
||||
if( ( peer->progress >= 1.0 )
|
||||
&& ( peer->tor->status & (TR_STATUS_SEED|TR_STATUS_DONE) ) )
|
||||
&& ( peer->tor->cpStatus != TR_CP_INCOMPLETE ) )
|
||||
{
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
@ -836,7 +836,7 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
|
|||
int deadbeatCount = 0;
|
||||
tr_peer_t ** deadbeats;
|
||||
|
||||
tr_lockLock( &tor->lock );
|
||||
tr_torrentWriterLock( tor );
|
||||
|
||||
deadbeats = tr_calloc( tor->peerCount, sizeof(tr_peer_t*) );
|
||||
for( i=0; i<tor->peerCount; ++i ) {
|
||||
|
@ -864,7 +864,7 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
|
|||
|
||||
free( deadbeats );
|
||||
|
||||
tr_lockUnlock( &tor->lock );
|
||||
tr_torrentWriterUnlock( tor );
|
||||
}
|
||||
void
|
||||
tr_swiftPulse( tr_handle_t * h )
|
||||
|
|
|
@ -200,6 +200,7 @@ tr_getTorrentsDirectory( void )
|
|||
static void ThreadFunc( void * _t )
|
||||
{
|
||||
tr_thread_t * t = _t;
|
||||
char* name = tr_strdup( t->name );
|
||||
|
||||
#ifdef SYS_BEOS
|
||||
/* This is required because on BeOS, SIGINT is sent to each thread,
|
||||
|
@ -207,9 +208,10 @@ static void ThreadFunc( void * _t )
|
|||
signal( SIGINT, SIG_IGN );
|
||||
#endif
|
||||
|
||||
tr_dbg( "Thread '%s' started", t->name );
|
||||
tr_dbg( "Thread '%s' started", name );
|
||||
t->func( t->arg );
|
||||
tr_dbg( "Thread '%s' exited", t->name );
|
||||
tr_dbg( "Thread '%s' exited", name );
|
||||
tr_free( name );
|
||||
}
|
||||
|
||||
void tr_threadCreate( tr_thread_t * t,
|
||||
|
@ -241,7 +243,7 @@ void tr_threadJoin( tr_thread_t * t )
|
|||
pthread_join( t->thread, NULL );
|
||||
#endif
|
||||
tr_dbg( "Thread '%s' joined", t->name );
|
||||
free( t->name );
|
||||
tr_free( t->name );
|
||||
t->name = NULL;
|
||||
t->func = NULL;
|
||||
}
|
||||
|
@ -270,6 +272,7 @@ int tr_lockTryLock( tr_lock_t * l )
|
|||
#ifdef SYS_BEOS
|
||||
#error how is this done in beos
|
||||
#else
|
||||
/* success on zero! */
|
||||
return pthread_mutex_trylock( l );
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -320,9 +320,9 @@ static void SetPublicPort( tr_shared_t * s, int port )
|
|||
|
||||
for( tor = h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_lockLock( &tor->lock );
|
||||
tr_torrentWriterLock( tor );
|
||||
tor->publicPort = port;
|
||||
tr_lockUnlock( &tor->lock );
|
||||
tr_torrentWriterUnlock( tor );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,22 +403,21 @@ static void DispatchPeers( tr_shared_t * s )
|
|||
|
||||
for( tor = h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_lockLock( &tor->lock );
|
||||
if( tor->status & TR_STATUS_INACTIVE )
|
||||
tr_torrentWriterLock( tor );
|
||||
if( tor->cpStatus != TR_RUN_RUNNING )
|
||||
{
|
||||
tr_lockUnlock( &tor->lock );
|
||||
tr_torrentWriterUnlock( tor );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( 0 == memcmp( tor->info.hash, hash,
|
||||
SHA_DIGEST_LENGTH ) )
|
||||
if( !memcmp( tor->info.hash, hash, SHA_DIGEST_LENGTH ) )
|
||||
{
|
||||
/* Found it! */
|
||||
tr_torrentAttachPeer( tor, s->peers[ii] );
|
||||
tr_lockUnlock( &tor->lock );
|
||||
tr_torrentWriterUnlock( tor );
|
||||
goto removePeer;
|
||||
}
|
||||
tr_lockUnlock( &tor->lock );
|
||||
tr_torrentWriterUnlock( tor );
|
||||
}
|
||||
|
||||
/* Couldn't find a torrent, we probably removed it */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -474,6 +474,9 @@ void tr_trackerCompleted( tr_tracker_t * tc )
|
|||
|
||||
void tr_trackerStopped( tr_tracker_t * tc )
|
||||
{
|
||||
if( tc == NULL )
|
||||
return;
|
||||
|
||||
/* If we are already sending a query at the moment, we need to
|
||||
reconnect */
|
||||
killHttp( &tc->http );
|
||||
|
@ -491,6 +494,9 @@ void tr_trackerClose( tr_tracker_t * tc )
|
|||
size_t ii;
|
||||
struct tclist * dead;
|
||||
|
||||
if( tc == NULL )
|
||||
return;
|
||||
|
||||
killHttp( &tc->http );
|
||||
killHttp( &tc->httpScrape );
|
||||
|
||||
|
@ -522,11 +528,8 @@ static tr_http_t * getQuery( tr_tracker_t * tc )
|
|||
if( tc->started )
|
||||
{
|
||||
event = "&event=started";
|
||||
|
||||
tor->downloadedPrev += tor->downloadedCur;
|
||||
tor->downloadedCur = 0;
|
||||
tor->uploadedPrev += tor->uploadedCur;
|
||||
tor->uploadedCur = 0;
|
||||
|
||||
tr_torrentResetTransferStats( tor );
|
||||
|
||||
if( shouldChangePort( tc ) )
|
||||
{
|
||||
|
@ -832,7 +835,7 @@ nodict:
|
|||
|
||||
if( tc->stopped )
|
||||
{
|
||||
tor->status = TR_STATUS_STOPPED;
|
||||
tr_torrentStop( tor );
|
||||
tc->stopped = 0;
|
||||
}
|
||||
else if( shouldChangePort( tc ) )
|
||||
|
|
|
@ -145,11 +145,11 @@ void tr_torrentRates( tr_handle_t * h, float * dl, float * ul )
|
|||
tr_sharedLock( h->shared );
|
||||
for( tor = h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_lockLock( &tor->lock );
|
||||
if( tor->status & TR_STATUS_DOWNLOAD )
|
||||
tr_torrentReaderLock( tor );
|
||||
if( tor->cpStatus == TR_CP_INCOMPLETE )
|
||||
*dl += tr_rcRate( tor->download );
|
||||
*ul += tr_rcRate( tor->upload );
|
||||
tr_lockUnlock( &tor->lock );
|
||||
tr_torrentReaderUnlock( tor );
|
||||
}
|
||||
tr_sharedUnlock( h->shared );
|
||||
}
|
||||
|
|
|
@ -213,8 +213,6 @@ enum
|
|||
|
||||
typedef int8_t tr_priority_t;
|
||||
|
||||
void tr_torrentInitFilePieces( tr_torrent_t * tor );
|
||||
|
||||
/* priorities should be an array of tor->info.fileCount bytes,
|
||||
* each holding a value of TR_PRI_NORMAL, _HIGH, _LOW, or _DND. */
|
||||
void tr_torrentSetFilePriorities ( tr_torrent_t *, const tr_priority_t * priorities );
|
||||
|
@ -265,7 +263,9 @@ void tr_close( tr_handle_t * );
|
|||
#define TR_EUNSUPPORTED 2
|
||||
#define TR_EDUPLICATE 3
|
||||
#define TR_EOTHER 666
|
||||
tr_torrent_t * tr_torrentInit( tr_handle_t *, const char * path,
|
||||
tr_torrent_t * tr_torrentInit( tr_handle_t *,
|
||||
const char * path,
|
||||
const char * destination,
|
||||
uint8_t * hash, int flags, int * error );
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -274,9 +274,10 @@ tr_torrent_t * tr_torrentInit( tr_handle_t *, const char * path,
|
|||
* Like tr_torrentInit, except the actual torrent data is passed in
|
||||
* instead of the filename.
|
||||
**********************************************************************/
|
||||
tr_torrent_t * tr_torrentInitData( tr_handle_t *, uint8_t * data,
|
||||
size_t size, uint8_t * hash,
|
||||
int flags, int * error );
|
||||
tr_torrent_t * tr_torrentInitData( tr_handle_t *,
|
||||
uint8_t * data, size_t size,
|
||||
const char * destination,
|
||||
uint8_t * hash, int flags, int * error );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentInitSaved
|
||||
|
@ -285,7 +286,9 @@ tr_torrent_t * tr_torrentInitData( tr_handle_t *, uint8_t * data,
|
|||
* the hash string of a saved torrent file instead of a filename. There
|
||||
* are currently no valid flags for this function.
|
||||
**********************************************************************/
|
||||
tr_torrent_t * tr_torrentInitSaved( tr_handle_t *, const char * hashStr,
|
||||
tr_torrent_t * tr_torrentInitSaved( tr_handle_t *,
|
||||
const char * hashStr,
|
||||
const char * destination,
|
||||
int flags, int * error );
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -317,9 +320,7 @@ tr_info_t * tr_torrentInfo( tr_torrent_t * );
|
|||
int tr_torrentScrape( tr_torrent_t *, int * s, int * l, int * d );
|
||||
|
||||
void tr_torrentSetFolder( tr_torrent_t *, const char * );
|
||||
char * tr_torrentGetFolder( tr_torrent_t * );
|
||||
|
||||
int tr_torrentDuplicateDownload( tr_torrent_t * tor );
|
||||
const char * tr_torrentGetFolder( const tr_torrent_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentStart
|
||||
|
@ -377,7 +378,7 @@ tr_stat_t * tr_torrentStat( tr_torrent_t * );
|
|||
* tr_torrentPeers
|
||||
***********************************************************************/
|
||||
typedef struct tr_peer_stat_s tr_peer_stat_t;
|
||||
tr_peer_stat_t * tr_torrentPeers( tr_torrent_t *, int * peerCount );
|
||||
tr_peer_stat_t * tr_torrentPeers( const tr_torrent_t *, int * peerCount );
|
||||
void tr_torrentPeersFree( tr_peer_stat_t *, int peerCount );
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -388,9 +389,9 @@ void tr_torrentPeersFree( tr_peer_stat_t *, int peerCount );
|
|||
* to either -1 if we have the piece, otherwise it is set to the number
|
||||
* of connected peers who have the piece.
|
||||
**********************************************************************/
|
||||
void tr_torrentAvailability( tr_torrent_t *, int8_t * tab, int size );
|
||||
void tr_torrentAvailability( const tr_torrent_t *, int8_t * tab, int size );
|
||||
|
||||
void tr_torrentAmountFinished( tr_torrent_t * tor, float * tab, int size );
|
||||
void tr_torrentAmountFinished( const tr_torrent_t * tor, float * tab, int size );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentCompletion
|
||||
|
@ -414,13 +415,13 @@ uint64_t tr_torrentFileBytesCompleted( const tr_torrent_t *, int fileIndex );
|
|||
**********************************************************************/
|
||||
void tr_torrentRemoveSaved( tr_torrent_t * );
|
||||
|
||||
void tr_torrentRemoveFastResume( tr_torrent_t * tor );
|
||||
void tr_torrentRecheck( tr_torrent_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentClose
|
||||
***********************************************************************
|
||||
* Frees memory allocated by tr_torrentInit. If the torrent was running,
|
||||
* you must call tr_torrentStop() before closing it.
|
||||
* it is stopped first.
|
||||
**********************************************************************/
|
||||
void tr_torrentClose( tr_torrent_t * );
|
||||
|
||||
|
@ -459,6 +460,7 @@ struct tr_info_s
|
|||
/* Flags */
|
||||
#define TR_FLAG_SAVE 0x01 /* save a copy of the torrent file */
|
||||
#define TR_FLAG_PRIVATE 0x02 /* do not share information for this torrent */
|
||||
#define TR_FLAG_PAUSED 0x04 /* don't start the torrent when adding it */
|
||||
int flags;
|
||||
|
||||
/* Tracker info */
|
||||
|
@ -488,32 +490,38 @@ struct tr_info_s
|
|||
|
||||
typedef enum
|
||||
{
|
||||
TR_CP_COMPLETE, /* has every piece */
|
||||
TR_CP_DONE, /* has all the pieces but the DND ones */
|
||||
TR_CP_INCOMPLETE /* doesn't have all the desired pieces */
|
||||
TR_CP_INCOMPLETE, /* doesn't have all the desired pieces */
|
||||
TR_CP_DONE, /* has all the pieces but the DND ones */
|
||||
TR_CP_COMPLETE /* has every piece */
|
||||
}
|
||||
cp_status_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_STATUS_CHECK_WAIT = (1<<0), /* Waiting in queue to check files */
|
||||
TR_STATUS_CHECK = (1<<1), /* Checking files */
|
||||
TR_STATUS_DOWNLOAD = (1<<2), /* Downloading */
|
||||
TR_STATUS_DONE = (1<<3), /* not at 100% so can't tell the tracker
|
||||
we're a seeder, but due to DND files
|
||||
there's nothing we want right now */
|
||||
TR_STATUS_SEED = (1<<4), /* Seeding */
|
||||
TR_STATUS_STOPPING = (1<<5), /* Sending 'stopped' to the tracker */
|
||||
TR_STATUS_STOPPED = (1<<6) /* Sent 'stopped' but thread still
|
||||
running (for internal use only) */
|
||||
}
|
||||
torrent_status_t;
|
||||
|
||||
#define TR_STATUS_ACTIVE \
|
||||
(TR_STATUS_CHECK_WAIT|TR_STATUS_CHECK|TR_STATUS_DOWNLOAD|TR_STATUS_DONE|TR_STATUS_SEED)
|
||||
#define TR_STATUS_INACTIVE \
|
||||
(TR_STATUS_STOPPING|TR_STATUS_STOPPED)
|
||||
|
||||
/***********************************************************************
|
||||
* tr_stat_s
|
||||
**********************************************************************/
|
||||
struct tr_stat_s
|
||||
{
|
||||
#define TR_STATUS_CHECK_WAIT (1<<0) /* Waiting in queue to check files */
|
||||
#define TR_STATUS_CHECK (1<<1) /* Checking files */
|
||||
#define TR_STATUS_DOWNLOAD (1<<2) /* Downloading */
|
||||
#define TR_STATUS_DONE (1<<3) /* not at 100% so can't tell the tracker
|
||||
we're a seeder, but due to DND files
|
||||
there's nothing we want right now */
|
||||
#define TR_STATUS_SEED (1<<4) /* Seeding */
|
||||
#define TR_STATUS_STOPPING (1<<5) /* Sending 'stopped' to the tracker */
|
||||
#define TR_STATUS_STOPPED (1<<6) /* Sent 'stopped' but thread still
|
||||
running (for internal use only) */
|
||||
#define TR_STATUS_PAUSE (1<<7) /* Paused */
|
||||
|
||||
#define TR_STATUS_ACTIVE (TR_STATUS_CHECK_WAIT|TR_STATUS_CHECK|TR_STATUS_DOWNLOAD|TR_STATUS_DONE|TR_STATUS_SEED)
|
||||
#define TR_STATUS_INACTIVE (TR_STATUS_STOPPING|TR_STATUS_STOPPED|TR_STATUS_PAUSE)
|
||||
int status;
|
||||
torrent_status_t status;
|
||||
cp_status_t cpStatus;
|
||||
|
||||
int error;
|
||||
|
|
Loading…
Reference in New Issue