source: trunk/libtransmission/utils.c @ 5976

Last change on this file since 5976 was 5976, checked in by charles, 14 years ago

minor speedups in tr_torrentStat() and in bitfield manipulation

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