source: trunk/daemon/torrents.c @ 3426

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

remove unused flags

  • Property svn:keywords set to Date Rev Author Id
File size: 21.1 KB
Line 
1/******************************************************************************
2 * $Id: torrents.c 3426 2007-10-15 20:58:39Z 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];
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_INACTIVE & 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_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        /* XXX 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_INACTIVE & st->status ? 1 : 0 ) );
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.