source: trunk/libtransmission/utils.c @ 7367

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

(trunk) #1559: Simplify tr_sessionInitFull

  • Property svn:keywords set to Date Rev Author Id
File size: 27.7 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 7367 2008-12-13 23:17:36Z 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_bitfieldNew( size_t bitCount )
750{
751    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
752
753    ret->bitCount = bitCount;
754    ret->byteCount = ( bitCount + 7u ) / 8u;
755    ret->bits = tr_new0( uint8_t, ret->byteCount );
756    return ret;
757}
758
759tr_bitfield*
760tr_bitfieldDup( const tr_bitfield * in )
761{
762    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
763
764    ret->bitCount = in->bitCount;
765    ret->byteCount = in->byteCount;
766    ret->bits = tr_memdup( in->bits, in->byteCount );
767    return ret;
768}
769
770void
771tr_bitfieldFree( tr_bitfield * bitfield )
772{
773    if( bitfield )
774    {
775        tr_free( bitfield->bits );
776        tr_free( bitfield );
777    }
778}
779
780void
781tr_bitfieldClear( tr_bitfield * bitfield )
782{
783    memset( bitfield->bits, 0, bitfield->byteCount );
784}
785
786int
787tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
788{
789    size_t i;
790
791    for( i = 0; i < bitfield->byteCount; ++i )
792        if( bitfield->bits[i] )
793            return 0;
794
795    return 1;
796}
797
798int
799tr_bitfieldAdd( tr_bitfield * bitfield,
800                size_t        nth )
801{
802    assert( bitfield );
803    assert( bitfield->bits );
804
805    if( nth >= bitfield->bitCount )
806        return -1;
807
808    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
809    return 0;
810}
811
812/* Sets bit range [begin, end) to 1 */
813int
814tr_bitfieldAddRange( tr_bitfield * b,
815                     size_t        begin,
816                     size_t        end )
817{
818    size_t        sb, eb;
819    unsigned char sm, em;
820
821    end--;
822
823    if( ( end >= b->bitCount ) || ( begin > end ) )
824        return -1;
825
826    sb = begin >> 3;
827    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
828    eb = end >> 3;
829    em = 0xff << ( 7 - ( end & 7 ) );
830
831    if( sb == eb )
832    {
833        b->bits[sb] |= ( sm & em );
834    }
835    else
836    {
837        b->bits[sb] |= sm;
838        b->bits[eb] |= em;
839        if( ++sb < eb )
840            memset ( b->bits + sb, 0xff, eb - sb );
841    }
842
843    return 0;
844}
845
846int
847tr_bitfieldRem( tr_bitfield * bitfield,
848                size_t        nth )
849{
850    assert( bitfield );
851    assert( bitfield->bits );
852
853    if( nth >= bitfield->bitCount )
854        return -1;
855
856    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
857    return 0;
858}
859
860/* Clears bit range [begin, end) to 0 */
861int
862tr_bitfieldRemRange( tr_bitfield * b,
863                     size_t        begin,
864                     size_t        end )
865{
866    size_t        sb, eb;
867    unsigned char sm, em;
868
869    end--;
870
871    if( ( end >= b->bitCount ) || ( begin > end ) )
872        return -1;
873
874    sb = begin >> 3;
875    sm = 0xff << ( 8 - ( begin & 7 ) );
876    eb = end >> 3;
877    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
878
879    if( sb == eb )
880    {
881        b->bits[sb] &= ( sm | em );
882    }
883    else
884    {
885        b->bits[sb] &= sm;
886        b->bits[eb] &= em;
887        if( ++sb < eb )
888            memset ( b->bits + sb, 0, eb - sb );
889    }
890
891    return 0;
892}
893
894tr_bitfield*
895tr_bitfieldOr( tr_bitfield *       a,
896               const tr_bitfield * b )
897{
898    uint8_t *      ait;
899    const uint8_t *aend, *bit;
900
901    assert( a->bitCount == b->bitCount );
902
903    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
904         ait != aend; )
905        *ait++ |= *bit++;
906
907    return a;
908}
909
910/* set 'a' to all the flags that were in 'a' but not 'b' */
911void
912tr_bitfieldDifference( tr_bitfield *       a,
913                       const tr_bitfield * b )
914{
915    uint8_t *      ait;
916    const uint8_t *aend, *bit;
917
918    assert( a->bitCount == b->bitCount );
919
920    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
921         ait != aend; )
922        *ait++ &= ~( *bit++ );
923}
924
925size_t
926tr_bitfieldCountTrueBits( const tr_bitfield* b )
927{
928    size_t           ret = 0;
929    const uint8_t *  it, *end;
930    static const int trueBitCount[512] = {
931        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
932        4, 2, 3, 3, 4, 3, 4, 4, 5,
933        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
934        5, 3, 4, 4, 5, 4, 5, 5, 6,
935        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
936        5, 3, 4, 4, 5, 4, 5, 5, 6,
937        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
938        6, 4, 5, 5, 6, 5, 6, 6, 7,
939        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
940        5, 3, 4, 4, 5, 4, 5, 5, 6,
941        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
942        6, 4, 5, 5, 6, 5, 6, 6, 7,
943        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
944        6, 4, 5, 5, 6, 5, 6, 6, 7,
945        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
946        7, 5, 6, 6, 7, 6, 7, 7, 8,
947        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
948        5, 3, 4, 4, 5, 4, 5, 5, 6,
949        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
950        6, 4, 5, 5, 6, 5, 6, 6, 7,
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        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
954        7, 5, 6, 6, 7, 6, 7, 7, 8,
955        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
956        6, 4, 5, 5, 6, 5, 6, 6, 7,
957        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
958        7, 5, 6, 6, 7, 6, 7, 7, 8,
959        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
960        7, 5, 6, 6, 7, 6, 7, 7, 8,
961        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
962        8, 6, 7, 7, 8, 7, 8, 8, 9
963    };
964
965    if( !b )
966        return 0;
967
968    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
969        ret += trueBitCount[*it];
970
971    return ret;
972}
973
974/***
975****
976***/
977
978uint64_t
979tr_date( void )
980{
981    struct timeval tv;
982
983    gettimeofday( &tv, NULL );
984    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
985}
986
987void
988tr_wait( uint64_t delay_milliseconds )
989{
990#ifdef WIN32
991    Sleep( (DWORD)delay_milliseconds );
992#else
993    usleep( 1000 * delay_milliseconds );
994#endif
995}
996
997/***
998****
999***/
1000
1001int
1002tr_snprintf( char *       buf,
1003             size_t       buflen,
1004             const char * fmt,
1005             ... )
1006{
1007    int     len;
1008    va_list args;
1009
1010    va_start( args, fmt );
1011    len = evutil_vsnprintf( buf, buflen, fmt, args );
1012    va_end( args );
1013    return len;
1014}
1015
1016/*
1017 * Copy src to string dst of size siz.  At most siz-1 characters
1018 * will be copied.  Always NUL terminates (unless siz == 0).
1019 * Returns strlen(src); if retval >= siz, truncation occurred.
1020 */
1021size_t
1022tr_strlcpy( char *       dst,
1023            const void * src,
1024            size_t       siz )
1025{
1026#ifdef HAVE_STRLCPY
1027    return strlcpy( dst, src, siz );
1028#else
1029    char *      d = dst;
1030    const char *s = src;
1031    size_t      n = siz;
1032
1033    assert( s );
1034    assert( d );
1035
1036    /* Copy as many bytes as will fit */
1037    if( n != 0 )
1038    {
1039        while( --n != 0 )
1040        {
1041            if( ( *d++ = *s++ ) == '\0' )
1042                break;
1043        }
1044    }
1045
1046    /* Not enough room in dst, add NUL and traverse rest of src */
1047    if( n == 0 )
1048    {
1049        if( siz != 0 )
1050            *d = '\0'; /* NUL-terminate dst */
1051        while( *s++ )
1052            ;
1053    }
1054
1055    return s - (char*)src - 1;  /* count does not include NUL */
1056#endif
1057}
1058
1059/***
1060****
1061***/
1062
1063double
1064tr_getRatio( double numerator,
1065             double denominator )
1066{
1067    double ratio;
1068
1069    if( denominator )
1070        ratio = numerator / denominator;
1071    else if( numerator )
1072        ratio = TR_RATIO_INF;
1073    else
1074        ratio = TR_RATIO_NA;
1075
1076    return ratio;
1077}
1078
1079void
1080tr_sha1_to_hex( char *          out,
1081                const uint8_t * sha1 )
1082{
1083    static const char hex[] = "0123456789abcdef";
1084    int               i;
1085
1086    for( i = 0; i < 20; i++ )
1087    {
1088        unsigned int val = *sha1++;
1089        *out++ = hex[val >> 4];
1090        *out++ = hex[val & 0xf];
1091    }
1092    *out = '\0';
1093}
1094
1095/***
1096****
1097***/
1098
1099int
1100tr_httpIsValidURL( const char * url )
1101{
1102    const char *        c;
1103    static const char * rfc2396_valid_chars =
1104        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1105        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1106        "0123456789"                 /* digit */
1107        "-_.!~*'()"                  /* mark */
1108        ";/?:@&=+$,"                 /* reserved */
1109        "<>#%<\""                    /* delims */
1110        "{}|\\^[]`";                 /* unwise */
1111
1112    if( url == NULL )
1113        return FALSE;
1114
1115    for( c = url; c && *c; ++c )
1116        if( !strchr( rfc2396_valid_chars, *c ) )
1117            return FALSE;
1118
1119    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1120}
1121
1122int
1123tr_httpParseURL( const char * url_in,
1124                 int          len,
1125                 char **      setme_host,
1126                 int *        setme_port,
1127                 char **      setme_path )
1128{
1129    int          err;
1130    int          port = 0;
1131    int          n;
1132    char *       tmp;
1133    char *       pch;
1134    const char * protocol = NULL;
1135    const char * host = NULL;
1136    const char * path = NULL;
1137
1138    tmp = tr_strndup( url_in, len );
1139    if( ( pch = strstr( tmp, "://" ) ) )
1140    {
1141        *pch = '\0';
1142        protocol = tmp;
1143        pch += 3;
1144/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1145  );*/
1146        if( ( n = strcspn( pch, ":/" ) ) )
1147        {
1148            const int havePort = pch[n] == ':';
1149            host = pch;
1150            pch += n;
1151            *pch++ = '\0';
1152/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1153            if( havePort )
1154            {
1155                char * end;
1156                port = strtol( pch, &end, 10 );
1157                pch = end;
1158/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1159            }
1160            path = pch;
1161/*fprintf( stderr, "path is [%s]\n", path );*/
1162        }
1163    }
1164
1165    err = !host || !path || !protocol
1166          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1167
1168    if( !err && !port )
1169    {
1170        if( !strcmp( protocol, "http" ) ) port = 80;
1171        if( !strcmp( protocol, "https" ) ) port = 443;
1172    }
1173
1174    if( !err )
1175    {
1176        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1177                              tr_strdup( protocol ); }
1178        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1179                              tr_strdup( path - 1 ); }
1180        if( setme_port ) *setme_port = port;
1181    }
1182
1183
1184    tr_free( tmp );
1185    return err;
1186}
1187
1188#include <string.h>
1189#include <openssl/sha.h>
1190#include <openssl/hmac.h>
1191#include <openssl/evp.h>
1192#include <openssl/bio.h>
1193#include <openssl/buffer.h>
1194
1195char *
1196tr_base64_encode( const void * input,
1197                  int          length,
1198                  int *        setme_len )
1199{
1200    char *    ret;
1201    BIO *     b64;
1202    BIO *     bmem;
1203    BUF_MEM * bptr;
1204
1205    if( length < 1 )
1206        length = strlen( input );
1207
1208    bmem = BIO_new( BIO_s_mem( ) );
1209    b64 = BIO_new( BIO_f_base64( ) );
1210    b64 = BIO_push( b64, bmem );
1211    BIO_write( b64, input, length );
1212    (void) BIO_flush( b64 );
1213    BIO_get_mem_ptr( b64, &bptr );
1214    ret = tr_strndup( bptr->data, bptr->length );
1215    if( setme_len )
1216        *setme_len = bptr->length;
1217
1218    BIO_free_all( b64 );
1219    return ret;
1220}
1221
1222char *
1223tr_base64_decode( const void * input,
1224                  int          length,
1225                  int *        setme_len )
1226{
1227    char * ret;
1228    BIO *  b64;
1229    BIO *  bmem;
1230    int    retlen;
1231
1232    if( length < 1 )
1233        length = strlen( input );
1234
1235    ret = tr_new0( char, length );
1236    b64 = BIO_new( BIO_f_base64( ) );
1237    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1238    bmem = BIO_push( b64, bmem );
1239    retlen = BIO_read( bmem, ret, length );
1240    if( !retlen )
1241    {
1242        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1243        BIO_free_all( bmem );
1244        b64 = BIO_new( BIO_f_base64( ) );
1245        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1246        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1247        bmem = BIO_push( b64, bmem );
1248        retlen = BIO_read( bmem, ret, length );
1249    }
1250
1251    if( setme_len )
1252        *setme_len = retlen;
1253
1254    BIO_free_all( bmem );
1255    return ret;
1256}
1257
Note: See TracBrowser for help on using the repository browser.