예제 #1
0
void
tr_ioFindFileLocation (const tr_torrent * tor,
                       tr_piece_index_t   pieceIndex,
                       uint32_t           pieceOffset,
                       tr_file_index_t  * fileIndex,
                       uint64_t         * fileOffset)
{
  const uint64_t  offset = tr_pieceOffset (tor, pieceIndex, pieceOffset, 0);
  const tr_file * file;

  assert (tr_isTorrent (tor));
  assert (offset < tor->info.totalSize);

  file = bsearch (&offset,
                  tor->info.files, tor->info.fileCount, sizeof (tr_file),
                  compareOffsetToFile);

  assert (file != NULL);

  *fileIndex = file - tor->info.files;
  *fileOffset = offset - file->offset;

  assert (*fileIndex < tor->info.fileCount);
  assert (*fileOffset < file->length);
  assert (tor->info.files[*fileIndex].offset + *fileOffset == offset);
}
예제 #2
0
void
tr_fdFileClose( tr_session        * session,
                const tr_torrent  * tor,
                tr_file_index_t     fileNum )
{
    struct tr_openfile * o;
    struct tr_fdInfo * gFd;
    const struct tr_openfile * end;
    const int torrentId = tr_torrentId( tor );

    assert( tr_isSession( session ) );
    assert( session->fdInfo != NULL );
    assert( tr_isTorrent( tor ) );
    assert( fileNum < tor->info.fileCount );

    gFd = session->fdInfo;

    for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o )
    {
        if( torrentId != o->torrentId )
            continue;
        if( fileNum != o->fileNum )
            continue;
        if( !fileIsOpen( o ) )
            continue;

        dbgmsg( "tr_fdFileClose closing \"%s\"", o->filename );
        TrCloseFile( o );
    }
}
예제 #3
0
static void
fireCheckDone( tr_torrent * tor, tr_verify_done_cb verify_done_cb )
{
    assert( tr_isTorrent( tor ) );

    if( verify_done_cb )
        verify_done_cb( tor );
}
예제 #4
0
void tr_torrentSaveResume(tr_torrent* tor)
{
    int err;
    tr_variant top;
    char* filename;

    if (!tr_isTorrent(tor))
    {
        return;
    }

    tr_variantInitDict(&top, 50); /* arbitrary "big enough" number */
    tr_variantDictAddInt(&top, TR_KEY_seeding_time_seconds, tor->secondsSeeding);
    tr_variantDictAddInt(&top, TR_KEY_downloading_time_seconds, tor->secondsDownloading);
    tr_variantDictAddInt(&top, TR_KEY_activity_date, tor->activityDate);
    tr_variantDictAddInt(&top, TR_KEY_added_date, tor->addedDate);
    tr_variantDictAddInt(&top, TR_KEY_corrupt, tor->corruptPrev + tor->corruptCur);
    tr_variantDictAddInt(&top, TR_KEY_done_date, tor->doneDate);
    tr_variantDictAddStr(&top, TR_KEY_destination, tor->downloadDir);

    if (tor->incompleteDir != NULL)
    {
        tr_variantDictAddStr(&top, TR_KEY_incomplete_dir, tor->incompleteDir);
    }

    tr_variantDictAddInt(&top, TR_KEY_downloaded, tor->downloadedPrev + tor->downloadedCur);
    tr_variantDictAddInt(&top, TR_KEY_uploaded, tor->uploadedPrev + tor->uploadedCur);
    tr_variantDictAddInt(&top, TR_KEY_max_peers, tor->maxConnectedPeers);
    tr_variantDictAddInt(&top, TR_KEY_bandwidth_priority, tr_torrentGetPriority(tor));
    tr_variantDictAddBool(&top, TR_KEY_paused, !tor->isRunning && !tor->isQueued);
    savePeers(&top, tor);

    if (tr_torrentHasMetadata(tor))
    {
        saveFilePriorities(&top, tor);
        saveDND(&top, tor);
        saveProgress(&top, tor);
    }

    saveSpeedLimits(&top, tor);
    saveRatioLimits(&top, tor);
    saveIdleLimits(&top, tor);
    saveFilenames(&top, tor);
    saveName(&top, tor);

    filename = getResumeFilename(tor);

    if ((err = tr_variantToFile(&top, TR_VARIANT_FMT_BENC, filename)) != 0)
    {
        tr_torrentSetLocalError(tor, "Unable to save resume file: %s", tr_strerror(err));
    }

    tr_free(filename);

    tr_variantFree(&top);
}
예제 #5
0
static void
gotError (tr_peerIo  * io,
          short        what,
          void       * vhandshake)
{
  int errcode = errno;
  tr_handshake * handshake = vhandshake;

  if (io->utp_socket && !io->isIncoming && handshake->state == AWAITING_YB)
    {
      /* This peer probably doesn't speak uTP. */

      tr_torrent *tor;

      if (tr_peerIoHasTorrentHash (io))
        tor = tr_torrentFindFromHash (handshake->session, tr_peerIoGetTorrentHash (io));
      else
        tor = NULL;

      /* Don't mark a peer as non-uTP unless it's really a connect failure. */
      if ((errcode == ETIMEDOUT || errcode == ECONNREFUSED) && tr_isTorrent(tor))
        tr_peerMgrSetUtpFailed (tor, tr_peerIoGetAddress (io, NULL), true);

      if (!tr_peerIoReconnect (handshake->io))
        {
          uint8_t msg[HANDSHAKE_SIZE];
          buildHandshakeMessage (handshake, msg);
          handshake->haveSentBitTorrentHandshake = 1;
          setReadState (handshake, AWAITING_HANDSHAKE);
          tr_peerIoWriteBytes (handshake->io, msg, sizeof (msg), false);
        }
    }

  /* if the error happened while we were sending a public key, we might
   * have encountered a peer that doesn't do encryption... reconnect and
   * try a plaintext handshake */
  if (((handshake->state == AWAITING_YB) || (handshake->state == AWAITING_VC))
      && (handshake->encryptionMode != TR_ENCRYPTION_REQUIRED)
      && (!tr_peerIoReconnect (handshake->io)))
    {
      uint8_t msg[HANDSHAKE_SIZE];

      dbgmsg (handshake, "handshake failed, trying plaintext...");
      buildHandshakeMessage (handshake, msg);
      handshake->haveSentBitTorrentHandshake = 1;
      setReadState (handshake, AWAITING_HANDSHAKE);
      tr_peerIoWriteBytes (handshake->io, msg, sizeof (msg), false);
    }
  else
    {
      dbgmsg (handshake, "libevent got an error what==%d, errno=%d (%s)",
                         (int)what, errno, tr_strerror (errno));
      tr_handshakeDone (handshake, false);
    }
}
예제 #6
0
uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor const* ctor)
{
    TR_ASSERT(tr_isTorrent(tor));

    uint64_t ret = 0;

    ret |= useManditoryFields(tor, fieldsToLoad, ctor);
    fieldsToLoad &= ~ret;
    ret |= loadFromFile(tor, fieldsToLoad);
    fieldsToLoad &= ~ret;
    ret |= useFallbackFields(tor, fieldsToLoad, ctor);

    return ret;
}
예제 #7
0
void
tr_torrentSaveResume( tr_torrent * tor )
{
    int err;
    tr_benc top;
    char * filename;

    if( !tr_isTorrent( tor ) )
        return;

    tr_bencInitDict( &top, 50 ); /* arbitrary "big enough" number */
    tr_bencDictAddInt( &top, KEY_TIME_SEEDING, tor->secondsSeeding );
    tr_bencDictAddInt( &top, KEY_TIME_DOWNLOADING, tor->secondsDownloading );
    tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE, tor->activityDate );
    tr_bencDictAddInt( &top, KEY_ADDED_DATE, tor->addedDate );
    tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
    tr_bencDictAddInt( &top, KEY_DONE_DATE, tor->doneDate );
    tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR, tor->downloadDir );
    if( tor->incompleteDir != NULL )
        tr_bencDictAddStr( &top, KEY_INCOMPLETE_DIR, tor->incompleteDir );
    tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
    tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
    tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
    tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) );
    tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
    savePeers( &top, tor );
    if( tr_torrentHasMetadata( tor ) )
    {
        saveFilePriorities( &top, tor );
        saveDND( &top, tor );
        saveProgress( &top, tor );
    }
    saveSpeedLimits( &top, tor );
    saveRatioLimits( &top, tor );
    saveIdleLimits( &top, tor );

    filename = getResumeFilename( tor );
    if(( err = tr_bencToFile( &top, TR_FMT_BENC, filename )))
        tr_torrentSetLocalError( tor, "Unable to save resume file: %s", tr_strerror( err ) );
    tr_free( filename );

    tr_bencFree( &top );
}
예제 #8
0
static uint64_t
loadFromFile( tr_torrent * tor,
              uint64_t     fieldsToLoad )
{
    int64_t  i;
    const char * str;
    uint64_t fieldsLoaded = 0;
    char * filename;
    tr_benc top;
    tr_bool boolVal;
    const tr_bool  wasDirty = tor->isDirty;

    assert( tr_isTorrent( tor ) );

    filename = getResumeFilename( tor );

    if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
    {
        tr_tordbg( tor, "Couldn't read \"%s\"", filename );

        tr_free( filename );
        return fieldsLoaded;
    }

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

    if( ( fieldsToLoad & TR_FR_CORRUPT )
      && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) )
    {
        tor->corruptPrev = i;
        fieldsLoaded |= TR_FR_CORRUPT;
    }

    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
      && ( tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) )
      && ( str && *str ) )
    {
        tr_free( tor->downloadDir );
        tor->downloadDir = tr_strdup( str );
        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    }

    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) )
      && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) )
      && ( str && *str ) )
    {
        tr_free( tor->incompleteDir );
        tor->incompleteDir = tr_strdup( str );
        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
    }

    if( ( fieldsToLoad & TR_FR_DOWNLOADED )
      && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) )
    {
        tor->downloadedPrev = i;
        fieldsLoaded |= TR_FR_DOWNLOADED;
    }

    if( ( fieldsToLoad & TR_FR_UPLOADED )
      && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) )
    {
        tor->uploadedPrev = i;
        fieldsLoaded |= TR_FR_UPLOADED;
    }

    if( ( fieldsToLoad & TR_FR_MAX_PEERS )
      && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) )
    {
        tor->maxConnectedPeers = i;
        fieldsLoaded |= TR_FR_MAX_PEERS;
    }

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

    if( ( fieldsToLoad & TR_FR_ADDED_DATE )
      && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) )
    {
        tor->addedDate = i;
        fieldsLoaded |= TR_FR_ADDED_DATE;
    }

    if( ( fieldsToLoad & TR_FR_DONE_DATE )
      && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) )
    {
        tor->doneDate = i;
        fieldsLoaded |= TR_FR_DONE_DATE;
    }

    if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE )
      && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) )
    {
        tr_torrentSetActivityDate( tor, i );
        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
    }

    if( ( fieldsToLoad & TR_FR_TIME_SEEDING )
      && tr_bencDictFindInt( &top, KEY_TIME_SEEDING, &i ) )
    {
        tor->secondsSeeding = i;
        fieldsLoaded |= TR_FR_TIME_SEEDING;
    }

    if( ( fieldsToLoad & TR_FR_TIME_DOWNLOADING )
      && tr_bencDictFindInt( &top, KEY_TIME_DOWNLOADING, &i ) )
    {
        tor->secondsDownloading = i;
        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
    }

    if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY )
      && tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i )
      && tr_isPriority( i ) )
    {
        tr_torrentSetPriority( tor, i );
        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
    }

    if( fieldsToLoad & TR_FR_PEERS )
        fieldsLoaded |= loadPeers( &top, tor );

    if( fieldsToLoad & TR_FR_FILE_PRIORITIES )
        fieldsLoaded |= loadFilePriorities( &top, tor );

    if( fieldsToLoad & TR_FR_PROGRESS )
        fieldsLoaded |= loadProgress( &top, tor );

    if( fieldsToLoad & TR_FR_DND )
        fieldsLoaded |= loadDND( &top, tor );

    if( fieldsToLoad & TR_FR_SPEEDLIMIT )
        fieldsLoaded |= loadSpeedLimits( &top, tor );

    if( fieldsToLoad & TR_FR_RATIOLIMIT )
        fieldsLoaded |= loadRatioLimits( &top, tor );

    if( fieldsToLoad & TR_FR_IDLELIMIT )
        fieldsLoaded |= loadIdleLimits( &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_bencFree( &top );
    tr_free( filename );
    return fieldsLoaded;
}
예제 #9
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;
}