source: trunk/libtransmission/utils.c @ 7592

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

(trunk libT) add "deep log" message to help track down freeze reported by the|Navigator. also, small + cheap speedup in tr_deepLoggingIsActive()

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