source: trunk/libtransmission/utils.c @ 7539

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

(trunk libT) avoid an unnecessary evbuffer_new() + evbuffer_free() pair in message logging

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