source: trunk/libtransmission/utils.c @ 7529

Last change on this file since 7529 was 7529, checked in by charles, 12 years ago

(trunk libT) wrap tr_inf(), tr_msg(), tr_dbg() calls inside a check to see if that debugging level is active. That way that function calls in the vararg list won't be invoked unless that level of verbosity is actually turned on.

  • Property svn:keywords set to Date Rev Author Id
File size: 28.1 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 7529 2008-12-29 18:11:56Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
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 <assert.h>
26#include <ctype.h> /* isalpha, tolower */
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h> /* strerror, memset */
32
33#include <libgen.h> /* basename */
34#include <sys/time.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <unistd.h> /* usleep, stat, getcwd */
38
39#include "event.h"
40
41#ifdef WIN32
42 #include <direct.h> /* _getcwd */
43 #include <windows.h> /* Sleep */
44#endif
45
46#include "transmission.h"
47#include "utils.h"
48#include "platform.h"
49
50static tr_lock *      messageLock = NULL;
51static int            messageLevel = 0;
52static tr_bool        messageQueuing = FALSE;
53static tr_msg_list *  messageQueue = NULL;
54static tr_msg_list ** messageQueueTail = &messageQueue;
55
56#ifndef WIN32
57    /* make null versions of these win32 functions */
58    static int IsDebuggerPresent( void ) { return FALSE; }
59    static void OutputDebugString( const void * unused UNUSED ) { }
60#endif
61
62static void
63tr_msgInit( void )
64{
65    static tr_bool initialized = FALSE;
66
67    if( !initialized )
68    {
69        char * env = getenv( "TR_DEBUG" );
70        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
71        messageLevel = MAX( 1, messageLevel );
72
73        messageLock = tr_lockNew( );
74
75        initialized = TRUE;
76    }
77}
78
79FILE*
80tr_getLog( void )
81{
82    static int    initialized = FALSE;
83    static FILE * file = NULL;
84
85    if( !initialized )
86    {
87        const char * str = getenv( "TR_DEBUG_FD" );
88        int          fd = 0;
89        if( str && *str )
90            fd = atoi( str );
91        switch( fd )
92        {
93            case 1:
94                file = stdout; break;
95
96            case 2:
97                file = stderr; break;
98
99            default:
100                file = NULL; break;
101        }
102        initialized = TRUE;
103    }
104
105    return file;
106}
107
108void
109tr_setMessageLevel( int level )
110{
111    tr_msgInit( );
112    tr_lockLock( messageLock );
113
114    messageLevel = MAX( 0, level );
115
116    tr_lockUnlock( messageLock );
117}
118
119int
120tr_getMessageLevel( void )
121{
122    int ret;
123    tr_msgInit( );
124    tr_lockLock( messageLock );
125
126    ret = messageLevel;
127
128    tr_lockUnlock( messageLock );
129    return ret;
130}
131
132void
133tr_setMessageQueuing( tr_bool enabled )
134{
135    tr_msgInit( );
136    tr_lockLock( messageLock );
137
138    messageQueuing = enabled;
139
140    tr_lockUnlock( messageLock );
141}
142
143tr_bool
144tr_getMessageQueuing( void )
145{
146    int ret;
147    tr_msgInit( );
148    tr_lockLock( messageLock );
149
150    ret = messageQueuing;
151
152    tr_lockUnlock( messageLock );
153    return ret;
154}
155
156tr_msg_list *
157tr_getQueuedMessages( void )
158{
159    tr_msg_list * ret;
160    tr_msgInit( );
161    tr_lockLock( messageLock );
162
163    ret = messageQueue;
164    messageQueue = NULL;
165    messageQueueTail = &messageQueue;
166
167    tr_lockUnlock( messageLock );
168    return ret;
169}
170
171void
172tr_freeMessageList( tr_msg_list * list )
173{
174    tr_msg_list * next;
175
176    while( NULL != list )
177    {
178        next = list->next;
179        free( list->message );
180        free( list->name );
181        free( list );
182        list = next;
183    }
184}
185
186/**
187***
188**/
189
190static struct tm *
191tr_localtime_r( time_t *_clock, struct tm *_result )
192{
193#ifdef HAVE_LOCALTIME_R
194    return localtime_r( _clock, _result );
195#else
196    struct tm *p = localtime( _clock );
197    if( p )
198        *(_result) = *p;
199    return p;
200#endif
201}
202
203char*
204tr_getLogTimeStr( char * buf,
205                  int    buflen )
206{
207    char           tmp[64];
208    time_t         now;
209    struct tm      now_tm;
210    struct timeval tv;
211    int            milliseconds;
212
213    now = time( NULL );
214    gettimeofday( &tv, NULL );
215
216    tr_localtime_r( &now, &now_tm );
217    strftime( tmp, sizeof( tmp ), "%H:%M:%S", &now_tm );
218    milliseconds = (int)( tv.tv_usec / 1000 );
219    tr_snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
220
221    return buf;
222}
223
224int
225tr_deepLoggingIsActive( void )
226{
227    return IsDebuggerPresent() || (tr_getLog()!=NULL);
228}
229
230void
231tr_deepLog( const char  * file,
232            int           line,
233            const char  * name,
234            const char  * fmt,
235            ... )
236{
237    FILE * fp = tr_getLog( );
238    if( fp || IsDebuggerPresent( ) )
239    {
240        va_list           args;
241        char              timestr[64];
242        struct evbuffer * buf = evbuffer_new( );
243        char *            base = tr_basename( file );
244
245        evbuffer_add_printf( buf, "[%s] ",
246                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
247        if( name )
248            evbuffer_add_printf( buf, "%s ", name );
249        va_start( args, fmt );
250        evbuffer_add_vprintf( buf, fmt, args );
251        va_end( args );
252        evbuffer_add_printf( buf, " (%s:%d)\n", base, line );
253        OutputDebugString( EVBUFFER_DATA( buf ) );
254        if(fp)
255            (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
256
257        tr_free( base );
258        evbuffer_free( buf );
259    }
260}
261
262/***
263****
264***/
265   
266
267int
268tr_msgLoggingIsActive( int level )
269{
270    tr_msgInit( );
271
272    return messageLevel >= level;
273}
274
275void
276tr_msg( const char * file,
277        int          line,
278        int          level,
279        const char * name,
280        const char * fmt,
281        ... )
282{
283    FILE * fp;
284    tr_msgInit( );
285    tr_lockLock( messageLock );
286
287    fp = tr_getLog( );
288
289    if( messageLevel >= level )
290    {
291        va_list           ap;
292        struct evbuffer * buf = evbuffer_new( );
293
294        /* build the text message */
295        va_start( ap, fmt );
296        evbuffer_add_vprintf( buf, fmt, ap );
297        va_end( ap );
298
299        OutputDebugString( EVBUFFER_DATA( buf ) );
300
301        if( EVBUFFER_LENGTH( buf ) )
302        {
303            if( messageQueuing )
304            {
305                tr_msg_list * newmsg;
306                newmsg = tr_new0( tr_msg_list, 1 );
307                newmsg->level = level;
308                newmsg->when = time( NULL );
309                newmsg->message = tr_strdup( EVBUFFER_DATA( buf ) );
310                newmsg->file = file;
311                newmsg->line = line;
312                newmsg->name = tr_strdup( name );
313
314                *messageQueueTail = newmsg;
315                messageQueueTail = &newmsg->next;
316            }
317            else
318            {
319                if( fp == NULL )
320                    fp = stderr;
321                if( name )
322                    fprintf( fp, "%s: %s\n", name,
323                            (char*)EVBUFFER_DATA( buf ) );
324                else
325                    fprintf( fp, "%s\n", (char*)EVBUFFER_DATA( buf ) );
326                fflush( fp );
327            }
328
329            evbuffer_free( buf );
330        }
331    }
332
333    tr_lockUnlock( messageLock );
334}
335
336/***
337****
338***/
339
340void
341tr_set_compare( const void * va,
342                size_t aCount,
343                const void * vb,
344                size_t bCount,
345                int compare( const void * a, const void * b ),
346                size_t elementSize,
347                tr_set_func in_a_cb,
348                tr_set_func in_b_cb,
349                tr_set_func in_both_cb,
350                void * userData )
351{
352    const uint8_t * a = (const uint8_t *) va;
353    const uint8_t * b = (const uint8_t *) vb;
354    const uint8_t * aend = a + elementSize * aCount;
355    const uint8_t * bend = b + elementSize * bCount;
356
357    while( a != aend || b != bend )
358    {
359        if( a == aend )
360        {
361            ( *in_b_cb )( (void*)b, userData );
362            b += elementSize;
363        }
364        else if( b == bend )
365        {
366            ( *in_a_cb )( (void*)a, userData );
367            a += elementSize;
368        }
369        else
370        {
371            const int val = ( *compare )( a, b );
372
373            if( !val )
374            {
375                ( *in_both_cb )( (void*)a, userData );
376                a += elementSize;
377                b += elementSize;
378            }
379            else if( val < 0 )
380            {
381                ( *in_a_cb )( (void*)a, userData );
382                a += elementSize;
383            }
384            else if( val > 0 )
385            {
386                ( *in_b_cb )( (void*)b, userData );
387                b += elementSize;
388            }
389        }
390    }
391}
392
393/***
394****
395***/
396
397#ifdef DISABLE_GETTEXT
398
399const char*
400tr_strip_positional_args( const char* str )
401{
402    static size_t bufsize = 0;
403    static char * buf = NULL;
404    const size_t  len = strlen( str );
405    char *        out;
406
407    if( bufsize < len )
408    {
409        bufsize = len * 2;
410        buf = tr_renew( char, buf, bufsize );
411    }
412
413    for( out = buf; *str; ++str )
414    {
415        *out++ = *str;
416        if( ( *str == '%' ) && isdigit( str[1] ) )
417        {
418            const char * tmp = str + 1;
419            while( isdigit( *tmp ) )
420                ++tmp;
421
422            if( *tmp == '$' )
423                str = tmp;
424        }
425    }
426    *out = '\0';
427
428    return buf;
429}
430
431#endif
432
433/**
434***
435**/
436
437void
438tr_timevalMsec( uint64_t milliseconds, struct timeval * setme )
439{
440    const uint64_t microseconds = milliseconds * 1000;
441    assert( setme != NULL );
442    setme->tv_sec  = microseconds / 1000000;
443    setme->tv_usec = microseconds % 1000000;
444}
445
446uint8_t *
447tr_loadFile( const char * path,
448             size_t *     size )
449{
450    uint8_t *    buf;
451    struct stat  sb;
452    FILE *       file;
453    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
454
455    /* try to stat the file */
456    errno = 0;
457    if( stat( path, &sb ) )
458    {
459        const int err = errno;
460        tr_dbg( err_fmt, path, tr_strerror( errno ) );
461        errno = err;
462        return NULL;
463    }
464
465    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
466    {
467        tr_err( err_fmt, path, _( "Not a regular file" ) );
468        errno = EISDIR;
469        return NULL;
470    }
471
472    /* Load the torrent file into our buffer */
473    file = fopen( path, "rb" );
474    if( !file )
475    {
476        const int err = errno;
477        tr_err( err_fmt, path, tr_strerror( errno ) );
478        errno = err;
479        return NULL;
480    }
481    buf = malloc( sb.st_size );
482    if( !buf )
483    {
484        const int err = errno;
485        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
486        fclose( file );
487        errno = err;
488        return NULL;
489    }
490    if( fread( buf, sb.st_size, 1, file ) != 1 )
491    {
492        const int err = errno;
493        tr_err( err_fmt, path, tr_strerror( errno ) );
494        fclose( file );
495        free( buf );
496        errno = err;
497        return NULL;
498    }
499
500    fclose( file );
501    *size = sb.st_size;
502    return buf;
503}
504
505char*
506tr_basename( const char * path )
507{
508    char * tmp = tr_strdup( path );
509    char * ret = tr_strdup( basename( tmp ) );
510    tr_free( tmp );
511    return ret;
512}
513
514char*
515tr_dirname( const char * path )
516{
517    char * tmp = tr_strdup( path );
518    char * ret = tr_strdup( dirname( tmp ) );
519    tr_free( tmp );
520    return ret;
521}
522
523int
524tr_mkdir( const char * path,
525          int permissions
526#ifdef WIN32
527                       UNUSED
528#endif
529        )
530{
531#ifdef WIN32
532    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
533        return 0;
534    return mkdir( path );
535#else
536    return mkdir( path, permissions );
537#endif
538}
539
540int
541tr_mkdirp( const char * path_in,
542           int          permissions )
543{
544    char *      path = tr_strdup( path_in );
545    char *      p, * pp;
546    struct stat sb;
547    int         done;
548
549    /* walk past the root */
550    p = path;
551    while( *p == TR_PATH_DELIMITER )
552        ++p;
553
554    pp = p;
555    done = 0;
556    while( ( p =
557                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
558    {
559        if( !*p )
560            done = 1;
561        else
562            *p = '\0';
563
564        if( stat( path, &sb ) )
565        {
566            /* Folder doesn't exist yet */
567            if( tr_mkdir( path, permissions ) )
568            {
569                const int err = errno;
570                tr_err( _(
571                           "Couldn't create \"%1$s\": %2$s" ), path,
572                       tr_strerror( err ) );
573                tr_free( path );
574                errno = err;
575                return -1;
576            }
577        }
578        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
579        {
580            /* Node exists but isn't a folder */
581            char * buf = tr_strdup_printf( _( "File \"%s\" is in the way" ), path );
582            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
583            tr_free( buf );
584            tr_free( path );
585            errno = ENOTDIR;
586            return -1;
587        }
588
589        if( done )
590            break;
591
592        *p = TR_PATH_DELIMITER;
593        p++;
594        pp = p;
595    }
596
597    tr_free( path );
598    return 0;
599}
600
601char*
602tr_buildPath( const char *first_element, ... )
603{
604    size_t bufLen = 0;
605    const char * element;
606    char * buf;
607    char * pch;
608    va_list vl;
609
610    /* pass 1: allocate enough space for the string */
611    va_start( vl, first_element );
612    element = first_element;
613    while( element ) {
614        bufLen += strlen( element ) + 1;
615        element = (const char*) va_arg( vl, const char* );
616    }
617    pch = buf = tr_new( char, bufLen );
618    va_end( vl );
619
620    /* pass 2: build the string piece by piece */
621    va_start( vl, first_element );
622    element = first_element;
623    while( element ) {
624        const size_t elementLen = strlen( element );
625        memcpy( pch, element, elementLen );
626        pch += elementLen;
627        *pch++ = TR_PATH_DELIMITER;
628        element = (const char*) va_arg( vl, const char* );
629    }
630    va_end( vl );
631
632    /* terminate the string.  if nonempty, eat the unwanted trailing slash */
633    if( pch != buf )
634        --pch;
635    *pch++ = '\0';
636
637    /* sanity checks & return */
638    assert( pch - buf == (off_t)bufLen );
639    return buf;
640}
641
642/****
643*****
644****/
645
646void*
647tr_memdup( const void * in,
648           int          byteCount )
649{
650    void * out = tr_new( uint8_t, byteCount );
651
652    memcpy( out, in, byteCount );
653    return out;
654}
655
656char*
657tr_strdup( const void * in )
658{
659    return tr_strndup( in, in ? strlen( (const char*)in ) : 0 );
660}
661
662char*
663tr_strndup( const void * in,
664            int          len )
665{
666    char * out = NULL;
667
668    if( len < 0 )
669    {
670        out = tr_strdup( in );
671    }
672    else if( in )
673    {
674        out = tr_malloc( len + 1 );
675        memcpy( out, in, len );
676        out[len] = '\0';
677    }
678
679    return out;
680}
681
682char*
683tr_strdup_printf( const char * fmt,
684                  ... )
685{
686    char *            ret = NULL;
687    struct evbuffer * buf;
688    va_list           ap;
689
690    buf = evbuffer_new( );
691    va_start( ap, fmt );
692
693    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
694        ret = tr_strdup( EVBUFFER_DATA( buf ) );
695
696    va_end( ap );
697    evbuffer_free( buf );
698    return ret;
699}
700
701void*
702tr_malloc( size_t size )
703{
704    return size ? malloc( size ) : NULL;
705}
706
707void*
708tr_malloc0( size_t size )
709{
710    return size ? calloc( 1, size ) : NULL;
711}
712
713void
714tr_free( void * p )
715{
716    if( p )
717        free( p );
718}
719
720const char*
721tr_strerror( int i )
722{
723    const char * ret = strerror( i );
724
725    if( ret == NULL )
726        ret = "Unknown Error";
727    return ret;
728}
729
730/****
731*****
732****/
733
734char*
735tr_strstrip( char * str )
736{
737    if( str != NULL )
738    {
739        size_t pos;
740        size_t len = strlen( str );
741
742        while( len && isspace( str[len - 1] ) )
743            --len;
744
745        str[len] = '\0';
746
747        for( pos = 0; pos < len && isspace( str[pos] ); )
748            ++pos;
749
750        len -= pos;
751        memmove( str, str + pos, len );
752        str[len] = '\0';
753    }
754
755    return str;
756}
757
758/****
759*****
760****/
761
762tr_bitfield*
763tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
764{
765    b->bitCount = bitCount;
766    b->byteCount = ( bitCount + 7u ) / 8u;
767    b->bits = tr_new0( uint8_t, b->byteCount );
768    return b;
769}
770
771void
772tr_bitfieldDestruct( tr_bitfield * b )
773{
774    tr_free( b->bits );
775}
776
777tr_bitfield*
778tr_bitfieldNew( size_t bitCount )
779{
780    return tr_bitfieldConstruct( tr_new0( tr_bitfield, 1 ), bitCount );
781}
782
783tr_bitfield*
784tr_bitfieldDup( const tr_bitfield * in )
785{
786    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
787
788    ret->bitCount = in->bitCount;
789    ret->byteCount = in->byteCount;
790    ret->bits = tr_memdup( in->bits, in->byteCount );
791    return ret;
792}
793
794void
795tr_bitfieldFree( tr_bitfield * bitfield )
796{
797    if( bitfield )
798    {
799        tr_bitfieldDestruct( bitfield );
800        tr_free( bitfield );
801    }
802}
803
804void
805tr_bitfieldClear( tr_bitfield * bitfield )
806{
807    memset( bitfield->bits, 0, bitfield->byteCount );
808}
809
810int
811tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
812{
813    size_t i;
814
815    for( i = 0; i < bitfield->byteCount; ++i )
816        if( bitfield->bits[i] )
817            return 0;
818
819    return 1;
820}
821
822int
823tr_bitfieldAdd( tr_bitfield * bitfield,
824                size_t        nth )
825{
826    assert( bitfield );
827    assert( bitfield->bits );
828
829    if( nth >= bitfield->bitCount )
830        return -1;
831
832    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
833    return 0;
834}
835
836/* Sets bit range [begin, end) to 1 */
837int
838tr_bitfieldAddRange( tr_bitfield * b,
839                     size_t        begin,
840                     size_t        end )
841{
842    size_t        sb, eb;
843    unsigned char sm, em;
844
845    end--;
846
847    if( ( end >= b->bitCount ) || ( begin > end ) )
848        return -1;
849
850    sb = begin >> 3;
851    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
852    eb = end >> 3;
853    em = 0xff << ( 7 - ( end & 7 ) );
854
855    if( sb == eb )
856    {
857        b->bits[sb] |= ( sm & em );
858    }
859    else
860    {
861        b->bits[sb] |= sm;
862        b->bits[eb] |= em;
863        if( ++sb < eb )
864            memset ( b->bits + sb, 0xff, eb - sb );
865    }
866
867    return 0;
868}
869
870int
871tr_bitfieldRem( tr_bitfield * bitfield,
872                size_t        nth )
873{
874    assert( bitfield );
875    assert( bitfield->bits );
876
877    if( nth >= bitfield->bitCount )
878        return -1;
879
880    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
881    return 0;
882}
883
884/* Clears bit range [begin, end) to 0 */
885int
886tr_bitfieldRemRange( tr_bitfield * b,
887                     size_t        begin,
888                     size_t        end )
889{
890    size_t        sb, eb;
891    unsigned char sm, em;
892
893    end--;
894
895    if( ( end >= b->bitCount ) || ( begin > end ) )
896        return -1;
897
898    sb = begin >> 3;
899    sm = 0xff << ( 8 - ( begin & 7 ) );
900    eb = end >> 3;
901    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
902
903    if( sb == eb )
904    {
905        b->bits[sb] &= ( sm | em );
906    }
907    else
908    {
909        b->bits[sb] &= sm;
910        b->bits[eb] &= em;
911        if( ++sb < eb )
912            memset ( b->bits + sb, 0, eb - sb );
913    }
914
915    return 0;
916}
917
918tr_bitfield*
919tr_bitfieldOr( tr_bitfield *       a,
920               const tr_bitfield * b )
921{
922    uint8_t *      ait;
923    const uint8_t *aend, *bit;
924
925    assert( a->bitCount == b->bitCount );
926
927    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
928         ait != aend; )
929        *ait++ |= *bit++;
930
931    return a;
932}
933
934/* set 'a' to all the flags that were in 'a' but not 'b' */
935void
936tr_bitfieldDifference( tr_bitfield *       a,
937                       const tr_bitfield * b )
938{
939    uint8_t *      ait;
940    const uint8_t *aend, *bit;
941
942    assert( a->bitCount == b->bitCount );
943
944    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
945         ait != aend; )
946        *ait++ &= ~( *bit++ );
947}
948
949size_t
950tr_bitfieldCountTrueBits( const tr_bitfield* b )
951{
952    size_t           ret = 0;
953    const uint8_t *  it, *end;
954    static const int trueBitCount[512] = {
955        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
956        4, 2, 3, 3, 4, 3, 4, 4, 5,
957        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
958        5, 3, 4, 4, 5, 4, 5, 5, 6,
959        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
960        5, 3, 4, 4, 5, 4, 5, 5, 6,
961        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
962        6, 4, 5, 5, 6, 5, 6, 6, 7,
963        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
964        5, 3, 4, 4, 5, 4, 5, 5, 6,
965        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
966        6, 4, 5, 5, 6, 5, 6, 6, 7,
967        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
968        6, 4, 5, 5, 6, 5, 6, 6, 7,
969        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
970        7, 5, 6, 6, 7, 6, 7, 7, 8,
971        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
972        5, 3, 4, 4, 5, 4, 5, 5, 6,
973        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
974        6, 4, 5, 5, 6, 5, 6, 6, 7,
975        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
976        6, 4, 5, 5, 6, 5, 6, 6, 7,
977        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
978        7, 5, 6, 6, 7, 6, 7, 7, 8,
979        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
980        6, 4, 5, 5, 6, 5, 6, 6, 7,
981        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
982        7, 5, 6, 6, 7, 6, 7, 7, 8,
983        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
984        7, 5, 6, 6, 7, 6, 7, 7, 8,
985        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
986        8, 6, 7, 7, 8, 7, 8, 8, 9
987    };
988
989    if( !b )
990        return 0;
991
992    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
993        ret += trueBitCount[*it];
994
995    return ret;
996}
997
998/***
999****
1000***/
1001
1002uint64_t
1003tr_date( void )
1004{
1005    struct timeval tv;
1006
1007    gettimeofday( &tv, NULL );
1008    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
1009}
1010
1011void
1012tr_wait( uint64_t delay_milliseconds )
1013{
1014#ifdef WIN32
1015    Sleep( (DWORD)delay_milliseconds );
1016#else
1017    usleep( 1000 * delay_milliseconds );
1018#endif
1019}
1020
1021/***
1022****
1023***/
1024
1025int
1026tr_snprintf( char *       buf,
1027             size_t       buflen,
1028             const char * fmt,
1029             ... )
1030{
1031    int     len;
1032    va_list args;
1033
1034    va_start( args, fmt );
1035    len = evutil_vsnprintf( buf, buflen, fmt, args );
1036    va_end( args );
1037    return len;
1038}
1039
1040/*
1041 * Copy src to string dst of size siz.  At most siz-1 characters
1042 * will be copied.  Always NUL terminates (unless siz == 0).
1043 * Returns strlen(src); if retval >= siz, truncation occurred.
1044 */
1045size_t
1046tr_strlcpy( char *       dst,
1047            const void * src,
1048            size_t       siz )
1049{
1050#ifdef HAVE_STRLCPY
1051    return strlcpy( dst, src, siz );
1052#else
1053    char *      d = dst;
1054    const char *s = src;
1055    size_t      n = siz;
1056
1057    assert( s );
1058    assert( d );
1059
1060    /* Copy as many bytes as will fit */
1061    if( n != 0 )
1062    {
1063        while( --n != 0 )
1064        {
1065            if( ( *d++ = *s++ ) == '\0' )
1066                break;
1067        }
1068    }
1069
1070    /* Not enough room in dst, add NUL and traverse rest of src */
1071    if( n == 0 )
1072    {
1073        if( siz != 0 )
1074            *d = '\0'; /* NUL-terminate dst */
1075        while( *s++ )
1076            ;
1077    }
1078
1079    return s - (char*)src - 1;  /* count does not include NUL */
1080#endif
1081}
1082
1083/***
1084****
1085***/
1086
1087double
1088tr_getRatio( double numerator,
1089             double denominator )
1090{
1091    double ratio;
1092
1093    if( denominator )
1094        ratio = numerator / denominator;
1095    else if( numerator )
1096        ratio = TR_RATIO_INF;
1097    else
1098        ratio = TR_RATIO_NA;
1099
1100    return ratio;
1101}
1102
1103void
1104tr_sha1_to_hex( char *          out,
1105                const uint8_t * sha1 )
1106{
1107    static const char hex[] = "0123456789abcdef";
1108    int               i;
1109
1110    for( i = 0; i < 20; i++ )
1111    {
1112        unsigned int val = *sha1++;
1113        *out++ = hex[val >> 4];
1114        *out++ = hex[val & 0xf];
1115    }
1116    *out = '\0';
1117}
1118
1119/***
1120****
1121***/
1122
1123int
1124tr_httpIsValidURL( const char * url )
1125{
1126    const char *        c;
1127    static const char * rfc2396_valid_chars =
1128        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1129        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1130        "0123456789"                 /* digit */
1131        "-_.!~*'()"                  /* mark */
1132        ";/?:@&=+$,"                 /* reserved */
1133        "<>#%<\""                    /* delims */
1134        "{}|\\^[]`";                 /* unwise */
1135
1136    if( url == NULL )
1137        return FALSE;
1138
1139    for( c = url; c && *c; ++c )
1140        if( !strchr( rfc2396_valid_chars, *c ) )
1141            return FALSE;
1142
1143    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1144}
1145
1146int
1147tr_httpParseURL( const char * url_in,
1148                 int          len,
1149                 char **      setme_host,
1150                 int *        setme_port,
1151                 char **      setme_path )
1152{
1153    int          err;
1154    int          port = 0;
1155    int          n;
1156    char *       tmp;
1157    char *       pch;
1158    const char * protocol = NULL;
1159    const char * host = NULL;
1160    const char * path = NULL;
1161
1162    tmp = tr_strndup( url_in, len );
1163    if( ( pch = strstr( tmp, "://" ) ) )
1164    {
1165        *pch = '\0';
1166        protocol = tmp;
1167        pch += 3;
1168/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1169  );*/
1170        if( ( n = strcspn( pch, ":/" ) ) )
1171        {
1172            const int havePort = pch[n] == ':';
1173            host = pch;
1174            pch += n;
1175            *pch++ = '\0';
1176/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1177            if( havePort )
1178            {
1179                char * end;
1180                port = strtol( pch, &end, 10 );
1181                pch = end;
1182/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1183            }
1184            path = pch;
1185/*fprintf( stderr, "path is [%s]\n", path );*/
1186        }
1187    }
1188
1189    err = !host || !path || !protocol
1190          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1191
1192    if( !err && !port )
1193    {
1194        if( !strcmp( protocol, "http" ) ) port = 80;
1195        if( !strcmp( protocol, "https" ) ) port = 443;
1196    }
1197
1198    if( !err )
1199    {
1200        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1201                              tr_strdup( protocol ); }
1202        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1203                              tr_strdup( path - 1 ); }
1204        if( setme_port ) *setme_port = port;
1205    }
1206
1207
1208    tr_free( tmp );
1209    return err;
1210}
1211
1212#include <string.h>
1213#include <openssl/sha.h>
1214#include <openssl/hmac.h>
1215#include <openssl/evp.h>
1216#include <openssl/bio.h>
1217#include <openssl/buffer.h>
1218
1219char *
1220tr_base64_encode( const void * input,
1221                  int          length,
1222                  int *        setme_len )
1223{
1224    char *    ret;
1225    BIO *     b64;
1226    BIO *     bmem;
1227    BUF_MEM * bptr;
1228
1229    if( length < 1 )
1230        length = strlen( input );
1231
1232    bmem = BIO_new( BIO_s_mem( ) );
1233    b64 = BIO_new( BIO_f_base64( ) );
1234    b64 = BIO_push( b64, bmem );
1235    BIO_write( b64, input, length );
1236    (void) BIO_flush( b64 );
1237    BIO_get_mem_ptr( b64, &bptr );
1238    ret = tr_strndup( bptr->data, bptr->length );
1239    if( setme_len )
1240        *setme_len = bptr->length;
1241
1242    BIO_free_all( b64 );
1243    return ret;
1244}
1245
1246char *
1247tr_base64_decode( const void * input,
1248                  int          length,
1249                  int *        setme_len )
1250{
1251    char * ret;
1252    BIO *  b64;
1253    BIO *  bmem;
1254    int    retlen;
1255
1256    if( length < 1 )
1257        length = strlen( input );
1258
1259    ret = tr_new0( char, length );
1260    b64 = BIO_new( BIO_f_base64( ) );
1261    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1262    bmem = BIO_push( b64, bmem );
1263    retlen = BIO_read( bmem, ret, length );
1264    if( !retlen )
1265    {
1266        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1267        BIO_free_all( bmem );
1268        b64 = BIO_new( BIO_f_base64( ) );
1269        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1270        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1271        bmem = BIO_push( b64, bmem );
1272        retlen = BIO_read( bmem, ret, length );
1273    }
1274
1275    if( setme_len )
1276        *setme_len = retlen;
1277
1278    BIO_free_all( bmem );
1279    return ret;
1280}
1281
1282tr_bool
1283tr_isDirection( tr_direction dir )
1284{
1285    return dir==TR_UP || dir==TR_DOWN;
1286}
Note: See TracBrowser for help on using the repository browser.