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

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

Very minor bugfix.

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