Example #1
0
void
tr_dhtUninit (tr_session *ss)
{
    if (session != ss)
        return;

    tr_logAddNamedDbg ("DHT", "Uninitializing DHT");

    if (dht_timer != NULL) {
        event_free (dht_timer);
        dht_timer = NULL;
    }

    /* Since we only save known good nodes, avoid erasing older data if we
       don't know enough nodes. */
    if ((tr_dhtStatus (ss, AF_INET, NULL) < TR_DHT_FIREWALLED) &&
      (tr_dhtStatus (ss, AF_INET6, NULL) < TR_DHT_FIREWALLED)) {
        tr_logAddNamedInfo ("DHT", "Not saving nodes, DHT not ready");
    } else {
        tr_variant benc;
        struct sockaddr_in sins[300];
        struct sockaddr_in6 sins6[300];
        char compact[300 * 6], compact6[300 * 18];
        char *dat_file;
        int i, j, num = 300, num6 = 300;
        int n = dht_get_nodes (sins, &num, sins6, &num6);

        tr_logAddNamedInfo ("DHT", "Saving %d (%d + %d) nodes", n, num, num6);

        j = 0;
        for (i=0; i<num; ++i) {
            memcpy (compact + j, &sins[i].sin_addr, 4);
            memcpy (compact + j + 4, &sins[i].sin_port, 2);
            j += 6;
        }
        j = 0;
        for (i=0; i<num6; ++i) {
            memcpy (compact6 + j, &sins6[i].sin6_addr, 16);
            memcpy (compact6 + j + 16, &sins6[i].sin6_port, 2);
            j += 18;
        }
        tr_variantInitDict (&benc, 3);
        tr_variantDictAddRaw (&benc, TR_KEY_id, myid, 20);
        if (num > 0)
            tr_variantDictAddRaw (&benc, TR_KEY_nodes, compact, num * 6);
        if (num6 > 0)
            tr_variantDictAddRaw (&benc, TR_KEY_nodes6, compact6, num6 * 18);
        dat_file = tr_buildPath (ss->configDir, "dht.dat", NULL);
        tr_variantToFile (&benc, TR_VARIANT_FMT_BENC, dat_file);
        tr_variantFree (&benc);
        tr_free (dat_file);
    }

    dht_uninit ();
    tr_logAddNamedDbg ("DHT", "Done uninitializing DHT");

    session = NULL;
}
Example #2
0
static void
event_callback (int s, short type UNUSED, void *sv)
{
    int rc;
    socklen_t fromlen;
    unsigned char buf[4096];
    struct sockaddr_storage from;
    tr_session *ss = sv;

    assert (tr_isSession (sv));
    assert (type == EV_READ);

    fromlen = sizeof (from);
    rc = recvfrom (s, buf, 4096 - 1, 0,
                (struct sockaddr*)&from, &fromlen);

    /* Since most packets we receive here are µTP, make quick inline
       checks for the other protocols.  The logic is as follows:
       - all DHT packets start with 'd';
       - all UDP tracker packets start with a 32-bit (!) "action", which
         is between 0 and 3;
       - the above cannot be µTP packets, since these start with a 4-bit
         version number (1). */
    if (rc > 0) {
        if (buf[0] == 'd') {
            if (tr_sessionAllowsDHT (ss)) {
                buf[rc] = '\0'; /* required by the DHT code */
                tr_dhtCallback (buf, rc, (struct sockaddr*)&from, fromlen, sv);
            }
        } else if (rc >= 8 &&
                   buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] <= 3) {
            rc = tau_handle_message (ss, buf, rc);
            if (!rc)
                tr_logAddNamedDbg ("UDP", "Couldn't parse UDP tracker packet.");
        } else {
            if (tr_sessionIsUTPEnabled (ss)) {
                rc = tr_utpPacket (buf, rc, (struct sockaddr*)&from, fromlen, ss);
                if (!rc)
                    tr_logAddNamedDbg ("UDP", "Unexpected UDP packet");
            }
        }
    }
}
Example #3
0
int
tr_cacheSetLimit (tr_cache * cache, int64_t max_bytes)
{
  char buf[128];

  cache->max_bytes = max_bytes;
  cache->max_blocks = getMaxBlocks (max_bytes);

  tr_formatter_mem_B (buf, cache->max_bytes, sizeof (buf));
  tr_logAddNamedDbg (MY_NAME, "Maximum cache size set to %s (%d blocks)", buf, cache->max_blocks);

  return cacheTrim (cache);
}
Example #4
0
static void
logVal (const char * func,
        int          ret)
{
    if (ret == NATPMP_TRYAGAIN)
        return;
    if (ret >= 0)
        tr_logAddNamedInfo (getKey (), _("%s succeeded (%d)"), func, ret);
    else
        tr_logAddNamedDbg (
             getKey (),
            "%s failed. Natpmp returned %d (%s); errno is %d (%s)",
            func, ret, strnatpmperr (ret), errno, tr_strerror (errno));
}
Example #5
0
static struct UPNPDev *
tr_upnpDiscover (int msec)
{
    struct UPNPDev * ret = NULL;

#if defined (HAVE_MINIUPNP_16)
    int err = UPNPDISCOVER_SUCCESS;
    ret = upnpDiscover (msec, NULL, NULL, 0, 0, &err);
    if (err != UPNPDISCOVER_SUCCESS)
#elif defined (HAVE_MINIUPNP_15)
    ret = upnpDiscover (msec, NULL, NULL, 0);
    if (ret == NULL)
#endif

        tr_logAddNamedDbg (getKey (), "upnpDiscover failed (errno %d - %s)", errno, tr_strerror (errno));

    return ret;
}
Example #6
0
static struct UPNPDev *
tr_upnpDiscover (int msec)
{
  struct UPNPDev * ret;
  bool have_err;

#if (MINIUPNPC_API_VERSION >= 8) /* adds ipv6 and error args */
  int err = UPNPDISCOVER_SUCCESS;
  ret = upnpDiscover (msec, NULL, NULL, 0, 0, &err);
  have_err = err != UPNPDISCOVER_SUCCESS;
#else
  ret = upnpDiscover (msec, NULL, NULL, 0);
  have_err = ret == NULL;
#endif

  if (have_err)
    tr_logAddNamedDbg (getKey (), "upnpDiscover failed (errno %d - %s)", errno, tr_strerror (errno));

  return ret;
}
Example #7
0
static int
tr_upnpAddPortMapping (const tr_upnp * handle, const char * proto, tr_port port, const char * desc)
{
    int err;
    const int old_errno = errno;
    char portStr[16];
    errno = 0;

    tr_snprintf (portStr, sizeof (portStr), "%d", (int)port);

#if (MINIUPNPC_API_VERSION >= 8)
    err = UPNP_AddPortMapping (handle->urls.controlURL, handle->data.first.servicetype, portStr, portStr, handle->lanaddr, desc, proto, NULL, NULL);
#else
    err = UPNP_AddPortMapping (handle->urls.controlURL, handle->data.first.servicetype, portStr, portStr, handle->lanaddr, desc, proto, NULL);
#endif

    if (err)
        tr_logAddNamedDbg (getKey (), "%s Port forwarding failed with error %d (errno %d - %s)", proto, err, errno, tr_strerror (errno));

    errno = old_errno;
    return err;
}
static int
pgpipe (int handles[2])
{
    SOCKET s;
    struct sockaddr_in serv_addr;
    int len = sizeof (serv_addr);

    handles[0] = handles[1] = INVALID_SOCKET;

    if ((s = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
    {
        tr_logAddDebug ("pgpipe failed to create socket: %ui", WSAGetLastError ());
        return -1;
    }

    memset (&serv_addr, 0, sizeof (serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons (0);
    serv_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
    if (bind (s, (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
    {
        tr_logAddDebug ("pgpipe failed to bind: %ui", WSAGetLastError ());
        closesocket (s);
        return -1;
    }
    if (listen (s, 1) == SOCKET_ERROR)
    {
        tr_logAddNamedDbg ("event","pgpipe failed to listen: %ui", WSAGetLastError ());
        closesocket (s);
        return -1;
    }
    if (getsockname (s, (SOCKADDR *) & serv_addr, &len) == SOCKET_ERROR)
    {
        tr_logAddDebug ("pgpipe failed to getsockname: %ui", WSAGetLastError ());
        closesocket (s);
        return -1;
    }
    if ((handles[1] = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
    {
        tr_logAddDebug ("pgpipe failed to create socket 2: %ui", WSAGetLastError ());
        closesocket (s);
        return -1;
    }

    if (connect (handles[1], (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
    {
        tr_logAddDebug ("pgpipe failed to connect socket: %ui", WSAGetLastError ());
        closesocket (s);
        return -1;
    }
    if ((handles[0] = accept (s, (SOCKADDR *) & serv_addr, &len)) == INVALID_SOCKET)
    {
        tr_logAddDebug ("pgpipe failed to accept socket: %ui", WSAGetLastError ());
        closesocket (handles[1]);
        handles[1] = INVALID_SOCKET;
        closesocket (s);
        return -1;
    }
    closesocket (s);
    return 0;
}
Example #9
0
int
tr_dhtInit (tr_session *ss)
{
    tr_variant benc;
    int rc;
    bool have_id = false;
    char * dat_file;
    uint8_t * nodes = NULL, * nodes6 = NULL;
    const uint8_t * raw;
    size_t len, len6;
    struct bootstrap_closure * cl;

    if (session) /* already initialized */
        return -1;

    tr_logAddNamedDbg ("DHT", "Initializing DHT");

    if (tr_env_key_exists ("TR_DHT_VERBOSE"))
        dht_debug = stderr;

    dat_file = tr_buildPath (ss->configDir, "dht.dat", NULL);
    rc = tr_variantFromFile (&benc, TR_VARIANT_FMT_BENC, dat_file, NULL) ? 0 : -1;
    tr_free (dat_file);
    if (rc == 0) {
        have_id = tr_variantDictFindRaw (&benc, TR_KEY_id, &raw, &len);
        if (have_id && len==20)
            memcpy (myid, raw, len);
        if (ss->udp_socket != TR_BAD_SOCKET &&
            tr_variantDictFindRaw (&benc, TR_KEY_nodes, &raw, &len) && ! (len%6)) {
                nodes = tr_memdup (raw, len);
        }
        if (ss->udp6_socket != TR_BAD_SOCKET &&
            tr_variantDictFindRaw (&benc, TR_KEY_nodes6, &raw, &len6) && ! (len6%18)) {
            nodes6 = tr_memdup (raw, len6);
        }
        tr_variantFree (&benc);
    }

    if (nodes == NULL)
        len = 0;
    if (nodes6 == NULL)
        len6 = 0;

    if (have_id)
        tr_logAddNamedInfo ("DHT", "Reusing old id");
    else {
        /* Note that DHT ids need to be distributed uniformly,
         * so it should be something truly random. */
        tr_logAddNamedInfo ("DHT", "Generating new id");
        tr_rand_buffer (myid, 20);
    }

    rc = dht_init (ss->udp_socket, ss->udp6_socket, myid, NULL);
    if (rc < 0)
        goto fail;

    session = ss;

    cl = tr_new (struct bootstrap_closure, 1);
    cl->session = session;
    cl->nodes = nodes;
    cl->nodes6 = nodes6;
    cl->len = len;
    cl->len6 = len6;
    tr_threadNew (dht_bootstrap, cl);

    dht_timer = evtimer_new (session->event_base, timer_callback, session);
    tr_timerAdd (dht_timer, 0, tr_rand_int_weak (1000000));

    tr_logAddNamedDbg ("DHT", "DHT initialized");

    return 1;

 fail:
    tr_logAddNamedDbg ("DHT", "DHT initialization failed (errno = %d)", errno);
    session = NULL;
    return -1;
}
Example #10
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_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");
}
Example #11
0
int
tr_upnpPulse (tr_upnp * handle,
              int       port,
              int       isEnabled,
              int       doPortCheck)
{
    int ret;

    if (isEnabled && (handle->state == TR_UPNP_DISCOVER))
    {
        struct UPNPDev * devlist;

        devlist = tr_upnpDiscover (2000);

        errno = 0;
        if (UPNP_GetValidIGD (devlist, &handle->urls, &handle->data,
                             handle->lanaddr, sizeof (handle->lanaddr)) == UPNP_IGD_VALID_CONNECTED)
        {
            tr_logAddNamedInfo (getKey (), _(
                         "Found Internet Gateway Device \"%s\""),
                     handle->urls.controlURL);
            tr_logAddNamedInfo (getKey (), _(
                         "Local Address is \"%s\""), handle->lanaddr);
            handle->state = TR_UPNP_IDLE;
            handle->hasDiscovered = true;
        }
        else
        {
            handle->state = TR_UPNP_ERR;
            tr_logAddNamedDbg (
                 getKey (), "UPNP_GetValidIGD failed (errno %d - %s)",
                errno,
                tr_strerror (errno));
            tr_logAddNamedDbg (
                getKey (),
                "If your router supports UPnP, please make sure UPnP is enabled!");
        }
        freeUPNPDevlist (devlist);
    }

    if (handle->state == TR_UPNP_IDLE)
    {
        if (handle->isMapped && (!isEnabled || (handle->port != port)))
            handle->state = TR_UPNP_UNMAP;
    }

    if (isEnabled && handle->isMapped && doPortCheck)
    {
        if ((tr_upnpGetSpecificPortMappingEntry (handle, "TCP") != UPNPCOMMAND_SUCCESS) ||
          (tr_upnpGetSpecificPortMappingEntry (handle, "UDP") != UPNPCOMMAND_SUCCESS))
        {
            tr_logAddNamedInfo (getKey (), _("Port %d isn't forwarded"), handle->port);
            handle->isMapped = false;
        }
    }

    if (handle->state == TR_UPNP_UNMAP)
    {
        tr_upnpDeletePortMapping (handle, "TCP", handle->port);
        tr_upnpDeletePortMapping (handle, "UDP", handle->port);

        tr_logAddNamedInfo (getKey (),
                 _("Stopping port forwarding through \"%s\", service \"%s\""),
                 handle->urls.controlURL, handle->data.first.servicetype);

        handle->isMapped = 0;
        handle->state = TR_UPNP_IDLE;
        handle->port = -1;
    }

    if (handle->state == TR_UPNP_IDLE)
    {
        if (isEnabled && !handle->isMapped)
            handle->state = TR_UPNP_MAP;
    }

    if (handle->state == TR_UPNP_MAP)
    {
        int  err_tcp = -1;
        int  err_udp = -1;
        errno = 0;

        if (!handle->urls.controlURL || !handle->data.first.servicetype)
            handle->isMapped = 0;
        else
        {
            char desc[64];
            tr_snprintf (desc, sizeof (desc), "%s at %d", TR_NAME, port);

            err_tcp = tr_upnpAddPortMapping (handle, "TCP", port, desc);
            err_udp = tr_upnpAddPortMapping (handle, "UDP", port, desc);

            handle->isMapped = !err_tcp | !err_udp;
        }
        tr_logAddNamedInfo (getKey (),
                 _("Port forwarding through \"%s\", service \"%s\". (local address: %s:%d)"),
                 handle->urls.controlURL, handle->data.first.servicetype,
                 handle->lanaddr, port);
        if (handle->isMapped)
        {
            tr_logAddNamedInfo (getKey (), "%s", _("Port forwarding successful!"));
            handle->port = port;
            handle->state = TR_UPNP_IDLE;
        }
        else
        {
            tr_logAddNamedDbg (getKey (), "If your router supports UPnP, please make sure UPnP is enabled!");
            handle->port = -1;
            handle->state = TR_UPNP_ERR;
        }
    }

    switch (handle->state)
    {
        case TR_UPNP_DISCOVER:
            ret = TR_PORT_UNMAPPED; break;

        case TR_UPNP_MAP:
            ret = TR_PORT_MAPPING; break;

        case TR_UPNP_UNMAP:
            ret = TR_PORT_UNMAPPING; break;

        case TR_UPNP_IDLE:
            ret = handle->isMapped ? TR_PORT_MAPPED
                  : TR_PORT_UNMAPPED; break;

        default:
            ret = TR_PORT_ERROR; break;
    }

    return ret;
}