static void event_enable( tr_peerIo * io, short event ) { assert( tr_amInEventThread( io->session ) ); assert( io->session != NULL ); assert( io->session->events != NULL ); assert( event_initialized( &io->event_read ) ); assert( event_initialized( &io->event_write ) ); if( io->socket < 0 ) return; if( ( event & EV_READ ) && ! ( io->pendingEvents & EV_READ ) ) { dbgmsg( io, "enabling libevent ready-to-read polling" ); event_add( &io->event_read, NULL ); io->pendingEvents |= EV_READ; } if( ( event & EV_WRITE ) && ! ( io->pendingEvents & EV_WRITE ) ) { dbgmsg( io, "enabling libevent ready-to-write polling" ); event_add( &io->event_write, NULL ); io->pendingEvents |= EV_WRITE; } }
void tr_peerIoWrite( tr_peerIo * io, const void * bytes, size_t byteCount, tr_bool isPieceData ) { /* FIXME(libevent2): this implementation snould be moved to tr_peerIoWriteBuf. This function should be implemented as evbuffer_new() + evbuffer_add_reference() + a call to tr_peerIoWriteBuf() + evbuffer_free() */ struct tr_datatype * datatype; assert( tr_amInEventThread( io->session ) ); dbgmsg( io, "adding %zu bytes into io->output", byteCount ); datatype = tr_new( struct tr_datatype, 1 ); datatype->isPieceData = isPieceData != 0; datatype->length = byteCount; tr_list_append( &io->outbuf_datatypes, datatype ); switch( io->encryptionMode ) { case PEER_ENCRYPTION_RC4: { /* FIXME(libevent2): use evbuffer_reserve_space() and evbuffer_commit_space() instead of tmp */ void * tmp = tr_sessionGetBuffer( io->session ); const size_t tmplen = SESSION_BUFFER_SIZE; const uint8_t * walk = bytes; evbuffer_expand( io->outbuf, byteCount ); while( byteCount > 0 ) { const size_t thisPass = MIN( byteCount, tmplen ); tr_cryptoEncrypt( io->crypto, thisPass, walk, tmp ); evbuffer_add( io->outbuf, tmp, thisPass ); walk += thisPass; byteCount -= thisPass; } tr_sessionReleaseBuffer( io->session ); break; } case PEER_ENCRYPTION_NONE: evbuffer_add( io->outbuf, bytes, byteCount ); break; default: assert( 0 ); break; } }
void tr_peerIoSetEnabled( tr_peerIo * io, tr_direction dir, tr_bool isEnabled ) { const short event = dir == TR_UP ? EV_WRITE : EV_READ; assert( tr_isPeerIo( io ) ); assert( tr_isDirection( dir ) ); assert( tr_amInEventThread( io->session ) ); assert( io->session->events != NULL ); if( isEnabled ) event_enable( io, event ); else event_disable( io, event ); }
static tr_peerIo* tr_peerIoNew( tr_session * session, tr_bandwidth * parent, const tr_address * addr, tr_port port, const uint8_t * torrentHash, tr_bool isIncoming, tr_bool isSeed, int socket ) { tr_peerIo * io; assert( session != NULL ); assert( session->events != NULL ); assert( tr_isBool( isIncoming ) ); assert( tr_isBool( isSeed ) ); assert( tr_amInEventThread( session ) ); if( socket >= 0 ) { tr_netSetTOS( socket, session->peerSocketTOS ); maybeSetCongestionAlgorithm( socket, session->peer_congestion_algorithm ); } io = tr_new0( tr_peerIo, 1 ); io->magicNumber = MAGIC_NUMBER; io->refCount = 1; io->crypto = tr_cryptoNew( torrentHash, isIncoming ); io->session = session; io->addr = *addr; io->isSeed = isSeed; io->port = port; io->socket = socket; io->isIncoming = isIncoming != 0; io->hasFinishedConnecting = FALSE; io->timeCreated = tr_time( ); io->inbuf = evbuffer_new( ); io->outbuf = evbuffer_new( ); tr_bandwidthConstruct( &io->bandwidth, session, parent ); tr_bandwidthSetPeer( &io->bandwidth, io ); dbgmsg( io, "bandwidth is %p; its parent is %p", &io->bandwidth, parent ); event_set( &io->event_read, io->socket, EV_READ, event_read_cb, io ); event_set( &io->event_write, io->socket, EV_WRITE, event_write_cb, io ); return io; }
void tr_timerFree( tr_timer ** ptimer ) { tr_timer * timer; /* zero out the argument passed in */ assert( ptimer ); timer = *ptimer; *ptimer = NULL; /* destroy the timer directly or via the command queue */ if( timer && !timer->inCallback ) { assert( tr_amInEventThread( timer->eh->h ) ); event_del( &timer->event ); tr_free( timer ); } }
tr_timer* tr_timerNew( tr_session * session, timer_func func, void * user_data, uint64_t interval_milliseconds ) { tr_timer * timer; assert( tr_amInEventThread( session ) ); timer = tr_new0( tr_timer, 1 ); timer->func = func; timer->user_data = user_data; timer->eh = session->events; tr_timevalMsec( interval_milliseconds, &timer->tv ); evtimer_set( &timer->event, timerCallback, timer ); evtimer_add( &timer->event, &timer->tv ); return timer; }
static void io_dtor( void * vio ) { tr_peerIo * io = vio; assert( tr_isPeerIo( io ) ); assert( tr_amInEventThread( io->session ) ); assert( io->session->events != NULL ); dbgmsg( io, "in tr_peerIo destructor" ); event_disable( io, EV_READ | EV_WRITE ); tr_bandwidthDestruct( &io->bandwidth ); evbuffer_free( io->outbuf ); evbuffer_free( io->inbuf ); tr_netClose( io->session, io->socket ); tr_cryptoFree( io->crypto ); tr_list_free( &io->outbuf_datatypes, tr_free ); memset( io, ~0, sizeof( tr_peerIo ) ); tr_free( io ); }
int tr_cacheWriteBlock (tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece, uint32_t offset, uint32_t length, struct evbuffer * writeme) { struct cache_block * cb = findBlock (cache, torrent, piece, offset); assert (tr_amInEventThread (torrent->session)); if (cb == NULL) { cb = tr_new (struct cache_block, 1); cb->tor = torrent; cb->piece = piece; cb->offset = offset; cb->length = length; cb->block = _tr_block (torrent, piece, offset); cb->evbuf = evbuffer_new (); tr_ptrArrayInsertSorted (&cache->blocks, cb, cache_block_compare); }
static void event_disable( struct tr_peerIo * io, short event ) { assert( tr_amInEventThread( io->session ) ); assert( io->session != NULL ); assert( io->session->events != NULL ); assert( event_initialized( &io->event_read ) ); assert( event_initialized( &io->event_write ) ); if( ( event & EV_READ ) && ( io->pendingEvents & EV_READ ) ) { dbgmsg( io, "disabling libevent ready-to-read polling" ); event_del( &io->event_read ); io->pendingEvents &= ~EV_READ; } if( ( event & EV_WRITE ) && ( io->pendingEvents & EV_WRITE ) ) { dbgmsg( io, "disabling libevent ready-to-write polling" ); event_del( &io->event_write ); io->pendingEvents &= ~EV_WRITE; } }
static void tr_sessionInitImpl( void * vdata ) { int64_t i; int64_t j; double d; tr_bool found; const char * str; tr_benc settings; char * filename; struct init_data * data = vdata; tr_benc * clientSettings = data->clientSettings; tr_session * session = data->session; assert( tr_amInEventThread( session ) ); assert( tr_bencIsDict( clientSettings ) ); dbgmsg( "tr_sessionInit: the session's top-level bandwidth object is %p", session->bandwidth ); tr_bencInitDict( &settings, 0 ); tr_sessionGetDefaultSettings( &settings ); tr_bencMergeDicts( &settings, clientSettings ); #ifndef WIN32 /* Don't exit when writing on a broken socket */ signal( SIGPIPE, SIG_IGN ); #endif found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ); assert( found ); session->peerLimitPerTorrent = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_MSGLEVEL, &i ); assert( found ); tr_setMessageLevel( i ); tr_setMessageQueuing( data->messageQueuingEnabled ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEX_ENABLED, &i ); assert( found ); session->isPexEnabled = i != 0; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_ENCRYPTION, &i ); assert( found ); assert( tr_isEncryptionMode( i ) ); session->encryptionMode = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PREALLOCATION, &i ); assert( found ); assert( tr_isPreallocationMode( i ) ); session->preallocationMode = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_SOCKET_TOS, &i ); assert( found ); session->peerSocketTOS = i; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, &str ); assert( found ); session->downloadDir = tr_strdup( str ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_ENABLED, &i ); assert( found ); session->isProxyEnabled = i != 0; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY, &str ); assert( found ); session->proxy = tr_strdup( str ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_PORT, &i ); assert( found ); session->proxyPort = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_TYPE, &i ); assert( found ); session->proxyType = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PROXY_AUTH_ENABLED, &i ); assert( found ); session->isProxyAuthEnabled = i != 0; found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_USERNAME, &str ); assert( found ); session->proxyUsername = tr_strdup( str ); found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_PROXY_PASSWORD, &str ); assert( found ); session->proxyPassword = tr_strdup( str ); session->so_sndbuf = 1500 * 3; /* 3x MTU for most ethernet/wireless */ session->so_rcvbuf = 8192; tr_setConfigDir( session, data->configDir ); tr_trackerSessionInit( session ); assert( session->tracker != NULL ); session->peerMgr = tr_peerMgrNew( session ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_LAZY_BITFIELD, &i ); assert( found ); session->useLazyBitfield = i != 0; /* Initialize rate and file descripts controls */ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_OPEN_FILE_LIMIT, &i ); assert( found ); session->openFileLimit = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, &j ); assert( found ); tr_fdInit( session->openFileLimit, j ); /** *** random port **/ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_ENABLED, &i ); assert( found ); session->isPortRandom = i != 0; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, &i ); assert( found ); session->randomPortLow = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, &i ); assert( found ); session->randomPortHigh = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_PORT_FORWARDING, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_PEER_PORT, &j ); assert( found ); session->peerPort = session->isPortRandom ? getRandomPort( session ) : j; session->shared = tr_sharedInit( session, i, session->peerPort ); session->isPortSet = session->isPortRandom || j>0; /** **/ found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT, &i ); assert( found ); session->uploadSlotsPerTorrent = i; found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_USPEED_ENABLED, &j ); assert( found ); tr_sessionSetSpeedLimit( session, TR_UP, i ); tr_sessionSetSpeedLimitEnabled( session, TR_UP, j ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED, &i ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_DSPEED_ENABLED, &j ); assert( found ); tr_sessionSetSpeedLimit( session, TR_DOWN, i ); tr_sessionSetSpeedLimitEnabled( session, TR_DOWN, j ); found = tr_bencDictFindDouble( &settings, TR_PREFS_KEY_RATIO, &d ) && tr_bencDictFindInt( &settings, TR_PREFS_KEY_RATIO_ENABLED, &j ); assert( found ); tr_sessionSetRatioLimit( session, d ); tr_sessionSetRatioLimited( session, j ); /* initialize the blocklist */ filename = tr_buildPath( session->configDir, "blocklists", NULL ); tr_mkdirp( filename, 0777 ); tr_free( filename ); found = tr_bencDictFindInt( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &i ); assert( found ); session->isBlocklistEnabled = i; loadBlocklists( session ); session->rpcServer = tr_rpcInit( session, &settings ); tr_bencFree( &settings ); assert( tr_isSession( session ) ); /* first %s is the application name second %s is the version number */ tr_inf( _( "%s %s started" ), TR_NAME, LONG_VERSION_STRING ); tr_statsInit( session ); session->web = tr_webInit( session ); metainfoLookupRescan( session ); session->isWaiting = FALSE; dbgmsg( "returning session %p; session->tracker is %p", session, session->tracker ); }