source: trunk/libtransmission/utils.c @ 6941

Last change on this file since 6941 was 6941, checked in by charles, 13 years ago

(libT) add tr_getMessageQueuing() for Spry

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