static void set_socket_buffers (int fd, int large) { int size, rbuf, sbuf, rc; socklen_t rbuf_len = sizeof (rbuf), sbuf_len = sizeof (sbuf); size = large ? RECV_BUFFER_SIZE : SMALL_BUFFER_SIZE; rc = setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)); if (rc < 0) tr_logAddNamedError ("UDP", "Failed to set receive buffer: %s", tr_strerror (errno)); size = large ? SEND_BUFFER_SIZE : SMALL_BUFFER_SIZE; rc = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)); if (rc < 0) tr_logAddNamedError ("UDP", "Failed to set send buffer: %s", tr_strerror (errno)); if (large) { rc = getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &rbuf_len); if (rc < 0) rbuf = 0; rc = getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &sbuf_len); if (rc < 0) sbuf = 0; if (rbuf < RECV_BUFFER_SIZE) { tr_logAddNamedError ("UDP", "Failed to set receive buffer: requested %d, got %d", RECV_BUFFER_SIZE, rbuf); #ifdef __linux__ tr_logAddNamedInfo ("UDP", "Please add the line " "\"net.core.rmem_max = %d\" to /etc/sysctl.conf", RECV_BUFFER_SIZE); #endif } if (sbuf < SEND_BUFFER_SIZE) { tr_logAddNamedError ("UDP", "Failed to set send buffer: requested %d, got %d", SEND_BUFFER_SIZE, sbuf); #ifdef __linux__ tr_logAddNamedInfo ("UDP", "Please add the line " "\"net.core.wmem_max = %d\" to /etc/sysctl.conf", SEND_BUFFER_SIZE); #endif } } }
void UTP_RBDrained (struct UTPSocket *socket) { tr_logAddNamedError (MY_NAME, "UTP_RBDrained (%p) was called.", socket); dbgmsg ("UTP_RBDrained (%p) was called.", socket); assert (0); /* FIXME: this is too much for the long term, but probably needed in the short term */ }
static void bootstrap_from_name (const char *name, tr_port port, int af) { struct addrinfo hints, *info, *infop; char pp[10]; int rc; memset (&hints, 0, sizeof (hints)); hints.ai_socktype = SOCK_DGRAM; hints.ai_family = af; /* No, just passing p + 1 to gai won't work. */ tr_snprintf (pp, sizeof (pp), "%d", (int)port); rc = getaddrinfo (name, pp, &hints, &info); if (rc != 0) { tr_logAddNamedError ("DHT", "%s:%s: %s", name, pp, gai_strerror (rc)); return; } infop = info; while (infop) { dht_ping_node (infop->ai_addr, infop->ai_addrlen); nap (15); if (bootstrap_done (session, af)) break; infop = infop->ai_next; } freeaddrinfo (info); }
bool UTP_Write(struct UTPSocket* socket, size_t count) { tr_logAddNamedError(MY_NAME, "UTP_RBDrained(%p, %zu) was called.", socket, count); dbgmsg("UTP_RBDrained(%p, %zu) was called.", socket, count); TR_ASSERT(false); /* FIXME: this is too much for the long term, but probably needed in the short term */ return false; }
uint8_t UTP_Write (struct UTPSocket *socket, size_t count) { tr_logAddNamedError (MY_NAME, "UTP_RBDrained (%p, %"TR_PRIuSIZE") was called.", socket, count); dbgmsg ("UTP_RBDrained (%p, %"TR_PRIuSIZE") was called.", socket, count); assert (0); /* FIXME: this is too much for the long term, but probably needed in the short term */ return false; }
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; } }
static void dht_bootstrap (void *closure) { struct bootstrap_closure *cl = closure; int i; int num = cl->len / 6, num6 = cl->len6 / 18; if (session != cl->session) return; if (cl->len > 0) tr_logAddNamedInfo ("DHT", "Bootstrapping from %d IPv4 nodes", num); if (cl->len6 > 0) tr_logAddNamedInfo ("DHT", "Bootstrapping from %d IPv6 nodes", num6); for (i = 0; i < MAX (num, num6); i++) { if (i < num && !bootstrap_done (cl->session, AF_INET)) { tr_port port; struct tr_address addr; memset (&addr, 0, sizeof (addr)); addr.type = TR_AF_INET; memcpy (&addr.addr.addr4, &cl->nodes[i * 6], 4); memcpy (&port, &cl->nodes[i * 6 + 4], 2); port = ntohs (port); tr_dhtAddNode (cl->session, &addr, port, 1); } if (i < num6 && !bootstrap_done (cl->session, AF_INET6)) { tr_port port; struct tr_address addr; memset (&addr, 0, sizeof (addr)); addr.type = TR_AF_INET6; memcpy (&addr.addr.addr6, &cl->nodes6[i * 18], 16); memcpy (&port, &cl->nodes6[i * 18 + 16], 2); port = ntohs (port); tr_dhtAddNode (cl->session, &addr, port, 1); } /* Our DHT code is able to take up to 9 nodes in a row without dropping any. After that, it takes some time to split buckets. So ping the first 8 nodes quickly, then slow down. */ if (i < 8) nap (2); else nap (15); if (bootstrap_done (session, 0)) break; } if (!bootstrap_done (cl->session, 0)) { char *bootstrap_file; tr_sys_file_t f = TR_BAD_SYS_FILE; bootstrap_file = tr_buildPath (cl->session->configDir, "dht.bootstrap", NULL); if (bootstrap_file) f = tr_sys_file_open (bootstrap_file, TR_SYS_FILE_READ, 0, NULL); if (f != TR_BAD_SYS_FILE) { tr_logAddNamedInfo ("DHT", "Attempting manual bootstrap"); for (;;) { char buf[201]; char *p; int port = 0; if (!tr_sys_file_read_line (f, buf, 200, NULL)) break; p = memchr (buf, ' ', strlen (buf)); if (p != NULL) port = atoi (p + 1); if (p == NULL || port <= 0 || port >= 0x10000) { tr_logAddNamedError ("DHT", "Couldn't parse %s", buf); continue; } *p = '\0'; bootstrap_from_name (buf, port, bootstrap_af (session)); if (bootstrap_done (cl->session, 0)) break; } tr_sys_file_close (f, NULL); } tr_free (bootstrap_file); } if (!bootstrap_done (cl->session, 0)) { for (i = 0; i < 6; i++) { /* We don't want to abuse our bootstrap nodes, so be very slow. The initial wait is to give other nodes a chance to contact us before we attempt to contact a bootstrap node, for example because we've just been restarted. */ nap (40); if (bootstrap_done (cl->session, 0)) break; if (i == 0) tr_logAddNamedInfo ("DHT", "Attempting bootstrap from dht.transmissionbt.com"); bootstrap_from_name ("dht.transmissionbt.com", 6881, bootstrap_af (session)); } } if (cl->nodes) tr_free (cl->nodes); if (cl->nodes6) tr_free (cl->nodes6); tr_free (closure); tr_logAddNamedDbg ("DHT", "Finished bootstrapping"); }
void UTP_Close(struct UTPSocket* socket) { tr_logAddNamedError(MY_NAME, "UTP_Close(%p) was called.", socket); dbgmsg("UTP_Close(%p) was called.", socket); TR_ASSERT(false); /* FIXME: this is too much for the long term, but probably needed in the short term */ }