source: trunk/libtransmission/utils.c @ 7525

Last change on this file since 7525 was 7525, checked in by charles, 13 years ago

(trunk libT) avoid some unnecessary memory fragmentation... for composited objects that have a tr_bitfield, contain it directly rather than a pointer to one allocated elsewhere on the heap.

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