source: trunk/daemon/torrents.c @ 3576

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

Whoops. Start the exit timer on the right libevent instance.
This should fix some problems with the daemon exiting.

  • Property svn:keywords set to Date Rev Author Id
File size: 21.0 KB
Line 
1/******************************************************************************
2 * $Id: torrents.c 3576 2007-10-26 03:36:02Z 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 <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];
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
182    assert( NULL != gl_handle );
183    assert( !gl_exiting );
184
185    tor = idlookup( id );
186    if( tor != NULL )
187    {
188        const tr_stat  * st = tr_torrentStat( tor->tor );
189
190        if( !TR_STATUS_IS_ACTIVE( st->status ) )
191        {
192            tr_torrentStart( tor->tor );
193            savestate();
194        }
195    }
196
197}
198
199void
200torrent_stop( int id )
201{
202    struct tor * tor;
203
204    assert( NULL != gl_handle );
205    assert( !gl_exiting );
206
207    tor = idlookup( id );
208    if( tor != NULL )
209    {
210        const tr_stat  * st = tr_torrentStat( tor->tor );
211
212        if( TR_STATUS_IS_ACTIVE( st->status ) )
213        {
214            tr_torrentStop( tor->tor );
215            savestate();
216        }
217    }
218}
219
220void
221torrent_remove( int id )
222{
223    struct tor * tor;
224
225    assert( NULL != gl_handle );
226    assert( !gl_exiting );
227
228    tor = idlookup( id );
229    if( tor != NULL )
230    {
231        closetor( tor, 1 );
232        savestate();
233    }
234}
235
236const tr_info *
237torrent_info( int id )
238{
239    struct tor * tor;
240
241    assert( NULL != gl_handle );
242    assert( !gl_exiting );
243
244    tor = idlookup( id );
245    if( NULL == tor )
246    {
247        return NULL;
248    }
249
250    return tr_torrentInfo( tor->tor );
251}
252
253const tr_stat *
254torrent_stat( int id )
255{
256    struct tor * tor;
257
258    assert( NULL != gl_handle );
259    assert( !gl_exiting );
260
261    tor = idlookup( id );
262    if( NULL == tor )
263    {
264        return NULL;
265    }
266
267    return tr_torrentStat( tor->tor );
268}
269
270int
271torrent_lookup( const uint8_t * hashstr )
272{
273    uint8_t      hash[SHA_DIGEST_LENGTH];
274    size_t       ii;
275    struct tor * tor;
276    char         buf[3];
277
278    assert( NULL != gl_handle );
279    assert( !gl_exiting );
280
281    memset( buf, 0, sizeof buf );
282    for( ii = 0; sizeof( hash ) > ii; ii++ )
283    {
284        if( !isxdigit( hashstr[2*ii] ) || !isxdigit( hashstr[1+2*ii] ) )
285        {
286            return -1;
287        }
288        memcpy( buf, &hashstr[2*ii], 2 );
289        hash[ii] = strtol( buf, NULL, 16 );
290    }
291
292    tor = hashlookup( hash );
293    if( NULL == tor )
294    {
295        return -1;
296    }
297
298    return tor->id;
299}
300
301void *
302torrent_iter( void * iter, int * id )
303{
304    struct tor * tor = iter;
305
306    assert( NULL != gl_handle );
307    assert( !gl_exiting );
308
309    tor = iterate( tor );
310
311    if( NULL != tor )
312    {
313        *id = tor->id;
314    }
315
316    return tor;
317}
318
319void
320torrent_exit( int exitval )
321{
322    struct tor * tor;
323
324    assert( NULL != gl_handle );
325    assert( !gl_exiting );
326    gl_exiting = time( NULL );
327    gl_exitval = exitval;
328
329    RB_FOREACH( tor, tortree, &gl_tree )
330    {
331        closetor( tor, 0 );
332    }
333
334    tr_natTraversalEnable( gl_handle, 0 );
335    starttimer( 1 );
336}
337
338void
339torrent_set_autostart( int autostart )
340{
341    assert( NULL != gl_handle );
342    assert( !gl_exiting );
343    gl_autostart = autostart;
344    savestate();
345}
346
347int
348torrent_get_autostart( void )
349{
350    return gl_autostart;
351}
352
353void
354torrent_set_port( int port )
355{
356    assert( NULL != gl_handle );
357    assert( !gl_exiting );
358    if( 0 < port && 0xffff > port )
359    {
360        gl_port = port;
361        tr_setBindPort( gl_handle, port );
362        savestate();
363    }
364}
365
366int
367torrent_get_port( void )
368{
369    return gl_port;
370}
371
372void
373torrent_set_pex( int pex )
374{
375    struct tor * tor;
376
377    assert( NULL != gl_handle );
378    assert( !gl_exiting );
379
380    if( pex == gl_pex )
381    {
382        return;
383    }
384    gl_pex = pex;
385
386    for( tor = iterate( NULL ); NULL != tor; tor = iterate( tor ) )
387    {
388        if( tor->pexset )
389        {
390            continue;
391        }
392        tr_torrentDisablePex( tor->tor, !gl_pex );
393    }
394
395    savestate();
396}
397
398int
399torrent_get_pex( void )
400{
401    return gl_pex;
402}
403
404void
405torrent_enable_port_mapping( int automap )
406{
407    assert( NULL != gl_handle );
408    assert( !gl_exiting );
409    gl_mapping = ( automap ? 1 : 0 );
410    tr_natTraversalEnable( gl_handle, gl_mapping );
411    savestate();
412}
413
414int
415torrent_get_port_mapping( void )
416{
417    return gl_mapping;
418}
419
420void
421torrent_set_uplimit( int uplimit )
422{
423    assert( NULL != gl_handle );
424    assert( !gl_exiting );
425    gl_uplimit = uplimit;
426    tr_setGlobalSpeedLimit   ( gl_handle, TR_UP, uplimit );
427    tr_setUseGlobalSpeedLimit( gl_handle, TR_UP, uplimit > 0 );
428    savestate();
429}
430
431int
432torrent_get_uplimit( void )
433{
434    return gl_uplimit;
435}
436
437void
438torrent_set_downlimit( int downlimit )
439{
440    assert( NULL != gl_handle );
441    assert( !gl_exiting );
442    gl_downlimit = downlimit;
443    tr_setGlobalSpeedLimit   ( gl_handle, TR_DOWN, downlimit );
444    tr_setUseGlobalSpeedLimit( gl_handle, TR_DOWN, downlimit > 0 );
445    savestate();
446}
447
448int
449torrent_get_downlimit( void )
450{
451    return gl_downlimit;
452}
453
454void
455torrent_set_directory( const char * path )
456{
457    assert( NULL != gl_handle );
458    assert( !gl_exiting );
459
460    absolutify( gl_dir, sizeof gl_dir, path );
461    savestate();
462}
463
464const char *
465torrent_get_directory( void )
466{
467    return gl_dir;
468}
469
470struct tor *
471opentor( const char * path, const char * hash, uint8_t * data, size_t size,
472         const char * dir )
473{
474    struct tor * tor, * found;
475    int          errcode;
476    const tr_info  * inf;
477
478    assert( ( NULL != path && NULL == hash && NULL == data ) ||
479            ( NULL == path && NULL != hash && NULL == data ) ||
480            ( NULL == path && NULL == hash && NULL != data ) );
481
482    /* XXX should probably wrap around back to 1 and avoid duplicates */
483    if( INT_MAX == gl_lastid )
484    {
485        errmsg( "Congratulations, you're the %ith torrent! Your prize the "
486                "inability to load any more torrents, enjoy!", INT_MAX );
487        return NULL;
488    }
489
490    tor = calloc( 1, sizeof *tor );
491    if( NULL == tor )
492    {
493        mallocmsg( sizeof *tor );
494        return NULL;
495    }
496
497    if( dir == NULL )
498        dir = gl_dir;
499
500    if( NULL != path )
501    {
502        tor->tor = tr_torrentInit( gl_handle, path, dir, 1, &errcode );
503    }
504    else if( NULL != hash )
505    {
506        tor->tor = tr_torrentInitSaved( gl_handle, hash, dir, 1, &errcode );
507    }
508    else
509    {
510        tor->tor = tr_torrentInitData( gl_handle, data, size, dir, 1, &errcode );
511    }
512
513    if( NULL == tor->tor )
514    {
515        found = NULL;
516        switch( errcode )
517        {
518            case TR_EINVALID:
519                if( NULL == path )
520                {
521                    errmsg( "invalid torrent file" );
522                }
523                else
524                {
525                    errmsg( "invalid torrent file: %s", path );
526                }
527                break;
528            case TR_EUNSUPPORTED:
529                if( NULL == path )
530                {
531                    errmsg( "unsupported torrent file" );
532                }
533                else
534                {
535                    errmsg( "unsupported torrent file: %s", path );
536                }
537                break;
538            case TR_EDUPLICATE:
539                /* XXX not yet
540                found = hashlookup( tor->hash, 1 );
541                assert( NULL != found );
542                found->deleting = 0;
543                */
544                errmsg( "XXX loaded duplicate torrent" );
545                break;
546            default:
547                if( NULL == path )
548                {
549                    errmsg( "torrent file failed to load" );
550                }
551                else
552                {
553                    errmsg( "torrent file failed to load: %s", path );
554                }
555                break;
556        }
557        free( tor );
558        return found;
559    }
560    gl_lastid++;
561    tor->id       = gl_lastid;
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    if( inf->isPrivate )
568    {
569        tor->pexset = 1;
570        tor->pex    = 0;
571    }
572    else
573    {
574        tr_torrentDisablePex( tor->tor, !gl_pex );
575    }
576
577    found = RB_INSERT( tortree, &gl_tree, tor );
578    assert( NULL == found );
579    found = RB_INSERT( hashtree, &gl_hashes, tor );
580    assert( NULL == found );
581
582    return tor;
583}
584
585static void
586freetor( struct tor * tor )
587{
588    tr_torrentClose( tor->tor );
589    RB_REMOVE( tortree, &gl_tree, tor );
590    RB_REMOVE( hashtree, &gl_hashes, tor );
591    free( tor );
592}
593
594void
595closetor( struct tor * tor, int calltimer )
596{
597    if( NULL != tor )
598    {
599        freetor( tor );
600
601        starttimer( calltimer );
602    }
603}
604
605void
606starttimer( int callnow )
607{
608    if( !evtimer_initialized( &gl_event ) )
609    {
610        evtimer_set( &gl_event, timerfunc, NULL );
611        event_base_set( gl_base, &gl_event );
612    }
613
614    if( callnow )
615    {
616        timerfunc( -1, EV_TIMEOUT, NULL );
617    }
618}
619
620static void
621timerfunc( int fd UNUSED, short event UNUSED, void * arg UNUSED )
622{
623    struct tor       * tor, * next;
624    tr_handle_status * hs;
625    int                stillmore;
626    struct timeval     tv;
627
628    /* true if we've still got live torrents... */
629    stillmore = tr_torrentCount( gl_handle ) != 0;
630
631    if( gl_exiting )
632    {
633        if( !stillmore )
634        {
635            hs = tr_handleStatus( gl_handle );
636            if( TR_NAT_TRAVERSAL_DISABLED != hs->natTraversalStatus )
637            {
638                stillmore = 1;
639            }
640        }
641
642        if( !stillmore || EXIT_TIMEOUT <= time( NULL ) - gl_exiting )
643        {
644            if( stillmore )
645            {
646                errmsg( "timing out trackers and/or port mapping on exit" );
647            }
648            for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
649            {
650                next = RB_NEXT( tortree, &gl_tree, tor );
651                freetor( tor );
652            }
653            tr_close( gl_handle );
654            exit( gl_exitval );
655        }
656    }
657
658    if( stillmore )
659    {
660        memset( &tv, 0, sizeof tv );
661        tv.tv_sec  = TIMER_SECS;
662        tv.tv_usec = TIMER_USECS;
663        evtimer_add( &gl_event, &tv );
664    }
665}
666
667int
668loadstate( void )
669{
670    uint8_t   *  buf;
671    size_t       len;
672    benc_val_t   top, * num, * str, * list, * dict;
673    int          ii;
674    struct tor * tor;
675    const char * dir;
676
677    buf = readfile( gl_state, &len );
678    if( NULL == buf )
679    {
680        return -1;
681    }
682
683    if( tr_bencLoad( buf, len, &top, NULL ) )
684    {
685        free( buf );
686        errmsg( "failed to load bencoded data from %s", gl_state );
687        return -1;
688    }
689    free( buf );
690
691    num = tr_bencDictFind( &top, "autostart" );
692    if( NULL != num && TYPE_INT == num->type )
693    {
694        gl_autostart = ( num->val.i ? 1 : 0 );
695    }
696
697    num = tr_bencDictFind( &top, "port" );
698    if( NULL != num && TYPE_INT == num->type &&
699        0 < num->val.i && 0xffff > num->val.i )
700    {
701        gl_port = num->val.i;
702    }
703    tr_setBindPort( gl_handle, gl_port );
704
705    num = tr_bencDictFind( &top, "default-pex" );
706    if( NULL != num && TYPE_INT == num->type )
707    {
708        gl_pex = ( num->val.i ? 1 : 0 );
709    }
710
711    num = tr_bencDictFind( &top, "port-mapping" );
712    if( NULL != num && TYPE_INT == num->type )
713    {
714        gl_mapping = ( num->val.i ? 1 : 0 );
715    }
716    tr_natTraversalEnable( gl_handle, gl_mapping );
717
718    num = tr_bencDictFind( &top, "upload-limit" );
719    if( NULL != num && TYPE_INT == num->type )
720    {
721        gl_uplimit = num->val.i;
722    }
723    tr_setGlobalSpeedLimit( gl_handle, TR_UP, gl_uplimit );
724    tr_setUseGlobalSpeedLimit( gl_handle, TR_UP, gl_uplimit > 0 );
725
726    num = tr_bencDictFind( &top, "download-limit" );
727    if( NULL != num && TYPE_INT == num->type )
728    {
729        gl_downlimit = num->val.i;
730    }
731    tr_setGlobalSpeedLimit( gl_handle, TR_DOWN, gl_downlimit );
732    tr_setUseGlobalSpeedLimit( gl_handle, TR_DOWN, gl_downlimit > 0 );
733
734    str = tr_bencDictFind( &top, "default-directory" );
735    if( NULL != str && TYPE_STR == str->type )
736    {
737        strlcpy( gl_dir, str->val.s.s, sizeof gl_dir );
738    }
739
740    list = tr_bencDictFind( &top, "torrents" );
741    if( NULL == list || TYPE_LIST != list->type )
742    {
743        return 0;
744    }
745
746    for( ii = 0; ii < list->val.l.count; ii++ )
747    {
748        dict = &list->val.l.vals[ii];
749        if( TYPE_DICT != dict->type )
750        {
751            continue;
752        }
753
754        str = tr_bencDictFind( dict, "directory" );
755        dir = ( NULL != str && TYPE_STR == str->type ? str->val.s.s : NULL );
756
757        str = tr_bencDictFind( dict, "hash" );
758        if( NULL == str || TYPE_STR != str->type ||
759            2 * SHA_DIGEST_LENGTH != str->val.s.i )
760        {
761            continue;
762        }
763
764        tor = opentor( NULL, str->val.s.s, NULL, 0, dir );
765        if( NULL == tor )
766        {
767            continue;
768        }
769
770        num = tr_bencDictFind( dict, "pex" );
771        if( NULL != num && TYPE_INT == num->type )
772        {
773            tor->pexset = 1;
774            tor->pex = ( num->val.i ? 1 : 0 );
775        }
776        tr_torrentDisablePex( tor->tor, !( tor->pexset ? tor->pex : gl_pex ) );
777
778        num = tr_bencDictFind( dict, "paused" );
779        if( NULL != num && TYPE_INT == num->type && !num->val.i )
780        {
781            tr_torrentStart( tor->tor );
782        }
783    }
784
785    return 0;
786}
787
788int
789savestate( void )
790{
791    benc_val_t   top, * list, * tor;
792    struct tor * ii;
793    uint8_t    * buf;
794    int          len, pexset;
795
796    tr_bencInit( &top, TYPE_DICT );
797    if( tr_bencDictReserve( &top, 8 ) )
798    {
799      nomem:
800        tr_bencFree( &top );
801        errmsg( "failed to save state: failed to allocate memory" );
802        return -1;
803    }
804    tr_bencInitInt( tr_bencDictAdd( &top, "autostart" ),      gl_autostart );
805    tr_bencInitInt( tr_bencDictAdd( &top, "port" ),           gl_port );
806    tr_bencInitInt( tr_bencDictAdd( &top, "default-pex" ),    gl_pex );
807    tr_bencInitInt( tr_bencDictAdd( &top, "port-mapping" ),   gl_mapping );
808    tr_bencInitInt( tr_bencDictAdd( &top, "upload-limit" ),   gl_uplimit );
809    tr_bencInitInt( tr_bencDictAdd( &top, "download-limit" ), gl_downlimit );
810    tr_bencInitStr( tr_bencDictAdd( &top, "default-directory" ),
811                    gl_dir, -1, 1 );
812    list = tr_bencDictAdd( &top, "torrents" );
813    tr_bencInit( list, TYPE_LIST );
814
815    len = 0;
816    RB_FOREACH( ii, tortree, &gl_tree )
817    {
818        len++;
819    }
820    if( tr_bencListReserve( list, len ) )
821    {
822        goto nomem;
823    }
824
825    RB_FOREACH( ii, tortree, &gl_tree )
826    {
827        const tr_info * inf;
828        const tr_stat * st;
829        tor = tr_bencListAdd( list );
830        assert( NULL != tor );
831        tr_bencInit( tor, TYPE_DICT );
832        inf    = tr_torrentInfo( ii->tor );
833        st     = tr_torrentStat( ii->tor );
834        pexset = ( ii->pexset && !inf->isPrivate );
835        if( tr_bencDictReserve( tor, ( pexset ? 4 : 3 ) ) )
836        {
837            goto nomem;
838        }
839        tr_bencInitStr( tr_bencDictAdd( tor, "hash" ),
840                        inf->hashString, 2 * SHA_DIGEST_LENGTH, 1 );
841        tr_bencInitInt( tr_bencDictAdd( tor, "paused" ),
842                        !TR_STATUS_IS_ACTIVE( st->status ) );
843        tr_bencInitStr( tr_bencDictAdd( tor, "directory" ),
844                        tr_torrentGetFolder( ii->tor ), -1, 1 );
845        if( pexset )
846        {
847            tr_bencInitInt( tr_bencDictAdd( tor, "pex" ), ii->pex );
848        }
849    }
850
851    buf = ( uint8_t * )tr_bencSaveMalloc( &top, &len );
852    SAFEBENCFREE( &top );
853    if( NULL == buf )
854    {
855        errnomsg( "failed to save state: bencoding failed" );
856        return -1;
857    }
858
859    if( 0 > writefile( gl_newstate, buf, len ) )
860    {
861        free( buf );
862        return -1;
863    }
864    free( buf );
865
866    if( 0 > rename( gl_newstate, gl_state ) )
867    {
868        errnomsg( "failed to save state: failed to rename %s to %s",
869                  gl_newstate, CONF_FILE_STATE );
870        return -1;
871    }
872
873    return 0;
874}
875
876int
877torhashcmp( struct tor * left, struct tor * right )
878{
879    return memcmp( left->hash, right->hash, sizeof left->hash );
880}
881
882struct tor *
883idlookup( int id )
884{
885    struct tor key, * found;
886
887    memset( &key, 0, sizeof key );
888    key.id = id;
889    found = RB_FIND( tortree, &gl_tree, &key );
890
891    return found;
892}
893
894struct tor *
895hashlookup( const uint8_t * hash )
896{
897    struct tor key, * found;
898
899    memset( &key, 0, sizeof key );
900    memcpy( key.hash, hash, sizeof key.hash );
901    found = RB_FIND( hashtree, &gl_hashes, &key );
902
903    return found;
904}
905
906struct tor *
907iterate( struct tor * tor )
908{
909    assert( NULL != gl_handle );
910    assert( !gl_exiting );
911
912    if( NULL == tor )
913    {
914        tor = RB_MIN( tortree, &gl_tree );
915    }
916    else
917    {
918        tor = RB_NEXT( tortree, &gl_tree, tor );
919    }
920
921    return tor;
922}
Note: See TracBrowser for help on using the repository browser.