void tr_dhtUninit(tr_session *ss) { if(session != ss) return; tr_ndbg( "DHT", "Uninitializing DHT" ); if( dht_timer != NULL ) { event_free( dht_timer ); dht_timer = NULL; } /* Since we only save known good nodes, avoid erasing older data if we don't know enough nodes. */ if(tr_dhtStatus(ss, AF_INET, NULL) < TR_DHT_FIREWALLED) tr_ninf( "DHT", "Not saving nodes, DHT not ready" ); else { tr_benc benc; struct sockaddr_in sins[300]; struct sockaddr_in6 sins6[300]; char compact[300 * 6], compact6[300 * 18]; char *dat_file; int i, j, num = 300, num6 = 300; int n = dht_get_nodes(sins, &num, sins6, &num6); tr_ninf( "DHT", "Saving %d (%d + %d) nodes", n, num, num6 ); j = 0; for( i=0; i<num; ++i ) { memcpy( compact + j, &sins[i].sin_addr, 4 ); memcpy( compact + j + 4, &sins[i].sin_port, 2 ); j += 6; } j = 0; for( i=0; i<num6; ++i ) { memcpy( compact6 + j, &sins6[i].sin6_addr, 16 ); memcpy( compact6 + j + 16, &sins6[i].sin6_port, 2 ); j += 18; } tr_bencInitDict( &benc, 3 ); tr_bencDictAddRaw( &benc, "id", myid, 20 ); if(num > 0) tr_bencDictAddRaw( &benc, "nodes", compact, num * 6 ); if(num6 > 0) tr_bencDictAddRaw( &benc, "nodes6", compact6, num6 * 18 ); dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL ); tr_bencToFile( &benc, TR_FMT_BENC, dat_file ); tr_bencFree( &benc ); tr_free( dat_file ); } dht_uninit(); tr_ndbg("DHT", "Done uninitializing DHT"); session = NULL; }
void tr_magnetCreateMetainfo( const tr_magnet_info * info, tr_benc * top ) { int i; tr_benc * d; tr_bencInitDict( top, 4 ); /* announce list */ if( info->trackerCount == 1 ) tr_bencDictAddStr( top, "announce", info->trackers[0] ); else { tr_benc * trackers = tr_bencDictAddList( top, "announce-list", info->trackerCount ); for( i=0; i<info->trackerCount; ++i ) tr_bencListAddStr( tr_bencListAddList( trackers, 1 ), info->trackers[i] ); } /* webseeds */ if( info->webseedCount > 0 ) { tr_benc * urls = tr_bencDictAddList( top, "url-list", info->webseedCount ); for( i=0; i<info->webseedCount; ++i ) tr_bencListAddStr( urls, info->webseeds[i] ); } /* nonstandard keys */ d = tr_bencDictAddDict( top, "magnet-info", 2 ); tr_bencDictAddRaw( d, "info_hash", info->hash, 20 ); if( info->displayName != NULL ) tr_bencDictAddStr( d, "display-name", info->displayName ); }
static void saveProgress( tr_benc * dict, const tr_torrent * tor ) { size_t i, n; time_t * mtimes; tr_benc * p; tr_benc * m; const tr_bitfield * bitfield; p = tr_bencDictAdd( dict, KEY_PROGRESS ); tr_bencInitDict( p, 2 ); /* add the mtimes */ mtimes = tr_torrentGetMTimes( tor, &n ); m = tr_bencDictAddList( p, KEY_PROGRESS_MTIMES, n ); for( i = 0; i < n; ++i ) { if( !tr_torrentIsFileChecked( tor, i ) ) mtimes[i] = ~(time_t)0; /* force a recheck */ tr_bencListAddInt( m, mtimes[i] ); } /* add the bitfield */ bitfield = tr_cpBlockBitfield( tor->completion ); tr_bencDictAddRaw( p, KEY_PROGRESS_BITFIELD, bitfield->bits, bitfield->byteCount ); /* cleanup */ tr_free( mtimes ); }
static void savePeers( tr_benc * dict, const tr_torrent * tor ) { int count; tr_pex * pex; count = tr_peerMgrGetPeers( (tr_torrent*) tor, &pex, TR_AF_INET, TR_PEERS_ALL, MAX_REMEMBERED_PEERS ); if( count > 0 ) tr_bencDictAddRaw( dict, KEY_PEERS, pex, sizeof( tr_pex ) * count ); tr_free( pex ); count = tr_peerMgrGetPeers( (tr_torrent*) tor, &pex, TR_AF_INET6, TR_PEERS_ALL, MAX_REMEMBERED_PEERS ); if( count > 0 ) tr_bencDictAddRaw( dict, KEY_PEERS6, pex, sizeof( tr_pex ) * count ); tr_free( pex ); }
static void savePeers( tr_benc * dict, const tr_torrent * tor ) { tr_pex * pex = NULL; const int count = tr_peerMgrGetPeers( tor->session->peerMgr, tor->info.hash, &pex ); if( count > 0 ) tr_bencDictAddRaw( dict, KEY_PEERS, pex, sizeof( tr_pex ) * count ); tr_free( pex ); }
static void saveProgress( tr_benc * dict, const tr_torrent * tor ) { tr_benc * l; tr_benc * prog; tr_file_index_t fi; const struct tr_bitfield * bitfield; const tr_info * inf = tr_torrentInfo( tor ); const time_t now = tr_time( ); prog = tr_bencDictAddDict( dict, KEY_PROGRESS, 3 ); /* add the file/piece check timestamps... */ l = tr_bencDictAddList( prog, KEY_PROGRESS_CHECKTIME, inf->fileCount ); for( fi=0; fi<inf->fileCount; ++fi ) { const tr_piece * p; const tr_piece * pend; time_t oldest_nonzero = now; time_t newest = 0; tr_bool has_zero = FALSE; const time_t mtime = tr_torrentGetFileMTime( tor, fi ); const tr_file * f = &inf->files[fi]; /* get the oldest and newest nonzero timestamps for pieces in this file */ for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p ) { if( !p->timeChecked ) has_zero = TRUE; else if( oldest_nonzero > p->timeChecked ) oldest_nonzero = p->timeChecked; if( newest < p->timeChecked ) newest = p->timeChecked; } /* 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. */ if( !has_zero && ( mtime <= oldest_nonzero ) ) /* all checked */ tr_bencListAddInt( l, oldest_nonzero ); else if( newest < mtime ) /* none checked */ tr_bencListAddInt( l, newest ); else { /* some are checked, some aren't... so list piece by piece */ const int offset = oldest_nonzero - 1; tr_benc * ll = tr_bencListAddList( l, 2 + f->lastPiece - f->firstPiece ); tr_bencListAddInt( ll, offset ); for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p ) tr_bencListAddInt( ll, p->timeChecked ? p->timeChecked - offset : 0 ); } } /* add the progress */ if( tor->completeness == TR_SEED ) tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" ); /* add the pieces bitfield */ bitfield = tr_cpBlockBitfield( &tor->completion ); tr_bencDictAddRaw( prog, KEY_PROGRESS_BITFIELD, bitfield->bits, bitfield->byteCount ); }