source: trunk/libtransmission/utils.c @ 7543

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

(trunk libT) eliminate a couple more unnecessary malloc() + free() pairs

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