static int testMerge( void ) { tr_benc dest, src; int64_t i; const char * s; /* initial dictionary (default values) */ tr_bencInitDict( &dest, 10 ); tr_bencDictAddInt( &dest, "i1", 1 ); tr_bencDictAddInt( &dest, "i2", 2 ); tr_bencDictAddInt( &dest, "i4", -35 ); /* remains untouched */ tr_bencDictAddStr( &dest, "s5", "abc" ); tr_bencDictAddStr( &dest, "s6", "def" ); tr_bencDictAddStr( &dest, "s7", "127.0.0.1" ); /* remains untouched */ /* new dictionary, will overwrite items in dest */ tr_bencInitDict( &src, 10 ); tr_bencDictAddInt( &src, "i1", 1 ); /* same value */ tr_bencDictAddInt( &src, "i2", 4 ); /* new value */ tr_bencDictAddInt( &src, "i3", 3 ); /* new key:value */ tr_bencDictAddStr( &src, "s5", "abc" ); /* same value */ tr_bencDictAddStr( &src, "s6", "xyz" ); /* new value */ tr_bencDictAddStr( &src, "s8", "ghi" ); /* new key:value */ tr_bencMergeDicts( &dest, /*const*/ &src ); check( tr_bencDictFindInt( &dest, "i1", &i )); check_int_eq (1, i); check( tr_bencDictFindInt( &dest, "i2", &i )); check_int_eq (4, i); check( tr_bencDictFindInt( &dest, "i3", &i )); check_int_eq (3, i); check( tr_bencDictFindInt( &dest, "i4", &i )); check_int_eq (-35, i); check( tr_bencDictFindStr( &dest, "s5", &s )); check_streq ("abc", s); check( tr_bencDictFindStr( &dest, "s6", &s )); check_streq ("xyz", s); check( tr_bencDictFindStr( &dest, "s7", &s )); check_streq ("127.0.0.1", s); check( tr_bencDictFindStr( &dest, "s8", &s )); check_streq ("ghi", s); tr_bencFree( &dest ); tr_bencFree( &src ); return 0; }
const char* gtr_pref_string_get( const char * key ) { const char * str = NULL; tr_bencDictFindStr( getPrefs( ), key, &str ); return str; }
int tr_ctorSetMetainfoFromFile( tr_ctor * ctor, const char * filename ) { uint8_t * metainfo; size_t len; int err; metainfo = tr_loadFile( filename, &len ); if( metainfo && len ) err = tr_ctorSetMetainfo( ctor, metainfo, len ); else { clearMetainfo( ctor ); err = 1; } setSourceFile( ctor, filename ); /* if no `name' field was set, then set it from the filename */ if( ctor->isSet_metainfo ) { tr_benc * info; if( tr_bencDictFindDict( &ctor->metainfo, "info", &info ) ) { const char * name; if( !tr_bencDictFindStr( info, "name.utf-8", &name ) ) if( !tr_bencDictFindStr( info, "name", &name ) ) name = NULL; if( !name || !*name ) { char * base = tr_basename( filename ); tr_bencDictAddStr( info, "name", base ); tr_free( base ); } } } tr_free( metainfo ); return err; }
static tr_bool addURL( tr_benc * metainfo, const char * url ) { const char * str; tr_benc * announce_list; tr_bool changed = FALSE; tr_bool match = FALSE; /* maybe add it to "announce" */ if( !tr_bencDictFindStr( metainfo, "announce", &str ) ) { printf( "\tAdded \"%s\" in \"announce\"\n", url ); tr_bencDictAddStr( metainfo, "announce", url ); changed = TRUE; } /* see if it's already in announce-list */ if( tr_bencDictFindList( metainfo, "announce-list", &announce_list ) ) { tr_benc * tier; int tierCount = 0; while(( tier = tr_bencListChild( announce_list, tierCount++ ))) { tr_benc * node; int nodeCount = 0; while(( node = tr_bencListChild( tier, nodeCount++ ))) if( tr_bencGetStr( node, &str ) && !strcmp( str, url ) ) match = TRUE; } } /* if it's not in announce-list, add it now */ if( !match ) { tr_benc * tier; if( !tr_bencDictFindList( metainfo, "announce-list", &announce_list ) ) announce_list = tr_bencDictAddList( metainfo, "announce-list", 1 ); tier = tr_bencListAddList( announce_list, 1 ); tr_bencListAddStr( tier, url ); printf( "\tAdded \"%s\" to \"announce-list\" tier %zu\n", url, tr_bencListSize( announce_list ) ); changed = TRUE; } return changed; }
static bool addURL (tr_benc * metainfo, const char * url) { const char * announce = NULL; tr_benc * announce_list = NULL; bool changed = false; const bool had_announce = tr_bencDictFindStr (metainfo, "announce", &announce); const bool had_announce_list = tr_bencDictFindList (metainfo, "announce-list", &announce_list); if (!had_announce && !had_announce_list) { /* this new tracker is the only one, so add it to "announce"... */ printf ("\tAdded \"%s\" in \"announce\"\n", url); tr_bencDictAddStr (metainfo, "announce", url); changed = true; } else { if (!had_announce_list) { announce_list = tr_bencDictAddList (metainfo, "announce-list", 2); if (had_announce) { /* we're moving from an 'announce' to an 'announce-list', * so copy the old announce URL to the list */ tr_benc * tier = tr_bencListAddList (announce_list, 1); tr_bencListAddStr (tier, announce); changed = true; } } /* If the user-specified URL isn't in the announce list yet, add it */ if (!announce_list_has_url (announce_list, url)) { tr_benc * tier = tr_bencListAddList (announce_list, 1); tr_bencListAddStr (tier, url); printf ("\tAdded \"%s\" to \"announce-list\" tier %zu\n", url, tr_bencListSize (announce_list)); changed = true; } } return changed; }
static bool replaceURL (tr_benc * metainfo, const char * in, const char * out) { const char * str; tr_benc * announce_list; bool changed = false; if (tr_bencDictFindStr (metainfo, "announce", &str) && strstr (str, in)) { char * newstr = replaceSubstr (str, in, out); printf ("\tReplaced in \"announce\": \"%s\" --> \"%s\"\n", str, newstr); tr_bencDictAddStr (metainfo, "announce", newstr); tr_free (newstr); changed = true; } if (tr_bencDictFindList (metainfo, "announce-list", &announce_list)) { tr_benc * tier; int tierCount = 0; while ((tier = tr_bencListChild (announce_list, tierCount++))) { tr_benc * node; int nodeCount = 0; while ((node = tr_bencListChild (tier, nodeCount++))) { if (tr_bencGetStr (node, &str) && strstr (str, in)) { char * newstr = replaceSubstr (str, in, out); printf ("\tReplaced in \"announce-list\" tier %d: \"%s\" --> \"%s\"\n", tierCount, str, newstr); tr_bencFree (node); tr_bencInitStr (node, newstr, -1); tr_free (newstr); changed = true; } } } } return changed; }
/* Convert to compact form */ static uint8_t * parseOldPeers( tr_benc * bePeers, size_t * byteCount ) { int i; uint8_t * compact, *walk; const int peerCount = bePeers->val.l.count; assert( bePeers->type == TYPE_LIST ); compact = tr_new( uint8_t, peerCount * 6 ); for( i = 0, walk = compact; i < peerCount; ++i ) { const char * s; int64_t itmp; struct in_addr addr; tr_port_t port; tr_benc * peer = &bePeers->val.l.vals[i]; if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) ) continue; memcpy( walk, &addr, 4 ); walk += 4; if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp < 0 || itmp > 0xffff ) continue; port = htons( itmp ); memcpy( walk, &port, 2 ); walk += 2; } *byteCount = peerCount * 6; return compact; }
static int testParse2( void ) { tr_benc top; tr_benc top2; int64_t intVal; const char * strVal; double realVal; bool boolVal; int len; char * benc; const uint8_t * end; tr_bencInitDict( &top, 0 ); tr_bencDictAddBool( &top, "this-is-a-bool", true ); tr_bencDictAddInt( &top, "this-is-an-int", 1234 ); tr_bencDictAddReal( &top, "this-is-a-real", 0.5 ); tr_bencDictAddStr( &top, "this-is-a-string", "this-is-a-string" ); benc = tr_bencToStr( &top, TR_FMT_BENC, &len ); check_streq( "d14:this-is-a-booli1e14:this-is-a-real8:0.50000016:this-is-a-string16:this-is-a-string14:this-is-an-inti1234ee", benc ); check( !tr_bencParse( benc, benc+len, &top2, &end ) ); check( (char*)end == benc + len ); check( tr_bencIsDict( &top2 ) ); check( tr_bencDictFindInt( &top, "this-is-an-int", &intVal ) ); check_int_eq (1234, intVal); check( tr_bencDictFindBool( &top, "this-is-a-bool", &boolVal ) ); check( boolVal == true ); check( tr_bencDictFindStr( &top, "this-is-a-string", &strVal ) ); check_streq ("this-is-a-string", strVal); check( tr_bencDictFindReal( &top, "this-is-a-real", &realVal ) ); check_int_eq (50, (int)(realVal*100)); tr_bencFree( &top2 ); tr_free( benc ); tr_bencFree( &top ); return 0; }
static tr_pex* listToPex( tr_benc * peerList, size_t * setme_len ) { size_t i; size_t n; const size_t len = tr_bencListSize( peerList ); tr_pex * pex = tr_new0( tr_pex, len ); for( i=n=0; i<len; ++i ) { int64_t port; const char * ip; tr_address addr; tr_benc * peer = tr_bencListChild( peerList, i ); if( peer == NULL ) continue; if( !tr_bencDictFindStr( peer, "ip", &ip ) ) continue; if( !tr_address_from_string( &addr, ip ) ) continue; if( !tr_bencDictFindInt( peer, "port", &port ) ) continue; if( ( port < 0 ) || ( port > USHRT_MAX ) ) continue; if( !tr_address_is_valid_for_peers( &addr, port ) ) continue; pex[n].addr = addr; pex[n].port = htons( (uint16_t)port ); ++n; } *setme_len = n; return pex; }
static bool removeURL (tr_benc * metainfo, const char * url) { const char * str; tr_benc * announce_list; bool changed = false; if (tr_bencDictFindStr (metainfo, "announce", &str) && !strcmp (str, url)) { printf ("\tRemoved \"%s\" from \"announce\"\n", str); tr_bencDictRemove (metainfo, "announce"); changed = true; } if (tr_bencDictFindList (metainfo, "announce-list", &announce_list)) { tr_benc * tier; int tierIndex = 0; while ((tier = tr_bencListChild (announce_list, tierIndex))) { tr_benc * node; int nodeIndex = 0; while ((node = tr_bencListChild (tier, nodeIndex))) { if (tr_bencGetStr (node, &str) && !strcmp (str, url)) { printf ("\tRemoved \"%s\" from \"announce-list\" tier #%d\n", str, (tierIndex+1)); tr_bencListRemove (tier, nodeIndex); changed = true; } else ++nodeIndex; } if (tr_bencListSize (tier) == 0) { printf ("\tNo URLs left in tier #%d... removing tier\n", (tierIndex+1)); tr_bencListRemove (announce_list, tierIndex); } else { ++tierIndex; } } if (tr_bencListSize (announce_list) == 0) { printf ("\tNo tiers left... removing announce-list\n"); tr_bencDictRemove (metainfo, "announce-list"); } } /* if we removed the "announce" field and there's still another track left, * use it as the "announce" field */ if (changed && !tr_bencDictFindStr (metainfo, "announce", &str)) { tr_benc * tier; tr_benc * node; if ((tier = tr_bencListChild (announce_list, 0))) { if ((node = tr_bencListChild (tier, 0))) { if (tr_bencGetStr (node, &str)) { tr_bencDictAddStr (metainfo, "announce", str); printf ("\tAdded \"%s\" to announce\n", str); } } } } return changed; }
static uint64_t loadProgress( tr_benc * dict, tr_torrent * tor ) { size_t i, n; uint64_t ret = 0; tr_benc * prog; const tr_info * inf = tr_torrentInfo( tor ); for( i=0, n=inf->pieceCount; i<n; ++i ) inf->pieces[i].timeChecked = 0; if( tr_bencDictFindDict( dict, KEY_PROGRESS, &prog ) ) { const char * err; const char * str; const uint8_t * raw; size_t rawlen; tr_benc * l; tr_benc * b; struct tr_bitset bitset = TR_BITSET_INIT; if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) ) { /* per-piece timestamps were added in 2.20. If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ tr_file_index_t fi; for( fi=0; fi<inf->fileCount; ++fi ) { tr_benc * b = tr_bencListChild( l, fi ); const tr_file * f = &inf->files[fi]; tr_piece * p = &inf->pieces[f->firstPiece]; const tr_piece * pend = &inf->pieces[f->lastPiece]+1; if( tr_bencIsInt( b ) ) { int64_t t; tr_bencGetInt( b, &t ); for( ; p!=pend; ++p ) p->timeChecked = (time_t)t; } else if( tr_bencIsList( b ) ) { int i = 0; int64_t offset = 0; const int pieces = f->lastPiece + 1 - f->firstPiece; tr_bencGetInt( tr_bencListChild( b, 0 ), &offset ); for( i=0; i<pieces; ++i ) { int64_t t = 0; tr_bencGetInt( tr_bencListChild( b, i+1 ), &t ); inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0); } } } } else if( tr_bencDictFindList( prog, KEY_PROGRESS_MTIMES, &l ) ) { tr_file_index_t fi; /* Before 2.20, we stored the files' mtimes in the .resume file. When loading the .resume file, a torrent's file would be flagged as untested if its stored mtime didn't match its real mtime. */ for( fi=0; fi<inf->fileCount; ++fi ) { int64_t t; if( tr_bencGetInt( tr_bencListChild( l, fi ), &t ) ) { const tr_file * f = &inf->files[fi]; tr_piece * p = &inf->pieces[f->firstPiece]; const tr_piece * pend = &inf->pieces[f->lastPiece]; const time_t mtime = tr_torrentGetFileMTime( tor, fi ); const time_t timeChecked = mtime==t ? mtime : 0; for( ; p!=pend; ++p ) p->timeChecked = timeChecked; } } } err = NULL; if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS ))) { if( !tr_bitsetFromBenc( &bitset, b ) ) err = "Invalid value for PIECES"; } else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) ) { if( !strcmp( str, "all" ) ) tr_bitsetSetHaveAll( &bitset ); else err = "Invalid value for HAVE"; } else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) ) { bitset.bitfield.bits = (void*) raw; bitset.bitfield.byteCount = rawlen; bitset.bitfield.bitCount = rawlen * 8; } else err = "Couldn't find 'pieces' or 'have' or 'bitfield'"; if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) ) err = "Error loading bitfield"; if( err != NULL ) tr_tordbg( tor, "Torrent needs to be verified - %s", err ); ret = TR_FR_PROGRESS; } return ret; }
static const char* getannounce( tr_info * inf, tr_benc * meta ) { const char * str; tr_tracker_info * trackers = NULL; int trackerCount = 0; tr_benc * tiers; /* Announce-list */ if( tr_bencDictFindList( meta, "announce-list", &tiers ) ) { int n; int i, j, validTiers; const int numTiers = tr_bencListSize( tiers ); n = 0; for( i = 0; i < numTiers; ++i ) n += tr_bencListSize( tr_bencListChild( tiers, i ) ); trackers = tr_new0( tr_tracker_info, n ); for( i = 0, validTiers = 0; i < numTiers; ++i ) { tr_benc * tier = tr_bencListChild( tiers, i ); const int tierSize = tr_bencListSize( tier ); tr_bool anyAdded = FALSE; for( j = 0; j < tierSize; ++j ) { if( tr_bencGetStr( tr_bencListChild( tier, j ), &str ) ) { char * url = tr_strstrip( tr_strdup( str ) ); if( tr_urlIsValidTracker( url ) ) { tr_tracker_info * t = trackers + trackerCount; t->tier = validTiers; t->announce = tr_strdup( url ); t->scrape = tr_convertAnnounceToScrape( url ); t->id = trackerCount; anyAdded = TRUE; ++trackerCount; } tr_free( url ); } } if( anyAdded ) ++validTiers; } /* did we use any of the tiers? */ if( !trackerCount ) { tr_free( trackers ); trackers = NULL; } } /* Regular announce value */ if( !trackerCount && tr_bencDictFindStr( meta, "announce", &str ) ) { char * url = tr_strstrip( tr_strdup( str ) ); if( tr_urlIsValidTracker( url ) ) { trackers = tr_new0( tr_tracker_info, 1 ); trackers[trackerCount].tier = 0; trackers[trackerCount].announce = tr_strdup( url ); trackers[trackerCount].scrape = tr_convertAnnounceToScrape( url ); trackers[trackerCount].id = 0; trackerCount++; /*fprintf( stderr, "single announce: [%s]\n", url );*/ } tr_free( url ); } inf->trackers = trackers; inf->trackerCount = trackerCount; return NULL; }
static uint64_t loadFromFile( tr_torrent * tor, uint64_t fieldsToLoad ) { int64_t i; const char * str; uint64_t fieldsLoaded = 0; char * filename; tr_benc top; filename = getResumeFilename( tor ); if( tr_bencLoadFile( filename, &top ) ) { tr_tordbg( tor, "Couldn't read \"%s\"; trying old format.", filename ); fieldsLoaded = tr_fastResumeLoad( tor, fieldsToLoad ); if( ( fieldsLoaded != 0 ) && ( fieldsToLoad == ~(uint64_t)0 ) ) { tr_torrentSaveResume( tor ); tr_fastResumeRemove( tor ); tr_tordbg( tor, "Migrated resume file to \"%s\"", filename ); } tr_free( filename ); return fieldsLoaded; } tr_tordbg( tor, "Read resume file \"%s\"", filename ); if( ( fieldsToLoad & TR_FR_CORRUPT ) && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) ) { tor->corruptPrev = i; fieldsLoaded |= TR_FR_CORRUPT; } if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) ) && tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) ) { tr_free( tor->downloadDir ); tor->downloadDir = tr_strdup( str ); fieldsLoaded |= TR_FR_DOWNLOAD_DIR; } if( ( fieldsToLoad & TR_FR_DOWNLOADED ) && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) ) { tor->downloadedPrev = i; fieldsLoaded |= TR_FR_DOWNLOADED; } if( ( fieldsToLoad & TR_FR_UPLOADED ) && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) ) { tor->uploadedPrev = i; fieldsLoaded |= TR_FR_UPLOADED; } if( ( fieldsToLoad & TR_FR_MAX_PEERS ) && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) ) { tor->maxConnectedPeers = i; fieldsLoaded |= TR_FR_MAX_PEERS; } if( ( fieldsToLoad & TR_FR_RUN ) && tr_bencDictFindInt( &top, KEY_PAUSED, &i ) ) { tor->isRunning = i ? 0 : 1; fieldsLoaded |= TR_FR_RUN; } if( ( fieldsToLoad & TR_FR_ADDED_DATE ) && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) ) { tor->addedDate = i; fieldsLoaded |= TR_FR_ADDED_DATE; } if( ( fieldsToLoad & TR_FR_DONE_DATE ) && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) ) { tor->doneDate = i; fieldsLoaded |= TR_FR_DONE_DATE; } if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE ) && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) ) { tor->activityDate = i; fieldsLoaded |= TR_FR_ACTIVITY_DATE; } if( fieldsToLoad & TR_FR_PEERS ) fieldsLoaded |= loadPeers( &top, tor ); if( fieldsToLoad & TR_FR_PRIORITY ) fieldsLoaded |= loadPriorities( &top, tor ); if( fieldsToLoad & TR_FR_PROGRESS ) fieldsLoaded |= loadProgress( &top, tor ); if( fieldsToLoad & TR_FR_DND ) fieldsLoaded |= loadDND( &top, tor ); if( fieldsToLoad & TR_FR_SPEEDLIMIT ) fieldsLoaded |= loadSpeedLimits( &top, tor ); tr_bencFree( &top ); tr_free( filename ); return fieldsLoaded; }
static const char* getannounce( tr_info * inf, tr_benc * meta ) { const char * str; tr_tracker_info * trackers = NULL; int trackerCount = 0; tr_benc * tiers; /* Announce-list */ if( tr_bencDictFindList( meta, "announce-list", &tiers ) ) { int n; int i, j; const int numTiers = tr_bencListSize( tiers ); n = 0; for( i = 0; i < numTiers; ++i ) n += tr_bencListSize( tr_bencListChild( tiers, i ) ); trackers = tr_new0( tr_tracker_info, n ); trackerCount = 0; for( i = 0; i < numTiers; ++i ) { tr_benc * tier = tr_bencListChild( tiers, i ); const int tierSize = tr_bencListSize( tier ); for( j = 0; j < tierSize; ++j ) { if( tr_bencGetStr( tr_bencListChild( tier, j ), &str ) ) { char * url = tr_strstrip( tr_strdup( str ) ); if( tr_httpIsValidURL( url ) ) { tr_tracker_info * t = trackers + trackerCount++; t->tier = i; t->announce = tr_strdup( url ); t->scrape = announceToScrape( url ); } tr_free( url ); } } } /* did we use any of the tiers? */ if( !trackerCount ) { tr_free( trackers ); trackers = NULL; } } /* Regular announce value */ if( !trackerCount && tr_bencDictFindStr( meta, "announce", &str ) ) { char * url = tr_strstrip( tr_strdup( str ) ); if( tr_httpIsValidURL( url ) ) { trackers = tr_new0( tr_tracker_info, 1 ); trackers[trackerCount].tier = 0; trackers[trackerCount].announce = tr_strdup( url ); trackers[trackerCount++].scrape = announceToScrape( url ); /*fprintf( stderr, "single announce: [%s]\n", url );*/ } tr_free( url ); } inf->trackers = trackers; inf->trackerCount = trackerCount; return inf->trackerCount ? NULL : "announce"; }
static void on_announce_done( tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata ) { tr_announce_response * response; struct announce_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg( data->log_name, "Got announce response" ); if( response_code != HTTP_OK ) { const char * fmt = _( "Tracker gave HTTP response code %1$ld (%2$s)" ); const char * response_str = tr_webGetResponseStr( response_code ); response->errmsg = tr_strdup_printf( fmt, response_code, response_str ); } else { tr_benc benc; const int benc_loaded = !tr_bencLoad( msg, msglen, &benc, NULL ); if( getenv( "TR_CURL_VERBOSE" ) != NULL ) { struct evbuffer * buf = tr_bencToBuf( &benc, TR_FMT_JSON ); fprintf( stderr, "Announce response:\n< %s\n", evbuffer_pullup( buf, -1 ) ); tr_free( buf ); } if( benc_loaded && tr_bencIsDict( &benc ) ) { int64_t i; size_t rawlen; tr_benc * tmp; const char * str; const uint8_t * raw; if( tr_bencDictFindStr( &benc, "failure reason", &str ) ) response->errmsg = tr_strdup( str ); if( tr_bencDictFindStr( &benc, "warning message", &str ) ) response->warning = tr_strdup( str ); if( tr_bencDictFindInt( &benc, "interval", &i ) ) response->interval = i; if( tr_bencDictFindInt( &benc, "min interval", &i ) ) response->min_interval = i; if( tr_bencDictFindStr( &benc, "tracker id", &str ) ) response->tracker_id_str = tr_strdup( str ); if( tr_bencDictFindInt( &benc, "complete", &i ) ) response->seeders = i; if( tr_bencDictFindInt( &benc, "incomplete", &i ) ) response->leechers = i; if( tr_bencDictFindInt( &benc, "downloaded", &i ) ) response->downloads = i; if( tr_bencDictFindRaw( &benc, "peers6", &raw, &rawlen ) ) { dbgmsg( data->log_name, "got a peers6 length of %zu", rawlen ); response->pex6 = tr_peerMgrCompact6ToPex( raw, rawlen, NULL, 0, &response->pex6_count ); } if( tr_bencDictFindRaw( &benc, "peers", &raw, &rawlen ) ) { dbgmsg( data->log_name, "got a compact peers length of %zu", rawlen ); response->pex = tr_peerMgrCompactToPex( raw, rawlen, NULL, 0, &response->pex_count ); } else if( tr_bencDictFindList( &benc, "peers", &tmp ) ) { response->pex = listToPex( tmp, &response->pex_count ); dbgmsg( data->log_name, "got a peers list with %zu entries", response->pex_count ); } } if( benc_loaded ) tr_bencFree( &benc ); } tr_runInEventThread( session, on_announce_done_eventthread, data ); }
static void on_scrape_done( tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata ) { tr_scrape_response * response; struct scrape_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg( data->log_name, "Got scrape response for \"%s\"", response->url ); if( response_code != HTTP_OK ) { const char * fmt = _( "Tracker gave HTTP response code %1$ld (%2$s)" ); const char * response_str = tr_webGetResponseStr( response_code ); response->errmsg = tr_strdup_printf( fmt, response_code, response_str ); } else { tr_benc top; int64_t intVal; tr_benc * files; const char * str; const int benc_loaded = !tr_bencLoad( msg, msglen, &top, NULL ); if( benc_loaded ) { if( tr_bencDictFindStr( &top, "failure reason", &str ) ) response->errmsg = tr_strdup( str ); if( tr_bencDictFindInt( &top, "min_request_interval", &intVal ) ) response->min_request_interval = intVal; if( tr_bencDictFindDict( &top, "files", &files ) ) { int i = 0; for( ;; ) { int j; tr_benc * val; const char * key; /* get the next "file" */ if( !tr_bencDictChild( files, i++, &key, &val ) ) break; /* populate the corresponding row in our response array */ for( j=0; j<response->row_count; ++j ) { struct tr_scrape_response_row * row = &response->rows[j]; if( !memcmp( key, row->info_hash, SHA_DIGEST_LENGTH ) ) { if( tr_bencDictFindInt( val, "complete", &intVal ) ) row->seeders = intVal; if( tr_bencDictFindInt( val, "incomplete", &intVal ) ) row->leechers = intVal; if( tr_bencDictFindInt( val, "downloaded", &intVal ) ) row->downloads = intVal; if( tr_bencDictFindInt( val, "downloaders", &intVal ) ) row->downloaders = intVal; break; } } } } tr_bencFree( &top ); } } tr_runInEventThread( session, on_scrape_done_eventthread, data ); }
static void tr_sessionInitImpl( void * vdata ) { int64_t i; int64_t j; double d; tr_bool found; const char * str; tr_benc settings; char * filename; struct init_data * data = vdata; tr_benc * clientSettings = data->clientSettings; tr_session * session = data->session; assert( tr_amInEventThread( session ) ); assert( tr_bencIsDict( clientSettings ) ); dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth ); tr_bencInitDict( &settings, 0 ); tr_sessionGetDefaultSettings( &settings ); tr_bencMergeDicts( &settings, clientSettings ); #ifndef WIN32 /* Don't exit when writing on a broken socket */ signal( SIGPIPE, SIG_IGN ); #endif found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ); assert( found ); session->peerLimitPerTorrent = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i ); assert( found ); tr_setMessageLevel( i ); tr_setMessageQueuing( data->messageQueuingEnabled ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEX_ENABLED, &i ); assert( found ); session->isPexEnabled = i != 0; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i ); assert( found ); assert( tr_isEncryptionMode( i ) ); session->encryptionMode = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i ); assert( found ); assert( tr_isPreallocationMode( i ) ); session->preallocationMode = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i ); assert( found ); session->peerSocketTOS = i; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ); assert( found ); session->downloadDir = tr_strdup( str ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_ENABLED, &i ); assert( found ); session->isProxyEnabled = i != 0; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str ); assert( found ); session->proxy = tr_strdup( str ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i ); assert( found ); session->proxyPort = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i ); assert( found ); session->proxyType = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &i ); assert( found ); session->isProxyAuthEnabled = i != 0; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str ); assert( found ); session->proxyUsername = tr_strdup( str ); found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str ); assert( found ); session->proxyPassword = tr_strdup( str ); session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */ session->so_rcvbuf = 8192; tr_setConfigDir( session, data->configDir ); tr_trackerSessionInit( session ); assert( session->tracker != NULL ); session->peerMgr = tr_peerMgrNew( session ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &i ); assert( found ); session->useLazyBitfield = i != 0; /* Initialize rate and file descripts controls */ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i ); assert( found ); session->openFileLimit = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j ); assert( found ); tr_fdInit( session->openFileLimit, j ); /** *** random port **/ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, &i ); assert( found ); session->isPortRandom = i != 0; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ); assert( found ); session->randomPortLow = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ); assert( found ); session->randomPortHigh = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PORT_FORWARDING, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j ); assert( found ); session->peerPort = session->isPortRandom ? getRandomPort( session ) : j; session->shared = tr_sharedInit( session, i, session->peerPort ); session->isPortSet = session->isPortRandom || j>0; /** **/ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i ); assert( found ); session->uploadSlotsPerTorrent = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED_ENABLED, &j ); assert( found ); tr_sessionSetSpeedLimit( session, TR_UP, i ); tr_sessionSetSpeedLimitEnabled( session, TR_UP, j ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &j ); assert( found ); tr_sessionSetSpeedLimit( session, TR_DOWN, i ); tr_sessionSetSpeedLimitEnabled( session, TR_DOWN, j ); found = tr_bencDictFindDouble( &settings, TR_PREFS_KEY_RATIO, &d ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_RATIO_ENABLED, &j ); assert( found ); tr_sessionSetRatioLimit( session, d ); tr_sessionSetRatioLimited( session, j ); /* initialize the blocklist */ filename = tr_buildPath( session->configDir, "blocklists", NULL ); tr_mkdirp( filename, 0777 ); tr_free( filename ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &i ); assert( found ); session->isBlocklistEnabled = i; loadBlocklists( session ); session->rpcServer = tr_rpcInit( session, &settings ); tr_bencFree( &settings ); assert( tr_isSession( session ) ); /* first %s is the application name second %s is the version number */ tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING ); tr_statsInit( session ); session->web = tr_webInit( session ); metainfoLookupRescan( session ); session->isWaiting = FALSE; dbgmsg( "returning session %p; session->tracker is %p", session, session->tracker ); }
static uint64_t loadFromFile( tr_torrent * tor, uint64_t fieldsToLoad ) { int64_t i; const char * str; uint64_t fieldsLoaded = 0; char * filename; tr_benc top; tr_bool boolVal; const tr_bool wasDirty = tor->isDirty; assert( tr_isTorrent( tor ) ); filename = getResumeFilename( tor ); if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) ) { tr_tordbg( tor, "Couldn't read \"%s\"", filename ); tr_free( filename ); return fieldsLoaded; } tr_tordbg( tor, "Read resume file \"%s\"", filename ); if( ( fieldsToLoad & TR_FR_CORRUPT ) && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) ) { tor->corruptPrev = i; fieldsLoaded |= TR_FR_CORRUPT; } if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) ) && ( tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) ) && ( str && *str ) ) { tr_free( tor->downloadDir ); tor->downloadDir = tr_strdup( str ); fieldsLoaded |= TR_FR_DOWNLOAD_DIR; } if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) ) && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) ) && ( str && *str ) ) { tr_free( tor->incompleteDir ); tor->incompleteDir = tr_strdup( str ); fieldsLoaded |= TR_FR_INCOMPLETE_DIR; } if( ( fieldsToLoad & TR_FR_DOWNLOADED ) && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) ) { tor->downloadedPrev = i; fieldsLoaded |= TR_FR_DOWNLOADED; } if( ( fieldsToLoad & TR_FR_UPLOADED ) && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) ) { tor->uploadedPrev = i; fieldsLoaded |= TR_FR_UPLOADED; } if( ( fieldsToLoad & TR_FR_MAX_PEERS ) && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) ) { tor->maxConnectedPeers = i; fieldsLoaded |= TR_FR_MAX_PEERS; } if( ( fieldsToLoad & TR_FR_RUN ) && tr_bencDictFindBool( &top, KEY_PAUSED, &boolVal ) ) { tor->isRunning = !boolVal; fieldsLoaded |= TR_FR_RUN; } if( ( fieldsToLoad & TR_FR_ADDED_DATE ) && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) ) { tor->addedDate = i; fieldsLoaded |= TR_FR_ADDED_DATE; } if( ( fieldsToLoad & TR_FR_DONE_DATE ) && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) ) { tor->doneDate = i; fieldsLoaded |= TR_FR_DONE_DATE; } if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE ) && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) ) { tr_torrentSetActivityDate( tor, i ); fieldsLoaded |= TR_FR_ACTIVITY_DATE; } if( ( fieldsToLoad & TR_FR_TIME_SEEDING ) && tr_bencDictFindInt( &top, KEY_TIME_SEEDING, &i ) ) { tor->secondsSeeding = i; fieldsLoaded |= TR_FR_TIME_SEEDING; } if( ( fieldsToLoad & TR_FR_TIME_DOWNLOADING ) && tr_bencDictFindInt( &top, KEY_TIME_DOWNLOADING, &i ) ) { tor->secondsDownloading = i; fieldsLoaded |= TR_FR_TIME_DOWNLOADING; } if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY ) && tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i ) && tr_isPriority( i ) ) { tr_torrentSetPriority( tor, i ); fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY; } if( fieldsToLoad & TR_FR_PEERS ) fieldsLoaded |= loadPeers( &top, tor ); if( fieldsToLoad & TR_FR_FILE_PRIORITIES ) fieldsLoaded |= loadFilePriorities( &top, tor ); if( fieldsToLoad & TR_FR_PROGRESS ) fieldsLoaded |= loadProgress( &top, tor ); if( fieldsToLoad & TR_FR_DND ) fieldsLoaded |= loadDND( &top, tor ); if( fieldsToLoad & TR_FR_SPEEDLIMIT ) fieldsLoaded |= loadSpeedLimits( &top, tor ); if( fieldsToLoad & TR_FR_RATIOLIMIT ) fieldsLoaded |= loadRatioLimits( &top, tor ); if( fieldsToLoad & TR_FR_IDLELIMIT ) fieldsLoaded |= loadIdleLimits( &top, tor ); /* loading the resume file triggers of a lot of changes, * but none of them needs to trigger a re-saving of the * same resume information... */ tor->isDirty = wasDirty; tr_bencFree( &top ); tr_free( filename ); return fieldsLoaded; }
int main( int argc, char ** argv ) { int c; const char * optarg; tr_benc settings; tr_bool boolVal; tr_bool loaded; tr_bool foreground = FALSE; tr_bool dumpSettings = FALSE; const char * configDir = NULL; const char * pid_filename; dtr_watchdir * watchdir = NULL; FILE * logfile = NULL; tr_bool pidfile_created = FALSE; signal( SIGINT, gotsig ); signal( SIGTERM, gotsig ); #ifndef WIN32 signal( SIGHUP, gotsig ); #endif /* load settings from defaults + config file */ tr_bencInitDict( &settings, 0 ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_ENABLED, TRUE ); configDir = getConfigDir( argc, (const char**)argv ); loaded = tr_sessionLoadSettings( &settings, configDir, MY_NAME ); /* overwrite settings from the comamndline */ tr_optind = 1; while(( c = tr_getopt( getUsage(), argc, (const char**)argv, options, &optarg ))) { switch( c ) { case 'a': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_WHITELIST, optarg ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, TRUE ); break; case 'b': tr_bencDictAddBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, TRUE ); break; case 'B': tr_bencDictAddBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE ); break; case 'c': tr_bencDictAddStr( &settings, PREF_KEY_DIR_WATCH, optarg ); tr_bencDictAddBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, TRUE ); break; case 'C': tr_bencDictAddBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, FALSE ); break; case 941: tr_bencDictAddStr( &settings, TR_PREFS_KEY_INCOMPLETE_DIR, optarg ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, TRUE ); break; case 942: tr_bencDictAddBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, FALSE ); break; case 'd': dumpSettings = TRUE; break; case 'e': logfile = fopen( optarg, "a+" ); if( logfile == NULL ) fprintf( stderr, "Couldn't open \"%s\": %s\n", optarg, tr_strerror( errno ) ); break; case 'f': foreground = TRUE; break; case 'g': /* handled above */ break; case 'V': /* version */ fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING); exit( 0 ); case 'o': tr_bencDictAddBool( &settings, TR_PREFS_KEY_DHT_ENABLED, TRUE ); break; case 'O': tr_bencDictAddBool( &settings, TR_PREFS_KEY_DHT_ENABLED, FALSE ); break; case 'p': tr_bencDictAddInt( &settings, TR_PREFS_KEY_RPC_PORT, atoi( optarg ) ); break; case 't': tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, TRUE ); break; case 'T': tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, FALSE ); break; case 'u': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_USERNAME, optarg ); break; case 'v': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_PASSWORD, optarg ); break; case 'w': tr_bencDictAddStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, optarg ); break; case 'P': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_PORT, atoi( optarg ) ); break; case 'm': tr_bencDictAddBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, TRUE ); break; case 'M': tr_bencDictAddBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, FALSE ); break; case 'L': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, atoi( optarg ) ); break; case 'l': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, atoi( optarg ) ); break; case 800: paused = TRUE; break; case 910: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_REQUIRED ); break; case 911: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_PREFERRED ); break; case 912: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_CLEAR_PREFERRED ); break; case 'i': tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, optarg ); break; case 'I': tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, optarg ); break; case 'r': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_BIND_ADDRESS, optarg ); break; case 953: tr_bencDictAddReal( &settings, TR_PREFS_KEY_RATIO, atof(optarg) ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, TRUE ); break; case 954: tr_bencDictAddBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, FALSE ); break; case 'x': tr_bencDictAddStr( &settings, PREF_KEY_PIDFILE, optarg ); break; case 'y': tr_bencDictAddBool( &settings, TR_PREFS_KEY_LPD_ENABLED, TRUE ); break; case 'Y': tr_bencDictAddBool( &settings, TR_PREFS_KEY_LPD_ENABLED, FALSE ); break; case 810: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_ERR ); break; case 811: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_INF ); break; case 812: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_DBG ); break; default: showUsage( ); break; } } if( foreground && !logfile ) logfile = stderr; if( !loaded ) { printMessage( logfile, TR_MSG_ERR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__ ); return -1; } if( dumpSettings ) { char * str = tr_bencToStr( &settings, TR_FMT_JSON, NULL ); fprintf( stderr, "%s", str ); tr_free( str ); return 0; } if( !foreground && tr_daemon( TRUE, FALSE ) < 0 ) { char buf[256]; tr_snprintf( buf, sizeof( buf ), "Failed to daemonize: %s", tr_strerror( errno ) ); printMessage( logfile, TR_MSG_ERR, MY_NAME, buf, __FILE__, __LINE__ ); exit( 1 ); } /* start the session */ tr_formatter_mem_init( MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR ); tr_formatter_size_init( DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR ); tr_formatter_speed_init( SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR ); mySession = tr_sessionInit( "daemon", configDir, TRUE, &settings ); tr_ninf( NULL, "Using settings from \"%s\"", configDir ); tr_sessionSaveSettings( mySession, configDir, &settings ); pid_filename = NULL; tr_bencDictFindStr( &settings, PREF_KEY_PIDFILE, &pid_filename ); if( pid_filename && *pid_filename ) { FILE * fp = fopen( pid_filename, "w+" ); if( fp != NULL ) { fprintf( fp, "%d", (int)getpid() ); fclose( fp ); tr_inf( "Saved pidfile \"%s\"", pid_filename ); pidfile_created = TRUE; } else tr_err( "Unable to save pidfile \"%s\": %s", pid_filename, strerror( errno ) ); } if( tr_bencDictFindBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, &boolVal ) && boolVal ) tr_ninf( MY_NAME, "requiring authentication" ); /* maybe add a watchdir */ { const char * dir; if( tr_bencDictFindBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, &boolVal ) && boolVal && tr_bencDictFindStr( &settings, PREF_KEY_DIR_WATCH, &dir ) && dir && *dir ) { tr_inf( "Watching \"%s\" for new .torrent files", dir ); watchdir = dtr_watchdir_new( mySession, dir, onFileAdded ); } } /* load the torrents */ { tr_torrent ** torrents; tr_ctor * ctor = tr_ctorNew( mySession ); if( paused ) tr_ctorSetPaused( ctor, TR_FORCE, TRUE ); torrents = tr_sessionLoadTorrents( mySession, ctor, NULL ); tr_free( torrents ); tr_ctorFree( ctor ); } #ifdef HAVE_SYSLOG if( !foreground ) openlog( MY_NAME, LOG_CONS|LOG_PID, LOG_DAEMON ); #endif while( !closing ) { tr_wait_msec( 1000 ); /* sleep one second */ dtr_watchdir_update( watchdir ); pumpLogMessages( logfile ); } /* shutdown */ #if HAVE_SYSLOG if( !foreground ) { syslog( LOG_INFO, "%s", "Closing session" ); closelog( ); } #endif printf( "Closing transmission session..." ); tr_sessionSaveSettings( mySession, configDir, &settings ); dtr_watchdir_free( watchdir ); tr_sessionClose( mySession ); printf( " done.\n" ); /* cleanup */ if( pidfile_created ) remove( pid_filename ); tr_bencFree( &settings ); return 0; }