static CURL * createEasy (tr_session * s, struct tr_web * web, struct tr_web_task * task) { bool is_default_value; const tr_address * addr; CURL * e = task->curl_easy = curl_easy_init (); task->timeout_secs = getTimeoutFromURL (task); curl_easy_setopt (e, CURLOPT_AUTOREFERER, 1L); curl_easy_setopt (e, CURLOPT_ENCODING, "gzip;q=1.0, deflate, identity"); curl_easy_setopt (e, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt (e, CURLOPT_MAXREDIRS, -1L); curl_easy_setopt (e, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (e, CURLOPT_PRIVATE, task); #ifdef USE_LIBCURL_SOCKOPT curl_easy_setopt (e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction); curl_easy_setopt (e, CURLOPT_SOCKOPTDATA, task); #endif if (web->curl_ssl_verify) { curl_easy_setopt (e, CURLOPT_CAINFO, web->curl_ca_bundle); } else { curl_easy_setopt (e, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt (e, CURLOPT_SSL_VERIFYPEER, 0L); } curl_easy_setopt (e, CURLOPT_TIMEOUT, task->timeout_secs); curl_easy_setopt (e, CURLOPT_URL, task->url); curl_easy_setopt (e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING); curl_easy_setopt (e, CURLOPT_VERBOSE, (long)(web->curl_verbose?1:0)); curl_easy_setopt (e, CURLOPT_WRITEDATA, task); curl_easy_setopt (e, CURLOPT_WRITEFUNCTION, writeFunc); if (((addr = tr_sessionGetPublicAddress (s, TR_AF_INET, &is_default_value))) && !is_default_value) curl_easy_setopt (e, CURLOPT_INTERFACE, tr_address_to_string (addr)); else if (((addr = tr_sessionGetPublicAddress (s, TR_AF_INET6, &is_default_value))) && !is_default_value) curl_easy_setopt (e, CURLOPT_INTERFACE, tr_address_to_string (addr)); if (task->cookies != NULL) curl_easy_setopt (e, CURLOPT_COOKIE, task->cookies); if (web->cookie_filename != NULL) curl_easy_setopt (e, CURLOPT_COOKIEFILE, web->cookie_filename); if (task->range != NULL) { curl_easy_setopt (e, CURLOPT_RANGE, task->range); /* don't bother asking the server to compress webseed fragments */ curl_easy_setopt (e, CURLOPT_ENCODING, "identity"); } return e; }
static CURL * createEasy( tr_session * s, struct tr_web_task * task ) { const tr_address * addr; tr_bool is_default_value; CURL * e = curl_easy_init( ); const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; char * cookie_filename = tr_buildPath( s->configDir, "cookies.txt", NULL ); task->timeout_secs = getTimeoutFromURL( task ); curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L ); curl_easy_setopt( e, CURLOPT_COOKIEFILE, cookie_filename ); curl_easy_setopt( e, CURLOPT_ENCODING, "gzip;q=1.0, deflate, identity" ); curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L ); curl_easy_setopt( e, CURLOPT_NOSIGNAL, 1L ); curl_easy_setopt( e, CURLOPT_PRIVATE, task ); #ifdef USE_LIBCURL_SOCKOPT curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction ); curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task ); #endif curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L ); curl_easy_setopt( e, CURLOPT_TIMEOUT, task->timeout_secs ); curl_easy_setopt( e, CURLOPT_URL, task->url ); curl_easy_setopt( e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING ); curl_easy_setopt( e, CURLOPT_VERBOSE, verbose ); curl_easy_setopt( e, CURLOPT_WRITEDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc ); if((( addr = tr_sessionGetPublicAddress( s, TR_AF_INET, &is_default_value ))) && !is_default_value ) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( addr ) ); else if ((( addr = tr_sessionGetPublicAddress( s, TR_AF_INET6, &is_default_value ))) && !is_default_value ) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( addr ) ); if( task->range ) curl_easy_setopt( e, CURLOPT_RANGE, task->range ); if( s->curl_easy_config_func != NULL ) s->curl_easy_config_func( s, e, task->url ); tr_free( cookie_filename ); return e; }
static CURL * createEasy( tr_session * s, struct tr_web_task * task ) { const tr_address * addr; CURL * e = curl_easy_init( ); const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; if( !task->range && s->isProxyEnabled ) { const long proxyType = getCurlProxyType( s->proxyType ); curl_easy_setopt( e, CURLOPT_PROXY, s->proxy ); curl_easy_setopt( e, CURLOPT_PROXYAUTH, CURLAUTH_ANY ); curl_easy_setopt( e, CURLOPT_PROXYPORT, s->proxyPort ); curl_easy_setopt( e, CURLOPT_PROXYTYPE, proxyType ); } if( !task->range && s->isProxyAuthEnabled ) { char * str = tr_strdup_printf( "%s:%s", s->proxyUsername, s->proxyPassword ); curl_easy_setopt( e, CURLOPT_PROXYUSERPWD, str ); tr_free( str ); } curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L ); curl_easy_setopt( e, CURLOPT_ENCODING, "gzip;q=1.0, deflate, identity" ); curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L ); curl_easy_setopt( e, CURLOPT_NOSIGNAL, 1L ); curl_easy_setopt( e, CURLOPT_PRIVATE, task ); #ifdef USE_LIBCURL_SOCKOPT curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction ); curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task ); #endif curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L ); curl_easy_setopt( e, CURLOPT_TIMEOUT, getTimeoutFromURL( task->url ) ); curl_easy_setopt( e, CURLOPT_URL, task->url ); curl_easy_setopt( e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING ); curl_easy_setopt( e, CURLOPT_VERBOSE, verbose ); curl_easy_setopt( e, CURLOPT_WRITEDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc ); if(( addr = tr_sessionGetPublicAddress( s, TR_AF_INET ))) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( addr ) ); if( task->range ) curl_easy_setopt( e, CURLOPT_RANGE, task->range ); return e; }
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed) { TR_ASSERT(tr_address_is_valid(addr)); struct tr_peer_socket ret = TR_PEER_SOCKET_INIT; static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 }; tr_socket_t s; struct sockaddr_storage sock; socklen_t addrlen; tr_address const* source_addr; socklen_t sourcelen; struct sockaddr_storage source_sock; char err_buf[512]; if (!tr_address_is_valid_for_peers(addr, port)) { return ret; } s = tr_fdSocketCreate(session, domains[addr->type], SOCK_STREAM); if (s == TR_BAD_SOCKET) { return ret; } /* seeds don't need much of a read buffer... */ if (clientIsSeed) { int n = 8192; if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void const*)&n, sizeof(n)) == -1) { tr_logAddInfo("Unable to set SO_RCVBUF on socket %" PRIdMAX ": %s", (intmax_t)s, tr_net_strerror(err_buf, sizeof(err_buf), sockerrno)); } } if (evutil_make_socket_nonblocking(s) == -1) { tr_netClose(session, s); return ret; } addrlen = setup_sockaddr(addr, port, &sock); /* set source address */ source_addr = tr_sessionGetPublicAddress(session, addr->type, NULL); TR_ASSERT(source_addr != NULL); sourcelen = setup_sockaddr(source_addr, 0, &source_sock); if (bind(s, (struct sockaddr*)&source_sock, sourcelen) == -1) { tr_logAddError(_("Couldn't set source address %s on %" PRIdMAX ": %s"), tr_address_to_string(source_addr), (intmax_t)s, tr_net_strerror(err_buf, sizeof(err_buf), sockerrno)); tr_netClose(session, s); return ret; } if (connect(s, (struct sockaddr*)&sock, addrlen) == -1 && #ifdef _WIN32 sockerrno != WSAEWOULDBLOCK && #endif sockerrno != EINPROGRESS) { int const tmperrno = sockerrno; if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr->type == TR_AF_INET) { tr_logAddError(_("Couldn't connect socket %" PRIdMAX " to %s, port %d (errno %d - %s)"), (intmax_t)s, tr_address_to_string(addr), (int)ntohs(port), tmperrno, tr_net_strerror(err_buf, sizeof(err_buf), tmperrno)); } tr_netClose(session, s); } else { ret = tr_peer_socket_tcp_create(s); } tr_logAddDeep(__FILE__, __LINE__, NULL, "New OUTGOING connection %" PRIdMAX " (%s)", (intmax_t)s, tr_peerIoAddrStr(addr, port)); return ret; }
void tr_udpInit (tr_session *ss) { bool is_default; const struct tr_address * public_addr; struct sockaddr_in sin; int rc; assert (ss->udp_socket < 0); assert (ss->udp6_socket < 0); ss->udp_port = tr_sessionGetPeerPort (ss); if (ss->udp_port <= 0) return; ss->udp_socket = socket (PF_INET, SOCK_DGRAM, 0); if (ss->udp_socket < 0) { tr_logAddNamedError ("UDP", "Couldn't create IPv4 socket"); goto ipv6; } memset (&sin, 0, sizeof (sin)); sin.sin_family = AF_INET; public_addr = tr_sessionGetPublicAddress (ss, TR_AF_INET, &is_default); if (public_addr && !is_default) memcpy (&sin.sin_addr, &public_addr->addr.addr4, sizeof (struct in_addr)); sin.sin_port = htons (ss->udp_port); rc = bind (ss->udp_socket, (struct sockaddr*)&sin, sizeof (sin)); if (rc < 0) { tr_logAddNamedError ("UDP", "Couldn't bind IPv4 socket"); close (ss->udp_socket); ss->udp_socket = -1; goto ipv6; } ss->udp_event = event_new (ss->event_base, ss->udp_socket, EV_READ | EV_PERSIST, event_callback, ss); if (ss->udp_event == NULL) tr_logAddNamedError ("UDP", "Couldn't allocate IPv4 event"); ipv6: if (tr_globalIPv6 ()) rebind_ipv6 (ss, true); if (ss->udp6_socket >= 0) { ss->udp6_event = event_new (ss->event_base, ss->udp6_socket, EV_READ | EV_PERSIST, event_callback, ss); if (ss->udp6_event == NULL) tr_logAddNamedError ("UDP", "Couldn't allocate IPv6 event"); } tr_udpSetSocketBuffers (ss); if (ss->isDHTEnabled) tr_dhtInit (ss); if (ss->udp_event) event_add (ss->udp_event, NULL); if (ss->udp6_event) event_add (ss->udp6_event, NULL); }
static void rebind_ipv6 (tr_session *ss, bool force) { bool is_default; const struct tr_address * public_addr; struct sockaddr_in6 sin6; const unsigned char *ipv6 = tr_globalIPv6 (); int s = -1, rc; int one = 1; /* We currently have no way to enable or disable IPv6 after initialisation. No way to fix that without some surgery to the DHT code itself. */ if (ipv6 == NULL || (!force && ss->udp6_socket < 0)) { if (ss->udp6_bound) { free (ss->udp6_bound); ss->udp6_bound = NULL; } return; } if (ss->udp6_bound != NULL && memcmp (ipv6, ss->udp6_bound, 16) == 0) return; s = socket (PF_INET6, SOCK_DGRAM, 0); if (s < 0) goto fail; #ifdef IPV6_V6ONLY /* Since we always open an IPv4 socket on the same port, this shouldn't matter. But I'm superstitious. */ setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof (one)); #endif memset (&sin6, 0, sizeof (sin6)); sin6.sin6_family = AF_INET6; if (ipv6) memcpy (&sin6.sin6_addr, ipv6, 16); sin6.sin6_port = htons (ss->udp_port); public_addr = tr_sessionGetPublicAddress (ss, TR_AF_INET6, &is_default); if (public_addr && !is_default) sin6.sin6_addr = public_addr->addr.addr6; rc = bind (s, (struct sockaddr*)&sin6, sizeof (sin6)); if (rc < 0) goto fail; if (ss->udp6_socket < 0) { ss->udp6_socket = s; } else { rc = dup2 (s, ss->udp6_socket); if (rc < 0) goto fail; close (s); } if (ss->udp6_bound == NULL) ss->udp6_bound = malloc (16); if (ss->udp6_bound) memcpy (ss->udp6_bound, ipv6, 16); return; fail: /* Something went wrong. It's difficult to recover, so let's simply set things up so that we try again next time. */ tr_logAddNamedError ("UDP", "Couldn't rebind IPv6 socket"); if (s >= 0) close (s); if (ss->udp6_bound) { free (ss->udp6_bound); ss->udp6_bound = NULL; } }