source: trunk/libtransmission/utils.c @ 2365

Last change on this file since 2365 was 2365, checked in by charles, 15 years ago

get UPNP working again. huge thanks to BigBossman? and persept for doggedly tracking down this bug.

  • Property svn:keywords set to Date Rev Author Id
File size: 14.8 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 2365 2007-07-15 22:18:49Z charles $
3 *
4 * Copyright (c) 2005-2007 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 <ctype.h>
26#include <stdarg.h>
27#include <sys/time.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <unistd.h> /* usleep, stat */
31#include "transmission.h"
32
33#define SPRINTF_BUFSIZE         100
34
35static tr_lock_t      * messageLock = NULL;
36static int              messageLevel = 0;
37static int              messageQueuing = 0;
38static tr_msg_list_t *  messageQueue = NULL;
39static tr_msg_list_t ** messageQueueTail = &messageQueue;
40
41void tr_msgInit( void )
42{
43    if( NULL == messageLock )
44    {
45        messageLock = calloc( 1, sizeof( *messageLock ) );
46        tr_lockInit( messageLock );
47    }
48}
49
50void tr_setMessageLevel( int level )
51{
52    tr_msgInit();
53    tr_lockLock( messageLock );
54    messageLevel = MAX( 0, level );
55    tr_lockUnlock( messageLock );
56}
57
58int tr_getMessageLevel( void )
59{
60    int ret;
61
62    tr_msgInit();
63    tr_lockLock( messageLock );
64    ret = messageLevel;
65    tr_lockUnlock( messageLock );
66
67    return ret;
68}
69
70void tr_setMessageQueuing( int enabled )
71{
72    tr_msgInit();
73    tr_lockLock( messageLock );
74    messageQueuing = enabled;
75    tr_lockUnlock( messageLock );
76}
77
78tr_msg_list_t * tr_getQueuedMessages( void )
79{
80    tr_msg_list_t * ret;
81
82    assert( NULL != messageLock );
83    tr_lockLock( messageLock );
84    ret = messageQueue;
85    messageQueue = NULL;
86    messageQueueTail = &messageQueue;
87    tr_lockUnlock( messageLock );
88
89    return ret;
90}
91
92void tr_freeMessageList( tr_msg_list_t * list )
93{
94    tr_msg_list_t * next;
95
96    while( NULL != list )
97    {
98        next = list->next;
99        free( list->message );
100        free( list );
101        list = next;
102    }
103}
104
105void tr_msg( int level, char * msg, ... )
106{
107    va_list         args1, args2;
108    tr_msg_list_t * newmsg;
109    int             len1, len2;
110
111    assert( NULL != messageLock );
112    tr_lockLock( messageLock );
113
114    if( !messageLevel )
115    {
116        char * env;
117        env          = getenv( "TR_DEBUG" );
118        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
119        messageLevel = MAX( 1, messageLevel );
120    }
121
122    if( messageLevel >= level )
123    {
124        va_start( args1, msg );
125        if( messageQueuing )
126        {
127            newmsg = calloc( 1, sizeof( *newmsg ) );
128            if( NULL != newmsg )
129            {
130                newmsg->level = level;
131                newmsg->when = time( NULL );
132                len1 = len2 = 0;
133                va_start( args2, msg );
134                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
135                             args1, args2 );
136                va_end( args2 );
137                if( NULL == newmsg->message )
138                {
139                    free( newmsg );
140                }
141                else
142                {
143                    *messageQueueTail = newmsg;
144                    messageQueueTail = &newmsg->next;
145                }
146            }
147        }
148        else
149        {
150            vfprintf( stderr, msg, args1 );
151            fputc( '\n', stderr );
152        }
153        va_end( args1 );
154    }
155
156    tr_lockUnlock( messageLock );
157}
158
159int tr_rand( int sup )
160{
161    static int init = 0;
162    if( !init )
163    {
164        srand( tr_date() );
165        init = 1;
166    }
167    return rand() % sup;
168}
169
170
171#if 0
172void*
173tr_memmem( const void* haystack, size_t hl,
174           const void* needle,   size_t nl)
175{
176    const char *walk, *end;
177
178    if( !nl )
179        return (void*) haystack;
180
181    if( hl < nl )
182        return NULL;
183
184    for (walk=(const char*)haystack, end=walk+hl-nl; walk!=end; ++walk)
185        if( !memcmp( walk, needle, nl ) )
186            return (void*) walk;
187
188    return NULL;
189}
190#else
191void * tr_memmem ( const void *vbig, size_t big_len,
192                   const void *vlittle, size_t little_len )
193{
194    const char *big = vbig;
195    const char *little = vlittle;
196    size_t ii, jj;
197
198    if( 0 == big_len || 0 == little_len )
199    {
200        return NULL;
201    }
202
203    for( ii = 0; ii + little_len <= big_len; ii++ )
204    {
205        for( jj = 0; jj < little_len; jj++ )
206        {
207            if( big[ii + jj] != little[jj] )
208            {
209                break;
210            }
211        }
212        if( jj == little_len )
213        {
214            return (char*)big + ii;
215        }
216    }
217
218    return NULL;
219}
220#endif
221
222
223int tr_mkdir( char * path )
224{
225    char      * p, * pp;
226    struct stat sb;
227    int done;
228
229    p = path;
230    while( '/' == *p )
231      p++;
232    pp = p;
233    done = 0;
234    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
235    {
236        if( '\0' == *p)
237        {
238            done = 1;
239        }
240        else
241        {
242            *p = '\0';
243        }
244        if( stat( path, &sb ) )
245        {
246            /* Folder doesn't exist yet */
247            if( mkdir( path, 0777 ) )
248            {
249                tr_err( "Could not create directory %s (%s)", path,
250                        strerror( errno ) );
251                *p = '/';
252                return 1;
253            }
254        }
255        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
256        {
257            /* Node exists but isn't a folder */
258            tr_err( "Remove %s, it's in the way.", path );
259            *p = '/';
260            return 1;
261        }
262        if( done )
263        {
264            break;
265        }
266        *p = '/';
267        p++;
268        pp = p;
269    }
270
271    return 0;
272}
273
274int
275tr_strncasecmp( const char * s1, const char * s2, size_t n )
276{
277    if ( !n )
278        return 0;
279
280    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
281        if( !n || !*s1 || !*s2 )
282            break;
283        ++s1;
284        ++s2;
285    }
286
287    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
288}
289
290int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
291{
292    va_list ap1, ap2;
293    int     ret;
294
295    va_start( ap1, format );
296    va_start( ap2, format );
297    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
298    va_end( ap2 );
299    va_end( ap1 );
300
301    return ret;
302}
303
304int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
305                 va_list ap1, va_list ap2 )
306{
307    int     want;
308
309    want = vsnprintf( NULL, 0, fmt, ap1 );
310
311    if( tr_concat( buf, used, max, NULL, want ) )
312    {
313        return 1;
314    }
315    assert( *used + want + 1 <= *max );
316
317    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
318
319    return 0;
320}
321
322int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
323{
324    int     newmax;
325    char  * newbuf;
326
327    newmax = *max;
328    while( *used + len + 1 > newmax )
329    {
330        newmax += SPRINTF_BUFSIZE;
331    }
332    if( newmax > *max )
333    {
334        newbuf = realloc( *buf, newmax );
335        if( NULL == newbuf )
336        {
337            return 1;
338        }
339        *buf = newbuf;
340        *max = newmax;
341    }
342
343    if( NULL != data )
344    {
345        memcpy( *buf + *used, data, len );
346        *used += len;
347    }
348
349    return 0;
350}
351
352void
353tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
354{
355    va_list vl;
356    char* walk = buf;
357    const char * element = first_element;
358    va_start( vl, first_element );
359    for( ;; ) {
360        const size_t n = strlen( element );
361        memcpy( walk, element, n );
362        walk += n;
363        element = (const char*) va_arg( vl, const char* );
364        if( element == NULL )
365            break;
366        *walk++ = TR_PATH_DELIMITER;
367    }
368    *walk = '\0';
369    assert( walk-buf <= (int)buflen );
370}
371
372int
373tr_ioErrorFromErrno( void )
374{
375    switch( errno )
376    {
377        case EACCES:
378        case EROFS:
379            return TR_ERROR_IO_PERMISSIONS;
380        case ENOSPC:
381            return TR_ERROR_IO_SPACE;
382        case EMFILE:
383            return TR_ERROR_IO_FILE_TOO_BIG;
384        case EFBIG:
385            return TR_ERROR_IO_OPEN_FILES;
386        default:
387            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
388            return TR_ERROR_IO_OTHER;
389    }
390}
391
392char *
393tr_errorString( int code )
394{
395    switch( code )
396    {
397        case TR_OK:
398            return "No error";
399        case TR_ERROR:
400            return "Generic error";
401        case TR_ERROR_ASSERT:
402            return "Assert error";
403        case TR_ERROR_IO_PARENT:
404            return "Download folder does not exist";
405        case TR_ERROR_IO_PERMISSIONS:
406            return "Insufficient permissions";
407        case TR_ERROR_IO_SPACE:
408            return "Insufficient free space";
409        case TR_ERROR_IO_DUP_DOWNLOAD:
410            return "Already active transfer with same name and download folder";
411        case TR_ERROR_IO_FILE_TOO_BIG:
412            return "File too large";
413        case TR_ERROR_IO_OPEN_FILES:
414            return "Too many open files";
415        case TR_ERROR_IO_OTHER:
416            return "Generic I/O error";
417    }
418    return "Unknown error";
419}
420
421/****
422*****
423****/
424
425char*
426tr_strdup( const char * in )
427{
428    return tr_strndup( in, in ? strlen(in) : 0 );
429}
430
431char*
432tr_strndup( const char * in, int len )
433{
434    char * out = NULL;
435
436    if( in != NULL )
437    {
438        out = tr_malloc( len+1 );
439        memcpy( out, in, len );
440        out[len] = '\0';
441    }
442    return out;
443}
444
445void*
446tr_calloc( size_t nmemb, size_t size )
447{
448    return nmemb && size ? calloc( nmemb, size ) : NULL;
449}
450
451void*
452tr_malloc( size_t size )
453{
454    return size ? malloc( size ) : NULL;
455}
456
457void*
458tr_malloc0( size_t size )
459{
460    void * ret = tr_malloc( size );
461    memset( ret, 0, size );
462    return ret;
463}
464
465void tr_free( void * p )
466{
467    if( p )
468        free( p );
469}
470
471/****
472*****
473****/
474
475/* note that the argument is how many bits are needed, not bytes */
476tr_bitfield_t*
477tr_bitfieldNew( size_t bitcount )
478{
479    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
480    if( NULL == ret )
481        return NULL;
482
483    ret->len = ( bitcount + 7u ) / 8u;
484    ret->bits = calloc( ret->len, 1 );
485    if( NULL == ret->bits ) {
486        free( ret );
487        return NULL;
488    }
489
490    return ret;
491}
492
493tr_bitfield_t*
494tr_bitfieldDup( const tr_bitfield_t * in )
495{
496    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
497    ret->len = in->len;
498    ret->bits = malloc( ret->len );
499    memcpy( ret->bits, in->bits, ret->len );
500    return ret;
501}
502
503void tr_bitfieldFree( tr_bitfield_t * bitfield )
504{
505    if( bitfield )
506    {
507        free( bitfield->bits );
508        free( bitfield );
509    }
510}
511
512void
513tr_bitfieldClear( tr_bitfield_t * bitfield )
514{
515    memset( bitfield->bits, 0, bitfield->len );
516}
517
518int
519tr_bitfieldIsEmpty( const tr_bitfield_t * bitfield )
520{
521    unsigned int i;
522
523    for( i=0; i<bitfield->len; ++i )
524        if( bitfield->bits[i] )
525            return 0;
526
527    return 1;
528}
529
530static const uint8_t bitmask[8] = { 128u, 64u, 32u, 16u, 8u, 4u, 2u, 1u };
531
532int
533tr_bitfieldHas( const tr_bitfield_t   * bitfield,
534                size_t                  bit )
535{
536    if ( bitfield == NULL ) return 0;
537    assert( bit / 8u < bitfield->len );
538    return ( bitfield->bits[ bit/8u ] & bitmask[bit%8] ) != 0;
539}
540
541void
542tr_bitfieldAdd( tr_bitfield_t  * bitfield, size_t bit )
543{
544    assert( bit / 8u < bitfield->len );
545    bitfield->bits[ bit/8u ] |= bitmask[bit%8];
546}
547
548void
549tr_bitfieldAddRange( tr_bitfield_t  * bitfield,
550                     size_t           begin,
551                     size_t           end )
552{
553    /* TODO: there are faster ways to do this */
554    unsigned int i;
555    for( i=begin; i<end; ++i )
556        tr_bitfieldAdd( bitfield, i );
557}
558
559void
560tr_bitfieldRem( tr_bitfield_t   * bitfield,
561                size_t            bit )
562{
563    if( bitfield != NULL )
564    {
565        assert( bit / 8u < bitfield->len );
566        bitfield->bits[bit/8u] &= ~bitmask[bit%8];
567    }
568}
569
570void
571tr_bitfieldRemRange ( tr_bitfield_t  * b,
572                      size_t           begin,
573                      size_t           end )
574{
575    /* TODO: there are faster ways to do this */
576    unsigned int i;
577    for( i=begin; i<end; ++i )
578        tr_bitfieldRem( b, i );
579}
580
581tr_bitfield_t*
582tr_bitfieldNegate( tr_bitfield_t * b )
583{
584    uint8_t *it;
585    const uint8_t *end;
586
587    for( it=b->bits, end=it+b->len; it!=end; ++it )
588        *it = ~*it;
589
590    return b;
591}
592
593tr_bitfield_t*
594tr_bitfieldAnd( tr_bitfield_t * a, const tr_bitfield_t * b )
595{
596    uint8_t *ait;
597    const uint8_t *aend, *bit;
598
599    assert( a->len == b->len );
600
601    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
602        *ait &= *bit;
603
604    return a;
605}
606
607size_t
608tr_bitfieldCountTrueBits( const tr_bitfield_t* b )
609{
610    size_t ret = 0;
611    const uint8_t *it, *end;
612    static const int trueBitCount[512] = {
613        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,
614        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,
615        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,
616        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,
617        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,
618        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,
619        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,
620        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,
621        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,
622        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,
623        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,
624        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,
625        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,
626        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,
627        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,
628        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
629    };
630
631    for( it=b->bits, end=it+b->len; it!=end; ++it )
632        ret += trueBitCount[*it];
633
634    return ret;
635}
636
637/***
638****
639***/
640
641uint64_t
642tr_date( void )
643{
644    struct timeval tv;
645    gettimeofday( &tv, NULL );
646    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
647}
648
649void
650tr_wait( uint64_t delay_msec )
651{
652#ifdef SYS_BEOS
653    snooze( 1000 * delay_msec );
654#else
655    usleep( 1000 * delay_msec );
656#endif
657}
Note: See TracBrowser for help on using the repository browser.