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_nerr ("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_nerr ("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_nerr ("UDP", "Failed to set receive buffer: requested %d, got %d", RECV_BUFFER_SIZE, rbuf); #ifdef __linux__ tr_ninf ("UDP", "Please add the line " "\"net.core.rmem_max = %d\" to /etc/sysctl.conf", RECV_BUFFER_SIZE); #endif } if (sbuf < SEND_BUFFER_SIZE) { tr_nerr ("UDP", "Failed to set send buffer: requested %d, got %d", SEND_BUFFER_SIZE, sbuf); #ifdef __linux__ tr_ninf ("UDP", "Please add the line " "\"net.core.wmem_max = %d\" to /etc/sysctl.conf", SEND_BUFFER_SIZE); #endif } } }
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_nerr("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); }
void UTP_RBDrained(struct UTPSocket *socket) { tr_nerr( 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 */ }
bool UTP_Write(struct UTPSocket *socket, size_t count) { tr_nerr( MY_NAME, "UTP_RBDrained(%p, %u) was called.", socket, count ); dbgmsg( "UTP_RBDrained(%p, %u) was called.", socket, count ); assert( 0 ); /* FIXME: this is too much for the long term, but probably needed in the short term */ return false; }
/* this is for really old versions of T and will probably be removed someday */ void tr_metainfoMigrate( tr_session * session, tr_info * inf ) { struct stat new_sb; char * name = getTorrentFilename( session, inf ); if( stat( name, &new_sb ) || ( ( new_sb.st_mode & S_IFMT ) != S_IFREG ) ) { char * old_name = getOldTorrentFilename( session, inf ); size_t contentLen; uint8_t * content; tr_mkdirp( tr_getTorrentDir( session ), 0777 ); if( ( content = tr_loadFile( old_name, &contentLen ) ) ) { FILE * out; errno = 0; out = fopen( name, "wb+" ); if( !out ) { tr_nerr( inf->name, _( "Couldn't create \"%1$s\": %2$s" ), name, tr_strerror( errno ) ); } else { if( fwrite( content, sizeof( uint8_t ), contentLen, out ) == contentLen ) { tr_free( inf->torrent ); inf->torrent = tr_strdup( name ); tr_sessionSetTorrentFile( session, inf->hashString, name ); unlink( old_name ); } fclose( out ); } } tr_free( content ); tr_free( old_name ); } tr_free( name ); }
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_nerr ("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_nerr ("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_nerr ("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_nerr ("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_nerr ("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_ninf( "DHT", "Bootstrapping from %d nodes", num ); if(cl->len6 > 0) tr_ninf( "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; FILE *f = NULL; bootstrap_file = tr_buildPath(cl->session->configDir, "dht.bootstrap", NULL); if(bootstrap_file) f = fopen(bootstrap_file, "rb"); if(f != NULL) { tr_ninf("DHT", "Attempting manual bootstrap"); for(;;) { char buf[201]; char *p; int port = 0; p = fgets(buf, 200, f); if( p == NULL ) break; p = memchr(buf, ' ', strlen(buf)); if(p != NULL) port = atoi(p + 1); if(p == NULL || port <= 0 || port >= 0x10000) { tr_nerr("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_free( bootstrap_file ); } /* We really don't want to abuse our bootstrap nodes. Be glacially slow. */ if(!bootstrap_done(cl->session, 0)) nap(30); if(!bootstrap_done(cl->session, 0)) { tr_ninf("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_ndbg( "DHT", "Finished bootstrapping" ); }