tr_session * tr_sessionInit( const char * tag, const char * configDir, tr_bool messageQueuingEnabled, tr_benc * clientSettings ) { tr_session * session; struct init_data data; assert( tr_bencIsDict( clientSettings ) ); /* initialize the bare skeleton of the session object */ session = tr_new0( tr_session, 1 ); session->bandwidth = tr_bandwidthNew( session, NULL ); session->lock = tr_lockNew( ); session->tag = tr_strdup( tag ); session->magicNumber = SESSION_MAGIC_NUMBER; /* start the libtransmission thread */ tr_netInit( ); /* must go before tr_eventInit */ tr_eventInit( session ); assert( session->events != NULL ); /* run the rest in the libtransmission thread */ session->isWaiting = TRUE; data.session = session; data.configDir = configDir; data.messageQueuingEnabled = messageQueuingEnabled; data.clientSettings = clientSettings; tr_runInEventThread( session, tr_sessionInitImpl, &data ); while( session->isWaiting ) tr_wait( 100 ); return session; }
void tr_fdInit( int globalPeerLimit ) { int i; assert( gFd == NULL ); gFd = tr_new0( struct tr_fd_s, 1 ); gFd->lock = tr_lockNew( ); #ifdef HAVE_GETRLIMIT { struct rlimit rlim; getrlimit( RLIMIT_NOFILE, &rlim ); rlim.rlim_cur = MIN( rlim.rlim_max, (rlim_t)( globalPeerLimit + NOFILE_BUFFER ) ); setrlimit( RLIMIT_NOFILE, &rlim ); gFd->socketMax = rlim.rlim_cur - NOFILE_BUFFER; tr_dbg( "setrlimit( RLIMIT_NOFILE, %d )", (int)rlim.rlim_cur ); } #else gFd->socketMax = globalPeerLimit; #endif tr_dbg( "%d usable file descriptors", globalPeerLimit ); for( i = 0; i < TR_MAX_OPEN_FILES; ++i ) gFd->open[i].fd = -1; }
static tr_lock* getVerifyLock( void ) { static tr_lock * lock = NULL; if( lock == NULL ) lock = tr_lockNew( ); return lock; }
static tr_lock* getMessageLock( void ) { if( !msglock ) msglock = tr_lockNew( ); return msglock; }
static tr_lock* getMessageLock( void ) { static tr_lock * l = NULL; if( !l ) l = tr_lockNew( ); return l; }
static tr_lock* getRecycledNodesLock (void) { static tr_lock * l = NULL; if (!l) l = tr_lockNew (); return l; }
void tr_msgInit( void ) { const char * env = getenv( "TR_DEBUG" ); messageLevel = ( env ? atoi( env ) : 0 ) + 1; messageLevel = MAX( 1, messageLevel ); if( messageLock == NULL ) messageLock = tr_lockNew( ); }
static tr_lock* get_rng_lock(void) { static tr_lock* lock = NULL; if (lock == NULL) { lock = tr_lockNew(); } return lock; }
void tr_eventInit( tr_handle * handle ) { tr_event_handle * eh; eh = tr_new0( tr_event_handle, 1 ); eh->lock = tr_lockNew( ); pipe( eh->fds ); eh->h = handle; eh->base = event_init( ); eh->thread = tr_threadNew( libeventThreadFunc, eh ); }
void tr_eventInit( tr_session * session ) { tr_event_handle * eh; session->events = NULL; eh = tr_new0( tr_event_handle, 1 ); eh->lock = tr_lockNew( ); pipe( eh->fds ); eh->session = session; eh->thread = tr_threadNew( libeventThreadFunc, eh ); /* wait until the libevent thread is running */ while( session->events == NULL ) tr_wait( 100 ); }
void tr_eventInit (tr_session * session) { tr_event_handle * eh; session->events = NULL; eh = tr_new0 (tr_event_handle, 1); eh->lock = tr_lockNew (); if (pipe (eh->fds) == -1) tr_logAddError ("Unable to write to pipe() in libtransmission: %s", tr_strerror(errno)); eh->session = session; eh->thread = tr_threadNew (libeventThreadFunc, eh); /* wait until the libevent thread is running */ while (session->events == NULL) tr_wait_msec (100); }
static void tr_webThreadFunc( void * vsession ) { int unused; CURLM * multi; struct tr_web * web; int taskCount = 0; tr_session * session = vsession; /* try to enable ssl for https support; but if that fails, * try a plain vanilla init */ if( curl_global_init( CURL_GLOBAL_SSL ) ) curl_global_init( 0 ); web = tr_new0( struct tr_web, 1 ); web->close_mode = ~0; web->taskLock = tr_lockNew( ); web->tasks = NULL; multi = curl_multi_init( ); session->web = web; for( ;; ) { long msec; CURLMsg * msg; CURLMcode mcode; struct tr_web_task * task; if( web->close_mode == TR_WEB_CLOSE_NOW ) break; if( ( web->close_mode == TR_WEB_CLOSE_WHEN_IDLE ) && !taskCount ) break; /* add tasks from the queue */ tr_lockLock( web->taskLock ); while(( task = tr_list_pop_front( &web->tasks ))) { dbgmsg( "adding task to curl: [%s]", task->url ); curl_multi_add_handle( multi, createEasy( session, task )); /*fprintf( stderr, "adding a task.. taskCount is now %d\n", taskCount );*/ ++taskCount; } tr_lockUnlock( web->taskLock ); /* maybe wait a little while before calling curl_multi_perform() */ msec = 0; curl_multi_timeout( multi, &msec ); if( msec < 0 ) msec = THREADFUNC_MAX_SLEEP_MSEC; if( msec > 0 ) { int usec; int max_fd; struct timeval t; fd_set r_fd_set, w_fd_set, c_fd_set; max_fd = 0; FD_ZERO( &r_fd_set ); FD_ZERO( &w_fd_set ); FD_ZERO( &c_fd_set ); curl_multi_fdset( multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd ); if( msec > THREADFUNC_MAX_SLEEP_MSEC ) msec = THREADFUNC_MAX_SLEEP_MSEC; usec = msec * 1000; t.tv_sec = usec / 1000000; t.tv_usec = usec % 1000000; tr_select( max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t ); } /* call curl_multi_perform() */ do { mcode = curl_multi_perform( multi, &unused ); } while( mcode == CURLM_CALL_MULTI_PERFORM ); /* pump completed tasks from the multi */ while(( msg = curl_multi_info_read( multi, &unused ))) { if(( msg->msg == CURLMSG_DONE ) && ( msg->easy_handle != NULL )) { struct tr_web_task * task; CURL * e = msg->easy_handle; curl_easy_getinfo( e, CURLINFO_PRIVATE, (void*)&task ); curl_easy_getinfo( e, CURLINFO_RESPONSE_CODE, &task->code ); curl_multi_remove_handle( multi, e ); curl_easy_cleanup( e ); /*fprintf( stderr, "removing a completed task.. taskCount is now %d (response code: %d, response len: %d)\n", taskCount, (int)task->code, (int)evbuffer_get_length(task->response) );*/ tr_runInEventThread( task->session, task_finish_func, task ); --taskCount; } } } /* cleanup */ curl_multi_cleanup( multi ); tr_lockFree( web->taskLock ); tr_free( web ); session->web = NULL; }
static void tr_webThreadFunc( void * vsession ) { CURLM * multi; struct tr_web * web; int taskCount = 0; struct tr_web_task * task; tr_session * session = vsession; /* try to enable ssl for https support; but if that fails, * try a plain vanilla init */ if( curl_global_init( CURL_GLOBAL_SSL ) ) curl_global_init( 0 ); web = tr_new0( struct tr_web, 1 ); web->close_mode = ~0; web->taskLock = tr_lockNew( ); web->tasks = NULL; web->curl_verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; web->cookie_filename = tr_buildPath( session->configDir, "cookies.txt", NULL ); multi = curl_multi_init( ); session->web = web; for( ;; ) { long msec; int unused; CURLMsg * msg; CURLMcode mcode; if( web->close_mode == TR_WEB_CLOSE_NOW ) break; if( ( web->close_mode == TR_WEB_CLOSE_WHEN_IDLE ) && ( web->tasks == NULL ) ) break; /* add tasks from the queue */ tr_lockLock( web->taskLock ); while( web->tasks != NULL ) { /* pop the task */ task = web->tasks; web->tasks = task->next; task->next = NULL; dbgmsg( "adding task to curl: [%s]", task->url ); curl_multi_add_handle( multi, createEasy( session, web, task )); /*fprintf( stderr, "adding a task.. taskCount is now %d\n", taskCount );*/ ++taskCount; } tr_lockUnlock( web->taskLock ); /* maybe wait a little while before calling curl_multi_perform() */ msec = 0; curl_multi_timeout( multi, &msec ); if( msec < 0 ) msec = THREADFUNC_MAX_SLEEP_MSEC; if( session->isClosed ) msec = 100; /* on shutdown, call perform() more frequently */ if( msec > 0 ) { int usec; int max_fd; struct timeval t; fd_set r_fd_set, w_fd_set, c_fd_set; max_fd = 0; FD_ZERO( &r_fd_set ); FD_ZERO( &w_fd_set ); FD_ZERO( &c_fd_set ); curl_multi_fdset( multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd ); if( msec > THREADFUNC_MAX_SLEEP_MSEC ) msec = THREADFUNC_MAX_SLEEP_MSEC; usec = msec * 1000; t.tv_sec = usec / 1000000; t.tv_usec = usec % 1000000; tr_select( max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t ); } /* call curl_multi_perform() */ do { mcode = curl_multi_perform( multi, &unused ); } while( mcode == CURLM_CALL_MULTI_PERFORM ); /* pump completed tasks from the multi */ while(( msg = curl_multi_info_read( multi, &unused ))) { if(( msg->msg == CURLMSG_DONE ) && ( msg->easy_handle != NULL )) { double total_time; struct tr_web_task * task; long req_bytes_sent; CURL * e = msg->easy_handle; curl_easy_getinfo( e, CURLINFO_PRIVATE, (void*)&task ); curl_easy_getinfo( e, CURLINFO_RESPONSE_CODE, &task->code ); curl_easy_getinfo( e, CURLINFO_REQUEST_SIZE, &req_bytes_sent ); curl_easy_getinfo( e, CURLINFO_TOTAL_TIME, &total_time ); task->did_connect = task->code>0 || req_bytes_sent>0; task->did_timeout = !task->code && ( total_time >= task->timeout_secs ); curl_multi_remove_handle( multi, e ); curl_easy_cleanup( e ); /*fprintf( stderr, "removing a completed task.. taskCount is now %d (response code: %d, response len: %d)\n", taskCount, (int)task->code, (int)evbuffer_get_length(task->response) );*/ tr_runInEventThread( task->session, task_finish_func, task ); --taskCount; } } } /* Discard any remaining tasks. * This is rare, but can happen on shutdown with unresponsive trackers. */ while( web->tasks != NULL ) { task = web->tasks; web->tasks = task->next; dbgmsg( "Discarding task \"%s\"", task->url ); task_free( task ); } /* cleanup */ curl_multi_cleanup( multi ); tr_lockFree( web->taskLock ); tr_free( web->cookie_filename ); tr_free( web ); session->web = NULL; }
static void tr_webThreadFunc (void * vsession) { char * str; CURLM * multi; struct tr_web * web; int taskCount = 0; struct tr_web_task * task; tr_session * session = vsession; /* try to enable ssl for https support; but if that fails, * try a plain vanilla init */ if (curl_global_init (CURL_GLOBAL_SSL)) curl_global_init (0); web = tr_new0 (struct tr_web, 1); web->close_mode = ~0; web->taskLock = tr_lockNew (); web->tasks = NULL; web->curl_verbose = getenv ("TR_CURL_VERBOSE") != NULL; web->curl_ssl_verify = getenv ("TR_CURL_SSL_VERIFY") != NULL; web->curl_ca_bundle = getenv ("CURL_CA_BUNDLE"); if (web->curl_ssl_verify) { tr_logAddNamedInfo ("web", "will verify tracker certs using envvar CURL_CA_BUNDLE: %s", web->curl_ca_bundle == NULL ? "none" : web->curl_ca_bundle); tr_logAddNamedInfo ("web", "NB: this only works if you built against libcurl with openssl or gnutls, NOT nss"); tr_logAddNamedInfo ("web", "NB: invalid certs will show up as 'Could not connect to tracker' like many other errors"); } str = tr_buildPath (session->configDir, "cookies.txt", NULL); if (tr_fileExists (str, NULL)) web->cookie_filename = tr_strdup (str); tr_free (str); multi = curl_multi_init (); session->web = web; for (;;) { long msec; int unused; CURLMsg * msg; CURLMcode mcode; if (web->close_mode == TR_WEB_CLOSE_NOW) break; if ((web->close_mode == TR_WEB_CLOSE_WHEN_IDLE) && (web->tasks == NULL)) break; /* add tasks from the queue */ tr_lockLock (web->taskLock); while (web->tasks != NULL) { /* pop the task */ task = web->tasks; web->tasks = task->next; task->next = NULL; dbgmsg ("adding task to curl: [%s]", task->url); curl_multi_add_handle (multi, createEasy (session, web, task)); /*fprintf (stderr, "adding a task.. taskCount is now %d\n", taskCount);*/ ++taskCount; } tr_lockUnlock (web->taskLock); /* unpause any paused curl handles */ if (paused_easy_handles != NULL) { CURL * handle; tr_list * tmp; /* swap paused_easy_handles to prevent oscillation between writeFunc this while loop */ tmp = paused_easy_handles; paused_easy_handles = NULL; while ((handle = tr_list_pop_front (&tmp))) curl_easy_pause (handle, CURLPAUSE_CONT); } /* maybe wait a little while before calling curl_multi_perform () */ msec = 0; curl_multi_timeout (multi, &msec); if (msec < 0) msec = THREADFUNC_MAX_SLEEP_MSEC; if (session->isClosed) msec = 100; /* on shutdown, call perform () more frequently */ if (msec > 0) { int usec; int max_fd; struct timeval t; fd_set r_fd_set, w_fd_set, c_fd_set; max_fd = 0; FD_ZERO (&r_fd_set); FD_ZERO (&w_fd_set); FD_ZERO (&c_fd_set); curl_multi_fdset (multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd); if (msec > THREADFUNC_MAX_SLEEP_MSEC) msec = THREADFUNC_MAX_SLEEP_MSEC; usec = msec * 1000; t.tv_sec = usec / 1000000; t.tv_usec = usec % 1000000; tr_select (max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t); } /* call curl_multi_perform () */ do mcode = curl_multi_perform (multi, &unused); while (mcode == CURLM_CALL_MULTI_PERFORM); /* pump completed tasks from the multi */ while ((msg = curl_multi_info_read (multi, &unused))) { if ((msg->msg == CURLMSG_DONE) && (msg->easy_handle != NULL)) { double total_time; struct tr_web_task * task; long req_bytes_sent; CURL * e = msg->easy_handle; curl_easy_getinfo (e, CURLINFO_PRIVATE, (void*)&task); assert (e == task->curl_easy); curl_easy_getinfo (e, CURLINFO_RESPONSE_CODE, &task->code); curl_easy_getinfo (e, CURLINFO_REQUEST_SIZE, &req_bytes_sent); curl_easy_getinfo (e, CURLINFO_TOTAL_TIME, &total_time); task->did_connect = task->code>0 || req_bytes_sent>0; task->did_timeout = !task->code && (total_time >= task->timeout_secs); curl_multi_remove_handle (multi, e); tr_list_remove_data (&paused_easy_handles, e); curl_easy_cleanup (e); tr_runInEventThread (task->session, task_finish_func, task); --taskCount; } } } /* Discard any remaining tasks. * This is rare, but can happen on shutdown with unresponsive trackers. */ while (web->tasks != NULL) { task = web->tasks; web->tasks = task->next; dbgmsg ("Discarding task \"%s\"", task->url); task_free (task); } /* cleanup */ tr_list_free (&paused_easy_handles, NULL); curl_multi_cleanup (multi); tr_lockFree (web->taskLock); tr_free (web->cookie_filename); tr_free (web); session->web = NULL; }