source: trunk/daemon/torrents.c @ 4277

Last change on this file since 4277 was 4277, checked in by charles, 15 years ago

brush away the last remnants of tr_torrentInit()

  • Property svn:keywords set to Date Rev Author Id
File size: 22.0 KB
Line 
1/******************************************************************************
2 * $Id: torrents.c 4277 2007-12-22 03:51:12Z charles $
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 <libtransmission/bsdtree.h>
43#include <libtransmission/bencode.h>
44#include <libtransmission/transmission.h>
45#include <libtransmission/trcompat.h>
46
47#include "errors.h"
48#include "misc.h"
49#include "torrents.h"
50
51#define EXIT_TIMEOUT 10         /* how many seconds to wait on exit */
52#define TIMER_SECS   1          /* timer interval seconds */
53#define TIMER_USECS  0          /* timer interval microseconds */
54
55struct tor
56{
57    int             id;
58    uint8_t         hash[SHA_DIGEST_LENGTH];
59    tr_torrent    * 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 );
79static struct tor * hashlookup ( const uint8_t * );
80static struct tor * iterate    ( struct tor * );
81
82static struct event_base * gl_base      = NULL;
83static tr_handle         * 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];
100static tr_encryption_mode  gl_crypto    = TR_ENCRYPTION_PREFERRED;
101
102RB_GENERATE_STATIC( tortree, tor, idlinks, toridcmp )
103RB_GENERATE_STATIC( hashtree, tor, hashlinks, torhashcmp )
104INTCMP_FUNC( toridcmp, tor, id )
105
106void
107torrent_init( struct event_base * base )
108{
109    assert( NULL == gl_handle && NULL == gl_base );
110
111    gl_base   = base;
112    gl_handle = tr_init( "daemon" );
113
114    confpath( gl_state, sizeof gl_state, CONF_FILE_STATE, 0 );
115    strlcpy( gl_newstate, gl_state, sizeof gl_state );
116    strlcat( gl_newstate, ".new", sizeof gl_state );
117    absolutify( gl_dir, sizeof gl_dir, "." );
118
119    loadstate();
120}
121
122int
123torrent_add_file( const char * path, const char * dir, int autostart )
124{
125    struct tor * tor;
126
127    assert( NULL != gl_handle );
128    assert( !gl_exiting );
129
130    tor = opentor( path, NULL, NULL, 0, dir );
131    if( NULL == tor )
132    {
133        return -1;
134    }
135
136    if( 0 > autostart )
137    {
138        autostart = gl_autostart;
139    }
140    if( autostart )
141    {
142        tr_torrentStart( tor->tor );
143    }
144
145    savestate();
146
147    return tor->id;
148}
149
150int
151torrent_add_data( uint8_t * data, size_t size, const char * dir, int autostart )
152{
153    struct tor * tor;
154
155    assert( NULL != gl_handle );
156    assert( !gl_exiting );
157
158    tor = opentor( NULL, NULL, data, size, dir );
159    if( NULL == tor )
160    {
161        return -1;
162    }
163
164    if( 0 > autostart )
165    {
166        autostart = gl_autostart;
167    }
168    if( autostart )
169    {
170        tr_torrentStart( tor->tor );
171    }
172
173    savestate();
174
175    return tor->id;
176}
177
178void
179torrent_start( int id )
180{
181    struct tor * tor;
182
183    assert( NULL != gl_handle );
184    assert( !gl_exiting );
185
186    tor = idlookup( id );
187    if( tor != NULL )
188    {
189        const tr_stat  * st = tr_torrentStat( tor->tor );
190
191        if( !TR_STATUS_IS_ACTIVE( st->status ) )
192        {
193            tr_torrentStart( tor->tor );
194            savestate();
195        }
196    }
197
198}
199
200void
201torrent_stop( int id )
202{
203    struct tor * tor;
204
205    assert( NULL != gl_handle );
206    assert( !gl_exiting );
207
208    tor = idlookup( id );
209    if( tor != NULL )
210    {
211        const tr_stat  * st = tr_torrentStat( tor->tor );
212
213        if( TR_STATUS_IS_ACTIVE( st->status ) )
214        {
215            tr_torrentStop( tor->tor );
216            savestate();
217        }
218    }
219}
220
221void
222torrent_remove( int id )
223{
224    struct tor * tor;
225
226    assert( NULL != gl_handle );
227    assert( !gl_exiting );
228
229    tor = idlookup( id );
230    if( tor != NULL )
231    {
232        closetor( tor, 1 );
233        savestate();
234    }
235}
236
237const tr_info *
238torrent_info( int id )
239{
240    struct tor * tor;
241
242    assert( NULL != gl_handle );
243    assert( !gl_exiting );
244
245    tor = idlookup( id );
246    if( NULL == tor )
247    {
248        return NULL;
249    }
250
251    return tr_torrentInfo( tor->tor );
252}
253
254const tr_stat *
255torrent_stat( int id )
256{
257    struct tor * tor;
258
259    assert( NULL != gl_handle );
260    assert( !gl_exiting );
261
262    tor = idlookup( id );
263    if( NULL == tor )
264    {
265        return NULL;
266    }
267
268    return tr_torrentStat( tor->tor );
269}
270
271int
272torrent_lookup( const uint8_t * hashstr )
273{
274    uint8_t      hash[SHA_DIGEST_LENGTH];
275    size_t       ii;
276    struct tor * tor;
277    char         buf[3];
278
279    assert( NULL != gl_handle );
280    assert( !gl_exiting );
281
282    memset( buf, 0, sizeof buf );
283    for( ii = 0; sizeof( hash ) > ii; ii++ )
284    {
285        if( !isxdigit( hashstr[2*ii] ) || !isxdigit( hashstr[1+2*ii] ) )
286        {
287            return -1;
288        }
289        memcpy( buf, &hashstr[2*ii], 2 );
290        hash[ii] = strtol( buf, NULL, 16 );
291    }
292
293    tor = hashlookup( hash );
294    if( NULL == tor )
295    {
296        return -1;
297    }
298
299    return tor->id;
300}
301
302void *
303torrent_iter( void * iter, int * id )
304{
305    struct tor * tor = iter;
306
307    assert( NULL != gl_handle );
308    assert( !gl_exiting );
309
310    tor = iterate( tor );
311
312    if( NULL != tor )
313    {
314        *id = tor->id;
315    }
316
317    return tor;
318}
319
320void
321torrent_exit( int exitval )
322{
323    struct tor * tor;
324
325    assert( NULL != gl_handle );
326    assert( !gl_exiting );
327    gl_exiting = time( NULL );
328    gl_exitval = exitval;
329
330    RB_FOREACH( tor, tortree, &gl_tree )
331    {
332        closetor( tor, 0 );
333    }
334
335    tr_natTraversalEnable( gl_handle, 0 );
336    starttimer( 1 );
337}
338
339void
340torrent_set_autostart( int autostart )
341{
342    assert( NULL != gl_handle );
343    assert( !gl_exiting );
344    gl_autostart = autostart;
345    savestate();
346}
347
348int
349torrent_get_autostart( void )
350{
351    return gl_autostart;
352}
353
354void
355torrent_set_port( int port )
356{
357    assert( NULL != gl_handle );
358    assert( !gl_exiting );
359    if( 0 < port && 0xffff > port )
360    {
361        gl_port = port;
362        tr_setBindPort( gl_handle, port );
363        savestate();
364    }
365}
366
367int
368torrent_get_port( void )
369{
370    return gl_port;
371}
372
373void
374torrent_set_pex( int pex )
375{
376    struct tor * tor;
377
378    assert( NULL != gl_handle );
379    assert( !gl_exiting );
380
381    if( pex == gl_pex )
382    {
383        return;
384    }
385    gl_pex = pex;
386
387    for( tor = iterate( NULL ); NULL != tor; tor = iterate( tor ) )
388    {
389        if( tor->pexset )
390        {
391            continue;
392        }
393        tr_torrentDisablePex( tor->tor, !gl_pex );
394    }
395
396    savestate();
397}
398
399int
400torrent_get_pex( void )
401{
402    return gl_pex;
403}
404
405void
406torrent_enable_port_mapping( int automap )
407{
408    assert( NULL != gl_handle );
409    assert( !gl_exiting );
410    gl_mapping = ( automap ? 1 : 0 );
411    tr_natTraversalEnable( gl_handle, gl_mapping );
412    savestate();
413}
414
415int
416torrent_get_port_mapping( void )
417{
418    return gl_mapping;
419}
420
421void
422torrent_set_uplimit( int uplimit )
423{
424    assert( NULL != gl_handle );
425    assert( !gl_exiting );
426    gl_uplimit = uplimit;
427    tr_setGlobalSpeedLimit   ( gl_handle, TR_UP, uplimit );
428    tr_setUseGlobalSpeedLimit( gl_handle, TR_UP, uplimit > 0 );
429    savestate();
430}
431
432int
433torrent_get_uplimit( void )
434{
435    return gl_uplimit;
436}
437
438void
439torrent_set_downlimit( int downlimit )
440{
441    assert( NULL != gl_handle );
442    assert( !gl_exiting );
443    gl_downlimit = downlimit;
444    tr_setGlobalSpeedLimit   ( gl_handle, TR_DOWN, downlimit );
445    tr_setUseGlobalSpeedLimit( gl_handle, TR_DOWN, downlimit > 0 );
446    savestate();
447}
448
449int
450torrent_get_downlimit( void )
451{
452    return gl_downlimit;
453}
454
455void
456torrent_set_directory( const char * path )
457{
458    assert( NULL != gl_handle );
459    assert( !gl_exiting );
460
461    absolutify( gl_dir, sizeof gl_dir, path );
462    savestate();
463}
464
465const char *
466torrent_get_directory( void )
467{
468    return gl_dir;
469}
470
471void
472torrent_set_encryption(tr_encryption_mode mode)
473{
474    tr_setEncryptionMode(gl_handle, mode);
475    gl_crypto = mode;
476    savestate();
477}
478
479tr_encryption_mode
480torrent_get_encryption(void)
481{
482    return tr_getEncryptionMode(gl_handle);
483}
484
485struct tor *
486opentor( const char * path, const char * hash, uint8_t * data, size_t size,
487         const char * dir )
488{
489    struct tor * tor, * found;
490    int          errcode;
491    const tr_info  * inf;
492    tr_ctor        * ctor;
493
494    assert( ( NULL != path && NULL == hash && NULL == data ) ||
495            ( NULL == path && NULL != hash && NULL == data ) ||
496            ( NULL == path && NULL == hash && NULL != data ) );
497
498    /* XXX should probably wrap around back to 1 and avoid duplicates */
499    if( INT_MAX == gl_lastid )
500    {
501        errmsg( "Congratulations, you're the %ith torrent! Your prize the "
502                "inability to load any more torrents, enjoy!", INT_MAX );
503        return NULL;
504    }
505
506    tor = calloc( 1, sizeof *tor );
507    if( NULL == tor )
508    {
509        mallocmsg( sizeof *tor );
510        return NULL;
511    }
512
513    if( dir == NULL )
514        dir = gl_dir;
515
516    ctor = tr_ctorNew( gl_handle );
517    tr_ctorSetPaused( ctor, TR_FORCE, 1 );
518    tr_ctorSetDestination( ctor, TR_FORCE, dir );
519    if( path != NULL )
520        tr_ctorSetMetainfoFromFile( ctor, path );
521    else if( hash != NULL )
522        tr_ctorSetMetainfoFromHash( ctor, hash );
523    else
524        tr_ctorSetMetainfo( ctor, data, size );
525    tor->tor = tr_torrentNew( gl_handle, ctor, &errcode );
526    tr_ctorFree( ctor );
527
528    if( NULL == tor->tor )
529    {
530        found = NULL;
531        switch( errcode )
532        {
533            case TR_EINVALID:
534                if( NULL == path )
535                {
536                    errmsg( "invalid torrent file" );
537                }
538                else
539                {
540                    errmsg( "invalid torrent file: %s", path );
541                }
542                break;
543            case TR_EUNSUPPORTED:
544                if( NULL == path )
545                {
546                    errmsg( "unsupported torrent file" );
547                }
548                else
549                {
550                    errmsg( "unsupported torrent file: %s", path );
551                }
552                break;
553            case TR_EDUPLICATE:
554                /* XXX not yet
555                found = hashlookup( tor->hash, 1 );
556                assert( NULL != found );
557                found->deleting = 0;
558                */
559                errmsg( "XXX loaded duplicate torrent" );
560                break;
561            default:
562                if( NULL == path )
563                {
564                    errmsg( "torrent file failed to load" );
565                }
566                else
567                {
568                    errmsg( "torrent file failed to load: %s", path );
569                }
570                break;
571        }
572        free( tor );
573        return found;
574    }
575    gl_lastid++;
576    tor->id       = gl_lastid;
577
578    assert( sizeof( inf->hash ) == sizeof( tor->hash ) );
579    inf = tr_torrentInfo( tor->tor );
580    memcpy( tor->hash, inf->hash, sizeof tor->hash );
581
582    if( inf->isPrivate )
583    {
584        tor->pexset = 1;
585        tor->pex    = 0;
586    }
587    else
588    {
589        tr_torrentDisablePex( tor->tor, !gl_pex );
590    }
591
592    found = RB_INSERT( tortree, &gl_tree, tor );
593    assert( NULL == found );
594    found = RB_INSERT( hashtree, &gl_hashes, tor );
595    assert( NULL == found );
596
597    return tor;
598}
599
600static void
601freetor( struct tor * tor )
602{
603    tr_torrentClose( tor->tor );
604    RB_REMOVE( tortree, &gl_tree, tor );
605    RB_REMOVE( hashtree, &gl_hashes, tor );
606    free( tor );
607}
608
609void
610closetor( struct tor * tor, int calltimer )
611{
612    if( NULL != tor )
613    {
614        freetor( tor );
615
616        starttimer( calltimer );
617    }
618}
619
620void
621starttimer( int callnow )
622{
623    if( !evtimer_initialized( &gl_event ) )
624    {
625        evtimer_set( &gl_event, timerfunc, NULL );
626        event_base_set( gl_base, &gl_event );
627    }
628
629    if( callnow )
630    {
631        timerfunc( -1, EV_TIMEOUT, NULL );
632    }
633}
634
635static void
636timerfunc( int fd UNUSED, short event UNUSED, void * arg UNUSED )
637{
638    struct tor       * tor, * next;
639    tr_handle_status * hs;
640    int                stillmore;
641    struct timeval     tv;
642
643    /* true if we've still got live torrents... */
644    stillmore = tr_torrentCount( gl_handle ) != 0;
645
646    if( gl_exiting )
647    {
648        if( !stillmore )
649        {
650            hs = tr_handleStatus( gl_handle );
651            if( TR_NAT_TRAVERSAL_UNMAPPED != hs->natTraversalStatus )
652            {
653                stillmore = 1;
654            }
655        }
656
657        if( !stillmore || EXIT_TIMEOUT <= time( NULL ) - gl_exiting )
658        {
659            if( stillmore )
660            {
661                errmsg( "timing out trackers and/or port mapping on exit" );
662            }
663            for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
664            {
665                next = RB_NEXT( tortree, &gl_tree, tor );
666                freetor( tor );
667            }
668            tr_close( gl_handle );
669            exit( gl_exitval );
670        }
671    }
672
673    if( stillmore )
674    {
675        memset( &tv, 0, sizeof tv );
676        tv.tv_sec  = TIMER_SECS;
677        tv.tv_usec = TIMER_USECS;
678        evtimer_add( &gl_event, &tv );
679    }
680}
681
682int
683loadstate( void )
684{
685    uint8_t   *  buf;
686    size_t       len;
687    benc_val_t   top, * num, * str, * list, * dict;
688    int          ii;
689    struct tor * tor;
690    const char * dir;
691
692    buf = readfile( gl_state, &len );
693    if( NULL == buf )
694    {
695        return -1;
696    }
697
698    if( tr_bencLoad( buf, len, &top, NULL ) )
699    {
700        free( buf );
701        errmsg( "failed to load bencoded data from %s", gl_state );
702        return -1;
703    }
704    free( buf );
705
706    num = tr_bencDictFind( &top, "autostart" );
707    if( NULL != num && TYPE_INT == num->type )
708    {
709        gl_autostart = ( num->val.i ? 1 : 0 );
710    }
711
712    num = tr_bencDictFind( &top, "port" );
713    if( NULL != num && TYPE_INT == num->type &&
714        0 < num->val.i && 0xffff > num->val.i )
715    {
716        gl_port = num->val.i;
717    }
718    tr_setBindPort( gl_handle, gl_port );
719
720    num = tr_bencDictFind( &top, "default-pex" );
721    if( NULL != num && TYPE_INT == num->type )
722    {
723        gl_pex = ( num->val.i ? 1 : 0 );
724    }
725
726    num = tr_bencDictFind( &top, "port-mapping" );
727    if( NULL != num && TYPE_INT == num->type )
728    {
729        gl_mapping = ( num->val.i ? 1 : 0 );
730    }
731    tr_natTraversalEnable( gl_handle, gl_mapping );
732
733    num = tr_bencDictFind( &top, "upload-limit" );
734    if( NULL != num && TYPE_INT == num->type )
735    {
736        gl_uplimit = num->val.i;
737    }
738    tr_setGlobalSpeedLimit( gl_handle, TR_UP, gl_uplimit );
739    tr_setUseGlobalSpeedLimit( gl_handle, TR_UP, gl_uplimit > 0 );
740
741    num = tr_bencDictFind( &top, "download-limit" );
742    if( NULL != num && TYPE_INT == num->type )
743    {
744        gl_downlimit = num->val.i;
745    }
746    tr_setGlobalSpeedLimit( gl_handle, TR_DOWN, gl_downlimit );
747    tr_setUseGlobalSpeedLimit( gl_handle, TR_DOWN, gl_downlimit > 0 );
748
749    str = tr_bencDictFind( &top, "default-directory" );
750    if( NULL != str && TYPE_STR == str->type )
751    {
752        strlcpy( gl_dir, str->val.s.s, sizeof gl_dir );
753    }
754
755    str = tr_bencDictFind( &top, "encryption-mode" );
756    if( NULL != str && TYPE_STR == str->type )
757    {
758        if(!strcasecmp(str->val.s.s, "preferred"))
759            gl_crypto = TR_ENCRYPTION_PREFERRED;
760        else if(!strcasecmp(str->val.s.s, "required"))
761            gl_crypto = TR_ENCRYPTION_REQUIRED;
762    }
763
764    tr_setEncryptionMode(gl_handle, gl_crypto);
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    uint8_t    * buf;
820    int          len, pexset;
821
822    tr_bencInit( &top, TYPE_DICT );
823    if( tr_bencDictReserve( &top, 9 ) )
824    {
825      nomem:
826        tr_bencFree( &top );
827        errmsg( "failed to save state: failed to allocate memory" );
828        return -1;
829    }
830    tr_bencInitInt( tr_bencDictAdd( &top, "autostart" ),      gl_autostart );
831    tr_bencInitInt( tr_bencDictAdd( &top, "port" ),           gl_port );
832    tr_bencInitInt( tr_bencDictAdd( &top, "default-pex" ),    gl_pex );
833    tr_bencInitInt( tr_bencDictAdd( &top, "port-mapping" ),   gl_mapping );
834    tr_bencInitInt( tr_bencDictAdd( &top, "upload-limit" ),   gl_uplimit );
835    tr_bencInitInt( tr_bencDictAdd( &top, "download-limit" ), gl_downlimit );
836    tr_bencInitStr( tr_bencDictAdd( &top, "default-directory" ),
837                    gl_dir, -1, 1 );
838    if(TR_ENCRYPTION_REQUIRED == gl_crypto)
839        tr_bencInitStr(tr_bencDictAdd(&top, "encryption-mode"), "required", -1, 1);
840    else
841        tr_bencInitStr(tr_bencDictAdd(&top, "encryption-mode"), "preferred", -1, 1);
842    list = tr_bencDictAdd( &top, "torrents" );
843    tr_bencInit( list, TYPE_LIST );
844
845    len = 0;
846    RB_FOREACH( ii, tortree, &gl_tree )
847    {
848        len++;
849    }
850    if( tr_bencListReserve( list, len ) )
851    {
852        goto nomem;
853    }
854
855    RB_FOREACH( ii, tortree, &gl_tree )
856    {
857        const tr_info * inf;
858        const tr_stat * st;
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 && !inf->isPrivate );
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_IS_ACTIVE( st->status ) );
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_bencSave( &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 )
914{
915    struct tor key, * found;
916
917    memset( &key, 0, sizeof key );
918    key.id = id;
919    found = RB_FIND( tortree, &gl_tree, &key );
920
921    return found;
922}
923
924struct tor *
925hashlookup( const uint8_t * hash )
926{
927    struct tor key, * found;
928
929    memset( &key, 0, sizeof key );
930    memcpy( key.hash, hash, sizeof key.hash );
931    found = RB_FIND( hashtree, &gl_hashes, &key );
932
933    return found;
934}
935
936struct tor *
937iterate( struct tor * tor )
938{
939    assert( NULL != gl_handle );
940    assert( !gl_exiting );
941
942    if( NULL == tor )
943    {
944        tor = RB_MIN( tortree, &gl_tree );
945    }
946    else
947    {
948        tor = RB_NEXT( tortree, &gl_tree, tor );
949    }
950
951    return tor;
952}
Note: See TracBrowser for help on using the repository browser.