source: trunk/libtransmission/utils.c @ 6420

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

Make it a little easier to trace backwards from "Unspecified I/O error" to find out what the real problem is.

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