From 256bda38ce551ffd07f32c4df9ccd660ef92bfea Mon Sep 17 00:00:00 2001 From: Eric Petit Date: Fri, 24 Mar 2006 12:18:38 +0000 Subject: [PATCH] Adds non-blocking (threaded) DNS resolution --- libtransmission/net.c | 99 ++++++++++++++++++++++++++++++++++----- libtransmission/net.h | 10 +++- libtransmission/tracker.c | 52 +++++++++++++------- 3 files changed, 131 insertions(+), 30 deletions(-) diff --git a/libtransmission/net.c b/libtransmission/net.c index 78637acfb..6da0657a4 100644 --- a/libtransmission/net.c +++ b/libtransmission/net.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2005 Eric Petit + * Copyright (c) 2005-2006 Transmission authors and contributors * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -58,24 +58,97 @@ static int createSocket() return makeSocketNonBlocking( s ); } -int tr_netResolve( char * address, struct in_addr * addr ) +struct tr_resolve_s { + int status; + char * address; + struct in_addr addr; + + tr_lock_t lock; + tr_thread_t thread; +}; + +static void resolveFunc( void * _r ) +{ + tr_resolve_t * r = _r; struct hostent * host; - addr->s_addr = inet_addr( address ); - if( addr->s_addr != 0xFFFFFFFF ) + tr_lockLock( &r->lock ); + r->addr.s_addr = inet_addr( r->address ); + if( r->addr.s_addr != 0xFFFFFFFF ) { - return 0; + r->status = TR_RESOLVE_OK; + tr_lockUnlock( &r->lock ); + return; + } + tr_lockUnlock( &r->lock ); + + if( !( host = gethostbyname( r->address ) ) ) + { + tr_lockLock( &r->lock ); + r->status = TR_RESOLVE_ERROR; + tr_lockUnlock( &r->lock ); + return; + } + tr_lockLock( &r->lock ); + memcpy( &r->addr, host->h_addr, host->h_length ); + r->status = TR_RESOLVE_OK; + tr_lockUnlock( &r->lock ); +} + +tr_resolve_t * tr_netResolveInit( char * address ) +{ + tr_resolve_t * r = malloc( sizeof( tr_resolve_t ) ); + + r->status = TR_RESOLVE_WAIT; + r->address = address; + + tr_lockInit( &r->lock ); + tr_threadCreate( &r->thread, resolveFunc, r ); + + return r; +} + +int tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr ) +{ + int ret; + + tr_lockLock( &r->lock ); + ret = r->status; + if( ret == TR_RESOLVE_OK ) + { + *addr = r->addr; + } + tr_lockUnlock( &r->lock ); + + return ret; +} + +void tr_netResolveClose( tr_resolve_t * r ) +{ + tr_threadJoin( &r->thread ); + tr_lockClose( &r->lock ); + free( r ); +} + +/* Blocking version */ +int tr_netResolve( char * address, struct in_addr * addr ) +{ + tr_resolve_t * r = tr_netResolveInit( address ); + int ret; + + for( ;; ) + { + ret = tr_netResolvePulse( r, addr ); + if( ret != TR_RESOLVE_WAIT ) + { + break; + } + tr_wait( 20 ); } - if( !( host = gethostbyname( address ) ) ) - { - tr_err( "Could not resolve (%s)", address ); - return -1; - } - memcpy( addr, host->h_addr, host->h_length ); - - return 0; + tr_netResolveClose( r ); + return ( ret != TR_RESOLVE_OK ); } int tr_netOpen( struct in_addr addr, in_port_t port ) diff --git a/libtransmission/net.h b/libtransmission/net.h index c0584eb71..361b13823 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2005 Eric Petit + * Copyright (c) 2005-2006 Transmission authors and contributors * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,6 +20,14 @@ * DEALINGS IN THE SOFTWARE. *****************************************************************************/ +#define TR_RESOLVE_WAIT 0 +#define TR_RESOLVE_ERROR 1 +#define TR_RESOLVE_OK 2 +typedef struct tr_resolve_s tr_resolve_t; +tr_resolve_t * tr_netResolveInit( char * ); +int tr_netResolvePulse( tr_resolve_t *, struct in_addr * ); +void tr_netResolveClose( tr_resolve_t * ); + int tr_netResolve ( char *, struct in_addr * ); int tr_netOpen ( struct in_addr addr, in_port_t port ); int tr_netBind ( int ); diff --git a/libtransmission/tracker.c b/libtransmission/tracker.c index b870bd03d..01a0f11e3 100644 --- a/libtransmission/tracker.c +++ b/libtransmission/tracker.c @@ -41,10 +41,12 @@ struct tr_tracker_s uint64_t dateOk; #define TC_STATUS_IDLE 1 -#define TC_STATUS_CONNECT 2 -#define TC_STATUS_RECV 4 +#define TC_STATUS_RESOLVE 2 +#define TC_STATUS_CONNECT 4 +#define TC_STATUS_RECV 8 char status; + tr_resolve_t * resolve; int socket; uint8_t * buf; int size; @@ -136,16 +138,43 @@ int tr_trackerPulse( tr_tracker_t * tc ) if( ( tc->status & TC_STATUS_IDLE ) && shouldConnect( tc ) ) { + tc->resolve = tr_netResolveInit( inf->trackerAddress ); + + tr_inf( "Tracker: connecting to %s:%d (%s)", + inf->trackerAddress, inf->trackerPort, + tc->started ? "sending 'started'" : + ( tc->completed ? "sending 'completed'" : + ( tc->stopped ? "sending 'stopped'" : + ( 0 < tc->newPort ? "sending 'stopped' to change port" : + "getting peers" ) ) ) ); + + tc->status = TC_STATUS_RESOLVE; + tc->dateTry = tr_date(); + } + + if( tc->status & TC_STATUS_RESOLVE ) + { + int ret; struct in_addr addr; - if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) ) + ret = tr_netResolvePulse( tc->resolve, &addr ); + if( ret == TR_RESOLVE_WAIT ) { return 0; } - - if( tr_netResolve( inf->trackerAddress, &addr ) ) + else + { + tr_netResolveClose( tc->resolve ); + } + + if( ret == TR_RESOLVE_ERROR ) + { + tc->status = TC_STATUS_IDLE; + return 0; + } + + if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) ) { - tr_fdSocketClosed( tor->fdlimit, 1 ); return 0; } @@ -156,16 +185,7 @@ int tr_trackerPulse( tr_tracker_t * tc ) return 0; } - tr_inf( "Tracker: connecting to %s:%d (%s)", - inf->trackerAddress, inf->trackerPort, - tc->started ? "sending 'started'" : - ( tc->completed ? "sending 'completed'" : - ( tc->stopped ? "sending 'stopped'" : - ( 0 < tc->newPort ? "sending 'stopped' to change port" : - "getting peers" ) ) ) ); - - tc->status = TC_STATUS_CONNECT; - tc->dateTry = tr_date(); + tc->status = TC_STATUS_CONNECT; } if( tc->status & TC_STATUS_CONNECT )