Example #1
0
void
tr_sessionClose( tr_session * session )
{
    int            i;
    const int      maxwait_msec = SHUTDOWN_MAX_SECONDS * 1000;
    const uint64_t deadline = tr_date( ) + maxwait_msec;

    assert( tr_isSession( session ) );

    dbgmsg( "shutting down transmission session %p", session );

    /* close the session */
    tr_runInEventThread( session, tr_closeAllConnections, session );
    while( !session->isClosed && !deadlineReached( deadline ) )
    {
        dbgmsg(
            "waiting for the shutdown commands to run in the main thread" );
        tr_wait( 100 );
    }

    /* "shared" and "tracker" have live sockets,
     * so we need to keep the transmission thread alive
     * for a bit while they tell the router & tracker
     * that we're closing now */
    while( ( session->shared
           || session->tracker ) && !deadlineReached( deadline ) )
    {
        dbgmsg( "waiting on port unmap (%p) or tracker (%p)",
                session->shared, session->tracker );
        tr_wait( 100 );
    }

    tr_fdClose( );

    /* close the libtransmission thread */
    tr_eventClose( session );
    while( session->events && !deadlineReached( deadline ) )
    {
        dbgmsg( "waiting for the libevent thread to shutdown cleanly" );
        tr_wait( 100 );
    }

    /* free the session memory */
    tr_bandwidthFree( session->bandwidth );
    tr_lockFree( session->lock );
    for( i = 0; i < session->metainfoLookupCount; ++i )
        tr_free( session->metainfoLookup[i].filename );
    tr_free( session->metainfoLookup );
    tr_free( session->tag );
    tr_free( session->configDir );
    tr_free( session->resumeDir );
    tr_free( session->torrentDir );
    tr_free( session->downloadDir );
    tr_free( session->proxy );
    tr_free( session->proxyUsername );
    tr_free( session->proxyPassword );
    tr_free( session );
}
Example #2
0
tr_session *
tr_sessionInit( const char  * tag,
                const char  * configDir,
                tr_bool       messageQueuingEnabled,
                tr_benc     * clientSettings )
{
    tr_session * session;
    struct init_data data;

    assert( tr_bencIsDict( clientSettings ) );

    /* initialize the bare skeleton of the session object */
    session = tr_new0( tr_session, 1 );
    session->bandwidth = tr_bandwidthNew( session, NULL );
    session->lock = tr_lockNew( );
    session->tag = tr_strdup( tag );
    session->magicNumber = SESSION_MAGIC_NUMBER;

    /* start the libtransmission thread */
    tr_netInit( ); /* must go before tr_eventInit */
    tr_eventInit( session );
    assert( session->events != NULL );

    /* run the rest in the libtransmission thread */
    session->isWaiting = TRUE;
    data.session = session;
    data.configDir = configDir;
    data.messageQueuingEnabled = messageQueuingEnabled;
    data.clientSettings = clientSettings;
    tr_runInEventThread( session, tr_sessionInitImpl, &data );
    while( session->isWaiting )
        tr_wait( 100 );

    return session;
}
Example #3
0
/***********************************************************************
 * tr_netResolveThreadClose
 ***********************************************************************
 * Notices the gethostbyname thread that is should terminate. Doesn't
 * wait until it does, in case it is stuck in a resolution: we let it
 * die and clean itself up.
 **********************************************************************/
void tr_netResolveThreadClose()
{
    tr_lockLock( &resolveLock );
    resolveDie = 1;
    tr_lockUnlock( &resolveLock );
    tr_condSignal( &resolveCond );
    tr_wait( 200 );
}
Example #4
0
void
tr_eventInit( tr_session * session )
{
    tr_event_handle * eh;

    session->events = NULL;

    eh = tr_new0( tr_event_handle, 1 );
    eh->lock = tr_lockNew( );
    pipe( eh->fds );
    eh->session = session;
    eh->thread = tr_threadNew( libeventThreadFunc, eh );

    /* wait until the libevent thread is running */
    while( session->events == NULL )
        tr_wait( 100 );
}
Example #5
0
/* returns an fd on success, or a -1 on failure and sets errno */
int
tr_fdFileCheckout( const char * folder,
                   const char * torrentFile,
                   int          doWrite,
                   int          doPreallocate,
                   uint64_t     desiredFileSize )
{
    int                  i, winner = -1;
    struct tr_openfile * o;
    char               * filename;

    assert( folder && *folder );
    assert( torrentFile && *torrentFile );
    assert( doWrite == 0 || doWrite == 1 );

    filename = tr_buildPath( folder, torrentFile, NULL );
    dbgmsg( "looking for file '%s', writable %c", filename,
            doWrite ? 'y' : 'n' );

    tr_lockLock( gFd->lock );

    /* Is it already open? */
    for( i = 0; i < TR_MAX_OPEN_FILES; ++i )
    {
        o = &gFd->open[i];

        if( !fileIsOpen( o ) )
            continue;

        if( strcmp( filename, o->filename ) )
            continue;

        if( fileIsCheckedOut( o ) )
        {
            dbgmsg( "found it!  it's open, but checked out.  waiting..." );
            tr_lockUnlock( gFd->lock );
            tr_wait( 200 );
            tr_lockLock( gFd->lock );
            i = -1; /* reloop */
            continue;
        }

        if( doWrite && !o->isWritable )
        {
            dbgmsg(
                "found it!  it's open and available, but isn't writable. closing..." );
            TrCloseFile( i );
            break;
        }

        dbgmsg( "found it!  it's ready for use!" );
        winner = i;
        break;
    }

    dbgmsg(
        "it's not already open.  looking for an open slot or an old file." );
    while( winner < 0 )
    {
        uint64_t date = tr_date( ) + 1;

        /* look for the file that's been open longest */
        for( i = 0; i < TR_MAX_OPEN_FILES; ++i )
        {
            o = &gFd->open[i];

            if( !fileIsOpen( o ) )
            {
                winner = i;
                dbgmsg( "found an empty slot in %d", winner );
                break;
            }

            if( date > o->date )
            {
                date = o->date;
                winner = i;
            }
        }

        if( winner >= 0 )
        {
            if( fileIsOpen( &gFd->open[winner] ) )
            {
                dbgmsg( "closing file '%s', slot #%d",
                        gFd->open[winner].filename,
                        winner );
                TrCloseFile( winner );
            }
        }
        else
        {
            dbgmsg(
                "everything's full!  waiting for someone else to finish something" );
            tr_lockUnlock( gFd->lock );
            tr_wait( 200 );
            tr_lockLock( gFd->lock );
        }
    }

    assert( winner >= 0 );
    o = &gFd->open[winner];
    if( !fileIsOpen( o ) )
    {
        const int err = TrOpenFile( winner, folder, torrentFile, doWrite, doPreallocate, desiredFileSize );
        if( err ) {
            tr_lockUnlock( gFd->lock );
            tr_free( filename );
            errno = err;
            return -1;
        }

        dbgmsg( "opened '%s' in slot %d, doWrite %c", filename, winner,
                doWrite ? 'y' : 'n' );
        tr_strlcpy( o->filename, filename, sizeof( o->filename ) );
        o->isWritable = doWrite;
    }

    dbgmsg( "checking out '%s' in slot %d", filename, winner );
    o->isCheckedOut = 1;
    o->closeWhenDone = 0;
    o->date = tr_date( );
    tr_free( filename );
    tr_lockUnlock( gFd->lock );
    return o->fd;
}
Example #6
0
int tr_trackerScrape( tr_torrent_t * tor, int * seeders, int * leechers )
{
    tr_info_t * inf = &tor->info;

    int s, i, ret;
    uint8_t buf[1024];
    benc_val_t scrape, * val1, * val2;
    struct in_addr addr;
    uint64_t date;
    int pos, len;
    tr_resolve_t * resolve;

    if( !tor->scrape[0] )
    {
        /* scrape not supported */
        return 1;
    }

    resolve = tr_netResolveInit( inf->trackerAddress );
    for( date = tr_date();; )
    {
        ret = tr_netResolvePulse( resolve, &addr );
        if( ret == TR_RESOLVE_OK )
        {
            tr_netResolveClose( resolve );
            break;
        }
        if( ret == TR_RESOLVE_ERROR ||
                ( ret == TR_RESOLVE_WAIT && tr_date() > date + 10000 ) )
        {
            fprintf( stderr, "Could not resolve %s\n", inf->trackerAddress );
            tr_netResolveClose( resolve );
            return 1;
        }
        tr_wait( 10 );
    }

    s = tr_netOpen( addr, htons( inf->trackerPort ) );
    if( s < 0 )
    {
        return 1;
    }

    len = snprintf( (char *) buf, sizeof( buf ),
                    "GET %s?info_hash=%s HTTP/1.1\r\n"
                    "Host: %s\r\n"
                    "Connection: close\r\n\r\n",
                    tor->scrape, tor->hashString,
                    inf->trackerAddress );

    for( date = tr_date();; )
    {
        ret = tr_netSend( s, buf, len );
        if( ret & TR_NET_CLOSE )
        {
            fprintf( stderr, "Could not connect to tracker\n" );
            tr_netClose( s );
            return 1;
        }
        else if( ret & TR_NET_BLOCK )
        {
            if( tr_date() > date + 10000 )
            {
                fprintf( stderr, "Could not connect to tracker\n" );
                tr_netClose( s );
                return 1;
            }
        }
        else
        {
            break;
        }
        tr_wait( 10 );
    }

    pos = 0;
    for( date = tr_date();; )
    {
        ret = tr_netRecv( s, &buf[pos], sizeof( buf ) - pos );
        if( ret & TR_NET_CLOSE )
        {
            break;
        }
        else if( ret & TR_NET_BLOCK )
        {
            if( tr_date() > date + 10000 )
            {
                fprintf( stderr, "Could not read from tracker\n" );
                tr_netClose( s );
                return 1;
            }
        }
        else
        {
            pos += ret;
        }
        tr_wait( 10 );
    }

    if( pos < 1 )
    {
        fprintf( stderr, "Could not read from tracker\n" );
        tr_netClose( s );
        return 1;
    }

    for( i = 0; i < pos - 8; i++ )
    {
        if( !memcmp( &buf[i], "d5:files", 8 ) )
        {
            break;
        }
    }
    if( i >= pos - 8 )
    {
        return 1;
    }
    if( tr_bencLoad( &buf[i], pos - i, &scrape, NULL ) )
    {
        return 1;
    }

    val1 = tr_bencDictFind( &scrape, "files" );
    if( !val1 )
    {
        return 1;
    }
    val1 = &val1->val.l.vals[1];
    if( !val1 )
    {
        return 1;
    }
    val2 = tr_bencDictFind( val1, "complete" );
    if( !val2 )
    {
        return 1;
    }
    *seeders = val2->val.i;
    val2 = tr_bencDictFind( val1, "incomplete" );
    if( !val2 )
    {
        return 1;
    }
    *leechers = val2->val.i;
    tr_bencFree( &scrape );

    return 0;
}
Example #7
0
static tr_bool
verifyTorrent( tr_torrent * tor, tr_bool * stopFlag )
{
    SHA_CTX sha;
    int fd = -1;
    int64_t filePos = 0;
    tr_bool changed = 0;
    tr_bool hadPiece = 0;
    uint32_t piecePos = 0;
    uint32_t pieceBytesRead = 0;
    tr_file_index_t fileIndex = 0;
    tr_piece_index_t pieceIndex = 0;
    const int64_t buflen = tor->info.pieceSize;
    uint8_t * buffer = tr_new( uint8_t, buflen );
#ifdef STOPWATCH
    time_t now = time( NULL );
#endif

    SHA1_Init( &sha );

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

        /* if we're starting a new piece... */
        if( piecePos == 0 )
        {
            hadPiece = tr_cpPieceIsComplete( &tor->completion, pieceIndex );
            /* fprintf( stderr, "starting piece %d of %d\n", (int)pieceIndex, (int)tor->info.pieceCount ); */
        }

        /* if we're starting a new file... */
        if( !filePos && (fd<0) )
        {
            char * filename = tr_buildPath( tor->downloadDir, file->name, NULL );
            fd = tr_open_file_for_scanning( filename );
            /* fprintf( stderr, "opening file #%d (%s) -- %d\n", fileIndex, filename, fd ); */
            tr_free( filename );
        }

        /* 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 );
        /* fprintf( stderr, "reading this pass: %d\n", (int)bytesThisPass ); */

        /* read a bit */
        if( (fd>=0) && tr_lseek( fd, filePos, SEEK_SET ) != -1 ) {
            const int64_t numRead = read( fd, buffer, bytesThisPass );
            if( numRead > 0 )
                pieceBytesRead += numRead;
            if( numRead == bytesThisPass )
                SHA1_Update( &sha, buffer, numRead );
        }

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

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

            SHA1_Final( hash, &sha );
            hasPiece = !memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH );
            /* fprintf( stderr, "do the hashes match? %s\n", (hasPiece?"yes":"no") ); */

            if( hasPiece ) {
                tr_torrentSetHasPiece( tor, pieceIndex, TRUE );
                if( !hadPiece )
                    changed = TRUE;
            } else if( hadPiece ) {
                tr_torrentSetHasPiece( tor, pieceIndex, FALSE );
                changed = TRUE;
            }
            tr_torrentSetPieceChecked( tor, pieceIndex, TRUE );
            tor->anyDate = time( NULL );

            /* going full-throttle on a verify can choke other processes'
             * disk IO, so wait a fwe msec between pieces.
             * The msec is arbitrary, and the "if" clause is to make sure we
             * don't slow down verification of files that don't exist */
            if( pieceBytesRead == tr_torPieceCountBytes( tor, pieceIndex ) )
                tr_wait( 50 );

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

        /* if we're finishing a file... */
        if( leftInFile == 0 )
        {
            /* fprintf( stderr, "closing file\n" ); */
            if( fd >= 0 ) {
                tr_close_file( fd );
                fd = -1;
            }
            ++fileIndex;
            filePos = 0;
        }
    }

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

#ifdef STOPWATCH
    {
        time_t now2 = time( NULL );
        fprintf( stderr, "it took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)\n",
                 (int)(now2-now), tor->info.totalSize, (uint64_t)(tor->info.totalSize/(1+(now2-now))) );
    }
#endif

    return changed;
}