source: trunk/libtransmission/utils.c @ 7581

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

(trunk libT) make the tr_bandwidth macros into safer inline funcs. inline utils' one-liners.

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