source: branches/1.4x/libtransmission/utils.c @ 7455

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

(1.4x libT) backport handshake, peer, bandwidth, peer-io to 1.4x.

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