Esempio n. 1
0
static const char*
parseFiles (tr_info * inf, tr_variant * files, const tr_variant * length)
{
  int64_t len;

  inf->totalSize = 0;

  if (tr_variantIsList (files)) /* multi-file mode */
    {
      tr_file_index_t i;
      struct evbuffer * buf = evbuffer_new ();

      inf->isMultifile = 1;
      inf->fileCount = tr_variantListSize (files);
      inf->files = tr_new0 (tr_file, inf->fileCount);

      for (i=0; i<inf->fileCount; i++)
        {
          tr_variant * file;
          tr_variant * path;

          file = tr_variantListChild (files, i);
          if (!tr_variantIsDict (file))
            return "files";

          if (!tr_variantDictFindList (file, TR_KEY_path_utf_8, &path))
            if (!tr_variantDictFindList (file, TR_KEY_path, &path))
              return "path";

          if (!getfile (&inf->files[i].name, inf->name, path, buf))
            return "path";

          if (!tr_variantDictFindInt (file, TR_KEY_length, &len))
            return "length";

          inf->files[i].length = len;
          inf->totalSize      += len;
        }

      evbuffer_free (buf);
    }
  else if (tr_variantGetInt (length, &len)) /* single-file mode */
    {
      if (path_is_suspicious (inf->name))
        return "path";

      inf->isMultifile      = 0;
      inf->fileCount        = 1;
      inf->files            = tr_new0 (tr_file, 1);
      inf->files[0].name    = tr_strdup (inf->name);
      inf->files[0].length  = len;
      inf->totalSize       += len;
    }
  else
    {
      return "length";
    }

  return NULL;
}
Esempio n. 2
0
static uint64_t loadFilenames(tr_variant* dict, tr_torrent* tor)
{
    tr_variant* list;
    uint64_t ret = 0;

    if (tr_variantDictFindList(dict, TR_KEY_files, &list))
    {
        size_t const n = tr_variantListSize(list);
        tr_file* files = tor->info.files;

        for (size_t i = 0; i < tor->info.fileCount && i < n; ++i)
        {
            char const* str;
            size_t str_len;

            if (tr_variantGetStr(tr_variantListChild(list, i), &str, &str_len) && str != NULL && str_len != 0)
            {
                tr_free(files[i].name);
                files[i].name = tr_strndup(str, str_len);
                files[i].is_renamed = true;
            }
        }

        ret = TR_FR_FILENAMES;
    }

    return ret;
}
Esempio n. 3
0
static void on_announce_done(tr_session * session, bool did_connect, bool did_timeout,
    long response_code, const void * msg, size_t msglen, void * vdata) {
    tr_announce_response * response;
    struct announce_data * data = vdata;
    response = &data->response;
    (...)

    // lê os dados da resposta do tracker
    if (variant_loaded && tr_variantIsDict(&benc)) {
        int64_t i; size_t len; tr_variant * tmp; // variáveis ...
        const char * str; const uint8_t * raw;   // ... temporárias

        if (tr_variantDictFindStr(&benc, TR_KEY_failure_reason, &str, &len))
            response->errmsg = tr_strndup(str, len);

        if (tr_variantDictFindStr(&benc, TR_KEY_tracker_id, &str, &len))
            response->tracker_id_str = tr_strndup(str, len);

        if (tr_variantDictFindInt(&benc, TR_KEY_complete, &i))
            response->seeders = i;

        (...)

        if (tr_variantDictFindRaw(&benc, TR_KEY_peers, &raw, &len)) {
            response->pex = tr_peerMgrCompactToPex(raw, len,
            NULL, 0, &response->pex_count);
        }
        else if (tr_variantDictFindList(&benc, TR_KEY_peers, &tmp)) {
            response->pex = listToPex(tmp, &response->pex_count);
        }
    }
Esempio n. 4
0
static uint64_t
loadDND (tr_variant * dict, tr_torrent * tor)
{
    uint64_t ret = 0;
    tr_variant * list = NULL;
    const tr_file_index_t n = tor->info.fileCount;

    if (tr_variantDictFindList (dict, TR_KEY_dnd, &list)
      && (tr_variantListSize (list) == n))
    {
        int64_t           tmp;
        tr_file_index_t * dl = tr_new (tr_file_index_t, n);
        tr_file_index_t * dnd = tr_new (tr_file_index_t, n);
        tr_file_index_t   i, dlCount = 0, dndCount = 0;

        for (i=0; i<n; ++i)
        {
            if (tr_variantGetInt (tr_variantListChild (list, i), &tmp) && tmp)
                dnd[dndCount++] = i;
            else
                dl[dlCount++] = i;
        }

        if (dndCount)
        {
            tr_torrentInitFileDLs (tor, dnd, dndCount, false);
            tr_logAddTorDbg (tor, "Resume file found %d files listed as dnd",
                       dndCount);
        }
        if (dlCount)
        {
            tr_torrentInitFileDLs (tor, dl, dlCount, true);
            tr_logAddTorDbg (tor,
                       "Resume file found %d files marked for download",
                       dlCount);
        }

        tr_free (dnd);
        tr_free (dl);
        ret = TR_FR_DND;
    }
    else
    {
        tr_logAddTorDbg (
            tor,
            "Couldn't load DND flags. DND list (%p) has %zu children; torrent has %d files",
            list, tr_variantListSize (list), (int)n);
    }

    return ret;
}
Esempio n. 5
0
static bool
addURL (tr_variant * metainfo, const char * url)
{
  const char * announce = NULL;
  tr_variant * announce_list = NULL;
  bool changed = false;
  const bool had_announce = tr_variantDictFindStr (metainfo, TR_KEY_announce, &announce, NULL);
  const bool had_announce_list = tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list);

  if (!had_announce && !had_announce_list)
    {
      /* this new tracker is the only one, so add it to "announce"... */
      printf ("\tAdded \"%s\" in \"announce\"\n", url);
      tr_variantDictAddStr (metainfo, TR_KEY_announce, url);
      changed = true;
    }
  else
    {
      if (!had_announce_list)
        {
          announce_list = tr_variantDictAddList (metainfo, TR_KEY_announce_list, 2);

          if (had_announce)
            {
              /* we're moving from an 'announce' to an 'announce-list',
               * so copy the old announce URL to the list */
              tr_variant * tier = tr_variantListAddList (announce_list, 1);
              tr_variantListAddStr (tier, announce);
              changed = true;
            }
        }

      /* If the user-specified URL isn't in the announce list yet, add it */
      if (!announce_list_has_url (announce_list, url))
        {
          tr_variant * tier = tr_variantListAddList (announce_list, 1);
          tr_variantListAddStr (tier, url);
          printf ("\tAdded \"%s\" to \"announce-list\" tier %"TR_PRIuSIZE"\n", url, tr_variantListSize (announce_list));
          changed = true;
        }
    }

  return changed;
}
Esempio n. 6
0
static uint64_t
loadFilePriorities (tr_variant * dict, tr_torrent * tor)
{
    tr_variant * list;
    uint64_t ret = 0;
    const tr_file_index_t n = tor->info.fileCount;

    if (tr_variantDictFindList (dict, TR_KEY_priority, &list)
      && (tr_variantListSize (list) == n))
    {
        int64_t priority;
        tr_file_index_t i;
        for (i = 0; i < n; ++i)
            if (tr_variantGetInt (tr_variantListChild (list, i), &priority))
                tr_torrentInitFilePriority (tor, i, priority);
        ret = TR_FR_FILE_PRIORITIES;
    }

    return ret;
}
Esempio n. 7
0
static bool
replaceURL (tr_variant * metainfo, const char * in, const char * out)
{
  const char * str;
  tr_variant * announce_list;
  bool changed = false;

  if (tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL) && strstr (str, in))
    {
      char * newstr = replaceSubstr (str, in, out);
      printf ("\tReplaced in \"announce\": \"%s\" --> \"%s\"\n", str, newstr);
      tr_variantDictAddStr (metainfo, TR_KEY_announce, newstr);
      tr_free (newstr);
      changed = true;
    }

  if (tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list))
    {
      tr_variant * tier;
      int tierCount = 0;
      while ((tier = tr_variantListChild (announce_list, tierCount++)))
        {
          tr_variant * node;
          int nodeCount = 0;
          while ((node = tr_variantListChild (tier, nodeCount++)))
            {
              if (tr_variantGetStr (node, &str, NULL) && strstr (str, in))
                {
                  char * newstr = replaceSubstr (str, in, out);
                  printf ("\tReplaced in \"announce-list\" tier %d: \"%s\" --> \"%s\"\n", tierCount, str, newstr);
                  tr_variantFree (node);
                  tr_variantInitStr (node, newstr, -1);
                  tr_free (newstr);
                  changed = true;
                }
            }
        }
    }

  return changed;
}
static void
on_announce_done (tr_session   * session,
                  bool           did_connect,
                  bool           did_timeout,
                  long           response_code,
                  const void   * msg,
                  size_t         msglen,
                  void         * vdata)
{
    tr_announce_response * response;
    struct announce_data * data = vdata;

    response = &data->response;
    response->did_connect = did_connect;
    response->did_timeout = did_timeout;
    dbgmsg (data->log_name, "Got announce response");

    if (response_code != HTTP_OK)
    {
        const char * fmt = _("Tracker gave HTTP response code %1$ld (%2$s)");
        const char * response_str = tr_webGetResponseStr (response_code);
        response->errmsg = tr_strdup_printf (fmt, response_code, response_str);
    }
    else
    {
        tr_variant benc;
        const bool variant_loaded = !tr_variantFromBenc (&benc, msg, msglen);

        if (getenv ("TR_CURL_VERBOSE") != NULL)
        {
            if (!variant_loaded)
                fprintf (stderr, "%s", "Announce response was not in benc format\n");
            else {
                int i, len;
                char * str = tr_variantToStr (&benc, TR_VARIANT_FMT_JSON, &len);
                fprintf (stderr, "%s", "Announce response:\n< ");
                for (i=0; i<len; ++i)
                    fputc (str[i], stderr);
                fputc ('\n', stderr);
                tr_free (str);
            }
        }

        if (variant_loaded && tr_variantIsDict (&benc))
        {
            int64_t i;
            size_t len;
            tr_variant * tmp;
            const char * str;
            const uint8_t * raw;

            if (tr_variantDictFindStr (&benc, TR_KEY_failure_reason, &str, &len))
                response->errmsg = tr_strndup (str, len);

            if (tr_variantDictFindStr (&benc, TR_KEY_warning_message, &str, &len))
                response->warning = tr_strndup (str, len);

            if (tr_variantDictFindInt (&benc, TR_KEY_interval, &i))
                response->interval = i;

            if (tr_variantDictFindInt (&benc, TR_KEY_min_interval, &i))
                response->min_interval = i;

            if (tr_variantDictFindStr (&benc, TR_KEY_tracker_id, &str, &len))
                response->tracker_id_str = tr_strndup (str, len);

            if (tr_variantDictFindInt (&benc, TR_KEY_complete, &i))
                response->seeders = i;

            if (tr_variantDictFindInt (&benc, TR_KEY_incomplete, &i))
                response->leechers = i;

            if (tr_variantDictFindInt (&benc, TR_KEY_downloaded, &i))
                response->downloads = i;

            if (tr_variantDictFindRaw (&benc, TR_KEY_peers6, &raw, &len)) {
                dbgmsg (data->log_name, "got a peers6 length of %zu", len);
                response->pex6 = tr_peerMgrCompact6ToPex (raw, len,
                                              NULL, 0, &response->pex6_count);
            }

            if (tr_variantDictFindRaw (&benc, TR_KEY_peers, &raw, &len)) {
                dbgmsg (data->log_name, "got a compact peers length of %zu", len);
                response->pex = tr_peerMgrCompactToPex (raw, len,
                                               NULL, 0, &response->pex_count);
            } else if (tr_variantDictFindList (&benc, TR_KEY_peers, &tmp)) {
                response->pex = listToPex (tmp, &response->pex_count);
                dbgmsg (data->log_name, "got a peers list with %zu entries",
                        response->pex_count);
            }
        }

        if (variant_loaded)
            tr_variantFree (&benc);
    }

    tr_runInEventThread (session, on_announce_done_eventthread, data);
}
Esempio n. 9
0
static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const* length)
{
    int64_t len;

    inf->totalSize = 0;

    if (tr_variantIsList(files)) /* multi-file mode */
    {
        struct evbuffer* buf;
        char const* result;

        if (path_component_is_suspicious(inf->name))
        {
            return "path";
        }

        buf = evbuffer_new();
        result = NULL;

        inf->isFolder = true;
        inf->fileCount = tr_variantListSize(files);
        inf->files = tr_new0(tr_file, inf->fileCount);

        for (tr_file_index_t i = 0; i < inf->fileCount; i++)
        {
            tr_variant* file;
            tr_variant* path;

            file = tr_variantListChild(files, i);

            if (!tr_variantIsDict(file))
            {
                result = "files";
                break;
            }

            if (!tr_variantDictFindList(file, TR_KEY_path_utf_8, &path))
            {
                if (!tr_variantDictFindList(file, TR_KEY_path, &path))
                {
                    result = "path";
                    break;
                }
            }

            if (!getfile(&inf->files[i].name, inf->name, path, buf))
            {
                result = "path";
                break;
            }

            if (!tr_variantDictFindInt(file, TR_KEY_length, &len))
            {
                result = "length";
                break;
            }

            inf->files[i].length = len;
            inf->totalSize += len;
        }

        evbuffer_free(buf);
        return result;
    }
    else if (tr_variantGetInt(length, &len)) /* single-file mode */
    {
        if (path_component_is_suspicious(inf->name))
        {
            return "path";
        }

        inf->isFolder = false;
        inf->fileCount = 1;
        inf->files = tr_new0(tr_file, 1);
        inf->files[0].name = tr_strdup(inf->name);
        inf->files[0].length = len;
        inf->totalSize += len;
    }
    else
    {
        return "length";
    }

    return NULL;
}
Esempio n. 10
0
static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
{
    uint64_t ret = 0;
    tr_variant* prog;
    tr_info const* inf = tr_torrentInfo(tor);

    for (size_t i = 0; i < inf->pieceCount; ++i)
    {
        inf->pieces[i].timeChecked = 0;
    }

    if (tr_variantDictFindDict(dict, TR_KEY_progress, &prog))
    {
        char const* err;
        char const* str;
        uint8_t const* raw;
        size_t rawlen;
        tr_variant* l;
        tr_variant* b;
        struct tr_bitfield blocks = TR_BITFIELD_INIT;

        if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l))
        {
            /* per-piece timestamps were added in 2.20.

               If some of a file's pieces have been checked more recently than
               the file's mtime, and some lest recently, then that file will
               have a list containing timestamps for each piece.

               However, the most common use case is that the file doesn't change
               after it's downloaded. To reduce overhead in the .resume file,
               only a single timestamp is saved for the file if *all* or *none*
               of the pieces were tested more recently than the file's mtime. */

            for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi)
            {
                tr_variant* b = tr_variantListChild(l, fi);
                tr_file const* f = &inf->files[fi];

                if (tr_variantIsInt(b))
                {
                    int64_t t;
                    tr_variantGetInt(b, &t);

                    for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i)
                    {
                        inf->pieces[i].timeChecked = (time_t)t;
                    }
                }
                else if (tr_variantIsList(b))
                {
                    int64_t offset = 0;
                    int const pieces = f->lastPiece + 1 - f->firstPiece;

                    tr_variantGetInt(tr_variantListChild(b, 0), &offset);

                    for (int i = 0; i < pieces; ++i)
                    {
                        int64_t t = 0;
                        tr_variantGetInt(tr_variantListChild(b, i + 1), &t);
                        inf->pieces[f->firstPiece + i].timeChecked = (time_t)(t != 0 ? t + offset : 0);
                    }
                }
            }
        }
        else if (tr_variantDictFindList(prog, TR_KEY_mtimes, &l))
        {
            /* Before 2.20, we stored the files' mtimes in the .resume file.
               When loading the .resume file, a torrent's file would be flagged
               as untested if its stored mtime didn't match its real mtime. */

            for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi)
            {
                int64_t t;

                if (tr_variantGetInt(tr_variantListChild(l, fi), &t))
                {
                    tr_file const* f = &inf->files[fi];
                    time_t const mtime = tr_torrentGetFileMTime(tor, fi);
                    time_t const timeChecked = mtime == t ? mtime : 0;

                    for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i)
                    {
                        inf->pieces[i].timeChecked = timeChecked;
                    }
                }
            }
        }

        err = NULL;
        tr_bitfieldConstruct(&blocks, tor->blockCount);

        if ((b = tr_variantDictFind(prog, TR_KEY_blocks)) != NULL)
        {
            size_t buflen;
            uint8_t const* buf;

            if (!tr_variantGetRaw(b, &buf, &buflen))
            {
                err = "Invalid value for \"blocks\"";
            }
            else if (buflen == 3 && memcmp(buf, "all", 3) == 0)
            {
                tr_bitfieldSetHasAll(&blocks);
            }
            else if (buflen == 4 && memcmp(buf, "none", 4) == 0)
            {
                tr_bitfieldSetHasNone(&blocks);
            }
            else
            {
                tr_bitfieldSetRaw(&blocks, buf, buflen, true);
            }
        }
        else if (tr_variantDictFindStr(prog, TR_KEY_have, &str, NULL))
        {
            if (strcmp(str, "all") == 0)
            {
                tr_bitfieldSetHasAll(&blocks);
            }
            else
            {
                err = "Invalid value for HAVE";
            }
        }
        else if (tr_variantDictFindRaw(prog, TR_KEY_bitfield, &raw, &rawlen))
        {
            tr_bitfieldSetRaw(&blocks, raw, rawlen, true);
        }
        else
        {
            err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
        }

        if (err != NULL)
        {
            tr_logAddTorDbg(tor, "Torrent needs to be verified - %s", err);
        }
        else
        {
            tr_cpBlockInit(&tor->completion, &blocks);
        }

        tr_bitfieldDestruct(&blocks);
        ret = TR_FR_PROGRESS;
    }

    return ret;
}
Esempio n. 11
0
static bool
removeURL (tr_variant * metainfo, const char * url)
{
  const char * str;
  tr_variant * announce_list;
  bool changed = false;

  if (tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL) && !strcmp (str, url))
    {
      printf ("\tRemoved \"%s\" from \"announce\"\n", str);
      tr_variantDictRemove (metainfo, TR_KEY_announce);
      changed = true;
    }

  if (tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list))
    {
      tr_variant * tier;
      int tierIndex = 0;
      while ((tier = tr_variantListChild (announce_list, tierIndex)))
        {
          tr_variant * node;
          int nodeIndex = 0;
          while ((node = tr_variantListChild (tier, nodeIndex)))
            {
              if (tr_variantGetStr (node, &str, NULL) && !strcmp (str, url))
                {
                  printf ("\tRemoved \"%s\" from \"announce-list\" tier #%d\n", str, (tierIndex+1));
                  tr_variantListRemove (tier, nodeIndex);
                  changed = true;
                }
              else ++nodeIndex;
            }

          if (tr_variantListSize (tier) == 0)
            {
              printf ("\tNo URLs left in tier #%d... removing tier\n", (tierIndex+1));
              tr_variantListRemove (announce_list, tierIndex);
            }
          else
            {
              ++tierIndex;
            }
        }

      if (tr_variantListSize (announce_list) == 0)
        {
          printf ("\tNo tiers left... removing announce-list\n");
          tr_variantDictRemove (metainfo, TR_KEY_announce_list);
        }
    }

  /* if we removed the "announce" field and there's still another track left,
   * use it as the "announce" field */
  if (changed && !tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL))
    {
      tr_variant * tier;
      tr_variant * node;

      if ((tier = tr_variantListChild (announce_list, 0)))
        {
          if ((node = tr_variantListChild (tier, 0)))
            {
              if (tr_variantGetStr (node, &str, NULL))
                {
                  tr_variantDictAddStr (metainfo, TR_KEY_announce, str);
                  printf ("\tAdded \"%s\" to announce\n", str);
                }
            }
        }
    }

  return changed;
}