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

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

Add strlcpy and strlcat from openbsd and use them when not provided by libc.

  • Property svn:keywords set to Date Rev Author Id
File size: 21.8 KB
Line 
1/******************************************************************************
2 * $Id: torrents.c 1696 2007-04-10 02:27:46Z 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                found = hashlookup( tor->hash, 1 );
542                assert( NULL != found );
543                found->deleting = 0;
544                break;
545            default:
546                if( NULL == path )
547                {
548                    errmsg( "torrent file failed to load" );
549                }
550                else
551                {
552                    errmsg( "torrent file failed to load: %s", path );
553                }
554                break;
555        }
556        free( tor );
557        return found;
558    }
559    gl_lastid++;
560    tor->id       = gl_lastid;
561    tor->deleting = 0;
562
563    assert( sizeof( inf->hash ) == sizeof( tor->hash ) );
564    inf = tr_torrentInfo( tor->tor );
565    memcpy( tor->hash, inf->hash, sizeof tor->hash );
566
567    tr_torrentSetFolder( tor->tor, ( NULL == dir ? gl_dir : dir ) );
568
569    if( TR_FLAG_PRIVATE & inf->flags )
570    {
571        tor->pexset = 1;
572        tor->pex    = 0;
573    }
574    else
575    {
576        tr_torrentDisablePex( tor->tor, !gl_pex );
577    }
578
579    found = RB_INSERT( tortree, &gl_tree, tor );
580    assert( NULL == found );
581    found = RB_INSERT( hashtree, &gl_hashes, tor );
582    assert( NULL == found );
583
584    return tor;
585}
586
587void
588closetor( struct tor * tor, int calltimer )
589{
590    tr_stat_t  * st;
591
592    if( NULL == tor || tor->deleting )
593    {
594        return;
595    }
596    tor->deleting = 1;
597
598    st = tr_torrentStat( tor->tor );
599    if( TR_STATUS_ACTIVE & st->status )
600    {
601        tr_torrentStop( tor->tor );
602    }
603
604    starttimer( calltimer );
605}
606
607void
608starttimer( int callnow )
609{
610    if( !evtimer_initialized( &gl_event ) )
611    {
612        evtimer_set( &gl_event, timerfunc, NULL );
613        event_base_set( gl_base, &gl_event );
614    }
615
616    if( callnow )
617    {
618        timerfunc( -1, EV_TIMEOUT, NULL );
619    }
620}
621
622void
623timerfunc( int fd UNUSED, short event UNUSED, void * arg UNUSED )
624{
625    struct tor         * tor, * next;
626    tr_handle_status_t * hs;
627    tr_stat_t          * st;
628    int                  stillmore;
629    struct timeval       tv;
630
631    stillmore = 0;
632    for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
633    {
634        next = RB_NEXT( tortree, &gl_tree, tor );
635        if( !tor->deleting )
636        {
637            continue;
638        }
639        st = tr_torrentStat( tor->tor );
640        if( TR_STATUS_PAUSE & st->status )
641        {
642            tr_torrentClose( gl_handle, tor->tor );
643            RB_REMOVE( tortree, &gl_tree, tor );
644            RB_REMOVE( hashtree, &gl_hashes, tor );
645            free( tor );
646        }
647        else
648        {
649            stillmore = 1;
650        }
651    }
652
653    if( gl_exiting )
654    {
655        if( !stillmore )
656        {
657            hs = tr_handleStatus( gl_handle );
658            if( TR_NAT_TRAVERSAL_DISABLED != hs->natTraversalStatus )
659            {
660                stillmore = 1;
661            }
662        }
663
664        if( !stillmore || EXIT_TIMEOUT <= time( NULL ) - gl_exiting )
665        {
666            if( stillmore )
667            {
668                errmsg( "timing out trackers and/or port mapping on exit" );
669            }
670            for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
671            {
672                next = RB_NEXT( tortree, &gl_tree, tor );
673                tr_torrentClose( gl_handle, tor->tor );
674                RB_REMOVE( tortree, &gl_tree, tor );
675                RB_REMOVE( hashtree, &gl_hashes, tor );
676                free( tor );
677            }
678            tr_close( gl_handle );
679            exit( gl_exitval );
680        }
681    }
682
683    if( stillmore )
684    {
685        bzero( &tv, sizeof tv );
686        tv.tv_sec  = TIMER_SECS;
687        tv.tv_usec = TIMER_USECS;
688        evtimer_add( &gl_event, &tv );
689    }
690}
691
692int
693loadstate( void )
694{
695    uint8_t   *  buf;
696    size_t       len;
697    benc_val_t   top, * num, * str, * list, * dict;
698    int          ii;
699    struct tor * tor;
700    const char * dir;
701
702    buf = readfile( gl_state, &len );
703    if( NULL == buf )
704    {
705        return -1;
706    }
707
708    if( tr_bencLoad( buf, len, &top, NULL ) )
709    {
710        free( buf );
711        errmsg( "failed to load bencoded data from %s", gl_state );
712        return -1;
713    }
714    free( buf );
715
716    num = tr_bencDictFind( &top, "autostart" );
717    if( NULL != num && TYPE_INT == num->type )
718    {
719        gl_autostart = ( num->val.i ? 1 : 0 );
720    }
721
722    num = tr_bencDictFind( &top, "port" );
723    if( NULL != num && TYPE_INT == num->type &&
724        0 < num->val.i && 0xffff > num->val.i )
725    {
726        gl_port = num->val.i;
727    }
728    tr_setBindPort( gl_handle, gl_port );
729
730    num = tr_bencDictFind( &top, "default-pex" );
731    if( NULL != num && TYPE_INT == num->type )
732    {
733        gl_pex = ( num->val.i ? 1 : 0 );
734    }
735
736    num = tr_bencDictFind( &top, "port-mapping" );
737    if( NULL != num && TYPE_INT == num->type )
738    {
739        gl_mapping = ( num->val.i ? 1 : 0 );
740    }
741    tr_natTraversalEnable( gl_handle, gl_mapping );
742
743    num = tr_bencDictFind( &top, "upload-limit" );
744    if( NULL != num && TYPE_INT == num->type )
745    {
746        gl_uplimit = num->val.i;
747    }
748    tr_setGlobalUploadLimit( gl_handle, gl_uplimit );
749
750    num = tr_bencDictFind( &top, "download-limit" );
751    if( NULL != num && TYPE_INT == num->type )
752    {
753        gl_downlimit = num->val.i;
754    }
755    tr_setGlobalDownloadLimit( gl_handle, gl_downlimit );
756
757    str = tr_bencDictFind( &top, "default-directory" );
758    if( NULL != str && TYPE_STR == str->type )
759    {
760        strlcpy( gl_dir, str->val.s.s, sizeof gl_dir );
761    }
762
763    list = tr_bencDictFind( &top, "torrents" );
764    if( NULL == list || TYPE_LIST != list->type )
765    {
766        return 0;
767    }
768
769    for( ii = 0; ii < list->val.l.count; ii++ )
770    {
771        dict = &list->val.l.vals[ii];
772        if( TYPE_DICT != dict->type )
773        {
774            continue;
775        }
776
777        str = tr_bencDictFind( dict, "directory" );
778        dir = ( NULL != str && TYPE_STR == str->type ? str->val.s.s : NULL );
779
780        str = tr_bencDictFind( dict, "hash" );
781        if( NULL == str || TYPE_STR != str->type ||
782            2 * SHA_DIGEST_LENGTH != str->val.s.i )
783        {
784            continue;
785        }
786
787        tor = opentor( NULL, str->val.s.s, NULL, 0, dir );
788        if( NULL == tor )
789        {
790            continue;
791        }
792
793        num = tr_bencDictFind( dict, "pex" );
794        if( NULL != num && TYPE_INT == num->type )
795        {
796            tor->pexset = 1;
797            tor->pex = ( num->val.i ? 1 : 0 );
798        }
799        tr_torrentDisablePex( tor->tor, !( tor->pexset ? tor->pex : gl_pex ) );
800
801        num = tr_bencDictFind( dict, "paused" );
802        if( NULL != num && TYPE_INT == num->type && !num->val.i )
803        {
804            tr_torrentStart( tor->tor );
805        }
806    }
807
808    return 0;
809}
810
811int
812savestate( void )
813{
814    benc_val_t   top, * list, * tor;
815    struct tor * ii;
816    tr_info_t  * inf;
817    tr_stat_t  * st;
818    uint8_t    * buf;
819    int          len, pexset;
820
821    tr_bencInit( &top, TYPE_DICT );
822    if( tr_bencDictReserve( &top, 8 ) )
823    {
824      nomem:
825        tr_bencFree( &top );
826        errmsg( "failed to save state: failed to allocate memory" );
827        return -1;
828    }
829    tr_bencInitInt( tr_bencDictAdd( &top, "autostart" ),      gl_autostart );
830    tr_bencInitInt( tr_bencDictAdd( &top, "port" ),           gl_port );
831    tr_bencInitInt( tr_bencDictAdd( &top, "default-pex" ),    gl_pex );
832    tr_bencInitInt( tr_bencDictAdd( &top, "port-mapping" ),   gl_mapping );
833    tr_bencInitInt( tr_bencDictAdd( &top, "upload-limit" ),   gl_uplimit );
834    tr_bencInitInt( tr_bencDictAdd( &top, "download-limit" ), gl_downlimit );
835    tr_bencInitStr( tr_bencDictAdd( &top, "default-directory" ),
836                    gl_dir, -1, 1 );
837    list = tr_bencDictAdd( &top, "torrents" );
838    tr_bencInit( list, TYPE_LIST );
839
840    len = 0;
841    RB_FOREACH( ii, tortree, &gl_tree )
842    {
843        if( !ii->deleting )
844        {
845            len++;
846        }
847    }
848    if( tr_bencListReserve( list, len ) )
849    {
850        goto nomem;
851    }
852
853    RB_FOREACH( ii, tortree, &gl_tree )
854    {
855        if( ii->deleting )
856        {
857            continue;
858        }
859        tor = tr_bencListAdd( list );
860        assert( NULL != tor );
861        tr_bencInit( tor, TYPE_DICT );
862        inf    = tr_torrentInfo( ii->tor );
863        st     = tr_torrentStat( ii->tor );
864        pexset = ( ii->pexset && !( TR_FLAG_PRIVATE & inf->flags ) );
865        if( tr_bencDictReserve( tor, ( pexset ? 4 : 3 ) ) )
866        {
867            goto nomem;
868        }
869        tr_bencInitStr( tr_bencDictAdd( tor, "hash" ),
870                        inf->hashString, 2 * SHA_DIGEST_LENGTH, 1 );
871        tr_bencInitInt( tr_bencDictAdd( tor, "paused" ),
872                        ( TR_STATUS_INACTIVE & st->status ? 1 : 0 ) );
873        tr_bencInitStr( tr_bencDictAdd( tor, "directory" ),
874                        tr_torrentGetFolder( ii->tor ), -1, 1 );
875        if( pexset )
876        {
877            tr_bencInitInt( tr_bencDictAdd( tor, "pex" ), ii->pex );
878        }
879    }
880
881    buf = ( uint8_t * )tr_bencSaveMalloc( &top, &len );
882    SAFEBENCFREE( &top );
883    if( NULL == buf )
884    {
885        errnomsg( "failed to save state: bencoding failed" );
886        return -1;
887    }
888
889    if( 0 > writefile( gl_newstate, buf, len ) )
890    {
891        free( buf );
892        return -1;
893    }
894    free( buf );
895
896    if( 0 > rename( gl_newstate, gl_state ) )
897    {
898        errnomsg( "failed to save state: failed to rename %s to %s",
899                  gl_newstate, CONF_FILE_STATE );
900        return -1;
901    }
902
903    return 0;
904}
905
906int
907torhashcmp( struct tor * left, struct tor * right )
908{
909    return memcmp( left->hash, right->hash, sizeof left->hash );
910}
911
912struct tor *
913idlookup( int id, int wantdel )
914{
915    struct tor key, * found;
916
917    bzero( &key, sizeof key );
918    key.id = id;
919    found = RB_FIND( tortree, &gl_tree, &key );
920    if( NULL != found && !wantdel && found->deleting )
921    {
922        found = NULL;
923    }
924
925    return found;
926}
927
928struct tor *
929hashlookup( const uint8_t * hash, int wantdel )
930{
931    struct tor key, * found;
932
933    bzero( &key, sizeof key );
934    memcpy( key.hash, hash, sizeof key.hash );
935    found = RB_FIND( hashtree, &gl_hashes, &key );
936    if( NULL != found && !wantdel && found->deleting )
937    {
938        found = NULL;
939    }
940
941    return found;
942}
943
944struct tor *
945iterate( struct tor * tor )
946{
947    assert( NULL != gl_handle );
948    assert( !gl_exiting );
949
950    if( NULL == tor )
951    {
952        tor = RB_MIN( tortree, &gl_tree );
953    }
954    else
955    {
956        tor = RB_NEXT( tortree, &gl_tree, tor );
957    }
958
959    while( NULL != tor && tor->deleting )
960    {
961        tor = RB_NEXT( tortree, &gl_tree, tor );
962    }
963
964    return tor;
965}
Note: See TracBrowser for help on using the repository browser.