source: trunk/libtransmission/utils.c @ 5979

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

on shutdown, close the most active torrents first. That way if we can't get everyting closed in a reasonable amount of time, at least we get the ones that affect stats first.

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