source: trunk/libtransmission/utils.c @ 6595

Last change on this file since 6595 was 6595, checked in by muks, 13 years ago

Make tr_bitfieldHas() a macro

  • Property svn:keywords set to Date Rev Author Id
File size: 26.3 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 6595 2008-08-20 13:45:52Z muks $
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 )
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
268/***
269****
270***/
271
272void
273tr_set_compare( const void * va, size_t aCount,
274                const void * vb, size_t bCount,
275                int compare( const void * a, const void * b ),
276                size_t elementSize,
277                tr_set_func in_a_cb,
278                tr_set_func in_b_cb,
279                tr_set_func in_both_cb,
280                void * userData )
281{
282    const uint8_t * a = (const uint8_t *) va;
283    const uint8_t * b = (const uint8_t *) vb;
284    const uint8_t * aend = a + elementSize*aCount;
285    const uint8_t * bend = b + elementSize*bCount;
286
287    while( a!=aend || b!=bend )
288    {
289        if( a==aend )
290        {
291            (*in_b_cb)( (void*)b, userData );
292            b += elementSize;
293        }
294        else if ( b==bend )
295        {
296            (*in_a_cb)( (void*)a, userData );
297            a += elementSize;
298        }
299        else
300        {
301            const int val = (*compare)( a, b );
302
303            if( !val )
304            {
305                (*in_both_cb)( (void*)a, userData );
306                a += elementSize;
307                b += elementSize;
308            }
309            else if( val < 0 )
310            {
311                (*in_a_cb)( (void*)a, userData );
312                a += elementSize;
313            }
314            else if( val > 0 )
315            {
316                (*in_b_cb)( (void*)b, userData );
317                b += elementSize;
318            }
319        }
320    }
321}
322
323/***
324****
325***/
326
327int
328tr_compareUint16( uint16_t a, uint16_t b )
329{
330    if( a < b ) return -1;
331    if( a > b ) return 1;
332    return 0;
333}
334
335int
336tr_compareUint32( uint32_t a, uint32_t b )
337{
338    if( a < b ) return -1;
339    if( a > b ) return 1;
340    return 0;
341}
342
343int
344tr_compareUint64( uint64_t a, uint64_t b )
345{
346    if( a < b ) return -1;
347    if( a > b ) return 1;
348    return 0;
349}
350
351int
352tr_compareDouble( double a, double b )
353{
354    if( a < b ) return -1;
355    if( a > b ) return 1;
356    return 0;
357}
358
359int
360tr_compareTime( time_t a, time_t b )
361{
362    if( a < b ) return -1;
363    if( a > b ) return 1;
364    return 0;
365}
366
367int
368tr_strcmp( const void * a, const void * b )
369{
370    if( a && b ) return strcmp( a, b );
371    if( a ) return 1;
372    if( b ) return -1;
373    return 0;
374}
375
376int
377tr_strcasecmp( const char * a, const char * b )
378{
379    if( !a && !b ) return 0;
380    if( !a ) return -1;
381    if( !b ) return 1;
382#ifdef HAVE_STRCASECMP
383    return strcasecmp( a, b );
384#else
385    while( *a && ( tolower( *(uint8_t*)a ) == tolower( *(uint8_t*)b ) ) )
386        ++a, ++b;
387    return tolower( *(uint8_t*)a) - tolower(*(uint8_t*)b );
388#endif
389}
390
391
392/**
393***
394**/
395
396struct timeval
397tr_timevalMsec( uint64_t milliseconds )
398{
399    struct timeval ret;
400    const uint64_t microseconds = milliseconds * 1000;
401    ret.tv_sec  = microseconds / 1000000;
402    ret.tv_usec = microseconds % 1000000;
403    return ret;
404}
405
406uint8_t *
407tr_loadFile( const char * path, size_t * size )
408{
409    uint8_t    * buf;
410    struct stat  sb;
411    FILE       * file;
412    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
413
414    /* try to stat the file */
415    errno = 0;
416    if( stat( path, &sb ) )
417    {
418        tr_dbg( err_fmt, path, tr_strerror(errno) );
419        return NULL;
420    }
421
422    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
423    {
424        tr_err( err_fmt, path, _( "Not a regular file" ) );
425        return NULL;
426    }
427
428    /* Load the torrent file into our buffer */
429    file = fopen( path, "rb" );
430    if( !file )
431    {
432        tr_err( err_fmt, path, tr_strerror(errno) );
433        return NULL;
434    }
435    buf = malloc( sb.st_size );
436    if( NULL == buf )
437    {
438        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
439        fclose( file );
440        return NULL;
441    }
442    fseek( file, 0, SEEK_SET );
443    if( fread( buf, sb.st_size, 1, file ) != 1 )
444    {
445        tr_err( err_fmt, path, tr_strerror(errno) );
446        free( buf );
447        fclose( file );
448        return NULL;
449    }
450    fclose( file );
451
452    *size = sb.st_size;
453
454    return buf;
455}
456
457int
458tr_mkdir( const char * path, int permissions
459#ifdef WIN32
460                                             UNUSED
461#endif
462                                                    )
463{
464#ifdef WIN32
465    if( path && isalpha(path[0]) && path[1]==':' && !path[2] )
466        return 0;
467    return mkdir( path );
468#else
469    return mkdir( path, permissions );
470#endif
471}
472
473int
474tr_mkdirp( const char * path_in, int permissions )
475{
476    char * path = tr_strdup( path_in );
477    char * p, * pp;
478    struct stat sb;
479    int done;
480
481    /* walk past the root */
482    p = path;
483    while( *p == TR_PATH_DELIMITER )
484        ++p;
485
486    pp = p;
487    done = 0;
488    while( ( p = strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
489    {
490        if( !*p )
491            done = 1;
492        else
493            *p = '\0';
494
495        if( stat( path, &sb ) )
496        {
497            /* Folder doesn't exist yet */
498            if( tr_mkdir( path, permissions ) ) {
499                const int err = errno;
500                tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path, tr_strerror( err ) );
501                tr_free( path );
502                errno = err;
503                return -1;
504            }
505        }
506        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
507        {
508            /* Node exists but isn't a folder */
509            char buf[MAX_PATH_LENGTH];
510            tr_snprintf( buf, sizeof( buf ), _( "File \"%s\" is in the way" ), path );
511            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
512            tr_free( path );
513            errno = ENOTDIR;
514            return -1;
515        }
516
517        if( done )
518            break;
519
520        *p = TR_PATH_DELIMITER;
521        p++;
522        pp = p;
523    }
524
525    tr_free( path );
526    return 0;
527}
528
529void
530tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
531{
532    struct evbuffer * evbuf;
533    const char * element = first_element;
534    va_list vl;
535
536    evbuf = evbuffer_new( );
537    va_start( vl, first_element );
538
539    while( element ) {
540        if( EVBUFFER_LENGTH(evbuf) )
541            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
542        evbuffer_add_printf( evbuf, "%s", element );
543        element = (const char*) va_arg( vl, const char* );
544    }
545    if( EVBUFFER_LENGTH(evbuf) )
546        tr_strlcpy( buf, (char*)EVBUFFER_DATA(evbuf), buflen );
547    else
548        *buf = '\0';
549
550    va_end( vl );
551    evbuffer_free( evbuf );
552}
553
554int
555tr_ioErrorFromErrno( int err )
556{
557    switch( err )
558    {
559        case 0:
560            return TR_OK;
561        case EACCES:
562        case EROFS:
563            return TR_ERROR_IO_PERMISSIONS;
564        case ENOSPC:
565            return TR_ERROR_IO_SPACE;
566        case EMFILE:
567            return TR_ERROR_IO_OPEN_FILES;
568        case EFBIG:
569            return TR_ERROR_IO_FILE_TOO_BIG;
570        default:
571            tr_err( "generic i/o errno from errno: %s", tr_strerror( errno ) );
572            return TR_ERROR_IO_OTHER;
573    }
574}
575
576const char *
577tr_errorString( int code )
578{
579    switch( code )
580    {
581        case TR_OK:
582            return _( "No error" );
583
584        case TR_ERROR:
585            return _( "Unspecified error" );
586        case TR_ERROR_ASSERT:
587            return _( "Assert error" );
588
589        case TR_ERROR_IO_PARENT:
590            return _( "Destination folder doesn't exist" );
591        case TR_ERROR_IO_PERMISSIONS:
592            return tr_strerror( EACCES );
593        case TR_ERROR_IO_SPACE:
594            return tr_strerror( ENOSPC );
595        case TR_ERROR_IO_FILE_TOO_BIG:
596            return tr_strerror( EFBIG );
597        case TR_ERROR_IO_OPEN_FILES:
598            return tr_strerror( EMFILE );
599        case TR_ERROR_IO_DUP_DOWNLOAD:
600            return _( "A torrent with this name and destination folder already exists." );
601        case TR_ERROR_IO_CHECKSUM:
602            return _( "Checksum failed" );
603        case TR_ERROR_IO_OTHER:
604            return _( "Unspecified I/O error" );
605
606        case TR_ERROR_TC_ERROR:
607            return _( "Tracker error" );
608        case TR_ERROR_TC_WARNING:
609            return _( "Tracker warning" );
610
611        case TR_ERROR_PEER_MESSAGE:
612            return _( "Peer sent a bad message" );
613
614        default:
615            return _( "Unknown error" );
616    }
617}
618
619/****
620*****
621****/
622
623void*
624tr_memdup( const void * in, int byteCount )
625{
626    void * out = tr_new( uint8_t, byteCount );
627    memcpy( out, in, byteCount );
628    return out;
629}
630   
631char*
632tr_strdup( const void * in )
633{
634    return tr_strndup( in, in ? strlen((const char*)in) : 0 );
635}
636
637char*
638tr_strndup( const void * in, int len )
639{
640    char * out = NULL;
641
642    if( len < 0 )
643    {
644        out = tr_strdup( in );
645    }
646    else if( in )
647    {
648        out = tr_malloc( len+1 );
649        memcpy( out, in, len );
650        out[len] = '\0';
651    }
652
653    return out;
654}
655
656char*
657tr_strdup_printf( const char * fmt, ... )
658{
659    char * ret = NULL;
660    struct evbuffer * buf;
661    va_list ap;
662
663    buf = evbuffer_new( );
664    va_start( ap, fmt );
665
666    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
667        ret = tr_strdup( (char*)EVBUFFER_DATA( buf ) );
668
669    va_end( ap );
670    evbuffer_free( buf );
671    return ret;
672}
673
674void*
675tr_calloc( size_t nmemb, size_t size )
676{
677    return nmemb && size ? calloc( nmemb, size ) : NULL;
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    void * ret = tr_malloc( size );
690    memset( ret, 0, size );
691    return ret;
692}
693
694void
695tr_free( void * p )
696{
697    if( p )
698        free( p );
699}
700
701const char*
702tr_strerror( int i )
703{
704    const char * ret = strerror( i );
705    if( ret == NULL )
706        ret = "Unknown Error";
707    return ret;
708}
709
710/****
711*****
712****/
713
714tr_bitfield*
715tr_bitfieldNew( size_t bitCount )
716{
717    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
718    ret->bitCount = bitCount;
719    ret->byteCount = (bitCount+7u) / 8u;
720    ret->bits = tr_new0( uint8_t, ret->byteCount );
721    return ret;
722}
723
724tr_bitfield*
725tr_bitfieldDup( const tr_bitfield * in )
726{
727    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
728    ret->bitCount = in->bitCount;
729    ret->byteCount = in->byteCount;
730    ret->bits = tr_memdup( in->bits, in->byteCount );
731    return ret;
732}
733
734void
735tr_bitfieldFree( tr_bitfield * bitfield )
736{
737    if( bitfield )
738    {
739        tr_free( bitfield->bits );
740        tr_free( bitfield );
741    }
742}
743
744void
745tr_bitfieldClear( tr_bitfield * bitfield )
746{
747    memset( bitfield->bits, 0, bitfield->byteCount );
748}
749
750int
751tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
752{
753    size_t i;
754
755    for( i=0; i<bitfield->byteCount; ++i )
756        if( bitfield->bits[i] )
757            return 0;
758
759    return 1;
760}
761
762int
763tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
764{
765    assert( bitfield );
766    assert( bitfield->bits );
767
768    if( nth >= bitfield->bitCount )
769        return -1;
770
771    bitfield->bits[nth>>3u] |= (0x80 >> (nth&7u));
772    return 0;
773}
774
775/* Sets bit range [begin, end) to 1 */
776int
777tr_bitfieldAddRange( tr_bitfield  * b,
778                     size_t         begin,
779                     size_t         end )
780{
781    size_t sb, eb;
782    unsigned char sm, em;
783
784    end--;
785
786    if( ( end >= b->bitCount ) || ( begin > end ) )
787        return -1;
788
789    sb = begin >> 3;
790    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
791    eb = end >> 3;
792    em = 0xff << ( 7 - ( end & 7 ) );
793
794    if ( sb == eb ) {
795        b->bits[sb] |= ( sm & em );
796    } else {
797        b->bits[sb] |= sm;
798        b->bits[eb] |= em;
799        if( ++sb < eb )
800            memset (b->bits + sb, 0xff, eb - sb);
801    }
802
803    return 0;
804}
805
806int
807tr_bitfieldRem( tr_bitfield   * bitfield,
808                size_t          nth )
809{
810    assert( bitfield );
811    assert( bitfield->bits );
812
813    if( nth >= bitfield->bitCount )
814        return -1;
815
816    bitfield->bits[nth>>3u] &= (0xff7f >> (nth&7u));
817    return 0;
818}
819
820/* Clears bit range [begin, end) to 0 */
821int
822tr_bitfieldRemRange ( tr_bitfield  * b,
823                      size_t         begin,
824                      size_t         end )
825{
826    size_t sb, eb;
827    unsigned char sm, em;
828
829    end--;
830
831    if( ( end >= b->bitCount ) || ( begin > end ) )
832        return -1;
833
834    sb = begin >> 3;
835    sm = 0xff << ( 8 - ( begin & 7 ) );
836    eb = end >> 3;
837    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
838
839    if ( sb == eb ) {
840        b->bits[sb] &= ( sm | em );
841    } else {
842        b->bits[sb] &= sm;
843        b->bits[eb] &= em;
844        if( ++sb < eb )
845            memset (b->bits + sb, 0, eb - sb);
846    }
847
848    return 0;
849}
850
851tr_bitfield*
852tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b )
853{
854    uint8_t *ait;
855    const uint8_t *aend, *bit;
856
857    assert( a->bitCount == b->bitCount );
858
859    for( ait=a->bits, bit=b->bits, aend=ait+a->byteCount; ait!=aend; )
860        *ait++ |= *bit++;
861
862    return a;
863}
864
865/* set 'a' to all the flags that were in 'a' but not 'b' */
866void
867tr_bitfieldDifference( tr_bitfield * a, const tr_bitfield * b )
868{
869    uint8_t *ait;
870    const uint8_t *aend, *bit;
871
872    assert( a->bitCount == b->bitCount );
873
874    for( ait=a->bits, bit=b->bits, aend=ait+a->byteCount; ait!=aend; )
875        *ait++ &= ~(*bit++);
876}
877
878
879size_t
880tr_bitfieldCountTrueBits( const tr_bitfield* b )
881{
882    size_t ret = 0;
883    const uint8_t *it, *end;
884    static const int trueBitCount[512] = {
885        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,
886        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,
887        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,
888        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,
889        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,
890        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,
891        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,
892        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,
893        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,
894        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,
895        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,
896        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,
897        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,
898        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,
899        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,
900        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
901    };
902
903    if( !b )
904        return 0;
905
906    for( it=b->bits, end=it+b->byteCount; it!=end; ++it )
907        ret += trueBitCount[*it];
908
909    return ret;
910}
911
912/***
913****
914***/
915
916uint64_t
917tr_date( void )
918{
919    struct timeval tv;
920    gettimeofday( &tv, NULL );
921    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
922}
923
924void
925tr_wait( uint64_t delay_milliseconds )
926{
927#ifdef __BEOS__
928    snooze( 1000 * delay_milliseconds );
929#elif defined(WIN32)
930    Sleep( (DWORD)delay_milliseconds );
931#else
932    usleep( 1000 * delay_milliseconds );
933#endif
934}
935
936/***
937****
938***/
939
940int
941tr_stringEndsWith( const char * str, const char * end )
942{
943    const size_t slen = strlen( str );
944    const size_t elen = strlen( end );
945    return slen>=elen && !memcmp( &str[slen-elen], end, elen );
946}
947
948int
949tr_snprintf( char * buf, size_t buflen, const char * fmt, ... )
950{
951    int len;
952    va_list args;
953    va_start( args, fmt );
954    len = evutil_vsnprintf( buf, buflen, fmt, args );
955    va_end( args );
956    return len;
957}
958
959
960/*
961 * Copy src to string dst of size siz.  At most siz-1 characters
962 * will be copied.  Always NUL terminates (unless siz == 0).
963 * Returns strlen(src); if retval >= siz, truncation occurred.
964 */
965size_t
966tr_strlcpy(char *dst, const char *src, size_t siz)
967{
968#ifdef HAVE_STRLCPY
969    return strlcpy( dst, src, siz );
970#else
971    char *d = dst;
972    const char *s = src;
973    size_t n = siz;
974
975    assert( s );
976    assert( d );
977
978    /* Copy as many bytes as will fit */
979    if (n != 0) {
980        while (--n != 0) {
981            if ((*d++ = *s++) == '\0')
982                break;
983        }
984    }
985
986    /* Not enough room in dst, add NUL and traverse rest of src */
987    if (n == 0) {
988        if (siz != 0)
989            *d = '\0'; /* NUL-terminate dst */
990        while (*s++)
991            ;
992    }
993
994    return(s - src - 1); /* count does not include NUL */
995#endif
996}
997
998/***
999****
1000***/
1001
1002double
1003tr_getRatio( double numerator, double denominator )
1004{
1005    double ratio;
1006
1007    if( denominator )
1008        ratio = numerator / denominator;
1009    else if( numerator )
1010        ratio = TR_RATIO_INF;
1011    else
1012        ratio = TR_RATIO_NA;
1013
1014    return ratio;
1015}
1016
1017void
1018tr_sha1_to_hex( char * out, const uint8_t * sha1 )
1019{
1020    static const char hex[] = "0123456789abcdef";
1021    int i;
1022    for (i = 0; i < 20; i++) {
1023        unsigned int val = *sha1++;
1024        *out++ = hex[val >> 4];
1025        *out++ = hex[val & 0xf];
1026    }
1027    *out = '\0';
1028}
1029
1030/***
1031****
1032***/
1033
1034int
1035tr_httpIsValidURL( const char * url )
1036{
1037    const char * c;
1038    static const char * rfc2396_valid_chars =
1039        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1040        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1041        "0123456789"                 /* digit */
1042        "-_.!~*'()"                  /* mark */
1043        ";/?:@&=+$,"                 /* reserved */
1044        "<>#%<\""                    /* delims */
1045        "{}|\\^[]`";                 /* unwise */
1046
1047    for( c=url; c && *c; ++c )
1048        if( !strchr( rfc2396_valid_chars, *c ) )
1049            return FALSE;
1050
1051    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1052}
1053
1054int
1055tr_httpParseURL( const char * url_in, int len,
1056                 char ** setme_host,
1057                 int * setme_port,
1058                 char ** setme_path )
1059{
1060    int err;
1061    int port = 0;
1062    int n;
1063    char * tmp;
1064    char * pch;
1065    const char * protocol = NULL;
1066    const char * host = NULL;
1067    const char * path = NULL;
1068
1069    tmp = tr_strndup( url_in, len );
1070    if(( pch = strstr( tmp, "://" )))
1071    {
1072       *pch = '\0';
1073       protocol = tmp;
1074       pch += 3;
1075/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch );*/
1076       if(( n = strcspn( pch, ":/" )))
1077       {
1078           const int havePort = pch[n] == ':';
1079           host = pch;
1080           pch += n;
1081           *pch++ = '\0';
1082/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1083           if( havePort )
1084           {
1085               char * end;
1086               port = strtol( pch, &end, 10 );
1087               pch = end;
1088/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1089           }
1090           path = pch;
1091/*fprintf( stderr, "path is [%s]\n", path );*/
1092       }
1093    }
1094
1095    err = !host || !path || !protocol || ( strcmp(protocol,"http") && strcmp(protocol,"https") );
1096
1097    if( !err && !port ) {
1098        if( !strcmp(protocol,"http") ) port = 80;
1099        if( !strcmp(protocol,"https") ) port = 443;
1100    }
1101
1102    if( !err ) {
1103        if( setme_host) { ((char*)host)[-3]=':'; *setme_host = tr_strdup( protocol ); }
1104        if( setme_path) { ((char*)path)[-1]='/'; *setme_path = tr_strdup( path-1 ); }
1105        if( setme_port) *setme_port = port;
1106    }
1107
1108
1109    tr_free( tmp );
1110    return err;
1111}
1112
1113#include <string.h>
1114#include <openssl/sha.h>
1115#include <openssl/hmac.h>
1116#include <openssl/evp.h>
1117#include <openssl/bio.h>
1118#include <openssl/buffer.h>
1119
1120char *
1121tr_base64_encode( const void * input, int length, int * setme_len )
1122{
1123    char * ret;
1124    BIO * b64;
1125    BIO * bmem;
1126    BUF_MEM * bptr;
1127
1128    if( length < 1 )
1129       length = strlen( input );
1130
1131    bmem = BIO_new( BIO_s_mem( ) );
1132    b64 = BIO_new( BIO_f_base64( ) );
1133    b64 = BIO_push( b64, bmem );
1134    BIO_write( b64, input, length );
1135    (void) BIO_flush( b64 );
1136    BIO_get_mem_ptr( b64, &bptr );
1137    ret = tr_strndup( bptr->data, bptr->length );
1138    if( setme_len )
1139        *setme_len = bptr->length;
1140
1141    BIO_free_all( b64 );
1142    return ret;
1143}
1144
1145char *
1146tr_base64_decode( const void * input, int length, int * setme_len )
1147{
1148    char * ret;
1149    BIO * b64;
1150    BIO * bmem;
1151    int retlen;
1152
1153    if( length < 1 )
1154       length = strlen( input );
1155
1156    ret = tr_new0( char, length );
1157    b64 = BIO_new( BIO_f_base64( ) );
1158    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1159    bmem = BIO_push( b64, bmem );
1160    retlen = BIO_read( bmem, ret, length );
1161    if( !retlen )
1162    {
1163        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1164        BIO_free_all( bmem );
1165        b64 = BIO_new( BIO_f_base64( ) );
1166        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1167        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1168        bmem = BIO_push( b64, bmem );
1169        retlen = BIO_read( bmem, ret, length );
1170    }
1171
1172    if( setme_len )
1173        *setme_len = retlen;
1174
1175    BIO_free_all( bmem );
1176    return ret;
1177}
Note: See TracBrowser for help on using the repository browser.