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 tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool suppressMsgs, int* errOut) { TR_ASSERT(tr_address_is_valid(addr)); static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 }; struct sockaddr_storage sock; tr_socket_t fd; int addrlen; int optval; fd = socket(domains[addr->type], SOCK_STREAM, 0); if (fd == TR_BAD_SOCKET) { *errOut = sockerrno; return TR_BAD_SOCKET; } if (evutil_make_socket_nonblocking(fd) == -1) { *errOut = sockerrno; tr_netCloseSocket(fd); return TR_BAD_SOCKET; } optval = 1; setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void const*)&optval, sizeof(optval)); setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void const*)&optval, sizeof(optval)); #ifdef IPV6_V6ONLY if (addr->type == TR_AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void const*)&optval, sizeof(optval)) == -1) { if (sockerrno != ENOPROTOOPT) /* if the kernel doesn't support it, ignore it */ { *errOut = sockerrno; tr_netCloseSocket(fd); return TR_BAD_SOCKET; } } } #endif addrlen = setup_sockaddr(addr, htons(port), &sock); if (bind(fd, (struct sockaddr*)&sock, addrlen) == -1) { int const err = sockerrno; if (!suppressMsgs) { char const* fmt; char const* hint; char err_buf[512]; if (err == EADDRINUSE) { hint = _("Is another copy of Transmission already running?"); } else { hint = NULL; } if (hint == NULL) { fmt = _("Couldn't bind port %d on %s: %s"); } else { fmt = _("Couldn't bind port %d on %s: %s (%s)"); } tr_logAddError(fmt, port, tr_address_to_string(addr), tr_net_strerror(err_buf, sizeof(err_buf), err), hint); } tr_netCloseSocket(fd); *errOut = err; return TR_BAD_SOCKET; } if (!suppressMsgs) { tr_logAddDebug("Bound socket %" PRIdMAX " to port %d on %s", (intmax_t)fd, port, tr_address_to_string(addr)); } #ifdef TCP_FASTOPEN #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif optval = 5; setsockopt(fd, SOL_TCP, TCP_FASTOPEN, (void const*)&optval, sizeof(optval)); #endif if (listen(fd, 128) == -1) { *errOut = sockerrno; tr_netCloseSocket(fd); return TR_BAD_SOCKET; } return fd; }
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; }