source: trunk/libtransmission/utils.c @ 11228

Last change on this file since 11228 was 11228, checked in by charles, 11 years ago

(trunk) #3547 "Wrong speed display in web UI" -- fixed

  • Property svn:keywords set to Date Rev Author Id
File size: 38.4 KB
Line 
1/*
2 * This file Copyright (C) 2009-2010 Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: utils.c 11228 2010-09-18 23:06:03Z charles $
11 */
12
13#ifdef HAVE_MEMMEM
14 #define _GNU_SOURCE /* glibc's string.h needs this to pick up memmem */
15#endif
16
17#if defined(SYS_DARWIN)
18 #define HAVE_GETPAGESIZE
19 #define HAVE_ICONV_OPEN
20 #define HAVE_VALLOC
21 #undef HAVE_POSIX_MEMALIGN /* not supported on OS X 10.5 and lower */
22#endif
23
24#include <assert.h>
25#include <ctype.h> /* isalpha(), tolower() */
26#include <errno.h>
27#include <math.h> /* pow(), fabs() */
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h> /* strerror(), memset(), memmem() */
32#include <time.h> /* nanosleep() */
33
34#ifdef HAVE_ICONV_OPEN
35 #include <iconv.h>
36#endif
37#include <libgen.h> /* basename() */
38#include <sys/time.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <unistd.h> /* stat(), getcwd(), getpagesize() */
42
43#include "event.h"
44
45#ifdef WIN32
46 #include <w32api.h>
47 #define WINVER WindowsXP /* freeaddrinfo(), getaddrinfo(), getnameinfo() */
48 #include <direct.h> /* _getcwd() */
49 #include <windows.h> /* Sleep() */
50#endif
51
52#include "transmission.h"
53#include "bencode.h"
54#include "fdlimit.h"
55#include "ConvertUTF.h"
56#include "list.h"
57#include "net.h"
58#include "utils.h"
59#include "platform.h"
60#include "version.h"
61
62
63time_t transmission_now = 0;
64
65tr_msg_level messageLevel = TR_MSG_INF;
66static tr_lock *      messageLock = NULL;
67static tr_bool        messageQueuing = FALSE;
68static tr_msg_list *  messageQueue = NULL;
69static tr_msg_list ** messageQueueTail = &messageQueue;
70static int            messageQueueCount = 0;
71
72#ifndef WIN32
73    /* make null versions of these win32 functions */
74    static inline int IsDebuggerPresent( void ) { return FALSE; }
75    static inline void OutputDebugString( const void * unused UNUSED ) { }
76#endif
77
78/***
79****
80***/
81
82void
83tr_msgInit( void )
84{
85    const char * env = getenv( "TR_DEBUG" );
86    messageLevel = ( env ? atoi( env ) : 0 ) + 1;
87    messageLevel = MAX( 1, messageLevel );
88
89    if( messageLock == NULL )
90        messageLock = tr_lockNew( );
91}
92
93FILE*
94tr_getLog( void )
95{
96    static tr_bool initialized = FALSE;
97    static FILE * file = NULL;
98
99    if( !initialized )
100    {
101        const char * str = getenv( "TR_DEBUG_FD" );
102        int          fd = 0;
103        if( str && *str )
104            fd = atoi( str );
105        switch( fd )
106        {
107            case 1:
108                file = stdout; break;
109
110            case 2:
111                file = stderr; break;
112
113            default:
114                file = NULL; break;
115        }
116        initialized = TRUE;
117    }
118
119    return file;
120}
121
122void
123tr_setMessageLevel( tr_msg_level level )
124{
125    messageLevel = level;
126}
127
128tr_msg_level
129tr_getMessageLevel( void )
130{
131    return messageLevel;
132}
133
134void
135tr_setMessageQueuing( tr_bool enabled )
136{
137    messageQueuing = enabled;
138}
139
140tr_bool
141tr_getMessageQueuing( void )
142{
143    return messageQueuing != 0;
144}
145
146tr_msg_list *
147tr_getQueuedMessages( void )
148{
149    tr_msg_list * ret;
150    tr_lockLock( messageLock );
151
152    ret = messageQueue;
153    messageQueue = NULL;
154    messageQueueTail = &messageQueue;
155
156    messageQueueCount = 0;
157
158    tr_lockUnlock( messageLock );
159    return ret;
160}
161
162void
163tr_freeMessageList( tr_msg_list * list )
164{
165    tr_msg_list * next;
166
167    while( NULL != list )
168    {
169        next = list->next;
170        free( list->message );
171        free( list->name );
172        free( list );
173        list = next;
174    }
175}
176
177/**
178***
179**/
180
181struct tm *
182tr_localtime_r( const time_t *_clock, struct tm *_result )
183{
184#ifdef HAVE_LOCALTIME_R
185    return localtime_r( _clock, _result );
186#else
187    struct tm *p = localtime( _clock );
188    if( p )
189        *(_result) = *p;
190    return p;
191#endif
192}
193
194char*
195tr_getLogTimeStr( char * buf, int buflen )
196{
197    char           tmp[64];
198    struct tm      now_tm;
199    struct timeval tv;
200    time_t         seconds;
201    int            milliseconds;
202
203    gettimeofday( &tv, NULL );
204
205    seconds = tv.tv_sec;
206    tr_localtime_r( &seconds, &now_tm );
207    strftime( tmp, sizeof( tmp ), "%H:%M:%S", &now_tm );
208    milliseconds = (int)( tv.tv_usec / 1000 );
209    tr_snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
210
211    return buf;
212}
213
214tr_bool
215tr_deepLoggingIsActive( void )
216{
217    static int8_t deepLoggingIsActive = -1;
218
219    if( deepLoggingIsActive < 0 )
220        deepLoggingIsActive = IsDebuggerPresent() || (tr_getLog()!=NULL);
221
222    return deepLoggingIsActive != 0;
223}
224
225void
226tr_deepLog( const char  * file,
227            int           line,
228            const char  * name,
229            const char  * fmt,
230            ... )
231{
232    FILE * fp = tr_getLog( );
233    if( fp || IsDebuggerPresent( ) )
234    {
235        va_list           args;
236        char              timestr[64];
237        struct evbuffer * buf = evbuffer_new( );
238        char *            base = tr_basename( file );
239
240        evbuffer_add_printf( buf, "[%s] ",
241                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
242        if( name )
243            evbuffer_add_printf( buf, "%s ", name );
244        va_start( args, fmt );
245        evbuffer_add_vprintf( buf, fmt, args );
246        va_end( args );
247        evbuffer_add_printf( buf, " (%s:%d)\n", base, line );
248        /* FIXME(libevent2) ifdef this out for nonwindows platforms */
249        OutputDebugString( EVBUFFER_DATA( buf ) );
250        if(fp) /* FIXME(libevent2) tr_getLog() should return an fd, then use evbuffer_write() here ) */
251            (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
252
253        tr_free( base );
254        evbuffer_free( buf );
255    }
256}
257
258/***
259****
260***/
261
262void
263tr_msg( const char * file, int line,
264        tr_msg_level level,
265        const char * name,
266        const char * fmt, ... )
267{
268    const int err = errno; /* message logging shouldn't affect errno */
269    char buf[1024];
270    va_list ap;
271
272    if( messageLock != NULL )
273        tr_lockLock( messageLock );
274
275    /* build the text message */
276    *buf = '\0';
277    va_start( ap, fmt );
278    evutil_vsnprintf( buf, sizeof( buf ), fmt, ap );
279    va_end( ap );
280
281    OutputDebugString( buf );
282
283    if( *buf )
284    {
285        if( messageQueuing )
286        {
287            tr_msg_list * newmsg;
288            newmsg = tr_new0( tr_msg_list, 1 );
289            newmsg->level = level;
290            newmsg->when = tr_time( );
291            newmsg->message = tr_strdup( buf );
292            newmsg->file = file;
293            newmsg->line = line;
294            newmsg->name = tr_strdup( name );
295
296            *messageQueueTail = newmsg;
297            messageQueueTail = &newmsg->next;
298            ++messageQueueCount;
299
300            if( messageQueueCount > TR_MAX_MSG_LOG )
301            {
302                tr_msg_list * old = messageQueue;
303                messageQueue = old->next;
304                old->next = NULL;
305                tr_freeMessageList(old);
306
307                --messageQueueCount;
308
309                assert( messageQueueCount == TR_MAX_MSG_LOG );
310            }
311        }
312        else
313        {
314            char timestr[64];
315            FILE * fp;
316
317            fp = tr_getLog( );
318            if( fp == NULL )
319                fp = stderr;
320
321            tr_getLogTimeStr( timestr, sizeof( timestr ) );
322
323            if( name )
324                fprintf( fp, "[%s] %s: %s\n", timestr, name, buf );
325            else
326                fprintf( fp, "[%s] %s\n", timestr, buf );
327            fflush( fp );
328        }
329    }
330
331    if( messageLock != NULL )
332        tr_lockUnlock( messageLock );
333
334    errno = err;
335}
336
337/***
338****
339***/
340
341void
342tr_set_compare( const void * va,
343                size_t aCount,
344                const void * vb,
345                size_t bCount,
346                int compare( const void * a, const void * b ),
347                size_t elementSize,
348                tr_set_func in_a_cb,
349                tr_set_func in_b_cb,
350                tr_set_func in_both_cb,
351                void * userData )
352{
353    const uint8_t * a = (const uint8_t *) va;
354    const uint8_t * b = (const uint8_t *) vb;
355    const uint8_t * aend = a + elementSize * aCount;
356    const uint8_t * bend = b + elementSize * bCount;
357
358    while( a != aend || b != bend )
359    {
360        if( a == aend )
361        {
362            ( *in_b_cb )( (void*)b, userData );
363            b += elementSize;
364        }
365        else if( b == bend )
366        {
367            ( *in_a_cb )( (void*)a, userData );
368            a += elementSize;
369        }
370        else
371        {
372            const int val = ( *compare )( a, b );
373
374            if( !val )
375            {
376                ( *in_both_cb )( (void*)a, userData );
377                a += elementSize;
378                b += elementSize;
379            }
380            else if( val < 0 )
381            {
382                ( *in_a_cb )( (void*)a, userData );
383                a += elementSize;
384            }
385            else if( val > 0 )
386            {
387                ( *in_b_cb )( (void*)b, userData );
388                b += elementSize;
389            }
390        }
391    }
392}
393
394/***
395****
396***/
397
398const char*
399tr_strip_positional_args( const char* str )
400{
401    const char * in = str;
402    static size_t bufsize = 0;
403    static char * buf = NULL;
404    const size_t  len = strlen( str );
405    char *        out;
406
407    if( bufsize < len )
408    {
409        bufsize = len * 2;
410        buf = tr_renew( char, buf, bufsize );
411    }
412
413    for( out = buf; *str; ++str )
414    {
415        *out++ = *str;
416
417        if( ( *str == '%' ) && isdigit( str[1] ) )
418        {
419            const char * tmp = str + 1;
420            while( isdigit( *tmp ) )
421                ++tmp;
422            if( *tmp == '$' )
423                str = tmp[1]=='\'' ? tmp+1 : tmp;
424        }
425
426        if( ( *str == '%' ) && ( str[1] == '\'' ) )
427            str = str + 1;
428 
429    }
430    *out = '\0';
431
432    return strcmp( buf, in ) ? buf : in;
433}
434
435/**
436***
437**/
438
439void
440tr_timerAdd( struct event * timer, int seconds, int microseconds )
441{
442    struct timeval tv;
443    tv.tv_sec = seconds;
444    tv.tv_usec = microseconds;
445
446    assert( tv.tv_sec >= 0 );
447    assert( tv.tv_usec >= 0 );
448    assert( tv.tv_usec < 1000000 );
449
450    evtimer_add( timer, &tv );
451}
452
453void
454tr_timerAddMsec( struct event * timer, int msec )
455{
456    const int seconds =  msec / 1000;
457    const int usec = (msec%1000) * 1000;
458    tr_timerAdd( timer, seconds, usec );
459}
460
461/**
462***
463**/
464
465uint8_t *
466tr_loadFile( const char * path,
467             size_t *     size )
468{
469    uint8_t * buf;
470    struct stat  sb;
471    int fd;
472    ssize_t n;
473    const char * const err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
474
475    /* try to stat the file */
476    errno = 0;
477    if( stat( path, &sb ) )
478    {
479        const int err = errno;
480        tr_dbg( err_fmt, path, tr_strerror( errno ) );
481        errno = err;
482        return NULL;
483    }
484
485    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
486    {
487        tr_err( err_fmt, path, _( "Not a regular file" ) );
488        errno = EISDIR;
489        return NULL;
490    }
491
492    /* Load the torrent file into our buffer */
493    fd = tr_open_file_for_scanning( path );
494    if( fd < 0 )
495    {
496        const int err = errno;
497        tr_err( err_fmt, path, tr_strerror( errno ) );
498        errno = err;
499        return NULL;
500    }
501    buf = malloc( sb.st_size + 1 );
502    if( !buf )
503    {
504        const int err = errno;
505        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
506        tr_close_file( fd );
507        errno = err;
508        return NULL;
509    }
510    n = read( fd, buf, (size_t)sb.st_size );
511    if( n == -1 )
512    {
513        const int err = errno;
514        tr_err( err_fmt, path, tr_strerror( errno ) );
515        tr_close_file( fd );
516        free( buf );
517        errno = err;
518        return NULL;
519    }
520
521    tr_close_file( fd );
522    buf[ sb.st_size ] = '\0';
523    *size = sb.st_size;
524    return buf;
525}
526
527char*
528tr_basename( const char * path )
529{
530    char * tmp = tr_strdup( path );
531    char * ret = tr_strdup( basename( tmp ) );
532    tr_free( tmp );
533    return ret;
534}
535
536char*
537tr_dirname( const char * path )
538{
539    char * tmp = tr_strdup( path );
540    char * ret = tr_strdup( dirname( tmp ) );
541    tr_free( tmp );
542    return ret;
543}
544
545int
546tr_mkdir( const char * path,
547          int permissions
548#ifdef WIN32
549                       UNUSED
550#endif
551        )
552{
553#ifdef WIN32
554    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
555        return 0;
556    return mkdir( path );
557#else
558    return mkdir( path, permissions );
559#endif
560}
561
562int
563tr_mkdirp( const char * path_in,
564           int          permissions )
565{
566    char *      path = tr_strdup( path_in );
567    char *      p, * pp;
568    struct stat sb;
569    int         done;
570
571    /* walk past the root */
572    p = path;
573    while( *p == TR_PATH_DELIMITER )
574        ++p;
575
576    pp = p;
577    done = 0;
578    while( ( p =
579                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
580    {
581        if( !*p )
582            done = 1;
583        else
584            *p = '\0';
585
586        if( stat( path, &sb ) )
587        {
588            /* Folder doesn't exist yet */
589            if( tr_mkdir( path, permissions ) )
590            {
591                const int err = errno;
592                tr_err( _(
593                           "Couldn't create \"%1$s\": %2$s" ), path,
594                       tr_strerror( err ) );
595                tr_free( path );
596                errno = err;
597                return -1;
598            }
599        }
600        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
601        {
602            /* Node exists but isn't a folder */
603            char * buf = tr_strdup_printf( _( "File \"%s\" is in the way" ), path );
604            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
605            tr_free( buf );
606            tr_free( path );
607            errno = ENOTDIR;
608            return -1;
609        }
610
611        if( done )
612            break;
613
614        *p = TR_PATH_DELIMITER;
615        p++;
616        pp = p;
617    }
618
619    tr_free( path );
620    return 0;
621}
622
623char*
624tr_buildPath( const char *first_element, ... )
625{
626    size_t bufLen = 0;
627    const char * element;
628    char * buf;
629    char * pch;
630    va_list vl;
631
632    /* pass 1: allocate enough space for the string */
633    va_start( vl, first_element );
634    element = first_element;
635    while( element ) {
636        bufLen += strlen( element ) + 1;
637        element = (const char*) va_arg( vl, const char* );
638    }
639    pch = buf = tr_new( char, bufLen );
640    va_end( vl );
641
642    /* pass 2: build the string piece by piece */
643    va_start( vl, first_element );
644    element = first_element;
645    while( element ) {
646        const size_t elementLen = strlen( element );
647        memcpy( pch, element, elementLen );
648        pch += elementLen;
649        *pch++ = TR_PATH_DELIMITER;
650        element = (const char*) va_arg( vl, const char* );
651    }
652    va_end( vl );
653
654    /* terminate the string.  if nonempty, eat the unwanted trailing slash */
655    if( pch != buf )
656        --pch;
657    *pch++ = '\0';
658
659    /* sanity checks & return */
660    assert( pch - buf == (off_t)bufLen );
661    return buf;
662}
663
664/****
665*****
666****/
667
668char*
669tr_strndup( const void * in, int len )
670{
671    char * out = NULL;
672
673    if( len < 0 )
674    {
675        out = tr_strdup( in );
676    }
677    else if( in )
678    {
679        out = tr_malloc( len + 1 );
680        memcpy( out, in, len );
681        out[len] = '\0';
682    }
683
684    return out;
685}
686
687const char*
688tr_memmem( const char * haystack, size_t haystacklen,
689           const char * needle, size_t needlelen )
690{
691#ifdef HAVE_MEMMEM
692    return memmem( haystack, haystacklen, needle, needlelen );
693#else
694    size_t i;
695    if( !needlelen )
696        return haystack;
697    if( needlelen > haystacklen || !haystack || !needle )
698        return NULL;
699    for( i=0; i<=haystacklen-needlelen; ++i )
700        if( !memcmp( haystack+i, needle, needlelen ) )
701            return haystack+i;
702    return NULL;
703#endif
704}
705
706char*
707tr_strdup_printf( const char * fmt, ... )
708{
709    va_list ap;
710    char * ret;
711    size_t len;
712    char statbuf[2048];
713
714    va_start( ap, fmt );
715    len = evutil_vsnprintf( statbuf, sizeof( statbuf ), fmt, ap );
716    va_end( ap );
717    if( len < sizeof( statbuf ) )
718        ret = tr_strndup( statbuf, len );
719    else {
720        ret = tr_new( char, len + 1 );
721        va_start( ap, fmt );
722        evutil_vsnprintf( ret, len + 1, fmt, ap );
723        va_end( ap );
724    }
725
726    return ret;
727}
728
729const char*
730tr_strerror( int i )
731{
732    const char * ret = strerror( i );
733
734    if( ret == NULL )
735        ret = "Unknown Error";
736    return ret;
737}
738
739/****
740*****
741****/
742
743char*
744tr_strstrip( char * str )
745{
746    if( str != NULL )
747    {
748        size_t pos;
749        size_t len = strlen( str );
750
751        while( len && isspace( str[len - 1] ) )
752            --len;
753
754        for( pos = 0; pos < len && isspace( str[pos] ); )
755            ++pos;
756
757        len -= pos;
758        memmove( str, str + pos, len );
759        str[len] = '\0';
760    }
761
762    return str;
763}
764
765tr_bool
766tr_str_has_suffix( const char *str, const char *suffix )
767{
768    size_t str_len;
769    size_t suffix_len;
770
771    if( !str )
772        return FALSE;
773    if( !suffix )
774        return TRUE;
775
776    str_len = strlen( str );
777    suffix_len = strlen( suffix );
778    if( str_len < suffix_len )
779        return FALSE;
780
781    return !strncasecmp( str + str_len - suffix_len, suffix, suffix_len );
782}
783
784/****
785*****
786****/
787
788uint64_t
789tr_time_msec( void )
790{
791    struct timeval tv;
792
793    gettimeofday( &tv, NULL );
794    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
795}
796
797void
798tr_wait_msec( long int msec )
799{
800#ifdef WIN32
801    Sleep( (DWORD)msec );
802#else
803    struct timespec ts;
804    ts.tv_sec = msec / 1000;
805    ts.tv_nsec = ( msec % 1000 ) * 1000000;
806    nanosleep( &ts, NULL );
807#endif
808}
809
810/***
811****
812***/
813
814int
815tr_snprintf( char * buf, size_t buflen, const char * fmt, ... )
816{
817    int     len;
818    va_list args;
819
820    va_start( args, fmt );
821    len = evutil_vsnprintf( buf, buflen, fmt, args );
822    va_end( args );
823    return len;
824}
825
826/*
827 * Copy src to string dst of size siz.  At most siz-1 characters
828 * will be copied.  Always NUL terminates (unless siz == 0).
829 * Returns strlen(src); if retval >= siz, truncation occurred.
830 */
831size_t
832tr_strlcpy( char *       dst,
833            const void * src,
834            size_t       siz )
835{
836#ifdef HAVE_STRLCPY
837    return strlcpy( dst, src, siz );
838#else
839    char *      d = dst;
840    const char *s = src;
841    size_t      n = siz;
842
843    assert( s );
844    assert( d );
845
846    /* Copy as many bytes as will fit */
847    if( n != 0 )
848    {
849        while( --n != 0 )
850        {
851            if( ( *d++ = *s++ ) == '\0' )
852                break;
853        }
854    }
855
856    /* Not enough room in dst, add NUL and traverse rest of src */
857    if( n == 0 )
858    {
859        if( siz != 0 )
860            *d = '\0'; /* NUL-terminate dst */
861        while( *s++ )
862            ;
863    }
864
865    return s - (char*)src - 1;  /* count does not include NUL */
866#endif
867}
868
869/***
870****
871***/
872
873double
874tr_getRatio( uint64_t numerator, uint64_t denominator )
875{
876    double ratio;
877
878    if( denominator > 0 )
879        ratio = numerator / (double)denominator;
880    else if( numerator > 0 )
881        ratio = TR_RATIO_INF;
882    else
883        ratio = TR_RATIO_NA;
884
885    return ratio;
886}
887
888void
889tr_sha1_to_hex( char * out, const uint8_t * sha1 )
890{
891    int i;
892    static const char hex[] = "0123456789abcdef";
893
894    for( i=0; i<20; ++i )
895    {
896        const unsigned int val = *sha1++;
897        *out++ = hex[val >> 4];
898        *out++ = hex[val & 0xf];
899    }
900
901    *out = '\0';
902}
903
904void
905tr_hex_to_sha1( uint8_t * out, const char * in )
906{
907    int i;
908    static const char hex[] = "0123456789abcdef";
909
910    for( i=0; i<20; ++i )
911    {
912        const int hi = strchr( hex, tolower( *in++ ) ) - hex;
913        const int lo = strchr( hex, tolower( *in++ ) ) - hex;
914        *out++ = (uint8_t)( (hi<<4) | lo );
915    }
916}
917
918/***
919****
920***/
921
922static tr_bool
923isValidURLChars( const char * url, int url_len )
924{
925    const char * c;
926    const char * end;
927    static const char * rfc2396_valid_chars =
928        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
929        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
930        "0123456789"                 /* digit */
931        "-_.!~*'()"                  /* mark */
932        ";/?:@&=+$,"                 /* reserved */
933        "<>#%<\""                    /* delims */
934        "{}|\\^[]`";                 /* unwise */
935
936    if( url == NULL )
937        return FALSE;
938
939    for( c=url, end=c+url_len; c && *c && c!=end; ++c )
940        if( !strchr( rfc2396_valid_chars, *c ) )
941            return FALSE;
942
943    return TRUE;
944}
945
946/** @brief return TRUE if the url is a http or https url that Transmission understands */
947tr_bool
948tr_urlIsValidTracker( const char * url )
949{
950    tr_bool valid;
951    char * scheme = NULL;
952    const int len = url ? strlen(url) : 0;
953
954    valid = isValidURLChars( url, len )
955         && !tr_urlParse( url, len, &scheme, NULL, NULL, NULL )
956         && ( scheme != NULL )
957         && ( !strcmp(scheme,"http") || !strcmp(scheme,"https") );
958
959    tr_free( scheme );
960    return valid;
961}
962
963/** @brief return TRUE if the url is a http or https or ftp or sftp url that Transmission understands */
964tr_bool
965tr_urlIsValid( const char * url, int url_len )
966{
967    tr_bool valid;
968    char * scheme = NULL;
969    if( ( url_len < 0 ) && ( url != NULL ) )
970        url_len = strlen( url );
971
972    valid = isValidURLChars( url, url_len )
973         && !tr_urlParse( url, url_len, &scheme, NULL, NULL, NULL )
974         && ( scheme != NULL )
975         && ( !strcmp(scheme,"http") || !strcmp(scheme,"https") || !strcmp(scheme,"ftp") || !strcmp(scheme,"sftp") );
976
977    tr_free( scheme );
978    return valid;
979}
980
981tr_bool
982tr_addressIsIP( const char * address )
983{
984    tr_address tempAddr;
985    return tr_pton(address, &tempAddr) != NULL;
986}
987
988int
989tr_urlParse( const char * url_in,
990             int          len,
991             char **      setme_protocol,
992             char **      setme_host,
993             int *        setme_port,
994             char **      setme_path )
995{
996    int          err;
997    int          port = 0;
998    int          n;
999    char *       tmp;
1000    char *       pch;
1001    const char * protocol = NULL;
1002    const char * host = NULL;
1003    const char * path = NULL;
1004
1005    tmp = tr_strndup( url_in, len );
1006    if( ( pch = strstr( tmp, "://" ) ) )
1007    {
1008        *pch = '\0';
1009        protocol = tmp;
1010        pch += 3;
1011/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch);*/
1012        if( ( n = strcspn( pch, ":/" ) ) )
1013        {
1014            const int havePort = pch[n] == ':';
1015            host = pch;
1016            pch += n;
1017            *pch++ = '\0';
1018/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1019            if( havePort )
1020            {
1021                char * end;
1022                port = strtol( pch, &end, 10 );
1023                pch = end;
1024/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1025            }
1026            path = pch;
1027/*fprintf( stderr, "path is [%s]\n", path );*/
1028        }
1029    }
1030
1031    err = !host || !path || !protocol;
1032
1033    if( !err && !port )
1034    {
1035        if( !strcmp( protocol, "ftp" ) ) port = 21;
1036        if( !strcmp( protocol, "sftp" ) ) port = 22;
1037        if( !strcmp( protocol, "http" ) ) port = 80;
1038        if( !strcmp( protocol, "https" ) ) port = 443;
1039    }
1040
1041    if( !err )
1042    {
1043        if( setme_protocol ) *setme_protocol = tr_strdup( protocol );
1044
1045        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1046                              tr_strdup( host ); }
1047        if( setme_path ){ if( path[0] == '/' ) *setme_path = tr_strdup( path );
1048                          else { ( (char*)path )[-1] = '/'; *setme_path = tr_strdup( path - 1 ); } }
1049        if( setme_port ) *setme_port = port;
1050    }
1051
1052
1053    tr_free( tmp );
1054    return err;
1055}
1056
1057#include <string.h>
1058#include <openssl/sha.h>
1059#include <openssl/hmac.h>
1060#include <openssl/evp.h>
1061#include <openssl/bio.h>
1062#include <openssl/buffer.h>
1063
1064char *
1065tr_base64_encode( const void * input, int length, int * setme_len )
1066{
1067    int retlen = 0;
1068    char * ret = NULL;
1069
1070    if( input != NULL )
1071    {
1072        BIO * b64;
1073        BIO * bmem;
1074        BUF_MEM * bptr;
1075
1076        if( length < 1 )
1077            length = (int)strlen( input );
1078
1079        bmem = BIO_new( BIO_s_mem( ) );
1080        b64 = BIO_new( BIO_f_base64( ) );
1081        b64 = BIO_push( b64, bmem );
1082        BIO_write( b64, input, length );
1083        (void) BIO_flush( b64 );
1084        BIO_get_mem_ptr( b64, &bptr );
1085        ret = tr_strndup( bptr->data, bptr->length );
1086        retlen = bptr->length;
1087        BIO_free_all( b64 );
1088    }
1089
1090    if( setme_len )
1091        *setme_len = retlen;
1092
1093    return ret;
1094}
1095
1096char *
1097tr_base64_decode( const void * input,
1098                  int          length,
1099                  int *        setme_len )
1100{
1101    char * ret;
1102    BIO *  b64;
1103    BIO *  bmem;
1104    int    retlen;
1105
1106    if( length < 1 )
1107        length = strlen( input );
1108
1109    ret = tr_new0( char, length );
1110    b64 = BIO_new( BIO_f_base64( ) );
1111    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1112    bmem = BIO_push( b64, bmem );
1113    retlen = BIO_read( bmem, ret, length );
1114    if( !retlen )
1115    {
1116        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1117        BIO_free_all( bmem );
1118        b64 = BIO_new( BIO_f_base64( ) );
1119        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1120        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1121        bmem = BIO_push( b64, bmem );
1122        retlen = BIO_read( bmem, ret, length );
1123    }
1124
1125    if( setme_len )
1126        *setme_len = retlen;
1127
1128    BIO_free_all( bmem );
1129    return ret;
1130}
1131
1132/***
1133****
1134***/
1135
1136int
1137tr_lowerBound( const void * key,
1138               const void * base,
1139               size_t       nmemb,
1140               size_t       size,
1141               int       (* compar)(const void* key, const void* arrayMember),
1142               tr_bool    * exact_match )
1143{
1144    size_t first = 0;
1145    const char * cbase = base;
1146    tr_bool exact = FALSE;
1147
1148    while( nmemb != 0 )
1149    {
1150        const size_t half = nmemb / 2;
1151        const size_t middle = first + half;
1152        const int c = compar( key, cbase + size*middle );
1153
1154        if( c <= 0 ) {
1155            if( c == 0 )
1156                exact = TRUE;
1157            nmemb = half;
1158        } else {
1159            first = middle + 1;
1160            nmemb = nmemb - half - 1;
1161        }
1162    }
1163
1164    *exact_match = exact;
1165
1166    return first;
1167}
1168
1169/***
1170****
1171***/
1172
1173static char*
1174strip_non_utf8( const char * in, size_t inlen )
1175{
1176    char * ret;
1177    const char * end;
1178    const char zero = '\0';
1179    struct evbuffer * buf = evbuffer_new( );
1180 
1181    while( !tr_utf8_validate( in, inlen, &end ) )
1182    {
1183        const int good_len = end - in;
1184
1185        evbuffer_add( buf, in, good_len );
1186        inlen -= ( good_len + 1 );
1187        in += ( good_len + 1 );
1188        evbuffer_add( buf, "?", 1 );
1189    }
1190 
1191    evbuffer_add( buf, in, inlen );
1192    evbuffer_add( buf, &zero, 1 );
1193    ret = tr_memdup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
1194    evbuffer_free( buf );
1195    return ret;
1196}
1197
1198static char*
1199to_utf8( const char * in, size_t inlen )
1200{
1201    char * ret = NULL;
1202
1203#ifdef HAVE_ICONV_OPEN
1204    int i;
1205    const char * encodings[] = { "CURRENT", "ISO-8859-15" };
1206    const int encoding_count = sizeof(encodings) / sizeof(encodings[1]);
1207    const size_t buflen = inlen*4 + 10;
1208    char * out = tr_new( char, buflen );
1209
1210    for( i=0; !ret && i<encoding_count; ++i )
1211    {
1212        char * inbuf = (char*) in;
1213        char * outbuf = out;
1214        size_t inbytesleft = inlen;
1215        size_t outbytesleft = buflen;
1216        const char * test_encoding = encodings[i];
1217
1218        iconv_t cd = iconv_open( "UTF-8", test_encoding );
1219        if( cd != (iconv_t)-1 ) {
1220            if( iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ) != (size_t)-1 )
1221                ret = tr_strndup( out, buflen-outbytesleft );
1222            iconv_close( cd );
1223        }
1224    }
1225#endif
1226
1227    if( ret == NULL )
1228        ret = strip_non_utf8( in, inlen );
1229
1230    return ret;
1231}
1232
1233char*
1234tr_utf8clean( const char * str, int max_len )
1235{
1236    char * ret;
1237    const char * end;
1238
1239    if( max_len < 0 )
1240        max_len = (int) strlen( str );
1241
1242    if( tr_utf8_validate( str, max_len, &end  ) )
1243        ret = tr_strndup( str, max_len );
1244    else
1245        ret = to_utf8( str, max_len );
1246
1247    assert( tr_utf8_validate( ret, -1, NULL ) );
1248    return ret;
1249}
1250
1251/***
1252****
1253***/
1254
1255struct number_range
1256{
1257    int low;
1258    int high;
1259};
1260
1261/**
1262 * This should be a single number (ex. "6") or a range (ex. "6-9").
1263 * Anything else is an error and will return failure.
1264 */
1265static tr_bool
1266parseNumberSection( const char * str, int len, struct number_range * setme )
1267{
1268    long a, b;
1269    tr_bool success;
1270    char * end;
1271    const int error = errno;
1272    char * tmp = tr_strndup( str, len );
1273
1274    errno = 0;
1275    a = b = strtol( tmp, &end, 10 );
1276    if( errno || ( end == tmp ) ) {
1277        success = FALSE;
1278    } else if( *end != '-' ) {
1279        b = a;
1280        success = TRUE;
1281    } else {
1282        const char * pch = end + 1;
1283        b = strtol( pch, &end, 10 );
1284        if( errno || ( pch == end ) )
1285            success = FALSE;
1286        else if( *end ) /* trailing data */
1287            success = FALSE;
1288        else
1289            success = TRUE;
1290    }
1291    tr_free( tmp );
1292
1293    setme->low = MIN( a, b );
1294    setme->high = MAX( a, b );
1295
1296    errno = error;
1297    return success;
1298}
1299
1300int
1301compareInt( const void * va, const void * vb )
1302{
1303    const int a = *(const int *)va;
1304    const int b = *(const int *)vb;
1305    return a - b;
1306}
1307
1308/**
1309 * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
1310 * array of setmeCount ints of all the values in the array.
1311 * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
1312 * It's the caller's responsibility to call tr_free() on the returned array.
1313 * If a fragment of the string can't be parsed, NULL is returned.
1314 */
1315int*
1316tr_parseNumberRange( const char * str_in, int len, int * setmeCount )
1317{
1318    int n = 0;
1319    int * uniq = NULL;
1320    char * str = tr_strndup( str_in, len );
1321    const char * walk;
1322    tr_list * ranges = NULL;
1323    tr_bool success = TRUE;
1324
1325    walk = str;
1326    while( walk && *walk && success ) {
1327        struct number_range range;
1328        const char * pch = strchr( walk, ',' );
1329        if( pch ) {
1330            success = parseNumberSection( walk, pch-walk, &range );
1331            walk = pch + 1;
1332        } else {
1333            success = parseNumberSection( walk, strlen( walk ), &range );
1334            walk += strlen( walk );
1335        }
1336        if( success )
1337            tr_list_append( &ranges, tr_memdup( &range, sizeof( struct number_range ) ) );
1338    }
1339
1340    if( !success )
1341    {
1342        *setmeCount = 0;
1343        uniq = NULL;
1344    }
1345    else
1346    {
1347        int i;
1348        int n2;
1349        tr_list * l;
1350        int * sorted = NULL;
1351
1352        /* build a sorted number array */
1353        n = n2 = 0;
1354        for( l=ranges; l!=NULL; l=l->next ) {
1355            const struct number_range * r = l->data;
1356            n += r->high + 1 - r->low;
1357        }
1358        sorted = tr_new( int, n );
1359        for( l=ranges; l!=NULL; l=l->next ) {
1360            const struct number_range * r = l->data;
1361            int i;
1362            for( i=r->low; i<=r->high; ++i )
1363                sorted[n2++] = i;
1364        }
1365        qsort( sorted, n, sizeof( int ), compareInt );
1366        assert( n == n2 );
1367
1368        /* remove duplicates */
1369        uniq = tr_new( int, n );
1370        for( i=n=0; i<n2; ++i )
1371            if( !n || uniq[n-1] != sorted[i] )
1372                uniq[n++] = sorted[i];
1373
1374        tr_free( sorted );
1375    }
1376
1377    /* cleanup */
1378    tr_list_free( &ranges, tr_free );
1379    tr_free( str );
1380
1381    /* return the result */
1382    *setmeCount = n;
1383    return uniq;
1384}
1385
1386/***
1387****
1388***/
1389
1390double
1391tr_truncd( double x, int decimal_places )
1392{
1393    const int i = (int) pow( 10, decimal_places ); 
1394    const double x2 = (int64_t)(x * i);
1395    return x2 / i;
1396}
1397
1398char*
1399tr_strtruncd( char * buf, double x, int precision, size_t buflen )
1400{
1401    tr_snprintf( buf, buflen, "%.*f", precision, tr_truncd( x, precision ) );
1402
1403    return buf;
1404}
1405
1406char*
1407tr_strpercent( char * buf, double x, size_t buflen )
1408{
1409    if( x < 10.0 )
1410        tr_strtruncd( buf, x, 2, buflen );
1411    else if( x < 100.0 )
1412        tr_strtruncd( buf, x, 1, buflen );
1413    else
1414        tr_strtruncd( buf, x, 0, buflen );
1415    return buf;
1416}
1417
1418char*
1419tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity )
1420{
1421    if( (int)ratio == TR_RATIO_NA )
1422        tr_strlcpy( buf, _( "None" ), buflen );
1423    else if( (int)ratio == TR_RATIO_INF )
1424        tr_strlcpy( buf, infinity, buflen );
1425    else
1426        tr_strpercent( buf, ratio, buflen );
1427    return buf;
1428}
1429
1430/***
1431****
1432***/
1433
1434int
1435tr_moveFile( const char * oldpath, const char * newpath, tr_bool * renamed )
1436{
1437    int in;
1438    int out;
1439    char * buf;
1440    struct stat st;
1441    off_t bytesLeft;
1442    const size_t buflen = 1024 * 128; /* 128 KiB buffer */
1443
1444    /* make sure the old file exists */
1445    if( stat( oldpath, &st ) ) {
1446        const int err = errno;
1447        errno = err;
1448        return -1;
1449    }
1450    if( !S_ISREG( st.st_mode ) ) {
1451        errno = ENOENT;
1452        return -1;
1453    }
1454    bytesLeft = st.st_size;
1455
1456    /* make sure the target directory exists */
1457    {
1458        char * newdir = tr_dirname( newpath );
1459        int i = tr_mkdirp( newdir, 0777 );
1460        tr_free( newdir );
1461        if( i )
1462            return i;
1463    }
1464
1465    /* they might be on the same filesystem... */
1466    {
1467        const int i = rename( oldpath, newpath );
1468        if( renamed != NULL )
1469            *renamed = i == 0;
1470        if( !i )
1471            return 0;
1472    }
1473
1474    /* copy the file */
1475    in = tr_open_file_for_scanning( oldpath );
1476    out = tr_open_file_for_writing( newpath );
1477    buf = tr_valloc( buflen );
1478    while( bytesLeft > 0 )
1479    {
1480        ssize_t bytesWritten;
1481        const off_t bytesThisPass = MIN( bytesLeft, (off_t)buflen );
1482        const int numRead = read( in, buf, bytesThisPass );
1483        if( numRead < 0 )
1484            break;
1485        bytesWritten = write( out, buf, numRead );
1486        if( bytesWritten < 0 )
1487            break;
1488        bytesLeft -= bytesWritten;
1489    }
1490
1491    /* cleanup */
1492    tr_free( buf );
1493    tr_close_file( out );
1494    tr_close_file( in );
1495    if( bytesLeft != 0 )
1496        return -1;
1497
1498    unlink( oldpath );
1499    return 0;
1500}
1501
1502/***
1503****
1504***/
1505
1506void*
1507tr_valloc( size_t bufLen )
1508{
1509    size_t allocLen;
1510    void * buf = NULL;
1511    static size_t pageSize = 0;
1512
1513    if( !pageSize ) {
1514#ifdef HAVE_GETPAGESIZE
1515        pageSize = (size_t) getpagesize();
1516#else /* guess */
1517        pageSize = 4096;
1518#endif
1519    }
1520
1521    allocLen = pageSize;
1522    while( allocLen < bufLen )
1523        allocLen += pageSize;
1524
1525#ifdef HAVE_POSIX_MEMALIGN
1526    if( !buf )
1527        posix_memalign( &buf, pageSize, allocLen );
1528#endif
1529#ifdef HAVE_VALLOC
1530    if( !buf )
1531        buf = valloc( allocLen );
1532#endif
1533    if( !buf )
1534        buf = malloc( allocLen );
1535
1536    return buf;
1537}
1538
1539char *
1540tr_realpath( const char * path, char * resolved_path )
1541{
1542#ifdef WIN32
1543    /* From a message to the Mingw-msys list, Jun 2, 2005 by Mark Junker. */
1544    if( GetFullPathNameA( path, TR_PATH_MAX, resolved_path, NULL ) == 0 )
1545        return NULL;
1546    return resolved_path;
1547#else
1548    return realpath( path, resolved_path );
1549#endif
1550}
1551
1552/***
1553****
1554****
1555****
1556***/
1557
1558struct formatter_unit
1559{
1560    char * name;
1561    uint64_t value;
1562};
1563 
1564struct formatter_units
1565{
1566    struct formatter_unit units[4];
1567};
1568
1569enum { TR_FMT_KB, TR_FMT_MB, TR_FMT_GB, TR_FMT_TB };
1570
1571static void
1572formatter_init( struct formatter_units * units,
1573                unsigned int kilo,
1574                const char * kb, const char * mb,
1575                const char * gb, const char * tb )
1576{
1577    uint64_t value = kilo;
1578    units->units[TR_FMT_KB].name = tr_strdup( kb );
1579    units->units[TR_FMT_KB].value = value;
1580
1581    value *= kilo;
1582    units->units[TR_FMT_MB].name = tr_strdup( mb );
1583    units->units[TR_FMT_MB].value = value;
1584
1585    value *= kilo;
1586    units->units[TR_FMT_GB].name = tr_strdup( gb );
1587    units->units[TR_FMT_GB].value = value;
1588
1589    value *= kilo;
1590    units->units[TR_FMT_TB].name = tr_strdup( tb );
1591    units->units[TR_FMT_TB].value = value;
1592}
1593
1594static char*
1595formatter_get_size_str( const struct formatter_units * u,
1596                        char * buf, uint64_t bytes, size_t buflen )
1597{
1598    int precision;
1599    double value;
1600    const char * units;
1601    const struct formatter_unit * unit;
1602
1603         if( bytes < u->units[1].value ) unit = &u->units[0];
1604    else if( bytes < u->units[2].value ) unit = &u->units[1];
1605    else if( bytes < u->units[3].value ) unit = &u->units[2];
1606    else                                 unit = &u->units[3];
1607
1608    value = (double)bytes / unit->value;
1609    units = unit->name;
1610    if( unit->value == 1 )
1611        precision = 0;
1612    else if( value < 100 )
1613        precision = 2;
1614    else
1615        precision = 1;
1616    tr_snprintf( buf, buflen, "%.*f %s", precision, value, units );
1617    return buf;
1618}
1619
1620static struct formatter_units size_units;
1621
1622void
1623tr_formatter_size_init( unsigned int kilo,
1624                        const char * kb, const char * mb,
1625                        const char * gb, const char * tb )
1626{
1627    formatter_init( &size_units, kilo, kb, mb, gb, tb );
1628}
1629
1630char*
1631tr_formatter_size_B( char * buf, uint64_t bytes, size_t buflen )
1632{
1633    return formatter_get_size_str( &size_units, buf, bytes, buflen );
1634}
1635
1636static struct formatter_units speed_units;
1637
1638unsigned int tr_speed_K = 0u;
1639
1640void
1641tr_formatter_speed_init( unsigned int kilo,
1642                         const char * kb, const char * mb,
1643                         const char * gb, const char * tb )
1644{
1645    tr_speed_K = kilo;
1646    formatter_init( &speed_units, kilo, kb, mb, gb, tb );
1647}
1648
1649char*
1650tr_formatter_speed_KBps( char * buf, double KBps, size_t buflen )
1651{
1652    const double K = speed_units.units[TR_FMT_KB].value;
1653    double speed = KBps;
1654
1655    if( speed <= 999.95 ) /* 0.0 KB to 999.9 KB */
1656        tr_snprintf( buf, buflen, "%.2f %s", speed, speed_units.units[TR_FMT_KB].name );
1657    else {
1658        speed /= K;
1659        if( speed <= 99.995 ) /* 0.98 MB to 99.99 MB */
1660            tr_snprintf( buf, buflen, "%.2f %s", speed, speed_units.units[TR_FMT_MB].name );
1661        else if (speed <= 999.95) /* 100.0 MB to 999.9 MB */
1662            tr_snprintf( buf, buflen, "%.1f %s", speed, speed_units.units[TR_FMT_MB].name );
1663        else {
1664            speed /= K;
1665            tr_snprintf( buf, buflen, "%.1f %s", speed, speed_units.units[TR_FMT_GB].name );
1666        }
1667    }
1668
1669    return buf;
1670}
1671
1672static struct formatter_units mem_units;
1673
1674unsigned int tr_mem_K = 0u;
1675 
1676void
1677tr_formatter_mem_init( unsigned int kilo,
1678                       const char * kb, const char * mb,
1679                       const char * gb, const char * tb )
1680{
1681    tr_mem_K = kilo;
1682    formatter_init( &mem_units, kilo, kb, mb, gb, tb );
1683}
1684
1685char*
1686tr_formatter_mem_B( char * buf, uint64_t bytes_per_second, size_t buflen )
1687{
1688    return formatter_get_size_str( &mem_units, buf, bytes_per_second, buflen );
1689}
1690
1691void
1692tr_formatter_get_units( tr_benc * d )
1693{
1694    int i;
1695    tr_benc * l;
1696
1697    tr_bencDictReserve( d, 6 );
1698
1699    tr_bencDictAddInt( d, "memory-bytes", mem_units.units[TR_FMT_KB].value );
1700    l = tr_bencDictAddList( d, "memory-units", 4 );
1701    for( i=0; i<4; i++ ) tr_bencListAddStr( l, mem_units.units[i].name );
1702
1703    tr_bencDictAddInt( d, "size-bytes",   size_units.units[TR_FMT_KB].value );
1704    l = tr_bencDictAddList( d, "size-units", 4 );
1705    for( i=0; i<4; i++ ) tr_bencListAddStr( l, size_units.units[i].name );
1706
1707    tr_bencDictAddInt( d, "speed-bytes",  speed_units.units[TR_FMT_KB].value );
1708    l = tr_bencDictAddList( d, "speed-units", 4 );
1709    for( i=0; i<4; i++ ) tr_bencListAddStr( l, speed_units.units[i].name );
1710}
1711
Note: See TracBrowser for help on using the repository browser.