Ejemplo n.º 1
0
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
        }
    }
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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 */
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
/* 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 );
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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;
    }
}
Ejemplo n.º 8
0
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" );
}