transmission: upgrade from 2.13 to 2.22 (thx rhester72)
[tomato.git] / release / src / router / transmission / libtransmission / torrent-magnet.c
blobc754dc3da07dec7dd9bffcdec67c0d10b3d875df
1 /*
2 * This file Copyright (C) Mnemosyne LLC
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
10 * $Id: torrent-magnet.c 11709 2011-01-19 13:48:47Z jordan $
13 #include <assert.h>
14 #include <stdio.h> /* remove() */
16 #include <event2/buffer.h>
18 #include "transmission.h"
19 #include "bencode.h"
20 #include "crypto.h"
21 #include "magnet.h"
22 #include "metainfo.h"
23 #include "resume.h"
24 #include "torrent.h"
25 #include "torrent-magnet.h"
26 #include "utils.h"
27 #include "web.h"
29 #define dbgmsg( tor, ... ) \
30 do { \
31 if( tr_deepLoggingIsActive( ) ) \
32 tr_deepLog( __FILE__, __LINE__, tor->info.name, __VA_ARGS__ ); \
33 } while( 0 )
35 /***
36 ****
37 ***/
39 enum
41 /* don't ask for the same metadata piece more than this often */
42 MIN_REPEAT_INTERVAL_SECS = 3
45 struct metadata_node
47 time_t requestedAt;
48 int piece;
51 struct tr_incomplete_metadata
53 uint8_t * metadata;
54 int metadata_size;
55 int pieceCount;
57 /** sorted from least to most recently requested */
58 struct metadata_node * piecesNeeded;
59 int piecesNeededCount;
62 static void
63 incompleteMetadataFree( struct tr_incomplete_metadata * m )
65 tr_free( m->metadata );
66 tr_free( m->piecesNeeded );
67 tr_free( m );
70 void
71 tr_torrentSetMetadataSizeHint( tr_torrent * tor, int size )
73 if( !tr_torrentHasMetadata( tor ) )
75 if( tor->incompleteMetadata == NULL )
77 int i;
78 struct tr_incomplete_metadata * m;
79 const int n = ( size + ( METADATA_PIECE_SIZE - 1 ) ) / METADATA_PIECE_SIZE;
80 dbgmsg( tor, "metadata is %d bytes in %d pieces", size, n );
82 m = tr_new( struct tr_incomplete_metadata, 1 );
83 m->pieceCount = n;
84 m->metadata = tr_new( uint8_t, size );
85 m->metadata_size = size;
86 m->piecesNeededCount = n;
87 m->piecesNeeded = tr_new( struct metadata_node, n );
89 for( i=0; i<n; ++i ) {
90 m->piecesNeeded[i].piece = i;
91 m->piecesNeeded[i].requestedAt = 0;
94 tor->incompleteMetadata = m;
99 static int
100 findInfoDictOffset( const tr_torrent * tor )
102 size_t fileLen;
103 uint8_t * fileContents;
104 int offset = 0;
106 /* load the file, and find the info dict's offset inside the file */
107 if(( fileContents = tr_loadFile( tor->info.torrent, &fileLen )))
109 tr_benc top;
111 if( !tr_bencParse( fileContents, fileContents + fileLen, &top, NULL ) )
113 tr_benc * infoDict;
115 if( tr_bencDictFindDict( &top, "info", &infoDict ) )
117 int infoLen;
118 char * infoContents = tr_bencToStr( infoDict, TR_FMT_BENC, &infoLen );
119 const uint8_t * i = (const uint8_t*) tr_memmem( (char*)fileContents, fileLen, infoContents, infoLen );
120 offset = i != NULL ? i - fileContents : 0;
121 tr_free( infoContents );
124 tr_bencFree( &top );
127 tr_free( fileContents );
130 return offset;
133 static void
134 ensureInfoDictOffsetIsCached( tr_torrent * tor )
136 assert( tr_torrentHasMetadata( tor ) );
138 if( !tor->infoDictOffsetIsCached )
140 tor->infoDictOffset = findInfoDictOffset( tor );
141 tor->infoDictOffsetIsCached = TRUE;
145 void*
146 tr_torrentGetMetadataPiece( tr_torrent * tor, int piece, int * len )
148 char * ret = NULL;
150 assert( tr_isTorrent( tor ) );
151 assert( piece >= 0 );
152 assert( len != NULL );
154 if( tr_torrentHasMetadata( tor ) )
156 FILE * fp;
158 ensureInfoDictOffsetIsCached( tor );
160 assert( tor->infoDictLength > 0 );
161 assert( tor->infoDictOffset >= 0 );
163 fp = fopen( tor->info.torrent, "rb" );
164 if( fp != NULL )
166 const int o = piece * METADATA_PIECE_SIZE;
168 if( !fseek( fp, tor->infoDictOffset + o, SEEK_SET ) )
170 const int l = o + METADATA_PIECE_SIZE <= tor->infoDictLength
171 ? METADATA_PIECE_SIZE
172 : tor->infoDictLength - o;
174 if( 0<l && l<=METADATA_PIECE_SIZE )
176 char * buf = tr_new( char, l );
177 const int n = fread( buf, 1, l, fp );
178 if( n == l )
180 *len = l;
181 ret = buf;
182 buf = NULL;
185 tr_free( buf );
189 fclose( fp );
193 return ret;
196 void
197 tr_torrentSetMetadataPiece( tr_torrent * tor, int piece, const void * data, int len )
199 int i;
200 struct tr_incomplete_metadata * m;
201 const int offset = piece * METADATA_PIECE_SIZE;
203 assert( tr_isTorrent( tor ) );
205 dbgmsg( tor, "got metadata piece %d", piece );
207 /* are we set up to download metadata? */
208 m = tor->incompleteMetadata;
209 if( m == NULL )
210 return;
212 /* does this data pass the smell test? */
213 if( offset + len > m->metadata_size )
214 return;
216 /* do we need this piece? */
217 for( i=0; i<m->piecesNeededCount; ++i )
218 if( m->piecesNeeded[i].piece == piece )
219 break;
220 if( i==m->piecesNeededCount )
221 return;
223 memcpy( m->metadata + offset, data, len );
225 tr_removeElementFromArray( m->piecesNeeded, i,
226 sizeof( struct metadata_node ),
227 m->piecesNeededCount-- );
229 dbgmsg( tor, "saving metainfo piece %d... %d remain", piece, m->piecesNeededCount );
231 /* are we done? */
232 if( m->piecesNeededCount == 0 )
234 tr_bool success = FALSE;
235 tr_bool checksumPassed = FALSE;
236 tr_bool metainfoParsed = FALSE;
237 uint8_t sha1[SHA_DIGEST_LENGTH];
239 /* we've got a complete set of metainfo... see if it passes the checksum test */
240 dbgmsg( tor, "metainfo piece %d was the last one", piece );
241 tr_sha1( sha1, m->metadata, m->metadata_size, NULL );
242 if(( checksumPassed = !memcmp( sha1, tor->info.hash, SHA_DIGEST_LENGTH )))
244 /* checksum passed; now try to parse it as benc */
245 tr_benc infoDict;
246 const int err = tr_bencLoad( m->metadata, m->metadata_size, &infoDict, NULL );
247 dbgmsg( tor, "err is %d", err );
248 if(( metainfoParsed = !err ))
250 /* yay we have bencoded metainfo... merge it into our .torrent file */
251 tr_benc newMetainfo;
252 char * path = tr_strdup( tor->info.torrent );
254 if( !tr_bencLoadFile( &newMetainfo, TR_FMT_BENC, path ) )
256 tr_bool hasInfo;
257 tr_info info;
258 int infoDictLength;
260 /* remove any old .torrent and .resume files */
261 remove( path );
262 tr_torrentRemoveResume( tor );
264 dbgmsg( tor, "Saving completed metadata to \"%s\"", path );
265 tr_bencMergeDicts( tr_bencDictAddDict( &newMetainfo, "info", 0 ), &infoDict );
267 memset( &info, 0, sizeof( tr_info ) );
268 success = tr_metainfoParse( tor->session, &newMetainfo, &info, &hasInfo, &infoDictLength );
270 if( success && !tr_getBlockSize( info.pieceSize ) )
272 tr_torrentSetLocalError( tor, "%s", _( "Magnet torrent's metadata is not usable" ) );
273 success = FALSE;
276 if( success )
278 /* keep the new info */
279 tor->info = info;
280 tor->infoDictLength = infoDictLength;
282 /* save the new .torrent file */
283 tr_bencToFile( &newMetainfo, TR_FMT_BENC, tor->info.torrent );
284 tr_sessionSetTorrentFile( tor->session, tor->info.hashString, tor->info.torrent );
285 tr_torrentGotNewInfoDict( tor );
286 tr_torrentSetDirty( tor );
289 tr_bencFree( &newMetainfo );
292 tr_bencFree( &infoDict );
293 tr_free( path );
297 if( success )
299 incompleteMetadataFree( tor->incompleteMetadata );
300 tor->incompleteMetadata = NULL;
302 else /* drat. */
304 const int n = m->pieceCount;
305 for( i=0; i<n; ++i )
307 m->piecesNeeded[i].piece = i;
308 m->piecesNeeded[i].requestedAt = 0;
310 m->piecesNeededCount = n;
311 dbgmsg( tor, "metadata error; trying again. %d pieces left", n );
313 tr_err( "magnet status: checksum passed %d, metainfo parsed %d",
314 (int)checksumPassed, (int)metainfoParsed );
319 tr_bool
320 tr_torrentGetNextMetadataRequest( tr_torrent * tor, time_t now, int * setme_piece )
322 tr_bool have_request = FALSE;
323 struct tr_incomplete_metadata * m;
325 assert( tr_isTorrent( tor ) );
327 m = tor->incompleteMetadata;
329 if( ( m != NULL )
330 && ( m->piecesNeededCount > 0 )
331 && ( m->piecesNeeded[0].requestedAt + MIN_REPEAT_INTERVAL_SECS < now ) )
333 int i;
334 const int piece = m->piecesNeeded[0].piece;
336 tr_removeElementFromArray( m->piecesNeeded, 0,
337 sizeof( struct metadata_node ),
338 m->piecesNeededCount-- );
340 i = m->piecesNeededCount++;
341 m->piecesNeeded[i].piece = piece;
342 m->piecesNeeded[i].requestedAt = now;
344 dbgmsg( tor, "next piece to request: %d", piece );
345 *setme_piece = piece;
346 have_request = TRUE;
349 return have_request;
352 double
353 tr_torrentGetMetadataPercent( const tr_torrent * tor )
355 double ret;
357 if( tr_torrentHasMetadata( tor ) )
358 ret = 1.0;
359 else {
360 const struct tr_incomplete_metadata * m = tor->incompleteMetadata;
361 if( !m || !m->pieceCount )
362 ret = 0.0;
363 else
364 ret = (m->pieceCount - m->piecesNeededCount) / (double)m->pieceCount;
367 return ret;
370 char*
371 tr_torrentGetMagnetLink( const tr_torrent * tor )
373 int i;
374 const char * name;
375 struct evbuffer * s;
377 assert( tr_isTorrent( tor ) );
379 s = evbuffer_new( );
380 evbuffer_add_printf( s, "magnet:?xt=urn:btih:%s", tor->info.hashString );
381 name = tr_torrentName( tor );
382 if( name && *name )
384 evbuffer_add_printf( s, "%s", "&dn=" );
385 tr_http_escape( s, tr_torrentName( tor ), -1, TRUE );
387 for( i=0; i<tor->info.trackerCount; ++i )
389 evbuffer_add_printf( s, "%s", "&tr=" );
390 tr_http_escape( s, tor->info.trackers[i].announce, -1, TRUE );
393 return evbuffer_free_to_str( s );