void tr_publisherFree( tr_publisher_t ** p ) { assert( p ); assert( *p ); tr_list_free( &( *p )->list, NULL ); tr_free( *p ); *p = NULL; }
static void io_dtor( void * vio ) { tr_peerIo * io = vio; assert( tr_isPeerIo( io ) ); assert( tr_amInEventThread( io->session ) ); assert( io->session->events != NULL ); dbgmsg( io, "in tr_peerIo destructor" ); event_disable( io, EV_READ | EV_WRITE ); tr_bandwidthDestruct( &io->bandwidth ); evbuffer_free( io->outbuf ); evbuffer_free( io->inbuf ); tr_netClose( io->session, io->socket ); tr_cryptoFree( io->crypto ); tr_list_free( &io->outbuf_datatypes, tr_free ); memset( io, ~0, sizeof( tr_peerIo ) ); tr_free( io ); }
static void tr_closeAllConnections( void * vsession ) { tr_session * session = vsession; tr_torrent * tor; int i, n; tr_torrent ** torrents; assert( tr_isSession( session ) ); tr_statsClose( session ); tr_sharedShuttingDown( session->shared ); tr_rpcClose( &session->rpcServer ); /* close the torrents. get the most active ones first so that * if we can't get them all closed in a reasonable amount of time, * at least we get the most important ones first. */ tor = NULL; n = session->torrentCount; torrents = tr_new( tr_torrent *, session->torrentCount ); for( i = 0; i < n; ++i ) torrents[i] = tor = tr_torrentNext( session, tor ); qsort( torrents, n, sizeof( tr_torrent* ), compareTorrentByCur ); for( i = 0; i < n; ++i ) tr_torrentFree( torrents[i] ); tr_free( torrents ); tr_peerMgrFree( session->peerMgr ); tr_trackerSessionClose( session ); tr_list_free( &session->blocklists, (TrListForeachFunc)_tr_blocklistFree ); tr_webClose( &session->web ); session->isClosed = TRUE; }
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; }