source: branches/daemon/daemon/torrents.c @ 1706

Last change on this file since 1706 was 1706, checked in by joshe, 15 years ago

Disable duplicate torrent detection,

it doesn't work right yetand can cause crashes.

  • Property svn:keywords set to Date Rev Author Id
File size: 21.9 KB
Line 
1/******************************************************************************
2 * $Id: torrents.c 1706 2007-04-12 12:59:12Z joshe $
3 *
4 * Copyright (c) 2007 Joshua Elsasser
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <sys/types.h>
26#include <sys/param.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <sys/uio.h>
30#include <assert.h>
31#include <ctype.h>
32#include <errno.h>
33#include <event.h>
34#include <fcntl.h>
35#include <time.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "bsdtree.h"
43#include "bencode.h"
44#include "errors.h"
45#include "misc.h"
46#include "torrents.h"
47#include "transmission.h"
48#include "trcompat.h"
49
50#define EXIT_TIMEOUT 10         /* how many seconds to wait on exit */
51#define TIMER_SECS   1          /* timer interval seconds */
52#define TIMER_USECS  0          /* timer interval microseconds */
53
54struct tor
55{
56    int             id;
57    int             deleting;
58    uint8_t         hash[SHA_DIGEST_LENGTH];
59    tr_torrent_t  * tor;
60    int             pexset;
61    int             pex;
62    RB_ENTRY( tor ) idlinks;
63    RB_ENTRY( tor ) hashlinks;
64};
65
66RB_HEAD( tortree, tor );
67RB_HEAD( hashtree, tor );
68
69static struct tor * opentor    ( const char *, const char *, uint8_t *, size_t,
70                                  const char * );
71static void         closetor   ( struct tor *, int );
72static void         starttimer ( int );
73static void         timerfunc  ( int, short, void * );
74static int          loadstate  ( void );
75static int          savestate  ( void );
76static int          toridcmp   ( struct tor *, struct tor * );
77static int          torhashcmp ( struct tor *, struct tor * );
78static struct tor * idlookup   ( int, int );
79static struct tor * hashlookup ( const uint8_t *, int );
80static struct tor * iterate    ( struct tor * );
81
82static struct event_base * gl_base      = NULL;
83static tr_handle_t       * gl_handle    = NULL;
84static struct tortree      gl_tree      = RB_INITIALIZER( &gl_tree );
85static struct hashtree     gl_hashes    = RB_INITIALIZER( &gl_hashes );
86static int                 gl_lastid    = 0;
87static struct event        gl_event;
88static time_t              gl_exiting   = 0;
89static int                 gl_exitval   = 0;
90static char                gl_state[MAXPATHLEN];
91static char                gl_newstate[MAXPATHLEN];
92
93static int                 gl_autostart = 1;
94static int                 gl_pex       = 1;
95static int                 gl_port      = TR_DEFAULT_PORT;
96static int                 gl_mapping   = 0;
97static int                 gl_uplimit   = -1;
98static int                 gl_downlimit = -1;
99static char                gl_dir[MAXPATHLEN];
100
101RB_GENERATE_STATIC( tortree, tor, idlinks, toridcmp )
102RB_GENERATE_STATIC( hashtree, tor, hashlinks, torhashcmp )
103INTCMP_FUNC( toridcmp, tor, id )
104
105void
106torrent_init( struct event_base * base )
107{
108    assert( NULL == gl_handle && NULL == gl_base );
109
110    gl_base   = base;
111    gl_handle = tr_init( "daemon" );
112
113    confpath( gl_state, sizeof gl_state, CONF_FILE_STATE, 0 );
114    strlcpy( gl_newstate, gl_state, sizeof gl_state );
115    strlcat( gl_newstate, ".new", sizeof gl_state );
116    absolutify( gl_dir, sizeof gl_dir, "." );
117
118    loadstate();
119}
120
121int
122torrent_add_file( const char * path, const char * dir, int autostart )
123{
124    struct tor * tor;
125
126    assert( NULL != gl_handle );
127    assert( !gl_exiting );
128
129    tor = opentor( path, NULL, NULL, 0, dir );
130    if( NULL == tor )
131    {
132        return -1;
133    }
134
135    if( 0 > autostart )
136    {
137        autostart = gl_autostart;
138    }
139    if( autostart )
140    {
141        tr_torrentStart( tor->tor );
142    }
143
144    savestate();
145
146    return tor->id;
147}
148
149int
150torrent_add_data( uint8_t * data, size_t size, const char * dir, int autostart )
151{
152    struct tor * tor;
153
154    assert( NULL != gl_handle );
155    assert( !gl_exiting );
156
157    tor = opentor( NULL, NULL, data, size, dir );
158    if( NULL == tor )
159    {
160        return -1;
161    }
162
163    if( 0 > autostart )
164    {
165        autostart = gl_autostart;
166    }
167    if( autostart )
168    {
169        tr_torrentStart( tor->tor );
170    }
171
172    savestate();
173
174    return tor->id;
175}
176
177void
178torrent_start( int id )
179{
180    struct tor * tor;
181    tr_stat_t  * st;
182
183    assert( NULL != gl_handle );
184    assert( !gl_exiting );
185
186    tor = idlookup( id, 0 );
187    if( NULL == tor )
188    {
189        return;
190    }
191
192    st = tr_torrentStat( tor->tor );
193    if( TR_STATUS_INACTIVE & st->status )
194    {
195        tr_torrentStart( tor->tor );
196        savestate();
197    }
198}
199
200void
201torrent_stop( int id )
202{
203    struct tor * tor;
204    tr_stat_t  * st;
205
206    assert( NULL != gl_handle );
207    assert( !gl_exiting );
208
209    tor = idlookup( id, 0 );
210    if( NULL == tor )
211    {
212        return;
213    }
214
215    st = tr_torrentStat( tor->tor );
216    if( TR_STATUS_ACTIVE & st->status )
217    {
218        tr_torrentStop( tor->tor );
219        savestate();
220    }
221}
222
223void
224torrent_remove( int id )
225{
226    struct tor * tor;
227
228    assert( NULL != gl_handle );
229    assert( !gl_exiting );
230
231    tor = idlookup( id, 0 );
232    if( NULL == tor )
233    {
234        return;
235    }
236
237    closetor( tor, 1 );
238    savestate();
239}
240
241tr_info_t *
242torrent_info( int id )
243{
244    struct tor * tor;
245
246    assert( NULL != gl_handle );
247    assert( !gl_exiting );
248
249    tor = idlookup( id, 0 );
250    if( NULL == tor )
251    {
252        return NULL;
253    }
254
255    return tr_torrentInfo( tor->tor );
256}
257
258tr_stat_t *
259torrent_stat( int id )
260{
261    struct tor * tor;
262
263    assert( NULL != gl_handle );
264    assert( !gl_exiting );
265
266    tor = idlookup( id, 0 );
267    if( NULL == tor )
268    {
269        return NULL;
270    }
271
272    return tr_torrentStat( tor->tor );
273}
274
275int
276torrent_lookup( const uint8_t * hashstr )
277{
278    uint8_t      hash[SHA_DIGEST_LENGTH];
279    size_t       ii;
280    struct tor * tor;
281    char         buf[3];
282
283    assert( NULL != gl_handle );
284    assert( !gl_exiting );
285
286    bzero( buf, sizeof buf );
287    for( ii = 0; sizeof( hash ) > ii; ii++ )
288    {
289        if( !isxdigit( hashstr[2*ii] ) || !isxdigit( hashstr[1+2*ii] ) )
290        {
291            return -1;
292        }
293        memcpy( buf, &hashstr[2*ii], 2 );
294        hash[ii] = strtol( buf, NULL, 16 );
295    }
296
297    tor = hashlookup( hash, 0 );
298    if( NULL == tor )
299    {
300        return -1;
301    }
302
303    return tor->id;
304}
305
306void *
307torrent_iter( void * iter, int * id )
308{
309    struct tor * tor = iter;
310
311    assert( NULL != gl_handle );
312    assert( !gl_exiting );
313
314    tor = iterate( tor );
315
316    if( NULL != tor )
317    {
318        *id = tor->id;
319    }
320
321    return tor;
322}
323
324void
325torrent_exit( int exitval )
326{
327    struct tor * tor;
328
329    assert( NULL != gl_handle );
330    assert( !gl_exiting );
331    gl_exiting = time( NULL );
332    gl_exitval = exitval;
333
334    RB_FOREACH( tor, tortree, &gl_tree )
335    {
336        closetor( tor, 0 );
337    }
338
339    tr_natTraversalEnable( gl_handle, 0 );
340    starttimer( 1 );
341}
342
343void
344torrent_set_autostart( int autostart )
345{
346    assert( NULL != gl_handle );
347    assert( !gl_exiting );
348    gl_autostart = autostart;
349    savestate();
350}
351
352int
353torrent_get_autostart( void )
354{
355    return gl_autostart;
356}
357
358void
359torrent_set_port( int port )
360{
361    assert( NULL != gl_handle );
362    assert( !gl_exiting );
363    if( 0 < port && 0xffff > port )
364    {
365        gl_port = port;
366        tr_setBindPort( gl_handle, port );
367        savestate();
368    }
369}
370
371int
372torrent_get_port( void )
373{
374    return gl_port;
375}
376
377void
378torrent_set_pex( int pex )
379{
380    struct tor * tor;
381
382    assert( NULL != gl_handle );
383    assert( !gl_exiting );
384
385    if( pex == gl_pex )
386    {
387        return;
388    }
389    gl_pex = pex;
390
391    for( tor = iterate( NULL ); NULL != tor; tor = iterate( tor ) )
392    {
393        if( tor->pexset )
394        {
395            continue;
396        }
397        tr_torrentDisablePex( tor->tor, !gl_pex );
398    }
399
400    savestate();
401}
402
403int
404torrent_get_pex( void )
405{
406    return gl_pex;
407}
408
409void
410torrent_enable_port_mapping( int automap )
411{
412    assert( NULL != gl_handle );
413    assert( !gl_exiting );
414    gl_mapping = ( automap ? 1 : 0 );
415    tr_natTraversalEnable( gl_handle, gl_mapping );
416    savestate();
417}
418
419int
420torrent_get_port_mapping( void )
421{
422    return gl_mapping;
423}
424
425void
426torrent_set_uplimit( int uplimit )
427{
428    assert( NULL != gl_handle );
429    assert( !gl_exiting );
430    gl_uplimit = uplimit;
431    tr_setGlobalUploadLimit( gl_handle, uplimit );
432    savestate();
433}
434
435int
436torrent_get_uplimit( void )
437{
438    return gl_uplimit;
439}
440
441void
442torrent_set_downlimit( int downlimit )
443{
444    assert( NULL != gl_handle );
445    assert( !gl_exiting );
446    gl_downlimit = downlimit;
447    tr_setGlobalDownloadLimit( gl_handle, downlimit );
448    savestate();
449}
450
451int
452torrent_get_downlimit( void )
453{
454    return gl_downlimit;
455}
456
457void
458torrent_set_directory( const char * path )
459{
460    assert( NULL != gl_handle );
461    assert( !gl_exiting );
462
463    absolutify( gl_dir, sizeof gl_dir, path );
464    savestate();
465}
466
467const char *
468torrent_get_directory( void )
469{
470    return gl_dir;
471}
472
473struct tor *
474opentor( const char * path, const char * hash, uint8_t * data, size_t size,
475         const char * dir )
476{
477    struct tor * tor, * found;
478    int          errcode;
479    tr_info_t  * inf;
480
481    assert( ( NULL != path && NULL == hash && NULL == data ) ||
482            ( NULL == path && NULL != hash && NULL == data ) ||
483            ( NULL == path && NULL == hash && NULL != data ) );
484
485    /* XXX should probably wrap around back to 1 and avoid duplicates */
486    if( INT_MAX == gl_lastid )
487    {
488        errmsg( "Congratulations, you're the %ith torrent! Your prize the "
489                "inability to load any more torrents, enjoy!", INT_MAX );
490        return NULL;
491    }
492
493    tor = calloc( 1, sizeof *tor );
494    if( NULL == tor )
495    {
496        mallocmsg( sizeof *tor );
497        return NULL;
498    }
499
500    if( NULL != path )
501    {
502        tor->tor = tr_torrentInit( gl_handle, path, tor->hash,
503                                   TR_FLAG_SAVE, &errcode );
504    }
505    else if( NULL != hash )
506    {
507        tor->tor = tr_torrentInitSaved( gl_handle, hash, 0, &errcode );
508    }
509    else
510    {
511        tor->tor = tr_torrentInitData( gl_handle, data, size, tor->hash,
512                                       TR_FLAG_SAVE, &errcode );
513    }
514
515    if( NULL == tor->tor )
516    {
517        found = NULL;
518        switch( errcode )
519        {
520            case TR_EINVALID:
521                if( NULL == path )
522                {
523                    errmsg( "invalid torrent file" );
524                }
525                else
526                {
527                    errmsg( "invalid torrent file: %s", path );
528                }
529                break;
530            case TR_EUNSUPPORTED:
531                if( NULL == path )
532                {
533                    errmsg( "unsupported torrent file" );
534                }
535                else
536                {
537                    errmsg( "unsupported torrent file: %s", path );
538                }
539                break;
540            case TR_EDUPLICATE:
541                /* XXX not yet
542                found = hashlookup( tor->hash, 1 );
543                assert( NULL != found );
544                found->deleting = 0;
545                */
546                errmsg( "XXX loaded duplicate torrent" );
547                break;
548            default:
549                if( NULL == path )
550                {
551                    errmsg( "torrent file failed to load" );
552                }
553                else
554                {
555                    errmsg( "torrent file failed to load: %s", path );
556                }
557                break;
558        }
559        free( tor );
560        return found;
561    }
562    gl_lastid++;
563    tor->id       = gl_lastid;
564    tor->deleting = 0;
565
566    assert( sizeof( inf->hash ) == sizeof( tor->hash ) );
567    inf = tr_torrentInfo( tor->tor );
568    memcpy( tor->hash, inf->hash, sizeof tor->hash );
569
570    tr_torrentSetFolder( tor->tor, ( NULL == dir ? gl_dir : dir ) );
571
572    if( TR_FLAG_PRIVATE & inf->flags )
573    {
574        tor->pexset = 1;
575        tor->pex    = 0;
576    }
577    else
578    {
579        tr_torrentDisablePex( tor->tor, !gl_pex );
580    }
581
582    found = RB_INSERT( tortree, &gl_tree, tor );
583    assert( NULL == found );
584    found = RB_INSERT( hashtree, &gl_hashes, tor );
585    assert( NULL == found );
586
587    return tor;
588}
589
590void
591closetor( struct tor * tor, int calltimer )
592{
593    tr_stat_t  * st;
594
595    if( NULL == tor || tor->deleting )
596    {
597        return;
598    }
599    tor->deleting = 1;
600
601    st = tr_torrentStat( tor->tor );
602    if( TR_STATUS_ACTIVE & st->status )
603    {
604        tr_torrentStop( tor->tor );
605    }
606
607    starttimer( calltimer );
608}
609
610void
611starttimer( int callnow )
612{
613    if( !evtimer_initialized( &gl_event ) )
614    {
615        evtimer_set( &gl_event, timerfunc, NULL );
616        event_base_set( gl_base, &gl_event );
617    }
618
619    if( callnow )
620    {
621        timerfunc( -1, EV_TIMEOUT, NULL );
622    }
623}
624
625void
626timerfunc( int fd UNUSED, short event UNUSED, void * arg UNUSED )
627{
628    struct tor         * tor, * next;
629    tr_handle_status_t * hs;
630    tr_stat_t          * st;
631    int                  stillmore;
632    struct timeval       tv;
633
634    stillmore = 0;
635    for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
636    {
637        next = RB_NEXT( tortree, &gl_tree, tor );
638        if( !tor->deleting )
639        {
640            continue;
641        }
642        st = tr_torrentStat( tor->tor );
643        if( TR_STATUS_PAUSE & st->status )
644        {
645            tr_torrentClose( gl_handle, tor->tor );
646            RB_REMOVE( tortree, &gl_tree, tor );
647            RB_REMOVE( hashtree, &gl_hashes, tor );
648            free( tor );
649        }
650        else
651        {
652            stillmore = 1;
653        }
654    }
655
656    if( gl_exiting )
657    {
658        if( !stillmore )
659        {
660            hs = tr_handleStatus( gl_handle );
661            if( TR_NAT_TRAVERSAL_DISABLED != hs->natTraversalStatus )
662            {
663                stillmore = 1;
664            }
665        }
666
667        if( !stillmore || EXIT_TIMEOUT <= time( NULL ) - gl_exiting )
668        {
669            if( stillmore )
670            {
671                errmsg( "timing out trackers and/or port mapping on exit" );
672            }
673            for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
674            {
675                next = RB_NEXT( tortree, &gl_tree, tor );
676                tr_torrentClose( gl_handle, tor->tor );
677                RB_REMOVE( tortree, &gl_tree, tor );
678                RB_REMOVE( hashtree, &gl_hashes, tor );
679                free( tor );
680            }
681            tr_close( gl_handle );
682            exit( gl_exitval );
683        }
684    }
685
686    if( stillmore )
687    {
688        bzero( &tv, sizeof tv );
689        tv.tv_sec  = TIMER_SECS;
690        tv.tv_usec = TIMER_USECS;
691        evtimer_add( &gl_event, &tv );
692    }
693}
694
695int
696loadstate( void )
697{
698    uint8_t   *  buf;
699    size_t       len;
700    benc_val_t   top, * num, * str, * list, * dict;
701    int          ii;
702    struct tor * tor;
703    const char * dir;
704
705    buf = readfile( gl_state, &len );
706    if( NULL == buf )
707    {
708        return -1;
709    }
710
711    if( tr_bencLoad( buf, len, &top, NULL ) )
712    {
713        free( buf );
714        errmsg( "failed to load bencoded data from %s", gl_state );
715        return -1;
716    }
717    free( buf );
718
719    num = tr_bencDictFind( &top, "autostart" );
720    if( NULL != num && TYPE_INT == num->type )
721    {
722        gl_autostart = ( num->val.i ? 1 : 0 );
723    }
724
725    num = tr_bencDictFind( &top, "port" );
726    if( NULL != num && TYPE_INT == num->type &&
727        0 < num->val.i && 0xffff > num->val.i )
728    {
729        gl_port = num->val.i;
730    }
731    tr_setBindPort( gl_handle, gl_port );
732
733    num = tr_bencDictFind( &top, "default-pex" );
734    if( NULL != num && TYPE_INT == num->type )
735    {
736        gl_pex = ( num->val.i ? 1 : 0 );
737    }
738
739    num = tr_bencDictFind( &top, "port-mapping" );
740    if( NULL != num && TYPE_INT == num->type )
741    {
742        gl_mapping = ( num->val.i ? 1 : 0 );
743    }
744    tr_natTraversalEnable( gl_handle, gl_mapping );
745
746    num = tr_bencDictFind( &top, "upload-limit" );
747    if( NULL != num && TYPE_INT == num->type )
748    {
749        gl_uplimit = num->val.i;
750    }
751    tr_setGlobalUploadLimit( gl_handle, gl_uplimit );
752
753    num = tr_bencDictFind( &top, "download-limit" );
754    if( NULL != num && TYPE_INT == num->type )
755    {
756        gl_downlimit = num->val.i;
757    }
758    tr_setGlobalDownloadLimit( gl_handle, gl_downlimit );
759
760    str = tr_bencDictFind( &top, "default-directory" );
761    if( NULL != str && TYPE_STR == str->type )
762    {
763        strlcpy( gl_dir, str->val.s.s, sizeof gl_dir );
764    }
765
766    list = tr_bencDictFind( &top, "torrents" );
767    if( NULL == list || TYPE_LIST != list->type )
768    {
769        return 0;
770    }
771
772    for( ii = 0; ii < list->val.l.count; ii++ )
773    {
774        dict = &list->val.l.vals[ii];
775        if( TYPE_DICT != dict->type )
776        {
777            continue;
778        }
779
780        str = tr_bencDictFind( dict, "directory" );
781        dir = ( NULL != str && TYPE_STR == str->type ? str->val.s.s : NULL );
782
783        str = tr_bencDictFind( dict, "hash" );
784        if( NULL == str || TYPE_STR != str->type ||
785            2 * SHA_DIGEST_LENGTH != str->val.s.i )
786        {
787            continue;
788        }
789
790        tor = opentor( NULL, str->val.s.s, NULL, 0, dir );
791        if( NULL == tor )
792        {
793            continue;
794        }
795
796        num = tr_bencDictFind( dict, "pex" );
797        if( NULL != num && TYPE_INT == num->type )
798        {
799            tor->pexset = 1;
800            tor->pex = ( num->val.i ? 1 : 0 );
801        }
802        tr_torrentDisablePex( tor->tor, !( tor->pexset ? tor->pex : gl_pex ) );
803
804        num = tr_bencDictFind( dict, "paused" );
805        if( NULL != num && TYPE_INT == num->type && !num->val.i )
806        {
807            tr_torrentStart( tor->tor );
808        }
809    }
810
811    return 0;
812}
813
814int
815savestate( void )
816{
817    benc_val_t   top, * list, * tor;
818    struct tor * ii;
819    tr_info_t  * inf;
820    tr_stat_t  * st;
821    uint8_t    * buf;
822    int          len, pexset;
823
824    tr_bencInit( &top, TYPE_DICT );
825    if( tr_bencDictReserve( &top, 8 ) )
826    {
827      nomem:
828        tr_bencFree( &top );
829        errmsg( "failed to save state: failed to allocate memory" );
830        return -1;
831    }
832    tr_bencInitInt( tr_bencDictAdd( &top, "autostart" ),      gl_autostart );
833    tr_bencInitInt( tr_bencDictAdd( &top, "port" ),           gl_port );
834    tr_bencInitInt( tr_bencDictAdd( &top, "default-pex" ),    gl_pex );
835    tr_bencInitInt( tr_bencDictAdd( &top, "port-mapping" ),   gl_mapping );
836    tr_bencInitInt( tr_bencDictAdd( &top, "upload-limit" ),   gl_uplimit );
837    tr_bencInitInt( tr_bencDictAdd( &top, "download-limit" ), gl_downlimit );
838    tr_bencInitStr( tr_bencDictAdd( &top, "default-directory" ),
839                    gl_dir, -1, 1 );
840    list = tr_bencDictAdd( &top, "torrents" );
841    tr_bencInit( list, TYPE_LIST );
842
843    len = 0;
844    RB_FOREACH( ii, tortree, &gl_tree )
845    {
846        if( !ii->deleting )
847        {
848            len++;
849        }
850    }
851    if( tr_bencListReserve( list, len ) )
852    {
853        goto nomem;
854    }
855
856    RB_FOREACH( ii, tortree, &gl_tree )
857    {
858        if( ii->deleting )
859        {
860            continue;
861        }
862        tor = tr_bencListAdd( list );
863        assert( NULL != tor );
864        tr_bencInit( tor, TYPE_DICT );
865        inf    = tr_torrentInfo( ii->tor );
866        st     = tr_torrentStat( ii->tor );
867        pexset = ( ii->pexset && !( TR_FLAG_PRIVATE & inf->flags ) );
868        if( tr_bencDictReserve( tor, ( pexset ? 4 : 3 ) ) )
869        {
870            goto nomem;
871        }
872        tr_bencInitStr( tr_bencDictAdd( tor, "hash" ),
873                        inf->hashString, 2 * SHA_DIGEST_LENGTH, 1 );
874        tr_bencInitInt( tr_bencDictAdd( tor, "paused" ),
875                        ( TR_STATUS_INACTIVE & st->status ? 1 : 0 ) );
876        tr_bencInitStr( tr_bencDictAdd( tor, "directory" ),
877                        tr_torrentGetFolder( ii->tor ), -1, 1 );
878        if( pexset )
879        {
880            tr_bencInitInt( tr_bencDictAdd( tor, "pex" ), ii->pex );
881        }
882    }
883
884    buf = ( uint8_t * )tr_bencSaveMalloc( &top, &len );
885    SAFEBENCFREE( &top );
886    if( NULL == buf )
887    {
888        errnomsg( "failed to save state: bencoding failed" );
889        return -1;
890    }
891
892    if( 0 > writefile( gl_newstate, buf, len ) )
893    {
894        free( buf );
895        return -1;
896    }
897    free( buf );
898
899    if( 0 > rename( gl_newstate, gl_state ) )
900    {
901        errnomsg( "failed to save state: failed to rename %s to %s",
902                  gl_newstate, CONF_FILE_STATE );
903        return -1;
904    }
905
906    return 0;
907}
908
909int
910torhashcmp( struct tor * left, struct tor * right )
911{
912    return memcmp( left->hash, right->hash, sizeof left->hash );
913}
914
915struct tor *
916idlookup( int id, int wantdel )
917{
918    struct tor key, * found;
919
920    bzero( &key, sizeof key );
921    key.id = id;
922    found = RB_FIND( tortree, &gl_tree, &key );
923    if( NULL != found && !wantdel && found->deleting )
924    {
925        found = NULL;
926    }
927
928    return found;
929}
930
931struct tor *
932hashlookup( const uint8_t * hash, int wantdel )
933{
934    struct tor key, * found;
935
936    bzero( &key, sizeof key );
937    memcpy( key.hash, hash, sizeof key.hash );
938    found = RB_FIND( hashtree, &gl_hashes, &key );
939    if( NULL != found && !wantdel && found->deleting )
940    {
941        found = NULL;
942    }
943
944    return found;
945}
946
947struct tor *
948iterate( struct tor * tor )
949{
950    assert( NULL != gl_handle );
951    assert( !gl_exiting );
952
953    if( NULL == tor )
954    {
955        tor = RB_MIN( tortree, &gl_tree );
956    }
957    else
958    {
959        tor = RB_NEXT( tortree, &gl_tree, tor );
960    }
961
962    while( NULL != tor && tor->deleting )
963    {
964        tor = RB_NEXT( tortree, &gl_tree, tor );
965    }
966
967    return tor;
968}
Note: See TracBrowser for help on using the repository browser.