Example #1
0
static void
requestNextChunk( tr_webseed * w )
{
    tr_torrent * tor = tr_torrentFindFromHash( w->session, w->hash );

    if( tor != NULL )
    {
        const tr_info * inf = tr_torrentInfo( tor );
        const uint32_t have = EVBUFFER_LENGTH( w->content );
        const uint32_t left = w->byteCount - have;
        const uint32_t pieceOffset = w->pieceOffset + have;
        tr_file_index_t fileIndex;
        uint64_t fileOffset;
        uint32_t thisPass;
        char * url;
        char * range;

        tr_ioFindFileLocation( tor, w->pieceIndex, pieceOffset,
                               &fileIndex, &fileOffset );
        thisPass = MIN( left, inf->files[fileIndex].length - fileOffset );

        url = makeURL( w, &inf->files[fileIndex] );
/*fprintf( stderr, "url is [%s]\n", url );*/
        range = tr_strdup_printf( "%"PRIu64"-%"PRIu64, fileOffset, fileOffset + thisPass - 1 );
/*fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are left, and we're asking for %lu this time\n", range, (unsigned long)w->byteCount, (unsigned long)have, (unsigned long)left, (unsigned long)thisPass );*/
        tr_webRun( w->session, url, range, webResponseFunc, w );
        tr_free( range );
        tr_free( url );
    }
}
Example #2
0
static int
readPeerId( tr_handshake    * handshake,
            struct evbuffer * inbuf )
{
    tr_bool peerIsGood;
    char client[128];
    tr_torrent * tor;
    const uint8_t * tor_peer_id;
    uint8_t peer_id[PEER_ID_LEN];

    if( evbuffer_get_length( inbuf ) < PEER_ID_LEN )
        return READ_LATER;

    /* peer id */
    tr_peerIoReadBytes( handshake->io, inbuf, peer_id, PEER_ID_LEN );
    tr_peerIoSetPeersId( handshake->io, peer_id );
    handshake->havePeerID = TRUE;
    tr_clientForId( client, sizeof( client ), peer_id );
    dbgmsg( handshake, "peer-id is [%s] ... isIncoming is %d", client,
            tr_peerIoIsIncoming( handshake->io ) );

    /* if we've somehow connected to ourselves, don't keep the connection */
    tor = tr_torrentFindFromHash( handshake->session, tr_peerIoGetTorrentHash( handshake->io ) );
    tor_peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );
    peerIsGood = memcmp( peer_id, tor_peer_id, PEER_ID_LEN ) != 0;
    dbgmsg( handshake, "isPeerGood == %d", (int)peerIsGood );
    return tr_handshakeDone( handshake, peerIsGood );
}
Example #3
0
static int
updateAddresses( tr_tracker * t,
                 int          success )
{
    int          retry;

    tr_torrent * torrent = tr_torrentFindFromHash( t->session, t->hash );

    if( success )
    {
        /* multitracker spec: "if a connection with a tracker is
           successful, it will be moved to the front of the tier." */
        t->trackerIndex = tr_torrentPromoteTracker( torrent, t->trackerIndex );
        retry = FALSE; /* we succeeded; no need to retry */
    }
    else if( ++t->trackerIndex >= torrent->info.trackerCount )
    {
        t->trackerIndex = 0;
        retry = FALSE; /* we've tried them all */
    }
    else
    {
        const tr_tracker_info * n = getCurrentAddressFromTorrent( t, torrent );
        tr_ninf( t->name, _( "Trying tracker \"%s\"" ), n->announce );
        retry = TRUE;
    }

    return retry;
}
Example #4
0
static void
buildHandshakeMessage( tr_handshake * handshake, uint8_t * buf )
{
    uint8_t          * walk = buf;
    const uint8_t    * torrentHash = tr_cryptoGetTorrentHash( handshake->crypto );
    const tr_torrent * tor = tr_torrentFindFromHash( handshake->session, torrentHash );
    const uint8_t    * peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );

    memcpy( walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
    walk += HANDSHAKE_NAME_LEN;
    memset( walk, 0, HANDSHAKE_FLAGS_LEN );
    HANDSHAKE_SET_LTEP( walk );
    HANDSHAKE_SET_FASTEXT( walk );

    /* Note that this doesn't depend on whether the torrent is private.
     * We don't accept DHT peers for a private torrent,
     * but we participate in the DHT regardless. */
    if( tr_dhtEnabled( handshake->session ) )
        HANDSHAKE_SET_DHT( walk );

    walk += HANDSHAKE_FLAGS_LEN;
    memcpy( walk, torrentHash, SHA_DIGEST_LENGTH );
    walk += SHA_DIGEST_LENGTH;
    memcpy( walk, peer_id, PEER_ID_LEN );
    walk += PEER_ID_LEN;

    assert( strlen( ( const char* )peer_id ) == PEER_ID_LEN );
    assert( walk - buf == HANDSHAKE_SIZE );
}
Example #5
0
static int
readPeerId (tr_handshake    * handshake,
            struct evbuffer * inbuf)
{
  bool connected_to_self;
  char client[128];
  uint8_t peer_id[PEER_ID_LEN];
  tr_torrent * tor;

  if (evbuffer_get_length (inbuf) < PEER_ID_LEN)
    return READ_LATER;

  /* peer id */
  tr_peerIoReadBytes (handshake->io, inbuf, peer_id, PEER_ID_LEN);
  tr_peerIoSetPeersId (handshake->io, peer_id);
  handshake->havePeerID = true;
  tr_clientForId (client, sizeof (client), peer_id);
  dbgmsg (handshake, "peer-id is [%s] ... isIncoming is %d", client,
          tr_peerIoIsIncoming (handshake->io));

  /* if we've somehow connected to ourselves, don't keep the connection */
  tor = tr_torrentFindFromHash (handshake->session, tr_peerIoGetTorrentHash (handshake->io));
  connected_to_self = (tor != NULL) && !memcmp (peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN);

  return tr_handshakeDone (handshake, !connected_to_self);
}
Example #6
0
static int
parseHandshake (tr_handshake *    handshake,
                struct evbuffer * inbuf)
{
  uint8_t name[HANDSHAKE_NAME_LEN];
  uint8_t reserved[HANDSHAKE_FLAGS_LEN];
  uint8_t hash[SHA_DIGEST_LENGTH];
  tr_torrent * tor;
  uint8_t peer_id[PEER_ID_LEN];

  dbgmsg (handshake, "payload: need %d, got %zu",
          HANDSHAKE_SIZE, evbuffer_get_length (inbuf));

  if (evbuffer_get_length (inbuf) < HANDSHAKE_SIZE)
    return READ_LATER;

  /* confirm the protocol */
  tr_peerIoReadBytes (handshake->io, inbuf, name, HANDSHAKE_NAME_LEN);
  if (memcmp (name, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN))
    return HANDSHAKE_ENCRYPTION_WRONG;

  /* read the reserved bytes */
  tr_peerIoReadBytes (handshake->io, inbuf, reserved, HANDSHAKE_FLAGS_LEN);

  /* torrent hash */
  tr_peerIoReadBytes (handshake->io, inbuf, hash, sizeof (hash));
  assert (tr_peerIoHasTorrentHash (handshake->io));
  if (!tr_torrentExists (handshake->session, hash)
      || memcmp (hash, tr_peerIoGetTorrentHash (handshake->io), SHA_DIGEST_LENGTH))
    {
      dbgmsg (handshake, "peer returned the wrong hash. wtf?");
      return HANDSHAKE_BAD_TORRENT;
    }

  /* peer_id */
  tr_peerIoReadBytes (handshake->io, inbuf, peer_id, sizeof (peer_id));
  tr_peerIoSetPeersId (handshake->io, peer_id);

  /* peer id */
  handshake->havePeerID = true;
  dbgmsg (handshake, "peer-id is [%*.*s]", PEER_ID_LEN, PEER_ID_LEN, peer_id);

  tor = tr_torrentFindFromHash (handshake->session, hash);
  if (!memcmp (peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN))
    {
      dbgmsg (handshake, "streuth!  we've connected to ourselves.");
      return HANDSHAKE_PEER_IS_SELF;
    }

  /**
  *** Extensions
  **/

  tr_peerIoEnableDHT  (handshake->io, HANDSHAKE_HAS_DHT    (reserved));
  tr_peerIoEnableLTEP (handshake->io, HANDSHAKE_HAS_LTEP    (reserved));
  tr_peerIoEnableFEXT (handshake->io, HANDSHAKE_HAS_FASTEXT (reserved));

  return HANDSHAKE_OK;
}
Example #7
0
static tr_tracker *
findTracker( tr_session *    session,
             const uint8_t * hash )
{
    tr_torrent * torrent = tr_torrentFindFromHash( session, hash );

    return torrent ? torrent->tracker : NULL;
}
Example #8
0
static const tr_tracker_info *
getCurrentAddress( tr_tracker * t )
{
    const tr_torrent * torrent;

    if( ( torrent = tr_torrentFindFromHash( t->session, t->hash ) ) )
        return getCurrentAddressFromTorrent( t, torrent );
    return NULL;
}
Example #9
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 =
            tr_peerIoHasTorrentHash( io ) ?
            tr_torrentFindFromHash( handshake->session,
                                    tr_peerIoGetTorrentHash( io ) ) :
            NULL;
        /* Don't mark a peer as non-uTP unless it's really a connect failure. */
        if( tor && ( errcode == ETIMEDOUT || errcode == ECONNREFUSED ) ) {
            tr_torrentLock( tor );
            tr_peerMgrSetUtpFailed( tor,
                                    tr_peerIoGetAddress( io, NULL ),
                                    TRUE );
            tr_torrentUnlock( tor );
        }

        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 );
    }
}
Example #10
0
static bool
buildHandshakeMessage (tr_handshake * handshake, uint8_t * buf)
{
  const unsigned char * peer_id = NULL;
  const uint8_t * torrentHash;
  tr_torrent * tor;
  bool success;

  if ((torrentHash = tr_cryptoGetTorrentHash (handshake->crypto)))
    if ((tor = tr_torrentFindFromHash (handshake->session, torrentHash)))
      peer_id = tr_torrentGetPeerId (tor);

  if (peer_id == NULL)
    {
      success = false;
    }
  else
    {
      uint8_t * walk = buf;

      memcpy (walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN);
      walk += HANDSHAKE_NAME_LEN;
      memset (walk, 0, HANDSHAKE_FLAGS_LEN);
      HANDSHAKE_SET_LTEP (walk);
      HANDSHAKE_SET_FASTEXT (walk);

      /* Note that this doesn't depend on whether the torrent is private.
       * We don't accept DHT peers for a private torrent,
       * but we participate in the DHT regardless. */
      if (tr_dhtEnabled (handshake->session))
        HANDSHAKE_SET_DHT (walk);

      walk += HANDSHAKE_FLAGS_LEN;
      memcpy (walk, torrentHash, SHA_DIGEST_LENGTH);
      walk += SHA_DIGEST_LENGTH;
      memcpy (walk, peer_id, PEER_ID_LEN);
      walk += PEER_ID_LEN;

      assert (walk - buf == HANDSHAKE_SIZE);
      success = true;
    }

  return success;
}
Example #11
0
static void
webResponseFunc( tr_session    * session,
                 long            response_code,
                 const void    * response,
                 size_t          response_byte_count,
                 void          * vw )
{
    tr_webseed * w = vw;
    tr_torrent * tor = tr_torrentFindFromHash( session, w->hash );
    const int    success = ( response_code == 206 );

/*fprintf( stderr, "server responded with code %ld and %lu bytes\n",
  response_code, (unsigned long)response_byte_count );*/
    if( !success )
    {
        /* FIXME */
    }
    else if( tor != NULL )
    {
        evbuffer_add( w->content, response, response_byte_count );
        if( !w->dead )
        {
            fireClientGotData( w, response_byte_count );
            tr_rcTransferred( &w->rateDown, response_byte_count );
        }

        if( EVBUFFER_LENGTH( w->content ) < w->byteCount )
            requestNextChunk( w );
        else {
            tr_ioWrite( tor, w->pieceIndex, w->pieceOffset, w->byteCount, EVBUFFER_DATA(w->content) );
            evbuffer_drain( w->content, EVBUFFER_LENGTH( w->content ) );
            w->busy = 0;
            if( w->dead )
                tr_webseedFree( w );
            else  {
                fireClientGotBlock( w, w->pieceIndex, w->pieceOffset, w->byteCount );
                fireNeedReq( w );
            }
        }
    }
}
Example #12
0
    case TR_DHT_BROKEN: return "broken";
    case TR_DHT_POOR: return "poor";
    case TR_DHT_FIREWALLED: return "firewalled";
    case TR_DHT_GOOD: return "good";
    default: return "???";
    }
}

static void
callback( void *ignore UNUSED, int event,
          unsigned char *info_hash, void *data, size_t data_len )
{
    if( event == DHT_EVENT_VALUES || event == DHT_EVENT_VALUES6 ) {
        tr_torrent *tor;
        tr_sessionLock( session );
        tor = tr_torrentFindFromHash( session, info_hash );
        if( tor && tr_torrentAllowsDHT( tor ))
        {
            size_t i, n;
            tr_pex * pex;
            if( event == DHT_EVENT_VALUES )
                pex = tr_peerMgrCompactToPex(data, data_len, NULL, 0, &n);
            else
                pex = tr_peerMgrCompact6ToPex(data, data_len, NULL, 0, &n);
            for( i=0; i<n; ++i )
                tr_peerMgrAddPex( tor, TR_PEER_FROM_DHT, pex+i, -1 );
            tr_free(pex);
            tr_tordbg(tor, "Learned %d%s peers from DHT",
                      (int)n,
                      event == DHT_EVENT_VALUES6 ? " IPv6" : "");
        }