source: trunk/libtransmission/utils.c @ 7574

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

(trunk libT) make tr_isAddress() and tr_isDirection() inline

  • Property svn:keywords set to Date Rev Author Id
File size: 28.7 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 7574 2009-01-02 04:47:37Z 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
225int
226tr_deepLoggingIsActive( void )
227{
228    return IsDebuggerPresent() || (tr_getLog()!=NULL);
229}
230
231void
232tr_deepLog( const char  * file,
233            int           line,
234            const char  * name,
235            const char  * fmt,
236            ... )
237{
238    FILE * fp = tr_getLog( );
239    if( fp || IsDebuggerPresent( ) )
240    {
241        va_list           args;
242        char              timestr[64];
243        struct evbuffer * buf = tr_getBuffer( );
244        char *            base = tr_basename( file );
245
246        evbuffer_add_printf( buf, "[%s] ",
247                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
248        if( name )
249            evbuffer_add_printf( buf, "%s ", name );
250        va_start( args, fmt );
251        evbuffer_add_vprintf( buf, fmt, args );
252        va_end( args );
253        evbuffer_add_printf( buf, " (%s:%d)\n", base, line );
254        OutputDebugString( EVBUFFER_DATA( buf ) );
255        if(fp)
256            (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
257
258        tr_free( base );
259        tr_releaseBuffer( buf );
260    }
261}
262
263/***
264****
265***/
266   
267
268int
269tr_msgLoggingIsActive( int level )
270{
271    tr_msgInit( );
272
273    return messageLevel >= level;
274}
275
276void
277tr_msg( const char * file,
278        int          line,
279        int          level,
280        const char * name,
281        const char * fmt,
282        ... )
283{
284    FILE * fp;
285    tr_msgInit( );
286    tr_lockLock( messageLock );
287
288    fp = tr_getLog( );
289
290    if( messageLevel >= level )
291    {
292        char buf[MAX_STACK_ARRAY_SIZE];
293        va_list ap;
294
295        /* build the text message */
296        *buf = '\0';
297        va_start( ap, fmt );
298        evutil_vsnprintf( buf, sizeof( buf ), fmt, ap );
299        va_end( ap );
300
301        OutputDebugString( buf );
302
303        if( *buf )
304        {
305            if( messageQueuing )
306            {
307                tr_msg_list * newmsg;
308                newmsg = tr_new0( tr_msg_list, 1 );
309                newmsg->level = level;
310                newmsg->when = time( NULL );
311                newmsg->message = tr_strdup( buf );
312                newmsg->file = file;
313                newmsg->line = line;
314                newmsg->name = tr_strdup( name );
315
316                *messageQueueTail = newmsg;
317                messageQueueTail = &newmsg->next;
318            }
319            else
320            {
321                if( fp == NULL )
322                    fp = stderr;
323                if( name )
324                    fprintf( fp, "%s: %s\n", name, buf );
325                else
326                    fprintf( fp, "%s\n", buf );
327                fflush( fp );
328            }
329        }
330    }
331
332    tr_lockUnlock( messageLock );
333}
334
335/***
336****
337***/
338
339void
340tr_set_compare( const void * va,
341                size_t aCount,
342                const void * vb,
343                size_t bCount,
344                int compare( const void * a, const void * b ),
345                size_t elementSize,
346                tr_set_func in_a_cb,
347                tr_set_func in_b_cb,
348                tr_set_func in_both_cb,
349                void * userData )
350{
351    const uint8_t * a = (const uint8_t *) va;
352    const uint8_t * b = (const uint8_t *) vb;
353    const uint8_t * aend = a + elementSize * aCount;
354    const uint8_t * bend = b + elementSize * bCount;
355
356    while( a != aend || b != bend )
357    {
358        if( a == aend )
359        {
360            ( *in_b_cb )( (void*)b, userData );
361            b += elementSize;
362        }
363        else if( b == bend )
364        {
365            ( *in_a_cb )( (void*)a, userData );
366            a += elementSize;
367        }
368        else
369        {
370            const int val = ( *compare )( a, b );
371
372            if( !val )
373            {
374                ( *in_both_cb )( (void*)a, userData );
375                a += elementSize;
376                b += elementSize;
377            }
378            else if( val < 0 )
379            {
380                ( *in_a_cb )( (void*)a, userData );
381                a += elementSize;
382            }
383            else if( val > 0 )
384            {
385                ( *in_b_cb )( (void*)b, userData );
386                b += elementSize;
387            }
388        }
389    }
390}
391
392/***
393****
394***/
395
396#ifdef DISABLE_GETTEXT
397
398const char*
399tr_strip_positional_args( const char* str )
400{
401    static size_t bufsize = 0;
402    static char * buf = NULL;
403    const size_t  len = strlen( str );
404    char *        out;
405
406    if( bufsize < len )
407    {
408        bufsize = len * 2;
409        buf = tr_renew( char, buf, bufsize );
410    }
411
412    for( out = buf; *str; ++str )
413    {
414        *out++ = *str;
415        if( ( *str == '%' ) && isdigit( str[1] ) )
416        {
417            const char * tmp = str + 1;
418            while( isdigit( *tmp ) )
419                ++tmp;
420
421            if( *tmp == '$' )
422                str = tmp;
423        }
424    }
425    *out = '\0';
426
427    return buf;
428}
429
430#endif
431
432/**
433***
434**/
435
436void
437tr_timevalMsec( uint64_t milliseconds, struct timeval * setme )
438{
439    const uint64_t microseconds = milliseconds * 1000;
440    assert( setme != NULL );
441    setme->tv_sec  = microseconds / 1000000;
442    setme->tv_usec = microseconds % 1000000;
443}
444
445uint8_t *
446tr_loadFile( const char * path,
447             size_t *     size )
448{
449    uint8_t *    buf;
450    struct stat  sb;
451    FILE *       file;
452    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
453
454    /* try to stat the file */
455    errno = 0;
456    if( stat( path, &sb ) )
457    {
458        const int err = errno;
459        tr_dbg( err_fmt, path, tr_strerror( errno ) );
460        errno = err;
461        return NULL;
462    }
463
464    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
465    {
466        tr_err( err_fmt, path, _( "Not a regular file" ) );
467        errno = EISDIR;
468        return NULL;
469    }
470
471    /* Load the torrent file into our buffer */
472    file = fopen( path, "rb" );
473    if( !file )
474    {
475        const int err = errno;
476        tr_err( err_fmt, path, tr_strerror( errno ) );
477        errno = err;
478        return NULL;
479    }
480    buf = malloc( sb.st_size );
481    if( !buf )
482    {
483        const int err = errno;
484        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
485        fclose( file );
486        errno = err;
487        return NULL;
488    }
489    if( fread( buf, sb.st_size, 1, file ) != 1 )
490    {
491        const int err = errno;
492        tr_err( err_fmt, path, tr_strerror( errno ) );
493        fclose( file );
494        free( buf );
495        errno = err;
496        return NULL;
497    }
498
499    fclose( file );
500    *size = sb.st_size;
501    return buf;
502}
503
504char*
505tr_basename( const char * path )
506{
507    char * tmp = tr_strdup( path );
508    char * ret = tr_strdup( basename( tmp ) );
509    tr_free( tmp );
510    return ret;
511}
512
513char*
514tr_dirname( const char * path )
515{
516    char * tmp = tr_strdup( path );
517    char * ret = tr_strdup( dirname( tmp ) );
518    tr_free( tmp );
519    return ret;
520}
521
522int
523tr_mkdir( const char * path,
524          int permissions
525#ifdef WIN32
526                       UNUSED
527#endif
528        )
529{
530#ifdef WIN32
531    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
532        return 0;
533    return mkdir( path );
534#else
535    return mkdir( path, permissions );
536#endif
537}
538
539int
540tr_mkdirp( const char * path_in,
541           int          permissions )
542{
543    char *      path = tr_strdup( path_in );
544    char *      p, * pp;
545    struct stat sb;
546    int         done;
547
548    /* walk past the root */
549    p = path;
550    while( *p == TR_PATH_DELIMITER )
551        ++p;
552
553    pp = p;
554    done = 0;
555    while( ( p =
556                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
557    {
558        if( !*p )
559            done = 1;
560        else
561            *p = '\0';
562
563        if( stat( path, &sb ) )
564        {
565            /* Folder doesn't exist yet */
566            if( tr_mkdir( path, permissions ) )
567            {
568                const int err = errno;
569                tr_err( _(
570                           "Couldn't create \"%1$s\": %2$s" ), path,
571                       tr_strerror( err ) );
572                tr_free( path );
573                errno = err;
574                return -1;
575            }
576        }
577        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
578        {
579            /* Node exists but isn't a folder */
580            char * buf = tr_strdup_printf( _( "File \"%s\" is in the way" ), path );
581            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
582            tr_free( buf );
583            tr_free( path );
584            errno = ENOTDIR;
585            return -1;
586        }
587
588        if( done )
589            break;
590
591        *p = TR_PATH_DELIMITER;
592        p++;
593        pp = p;
594    }
595
596    tr_free( path );
597    return 0;
598}
599
600char*
601tr_buildPath( const char *first_element, ... )
602{
603    size_t bufLen = 0;
604    const char * element;
605    char * buf;
606    char * pch;
607    va_list vl;
608
609    /* pass 1: allocate enough space for the string */
610    va_start( vl, first_element );
611    element = first_element;
612    while( element ) {
613        bufLen += strlen( element ) + 1;
614        element = (const char*) va_arg( vl, const char* );
615    }
616    pch = buf = tr_new( char, bufLen );
617    va_end( vl );
618
619    /* pass 2: build the string piece by piece */
620    va_start( vl, first_element );
621    element = first_element;
622    while( element ) {
623        const size_t elementLen = strlen( element );
624        memcpy( pch, element, elementLen );
625        pch += elementLen;
626        *pch++ = TR_PATH_DELIMITER;
627        element = (const char*) va_arg( vl, const char* );
628    }
629    va_end( vl );
630
631    /* terminate the string.  if nonempty, eat the unwanted trailing slash */
632    if( pch != buf )
633        --pch;
634    *pch++ = '\0';
635
636    /* sanity checks & return */
637    assert( pch - buf == (off_t)bufLen );
638    return buf;
639}
640
641/****
642*****
643****/
644
645void*
646tr_memdup( const void * in,
647           int          byteCount )
648{
649    void * out = tr_new( uint8_t, byteCount );
650
651    memcpy( out, in, byteCount );
652    return out;
653}
654
655char*
656tr_strdup( const void * in )
657{
658    return tr_strndup( in, in ? strlen( (const char*)in ) : 0 );
659}
660
661char*
662tr_strndup( const void * in,
663            int          len )
664{
665    char * out = NULL;
666
667    if( len < 0 )
668    {
669        out = tr_strdup( in );
670    }
671    else if( in )
672    {
673        out = tr_malloc( len + 1 );
674        memcpy( out, in, len );
675        out[len] = '\0';
676    }
677
678    return out;
679}
680
681char*
682tr_strdup_printf( const char * fmt, ... )
683{
684    char *            ret = NULL;
685    struct evbuffer * buf;
686    va_list           ap;
687
688    buf = tr_getBuffer( );
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    tr_releaseBuffer( 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
1280int
1281tr_ptr2int( void* v )
1282{
1283    return (intptr_t)v;
1284}
1285
1286void*
1287tr_int2ptr( int i )
1288{
1289    return (void*)(intptr_t)i;
1290}
1291
1292/***
1293****
1294***/
1295
1296static tr_list * _bufferList = NULL;
1297
1298static tr_lock *
1299getBufferLock( void )
1300{
1301    static tr_lock * lock = NULL;
1302    if( lock == NULL )
1303        lock = tr_lockNew( );
1304    return lock;
1305}
1306
1307struct evbuffer*
1308tr_getBuffer( void )
1309{
1310    struct evbuffer * buf;
1311    tr_lock * l = getBufferLock( );
1312    tr_lockLock( l );
1313
1314    buf = tr_list_pop_front( &_bufferList );
1315    if( buf == NULL )
1316        buf = evbuffer_new( );
1317
1318    tr_lockUnlock( l );
1319    return buf;
1320}
1321
1322void
1323tr_releaseBuffer( struct evbuffer * buf )
1324{
1325    tr_lock * l = getBufferLock( );
1326    tr_lockLock( l );
1327
1328    evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
1329    assert( EVBUFFER_LENGTH( buf ) == 0 );
1330    tr_list_prepend( &_bufferList, buf );
1331
1332    tr_lockUnlock( l );
1333}
Note: See TracBrowser for help on using the repository browser.