Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
/**
 * @brief Announce the given torrent on the local network
 *
 * @param[in] t Torrent to announce
 * @return Returns true on success
 *
 * Send a query for torrent t out to the LPD multicast group (or the LAN, for that
 * matter). A listening client on the same network might react by adding us to his
 * peer pool for torrent t.
 */
bool tr_lpdSendAnnounce(const tr_torrent* t) {
    size_t i;
    const char fmt[] = "BT-SEARCH * HTTP/1.1\r\n" // BT-SEARCH * HTTP/1.1
    "Host: %s:%u\r\n"                             // Host: 239.192.152.143:6771
    "Port: %u\r\n"                                // Port: <porta do Transmission>
    "Infohash: %s\r\n"                            // Infohash: <hash do torrent>
    "\r\n"
    "\r\n";

    // info_hash do torrent
    char hashString[lengthof(t->info.hashString)];

    // mensagem de announce multicast montada
    char query[lpd_maxDatagramLength + 1] = { };

    (...)

    /* prepare a zero-terminated announce message */
    tr_snprintf(query, lpd_maxDatagramLength + 1, fmt, (...), "239.192.152.143", 6771,
        lpd_port, hashString); // porta de conexão do Transmission e hash do torrent

    /* actually send the query out using [lpd_socket2] */
    {
        const int len = strlen(query);

        /* destination address info has already been set up in tr_lpdInit (),
         * so we refrain from preparing another sockaddr_in here */
        int res = sendto(lpd_socket2, query, len, 0,
                (const struct sockaddr*) &lpd_mcastAddr, sizeof lpd_mcastAddr);

        if (res != len) return false;
    }
    tr_logAddTorDbg(t, "LPD announce message away");
    return true;
}
Ejemplo n.º 3
0
static uint64_t loadPeers(tr_variant* dict, tr_torrent* tor)
{
    uint8_t const* str;
    size_t len;
    uint64_t ret = 0;

    if (tr_variantDictFindRaw(dict, TR_KEY_peers2, &str, &len))
    {
        int const numAdded = addPeers(tor, str, len);
        tr_logAddTorDbg(tor, "Loaded %d IPv4 peers from resume file", numAdded);
        ret = TR_FR_PEERS;
    }

    if (tr_variantDictFindRaw(dict, TR_KEY_peers2_6, &str, &len))
    {
        int const numAdded = addPeers(tor, str, len);
        tr_logAddTorDbg(tor, "Loaded %d IPv6 peers from resume file", numAdded);
        ret = TR_FR_PEERS;
    }

    return ret;
}
Ejemplo n.º 4
0
static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad)
{
    TR_ASSERT(tr_isTorrent(tor));

    size_t len;
    int64_t i;
    char const* str;
    char* filename;
    tr_variant top;
    bool boolVal;
    uint64_t fieldsLoaded = 0;
    bool const wasDirty = tor->isDirty;
    tr_error* error = NULL;

    filename = getResumeFilename(tor);

    if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error))
    {
        tr_logAddTorDbg(tor, "Couldn't read \"%s\": %s", filename, error->message);
        tr_error_free(error);

        tr_free(filename);
        return fieldsLoaded;
    }

    tr_logAddTorDbg(tor, "Read resume file \"%s\"", filename);

    if ((fieldsToLoad & TR_FR_CORRUPT) != 0 && tr_variantDictFindInt(&top, TR_KEY_corrupt, &i))
    {
        tor->corruptPrev = i;
        fieldsLoaded |= TR_FR_CORRUPT;
    }

    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR)) != 0 &&
        tr_variantDictFindStr(&top, TR_KEY_destination, &str, &len) && str != NULL && *str != '\0')
    {
        bool const is_current_dir = tor->currentDir == tor->downloadDir;
        tr_free(tor->downloadDir);
        tor->downloadDir = tr_strndup(str, len);

        if (is_current_dir)
        {
            tor->currentDir = tor->downloadDir;
        }

        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    }

    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR)) != 0 &&
        tr_variantDictFindStr(&top, TR_KEY_incomplete_dir, &str, &len) && str != NULL && *str != '\0')
    {
        bool const is_current_dir = tor->currentDir == tor->incompleteDir;
        tr_free(tor->incompleteDir);
        tor->incompleteDir = tr_strndup(str, len);

        if (is_current_dir)
        {
            tor->currentDir = tor->incompleteDir;
        }

        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
    }

    if ((fieldsToLoad & TR_FR_DOWNLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloaded, &i))
    {
        tor->downloadedPrev = i;
        fieldsLoaded |= TR_FR_DOWNLOADED;
    }

    if ((fieldsToLoad & TR_FR_UPLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_uploaded, &i))
    {
        tor->uploadedPrev = i;
        fieldsLoaded |= TR_FR_UPLOADED;
    }

    if ((fieldsToLoad & TR_FR_MAX_PEERS) != 0 && tr_variantDictFindInt(&top, TR_KEY_max_peers, &i))
    {
        tor->maxConnectedPeers = i;
        fieldsLoaded |= TR_FR_MAX_PEERS;
    }

    if ((fieldsToLoad & TR_FR_RUN) != 0 && tr_variantDictFindBool(&top, TR_KEY_paused, &boolVal))
    {
        tor->isRunning = !boolVal;
        fieldsLoaded |= TR_FR_RUN;
    }

    if ((fieldsToLoad & TR_FR_ADDED_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_added_date, &i))
    {
        tor->addedDate = i;
        fieldsLoaded |= TR_FR_ADDED_DATE;
    }

    if ((fieldsToLoad & TR_FR_DONE_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_done_date, &i))
    {
        tor->doneDate = i;
        fieldsLoaded |= TR_FR_DONE_DATE;
    }

    if ((fieldsToLoad & TR_FR_ACTIVITY_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_activity_date, &i))
    {
        tr_torrentSetActivityDate(tor, i);
        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
    }

    if ((fieldsToLoad & TR_FR_TIME_SEEDING) != 0 && tr_variantDictFindInt(&top, TR_KEY_seeding_time_seconds, &i))
    {
        tor->secondsSeeding = i;
        fieldsLoaded |= TR_FR_TIME_SEEDING;
    }

    if ((fieldsToLoad & TR_FR_TIME_DOWNLOADING) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloading_time_seconds, &i))
    {
        tor->secondsDownloading = i;
        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
    }

    if ((fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY) != 0 &&
        tr_variantDictFindInt(&top, TR_KEY_bandwidth_priority, &i) && tr_isPriority(i))
    {
        tr_torrentSetPriority(tor, i);
        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
    }

    if ((fieldsToLoad & TR_FR_PEERS) != 0)
    {
        fieldsLoaded |= loadPeers(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_FILE_PRIORITIES) != 0)
    {
        fieldsLoaded |= loadFilePriorities(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_PROGRESS) != 0)
    {
        fieldsLoaded |= loadProgress(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_DND) != 0)
    {
        fieldsLoaded |= loadDND(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_SPEEDLIMIT) != 0)
    {
        fieldsLoaded |= loadSpeedLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_RATIOLIMIT) != 0)
    {
        fieldsLoaded |= loadRatioLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_IDLELIMIT) != 0)
    {
        fieldsLoaded |= loadIdleLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_FILENAMES) != 0)
    {
        fieldsLoaded |= loadFilenames(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_NAME) != 0)
    {
        fieldsLoaded |= loadName(&top, tor);
    }

    /* loading the resume file triggers of a lot of changes,
     * but none of them needs to trigger a re-saving of the
     * same resume information... */
    tor->isDirty = wasDirty;

    tr_variantFree(&top);
    tr_free(filename);
    return fieldsLoaded;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
{
    time_t end;
    tr_sha1_ctx_t sha;
    tr_sys_file_t fd = TR_BAD_SYS_FILE;
    uint64_t filePos = 0;
    bool changed = false;
    bool hadPiece = false;
    time_t lastSleptAt = 0;
    uint32_t piecePos = 0;
    tr_file_index_t fileIndex = 0;
    tr_file_index_t prevFileIndex = !fileIndex;
    tr_piece_index_t pieceIndex = 0;
    time_t const begin = tr_time();
    size_t const buflen = 1024 * 128; /* 128 KiB buffer */
    uint8_t* buffer = tr_valloc(buflen);

    sha = tr_sha1_init();

    tr_logAddTorDbg(tor, "%s", "verifying torrent...");
    tr_torrentSetChecked(tor, 0);

    while (!*stopFlag && pieceIndex < tor->info.pieceCount)
    {
        uint64_t leftInPiece;
        uint64_t bytesThisPass;
        uint64_t leftInFile;
        tr_file const* file = &tor->info.files[fileIndex];

        /* if we're starting a new piece... */
        if (piecePos == 0)
        {
            hadPiece = tr_torrentPieceIsComplete(tor, pieceIndex);
        }

        /* if we're starting a new file... */
        if (filePos == 0 && fd == TR_BAD_SYS_FILE && fileIndex != prevFileIndex)
        {
            char* filename = tr_torrentFindFile(tor, fileIndex);
            fd = filename == NULL ? TR_BAD_SYS_FILE : tr_sys_file_open(filename, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0,
                NULL);
            tr_free(filename);
            prevFileIndex = fileIndex;
        }

        /* figure out how much we can read this pass */
        leftInPiece = tr_torPieceCountBytes(tor, pieceIndex) - piecePos;
        leftInFile = file->length - filePos;
        bytesThisPass = MIN(leftInFile, leftInPiece);
        bytesThisPass = MIN(bytesThisPass, buflen);

        /* read a bit */
        if (fd != TR_BAD_SYS_FILE)
        {
            uint64_t numRead;

            if (tr_sys_file_read_at(fd, buffer, bytesThisPass, filePos, &numRead, NULL) && numRead > 0)
            {
                bytesThisPass = numRead;
                tr_sha1_update(sha, buffer, bytesThisPass);
#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
                (void)posix_fadvise(fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED);
#endif
            }
        }

        /* move our offsets */
        leftInPiece -= bytesThisPass;
        leftInFile -= bytesThisPass;
        piecePos += bytesThisPass;
        filePos += bytesThisPass;

        /* if we're finishing a piece... */
        if (leftInPiece == 0)
        {
            time_t now;
            bool hasPiece;
            uint8_t hash[SHA_DIGEST_LENGTH];

            tr_sha1_final(sha, hash);
            hasPiece = memcmp(hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH) == 0;

            if (hasPiece || hadPiece)
            {
                tr_torrentSetHasPiece(tor, pieceIndex, hasPiece);
                changed |= hasPiece != hadPiece;
            }

            tr_torrentSetPieceChecked(tor, pieceIndex);
            now = tr_time();
            tor->anyDate = now;

            /* sleeping even just a few msec per second goes a long
             * way towards reducing IO load... */
            if (lastSleptAt != now)
            {
                lastSleptAt = now;
                tr_wait_msec(MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY);
            }

            sha = tr_sha1_init();
            pieceIndex++;
            piecePos = 0;
        }

        /* if we're finishing a file... */
        if (leftInFile == 0)
        {
            if (fd != TR_BAD_SYS_FILE)
            {
                tr_sys_file_close(fd, NULL);
                fd = TR_BAD_SYS_FILE;
            }

            fileIndex++;
            filePos = 0;
        }
    }

    /* cleanup */
    if (fd != TR_BAD_SYS_FILE)
    {
        tr_sys_file_close(fd, NULL);
    }

    tr_sha1_final(sha, NULL);
    free(buffer);

    /* stopwatch */
    end = tr_time();
    tr_logAddTorDbg(tor, "Verification is done. It took %d seconds to verify %" PRIu64 " bytes (%" PRIu64 " bytes per second)",
        (int)(end - begin), tor->info.totalSize, (uint64_t)(tor->info.totalSize / (1 + (end - begin))));

    return changed;
}
Ejemplo n.º 7
0
static bool
verifyTorrent (tr_torrent * tor, bool * stopFlag)
{
  time_t end;
  SHA_CTX sha;
  int fd = -1;
  int64_t filePos = 0;
  bool changed = 0;
  bool hadPiece = 0;
  time_t lastSleptAt = 0;
  uint32_t piecePos = 0;
  tr_file_index_t fileIndex = 0;
  tr_file_index_t prevFileIndex = !fileIndex;
  tr_piece_index_t pieceIndex = 0;
  const time_t begin = tr_time ();
  const size_t buflen = 1024 * 128; /* 128 KiB buffer */
  uint8_t * buffer = tr_valloc (buflen);

  SHA1_Init (&sha);

  tr_logAddTorDbg (tor, "%s", "verifying torrent...");
  tr_torrentSetChecked (tor, 0);
  while (!*stopFlag && (pieceIndex < tor->info.pieceCount))
    {
      uint32_t leftInPiece;
      uint32_t bytesThisPass;
      uint64_t leftInFile;
      const tr_file * file = &tor->info.files[fileIndex];

      /* if we're starting a new piece... */
      if (piecePos == 0)
        hadPiece = tr_cpPieceIsComplete (&tor->completion, pieceIndex);

      /* if we're starting a new file... */
      if (!filePos && (fd<0) && (fileIndex!=prevFileIndex))
        {
          char * filename = tr_torrentFindFile (tor, fileIndex);
          fd = filename == NULL ? -1 : tr_open_file_for_scanning (filename);
          tr_free (filename);
          prevFileIndex = fileIndex;
        }

      /* figure out how much we can read this pass */
      leftInPiece = tr_torPieceCountBytes (tor, pieceIndex) - piecePos;
      leftInFile = file->length - filePos;
      bytesThisPass = MIN (leftInFile, leftInPiece);
      bytesThisPass = MIN (bytesThisPass, buflen);

      /* read a bit */
      if (fd >= 0)
        {
          const ssize_t numRead = tr_pread (fd, buffer, bytesThisPass, filePos);
          if (numRead > 0)
            {
              bytesThisPass = (uint32_t)numRead;
              SHA1_Update (&sha, buffer, bytesThisPass);
#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
              posix_fadvise (fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED);
#endif
            }
        }

      /* move our offsets */
      leftInPiece -= bytesThisPass;
      leftInFile -= bytesThisPass;
      piecePos += bytesThisPass;
      filePos += bytesThisPass;

      /* if we're finishing a piece... */
      if (leftInPiece == 0)
        {
          time_t now;
          bool hasPiece;
          uint8_t hash[SHA_DIGEST_LENGTH];

          SHA1_Final (hash, &sha);
          hasPiece = !memcmp (hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH);

          if (hasPiece || hadPiece)
            {
              tr_torrentSetHasPiece (tor, pieceIndex, hasPiece);
              changed |= hasPiece != hadPiece;
            }

          tr_torrentSetPieceChecked (tor, pieceIndex);
          now = tr_time ();
          tor->anyDate = now;

          /* sleeping even just a few msec per second goes a long
           * way towards reducing IO load... */
          if (lastSleptAt != now)
            {
              lastSleptAt = now;
              tr_wait_msec (MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY);
            }

          SHA1_Init (&sha);
          pieceIndex++;
          piecePos = 0;
        }

      /* if we're finishing a file... */
      if (leftInFile == 0)
        {
          if (fd >= 0)
            {
              tr_close_file (fd);
              fd = -1;
            }
          fileIndex++;
          filePos = 0;
        }
    }

  /* cleanup */
  if (fd >= 0)
    tr_close_file (fd);
  free (buffer);

  /* stopwatch */
  end = tr_time ();
  tr_logAddTorDbg (tor, "Verification is done. It took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)",
             (int)(end-begin), tor->info.totalSize,
             (uint64_t)(tor->info.totalSize/ (1+ (end-begin))));

  return changed;
}