diff --git a/libtransmission/Makefile.am b/libtransmission/Makefile.am index 9178f1762..094adedea 100644 --- a/libtransmission/Makefile.am +++ b/libtransmission/Makefile.am @@ -1,4 +1,4 @@ -AM_CPPFLAGS = -I. -I$(top_srcdir) $(LIBEVENT_CPPFLAGS) -D__TRANSMISSION__ +AM_CPPFLAGS = -I. -I@top_srcdir@ -D__TRANSMISSION__ noinst_LIBRARIES = libtransmission.a @@ -23,11 +23,14 @@ libtransmission_a_SOURCES = \ net.c \ peer.c \ platform.c \ + ptrarray.c \ + publish.c \ ratecontrol.c \ sha1.c \ shared.c \ strlcat.c \ strlcpy.c \ + timer.c \ torrent.c \ tracker.c \ transmission.c \ @@ -61,9 +64,12 @@ noinst_HEADERS = \ peertree.h \ peerutils.h \ platform.h \ + ptrarray.h \ + publish.h \ ratecontrol.h \ sha1.h \ shared.h \ + timer.h \ tracker.h \ transmission.h \ trcompat.h \ diff --git a/libtransmission/ptrarray.c b/libtransmission/ptrarray.c new file mode 100644 index 000000000..3d6489811 --- /dev/null +++ b/libtransmission/ptrarray.c @@ -0,0 +1,186 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#include +#include +#include /* memmove */ + +#include "ptrarray.h" +#include "utils.h" + +#define GROW 32 + +struct tr_ptrArray_s +{ + void ** items; + int n_items; + int n_alloc; +}; + +tr_ptrArray_t* +tr_ptrArrayNew( void ) +{ + tr_ptrArray_t * p; + + p = tr_new( tr_ptrArray_t, 1 ); + p->n_items = 0; + p->n_alloc = GROW; + p->items = tr_new( void*, p->n_alloc ); + + return p; +} + +void +tr_ptrArrayFree( tr_ptrArray_t * t ) +{ + assert( t != NULL ); + assert( t->items != NULL ); + + tr_free( t->items ); + tr_free( t ); +} + +void** +tr_ptrArrayPeek( tr_ptrArray_t * t, int * size ) +{ + *size = t->n_items; + return t->items; +} + +int +tr_ptrArraySize( const tr_ptrArray_t * t ) +{ + return t->n_items; +} + +int +tr_ptrArrayEmpty( const tr_ptrArray_t * t ) +{ + return t->n_items == 0; +} + +void +tr_ptrArrayClear( tr_ptrArray_t * t ) +{ + t->n_items = 0; +} + +int +tr_ptrArrayInsert( tr_ptrArray_t * t, void * ptr, int pos ) +{ + if( pos<0 || pos>t->n_items ) + pos = t->n_items; + + if( t->n_items >= t->n_alloc ) { + t->n_alloc = t->n_items + GROW; + t->items = tr_renew( void*, t->items, t->n_alloc ); + } + + memmove( t->items + pos + 1, + t->items + pos, + sizeof(void*) * (t->n_items - pos)); + + t->items[pos] = ptr; + t->n_items++; + return pos; +} + +int +tr_ptrArrayAppend( tr_ptrArray_t * t, void * ptr ) +{ + return tr_ptrArrayInsert( t, ptr, -1 ); +} + +void +tr_ptrArrayErase( tr_ptrArray_t * t, int begin, int end ) +{ + assert( begin >= 0 ); + if( end < 0 ) end = t->n_items; + assert( end > begin ); + assert( end <= t->n_items ); + + memmove( t->items + begin, + t->items + end, + sizeof(void*) * (t->n_items - end) ); + + t->n_items -= (end - begin); +} + +/** +*** +**/ + +int +tr_ptrArrayLowerBound( const tr_ptrArray_t * t, + void * ptr, + int compare( const void *,const void * ), + int * exact_match ) +{ + int c = -1; + int len = t->n_items; + int first = 0; + + while( len > 0 ) + { + int half = len / 2; + int middle = first + half; + c = compare( t->items[middle], ptr ); + if( c < 0 ) { + first = middle + 1; + len = len - half - 1; + } else if (!c ) { + if( exact_match ) + *exact_match = 1; + return middle; + break; + } else { + len = half; + } + } + + if( exact_match ) + *exact_match = 0; + + return first; +} + +int +tr_ptrArrayInsertSorted( tr_ptrArray_t * t, + void * ptr, + int compare(const void*,const void*) ) +{ + const int pos = tr_ptrArrayLowerBound( t, ptr, compare, NULL ); + return tr_ptrArrayInsert( t, ptr, pos ); +} + +void* +tr_ptrArrayFindSorted( tr_ptrArray_t * t, + void * ptr, + int compare(const void*,const void*) ) +{ + int match; + const int pos = tr_ptrArrayLowerBound( t, ptr, compare, &match ); + return match ? t->items[pos] : NULL; +} + +void* +tr_ptrArrayRemoveSorted( tr_ptrArray_t * t, + void * ptr, + int compare(const void*,const void*) ) +{ + void * ret = NULL; + int match; + const int pos = tr_ptrArrayLowerBound( t, ptr, compare, &match ); + if( match ) { + ret = t->items[pos]; + tr_ptrArrayErase( t, pos, pos+1 ); + } + return ret; +} diff --git a/libtransmission/ptrarray.h b/libtransmission/ptrarray.h new file mode 100644 index 000000000..07839c22d --- /dev/null +++ b/libtransmission/ptrarray.h @@ -0,0 +1,37 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#ifndef _TR_POINTERS_H_ +#define _TR_POINTERS_H_ + +/** + * A simple pointer array that resizes itself dynamically. + */ +typedef struct tr_ptrArray_s tr_ptrArray_t; + +tr_ptrArray_t * tr_ptrArrayNew ( void ); +void tr_ptrArrayFree ( tr_ptrArray_t* ); +void** tr_ptrArrayPeek ( tr_ptrArray_t*, int * size ); +void** tr_ptrArrayBase ( tr_ptrArray_t* ); +void tr_ptrArrayClear ( tr_ptrArray_t* ); +int tr_ptrArrayInsert ( tr_ptrArray_t*, void*, int pos ); +int tr_ptrArrayAppend ( tr_ptrArray_t*, void* ); +void tr_ptrArrayErase ( tr_ptrArray_t*, int begin, int end ); +int tr_ptrArraySize ( const tr_ptrArray_t* ); +int tr_ptrArrayEmpty ( const tr_ptrArray_t* ); + +int tr_ptrArrayInsertSorted( tr_ptrArray_t*, void*, + int compare(const void*,const void*) ); +void* tr_ptrArrayRemoveSorted( tr_ptrArray_t*, void*, + int compare(const void*,const void*) ); +void* tr_ptrArrayFindSorted ( tr_ptrArray_t*, void*, + int compare(const void*,const void*) ); + +#endif diff --git a/libtransmission/publish.c b/libtransmission/publish.c new file mode 100644 index 000000000..46a0dd03f --- /dev/null +++ b/libtransmission/publish.c @@ -0,0 +1,72 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#include "list.h" +#include "publish.h" +#include "utils.h" + +struct tr_publisher_node +{ + tr_delivery_func * func; + void * user_data; +}; + +struct tr_publisher_s +{ + tr_list_t * list; +}; + +tr_publisher_t* +tr_publisherNew( void ) +{ + return tr_new0( tr_publisher_t, 1 ); +} + +void +tr_publisherFree( tr_publisher_t * p ) +{ + tr_list_free( &p->list ); + tr_free( p ); +} + +tr_publisher_tag +tr_publisherSubscribe ( tr_publisher_t * p, + tr_delivery_func func, + void * user_data ) +{ + struct tr_publisher_node * node = tr_new( struct tr_publisher_node, 1 ); + node->func = func; + node->user_data = user_data; + tr_list_append( &p->list, node ); + return node; +} + +void +tr_publisherUnsubscribe( tr_publisher_t * p, + tr_publisher_tag tag ) +{ + tr_list_remove_data( &p->list, tag ); + tr_free( tag ); +} + +void +tr_publisherPublish( tr_publisher_t * p, + void * source, + void * event ) +{ + tr_list_t * walk; + for( walk=p->list; walk!=NULL; ) + { + tr_list_t * next = walk->next; + struct tr_publisher_node * node = (struct tr_publisher_node*)walk->data; + (node->func)(source, event, node->user_data); + walk = next; + } +} diff --git a/libtransmission/publish.h b/libtransmission/publish.h new file mode 100644 index 000000000..07ffdce72 --- /dev/null +++ b/libtransmission/publish.h @@ -0,0 +1,49 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#ifndef _TR_PUBLISHER_H_ +#define _TR_PUBLISHER_H_ + +/** +*** A lightweight implementation of the 'Observable' design pattern. +**/ + +typedef struct tr_publisher_s tr_publisher_t; + +typedef void * tr_publisher_tag; + +typedef void tr_delivery_func( void * source, + void * event, + void * user_data ); + +/** +*** Observer API +**/ + +tr_publisher_tag tr_publisherSubscribe ( tr_publisher_t * publisher, + tr_delivery_func delivery_func, + void * user_data ); + +void tr_publisherUnsubscribe ( tr_publisher_t * publisher, + tr_publisher_tag tag ); + +/** +*** Observable API +**/ + +tr_publisher_t * tr_publisherNew ( void ); + +void tr_publisherFree ( tr_publisher_t * publisher ); + +void tr_publisherPublish ( tr_publisher_t * publisher, + void * source, + void * event ); + +#endif diff --git a/libtransmission/timer.c b/libtransmission/timer.c new file mode 100644 index 000000000..7e1369e31 --- /dev/null +++ b/libtransmission/timer.c @@ -0,0 +1,104 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#include + +#include /* u_char for event.h */ +#include + +#include "transmission.h" +#include "timer.h" +#include "utils.h" + +typedef int tr_timer_func ( void * user_data ); +typedef void tr_data_free_func( void * user_data ); + +/*** +**** +***/ + +struct timer_node +{ + struct event event; + tr_timer_func * func; + void * user_data; + tr_data_free_func * free_func; + struct timeval tv; + int refcount; +}; + +static void +unref( struct timer_node * node, int count ) +{ + assert( node != NULL ); + assert( node->refcount > 0 ); + + node->refcount -= count; + if( node->refcount > 0 ) + return; + + if( node->free_func != NULL ) + (node->free_func)( node->user_data ); + event_del( &node->event ); + tr_free( node ); +} + +void +tr_timerFree( struct timer_node ** node ) +{ + assert( node != NULL ); + + if( *node ) + { + unref( *node, 1 ); + *node = NULL; + } +} + +static void +timerCB( int fd UNUSED, short event UNUSED, void * arg ) +{ + struct timer_node * node = (struct timer_node *) arg; + int val; + + ++node->refcount; + val = (node->func)(node->user_data); + if( !val ) + unref( node, 2 ); + else { + timeout_add( &node->event, &node->tv ); + unref( node, 1 ); + } +} + + +tr_timer_tag +tr_timerNew( tr_timer_func func, + void * user_data, + tr_data_free_func free_func, + int timeout_milliseconds ) +{ + struct timer_node * node; + const unsigned long microseconds = timeout_milliseconds * 1000; + + assert( func != NULL ); + assert( timeout_milliseconds >= 0 ); + + node = tr_new( struct timer_node, 1 ); + node->func = func; + node->user_data = user_data; + node->free_func = free_func; + node->refcount = 1; + node->tv.tv_sec = microseconds / 1000000; + node->tv.tv_usec = microseconds % 1000000; + timeout_set( &node->event, timerCB, node ); + timeout_add( &node->event, &node->tv ); + return node; +} diff --git a/libtransmission/timer.h b/libtransmission/timer.h new file mode 100644 index 000000000..b770caf19 --- /dev/null +++ b/libtransmission/timer.h @@ -0,0 +1,37 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#ifndef _TR_TIMER_H_ +#define _TR_TIMER_H_ + +typedef struct timer_node * tr_timer_tag; + +/** + * Calls timer_func(user_data) after the specified interval. + * The timer is freed if timer_func returns zero. + * Otherwise, it's called again after the same interval. + * + * If free_func is non-NULL, free_func(user_data) is called + * by the timer when it's freed (either from timer_func returning + * zero or from a client call to tr_timerFree). This is useful + * if user_data has resources that need to be freed. + */ +tr_timer_tag tr_timerNew( int timer_func( void * user_data ), + void * user_data, + void free_func( void * user_data ), + int timeout_milliseconds ); + +/** + * Frees a timer and sets its tag to NULL. + */ +void tr_timerFree( tr_timer_tag * tag ); + + +#endif diff --git a/libtransmission/transmission.c b/libtransmission/transmission.c index cdcf5605b..deccde2b4 100644 --- a/libtransmission/transmission.c +++ b/libtransmission/transmission.c @@ -33,6 +33,8 @@ #include /* stat */ #include /* opendir */ +#include + #include "transmission.h" #include "fdlimit.h" #include "list.h" @@ -61,6 +63,19 @@ tr_peerIdNew ( char * buf, int buflen ) buf[TR_ID_LEN] = '\0'; } +static void +libeventThreadFunc( void * unused UNUSED ) +{ + tr_dbg( "libevent thread starting" ); + event_init( ); + for ( ;; ) + { + event_dispatch( ); + tr_wait( 50 ); /* 1/20th of a second */ + } + tr_dbg( "libevent thread exiting" ); +} + /*********************************************************************** * tr_init @@ -72,6 +87,8 @@ tr_handle_t * tr_init( const char * tag ) tr_handle_t * h; int i; + tr_threadNew( libeventThreadFunc, NULL, "libeventThreadFunc" ); + tr_msgInit(); tr_netInit(); tr_netResolveThreadInit(); diff --git a/libtransmission/utils.h b/libtransmission/utils.h index e18043305..b02d85eeb 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -27,6 +27,7 @@ #include #include +#include /* for size_t */ void tr_msgInit( void );