void tr_natpmpRemoveForwarding( tr_natpmp_t * pmp ) { tr_inf( "nat-pmp unset port" ); pmp->newport = -1; unmap( pmp ); }
static void watchdir_update_impl( dtr_watchdir * w ) { int ret; fd_set rfds; struct timeval time; const int fd = w->inotify_fd; /* timeout after one second */ time.tv_sec = 1; time.tv_usec = 0; /* make the fd_set hold the inotify fd */ FD_ZERO( &rfds ); FD_SET( fd, &rfds ); /* check for added files */ ret = select( fd+1, &rfds, NULL, NULL, &time ); if( ret < 0 ) { perror( "select" ); } else if( !ret ) { /* timed out! */ } else if( FD_ISSET( fd, &rfds ) ) { int i = 0; char buf[BUF_LEN]; int len = read( fd, buf, sizeof( buf ) ); while (i < len) { struct inotify_event * event = (struct inotify_event *) &buf[i]; tr_inf( "Found new .torrent file \"%s\" in watchdir \"%s\"", event->name, w->dir ); w->callback( w->session, w->dir, event->name ); i += EVENT_SIZE + event->len; } } }
static void deviceRemove( tr_upnp_device_t ** prevptr, tr_fd_t * fdlimit ) { tr_upnp_device_t * dead; dead = *prevptr; *prevptr = dead->next; tr_inf( "forgetting upnp device %s", dead->host ); free( dead->id ); free( dead->host ); free( dead->root ); free( dead->soap ); free( dead->scpd ); free( dead->myaddr ); if( NULL != dead->http ) { killHttp( fdlimit, &dead->http ); } actionFree( &dead->getcmd ); actionFree( &dead->addcmd ); actionFree( &dead->delcmd ); free( dead ); }
static void moveFiles( const char * oldDir, const char * newDir ) { if( oldDir && newDir && strcmp( oldDir, newDir ) ) { DIR * dirh = opendir( oldDir ); if( dirh ) { int count = 0; struct dirent * dirp; while( ( dirp = readdir( dirh ) ) ) { if( strcmp( dirp->d_name, "." ) && strcmp( dirp->d_name, ".." ) ) { char * o = tr_buildPath( oldDir, dirp->d_name, NULL ); char * n = tr_buildPath( newDir, dirp->d_name, NULL ); rename( o, n ); ++count; tr_free( n ); tr_free( o ); } } if( count ) tr_inf( _( "Migrated %1$d files from \"%2$s\" to \"%3$s\"" ), count, oldDir, newDir ); closedir( dirh ); } } }
/** * returns 0 on success, or an errno value on failure. * errno values include ENOENT if the parent folder doesn't exist, * plus the errno values set by tr_mkdirp() and open(). */ static int TrOpenFile( int i, const char * folder, const char * torrentFile, int doWrite, int doPreallocate, uint64_t desiredFileSize ) { struct tr_openfile * file = &gFd->open[i]; int flags; char * filename; struct stat sb; int alreadyExisted; /* confirm the parent folder exists */ if( stat( folder, &sb ) || !S_ISDIR( sb.st_mode ) ) return ENOENT; /* create subfolders, if any */ filename = tr_buildPath( folder, torrentFile, NULL ); if( doWrite ) { char * tmp = tr_dirname( filename ); const int err = tr_mkdirp( tmp, 0777 ) ? errno : 0; tr_free( tmp ); if( err ) { tr_free( filename ); return err; } } alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode ); if( doWrite && !alreadyExisted && doPreallocate ) if( preallocateFile( filename, desiredFileSize ) ) tr_inf( _( "Preallocated file \"%s\"" ), filename ); /* open the file */ flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY; #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif #ifdef WIN32 flags |= O_BINARY; #endif file->fd = open( filename, flags, 0666 ); if( file->fd == -1 ) { const int err = errno; tr_err( _( "Couldn't open \"%1$s\": %2$s" ), filename, tr_strerror( err ) ); tr_free( filename ); return err; } tr_free( filename ); return 0; }
static int isClutchDir( const char * path ) { struct stat sb; char * tmp = tr_buildPath( path, "javascript", "transmission.js", NULL ); const int ret = !stat( tmp, &sb ); tr_inf( _( "Searching for web interface file \"%s\"" ), tmp ); tr_free( tmp ); return ret; }
static int isWebClientDir( const char * path ) { struct stat sb; char * tmp = tr_buildPath( path, "index.html", NULL ); const int ret = !stat( tmp, &sb ); tr_inf( _( "Searching for web interface file \"%s\"" ), tmp ); tr_free( tmp ); return ret; }
static void watchdir_new_impl( dtr_watchdir * w ) { int i; w->inotify_fd = inotify_init( ); tr_inf( "Using inotify to watch directory \"%s\"", w->dir ); i = inotify_add_watch( w->inotify_fd, w->dir, DTR_INOTIFY_MASK ); if( i < 0 ) tr_err( "Unable to watch \"%s\": %s", w->dir, strerror (errno) ); }
void tr_natpmpStop( tr_natpmp_t * pmp ) { if( pmp->active ) { tr_inf( "stopping nat-pmp" ); pmp->active = 0; killsock( &pmp->mcastfd ); unmap( pmp ); } }
static void watchdir_new_impl (dtr_watchdir * w) { int i; DIR * odir; w->inotify_fd = inotify_init (); if (w->inotify_fd < 0) { i = -1; } else { tr_inf ("Using inotify to watch directory \"%s\"", w->dir); i = inotify_add_watch (w->inotify_fd, w->dir, DTR_INOTIFY_MASK); } if (i < 0) { tr_err ("Unable to watch \"%s\": %s", w->dir, tr_strerror (errno)); } else if ((odir = opendir (w->dir))) { struct dirent * d; while ((d = readdir (odir))) { const char * name = d->d_name; if (!tr_str_has_suffix (name, ".torrent")) /* skip non-torrents */ continue; tr_inf ("Found new .torrent file \"%s\" in watchdir \"%s\"", name, w->dir); w->callback (w->session, w->dir, name); } closedir (odir); } }
void tr_natpmpStart( tr_natpmp_t * pmp ) { if( !pmp->active ) { tr_inf( "starting nat-pmp" ); pmp->active = 1; if( 0 > pmp->mcastfd ) { pmp->mcastfd = mcastsetup(); } } }
static void onFileAdded( tr_session * session, const char * dir, const char * file ) { char * filename = tr_buildPath( dir, file, NULL ); tr_ctor * ctor = tr_ctorNew( session ); int err = tr_ctorSetMetainfoFromFile( ctor, filename ); if( !err ) { tr_torrentNew( ctor, &err ); if( err == TR_PARSE_ERR ) tr_err( "Error parsing .torrent file \"%s\"", file ); else { tr_bool trash = FALSE; int test = tr_ctorGetDeleteSource( ctor, &trash ); tr_inf( "Parsing .torrent file successful \"%s\"", file ); if( !test && trash ) { tr_inf( "Deleting input .torrent file \"%s\"", file ); if( remove( filename ) ) tr_err( "Error deleting .torrent file: %s", tr_strerror( errno ) ); } else { char * new_filename = tr_strdup_printf( "%s.added", filename ); rename( filename, new_filename ); tr_free( new_filename ); } } } tr_ctorFree( ctor ); tr_free( filename ); }
static void mcastpulse( tr_natpmp_t * pmp ) { struct sockaddr_in sin; uint8_t buf[16]; int res; char dbgstr[INET_ADDRSTRLEN]; tr_natpmp_parse_t parse; res = tr_netRecvFrom( pmp->mcastfd, buf, sizeof( buf ), &sin ); if( TR_NET_BLOCK & res ) { return; } else if( TR_NET_CLOSE & res ) { tr_err( "error reading nat-pmp multicast message" ); killsock( &pmp->mcastfd ); return; } tr_netNtop( &sin.sin_addr, dbgstr, sizeof( dbgstr ) ); tr_dbg( "nat-pmp read %i byte multicast packet from %s", res, dbgstr ); if( pmp->dest.s_addr != sin.sin_addr.s_addr ) { tr_dbg( "nat-pmp ignoring multicast packet from unknown host %s", dbgstr ); return; } if( TR_NET_OK == parseresponse( buf, res, -1, &parse ) ) { if( checktime( &pmp->uptime, parse.seconds ) ) { pmp->renew = 0; tr_inf( "detected nat-pmp device reset" ); if( NULL != pmp->req ) { resetreq( pmp->req ); } } if( PMP_STATE_NOBODYHOME == pmp->state ) { tr_dbg( "nat-pmp state notfound -> idle" ); pmp->state = PMP_STATE_IDLE; } } }
void tr_upnpStop( tr_upnp_t * upnp ) { tr_lockLock( &upnp->lock ); if( upnp->active ) { tr_inf( "stopping upnp" ); upnp->active = 0; killSock( upnp->fdlimit, &upnp->infd ); killSock( upnp->fdlimit, &upnp->outfd ); } tr_lockUnlock( &upnp->lock ); }
void tr_upnpStart( tr_upnp_t * upnp ) { tr_lockLock( &upnp->lock ); if( !upnp->active ) { tr_inf( "starting upnp" ); upnp->active = 1; upnp->discovering = 1; upnp->infd = mcastStart( upnp->fdlimit ); upnp->lastdiscover = 0; upnp->lastdelay = SSDP_FIRST_DELAY / 2; } tr_lockUnlock( &upnp->lock ); }
static void blocklistLoad( tr_blocklist * b ) { int fd; struct stat st; const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" ); blocklistClose( b ); if( stat( b->filename, &st ) == -1 ) return; fd = open( b->filename, O_RDONLY ); if( fd == -1 ) { tr_err( err_fmt, b->filename, tr_strerror( errno ) ); return; } #ifndef WIN32 b->rules = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 ); #else b->rules = mmap( NULL, st.st_size, 0, 0, fd, 0 ); #endif if( !b->rules ) { tr_err( err_fmt, b->filename, tr_strerror( errno ) ); close( fd ); return; } b->byteCount = st.st_size; b->ruleCount = st.st_size / sizeof( struct tr_ip_range ); b->fd = fd; { char * base = tr_basename( b->filename ); tr_inf( _( "Blocklist \"%s\" contains %'zu entries" ), base, b->ruleCount ); tr_free( base ); } }
static void blocklistLoad (tr_blocklist * b) { int fd; size_t byteCount; struct stat st; const char * err_fmt = _("Couldn't read \"%1$s\": %2$s"); blocklistClose (b); if (stat (b->filename, &st) == -1) return; fd = open (b->filename, O_RDONLY | O_BINARY); if (fd == -1) { tr_err (err_fmt, b->filename, tr_strerror (errno)); return; } byteCount = (size_t) st.st_size; b->rules = mmap (NULL, byteCount, PROT_READ, MAP_PRIVATE, fd, 0); if (!b->rules) { tr_err (err_fmt, b->filename, tr_strerror (errno)); close (fd); return; } b->fd = fd; b->byteCount = byteCount; b->ruleCount = byteCount / sizeof (struct tr_ipv4_range); { char * base = tr_basename (b->filename); tr_inf (_("Blocklist \"%s\" contains %zu entries"), base, b->ruleCount); tr_free (base); } }
static void deviceAdd( tr_upnp_device_t ** first, const char * id, int idLen, const char * url, int urlLen ) { tr_upnp_device_t * ii; for( ii = *first; NULL != ii; ii = ii->next ) { if( 0 == tr_strncasecmp( ii->id, id, idLen ) ) { /* this device may have gone away and came back, recheck it */ ii->lastcheck = 0; return; } } ii = malloc( sizeof( *ii ) ); if( NULL == ii ) { return; } memset( ii, 0, sizeof( *ii ) ); if( tr_httpParseUrl( url, urlLen, &ii->host, &ii->port, &ii->root ) ) { free( ii ); return; } ii->id = tr_dupstr( id, idLen ); ii->state = UPNPDEV_STATE_ROOT; actionSetup( &ii->getcmd, "GetSpecificPortMappingEntry", 8 ); actionSetup( &ii->addcmd, "AddPortMapping", 8 ); actionSetup( &ii->delcmd, "DeletePortMapping", 3 ); ii->next = *first; *first = ii; tr_inf( "new upnp device %s, port %i, path %s", ii->host, ii->port, ii->root ); }
void tr_sessionSaveSettings( tr_session * session, const char * configDir, tr_benc * settings ) { tr_benc fileSettings; char * filename; assert( tr_bencIsDict( settings ) ); filename = tr_buildPath( configDir, "settings.json", NULL ); tr_sessionGetSettings( session, settings ); if( tr_bencLoadJSONFile( filename, &fileSettings ) ) { tr_bencSaveJSONFile( filename, settings ); } else { tr_bencMergeDicts( &fileSettings, settings ); tr_bencSaveJSONFile( filename, &fileSettings ); tr_bencFree( &fileSettings ); } tr_inf( "Saved \"%s\"", filename ); tr_free( filename ); }
static void gotsig( int sig ) { switch( sig ) { case SIGHUP: { tr_benc settings; const char * configDir = tr_sessionGetConfigDir( mySession ); tr_inf( "Reloading settings from \"%s\"", configDir ); tr_bencInitDict( &settings, 0 ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_ENABLED, TRUE ); tr_sessionLoadSettings( &settings, configDir, MY_NAME ); tr_sessionSet( mySession, &settings ); tr_bencFree( &settings ); tr_sessionReloadBlocklists( mySession ); break; } default: closing = TRUE; break; } }
int _tr_blocklistSetContent( tr_blocklist * b, const char * filename ) { FILE * in; FILE * out; int inCount = 0; int outCount = 0; char line[2048]; const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" ); if( !filename ) { blocklistDelete( b ); return 0; } in = fopen( filename, "rb" ); if( !in ) { tr_err( err_fmt, filename, tr_strerror( errno ) ); return 0; } blocklistClose( b ); out = fopen( b->filename, "wb+" ); if( !out ) { tr_err( err_fmt, b->filename, tr_strerror( errno ) ); fclose( in ); return 0; } while( fgets( line, sizeof( line ), in ) != NULL ) { char * walk; struct tr_ip_range range; ++inCount; /* zap the linefeed */ if(( walk = strchr( line, '\r' ))) *walk = '\0'; if(( walk = strchr( line, '\n' ))) *walk = '\0'; if( !parseLine( line, &range ) ) { /* don't try to display the actual lines - it causes issues */ tr_err( _( "blocklist skipped invalid address at line %d" ), inCount ); continue; } if( fwrite( &range, sizeof( struct tr_ip_range ), 1, out ) != 1 ) { tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename, tr_strerror( errno ) ); break; } ++outCount; } { char * base = tr_basename( b->filename ); tr_inf( _( "Blocklist \"%s\" updated with %d entries" ), base, outCount ); tr_free( base ); } fclose( out ); fclose( in ); blocklistLoad( b ); return outCount; }
static int devicePulse( tr_upnp_device_t * dev, tr_fd_t * fdlimit, int port ) { const char * body; int len, code; uint8_t laststate; switch( dev->state ) { case UPNPDEV_STATE_READY: if( 0 < port ) { tr_dbg( "upnp device %s: want mapping, state ready -> get", dev->host ); dev->mappedport = port; dev->state = UPNPDEV_STATE_GET; break; } return 1; case UPNPDEV_STATE_MAPPED: if( port != dev->mappedport ) { tr_dbg( "upnp device %s: change mapping, " "state mapped -> delete", dev->host ); dev->state = UPNPDEV_STATE_DEL; break; } if( tr_date() > dev->lastcheck + MAPPING_CHECK_INTERVAL ) { tr_dbg( "upnp device %s: check mapping, " "state mapped -> get", dev->host ); dev->state = UPNPDEV_STATE_GET; } return 1; case UPNPDEV_STATE_ERROR: return 0; } code = devicePulseHttp( dev, fdlimit, &body, &len ); if( 0 > code ) { return 1; } if( LOOP_DETECT_THRESHOLD <= dev->looping ) { tr_dbg( "upnp device %s: loop detected, state %hhu -> error", dev->host, dev->state ); dev->state = UPNPDEV_STATE_ERROR; dev->looping = 0; killHttp( fdlimit, &dev->http ); return 1; } laststate = dev->state; dev->state = UPNPDEV_STATE_ERROR; switch( laststate ) { case UPNPDEV_STATE_ROOT: if( !TR_HTTP_STATUS_OK( code ) ) { tr_dbg( "upnp device %s: fetch root failed with http code %i", dev->host, code ); } else if( parseRoot( body, len, &dev->soap, &dev->scpd ) ) { tr_dbg( "upnp device %s: parse root failed", dev->host ); } else { tr_dbg( "upnp device %s: found scpd \"%s\" and soap \"%s\"", dev->root, dev->scpd, dev->soap ); tr_dbg( "upnp device %s: parsed root, state root -> scpd", dev->host ); dev->state = UPNPDEV_STATE_SCPD; } break; case UPNPDEV_STATE_SCPD: if( !TR_HTTP_STATUS_OK( code ) ) { tr_dbg( "upnp device %s: fetch scpd failed with http code %i", dev->host, code ); } else if( parseScpd( body, len, &dev->getcmd, &dev->addcmd, &dev->delcmd ) ) { tr_dbg( "upnp device %s: parse scpd failed", dev->host ); } else { tr_dbg( "upnp device %s: parsed scpd, state scpd -> ready", dev->host ); dev->state = UPNPDEV_STATE_READY; dev->looping = 0; } break; case UPNPDEV_STATE_ADD: dev->looping++; if( IGD_ADD_CONFLICT == code ) { tr_dbg( "upnp device %s: add conflict, state add -> delete", dev->host ); dev->state = UPNPDEV_STATE_DEL; } else if( TR_HTTP_STATUS_OK( code ) || IGD_GENERIC_ERROR == code || IGD_GENERIC_FAILED == code ) { tr_dbg( "upnp device %s: add attempt, state add -> get", dev->host ); dev->state = UPNPDEV_STATE_GET; } else { tr_dbg( "upnp device %s: add failed with http code %i", dev->host, code ); } break; case UPNPDEV_STATE_GET: dev->looping++; if( TR_HTTP_STATUS_OK( code ) ) { switch( parseMapping( dev, body, len ) ) { case -1: break; case 0: tr_dbg( "upnp device %s: invalid mapping, " "state get -> delete", dev->host ); dev->state = UPNPDEV_STATE_DEL; break; case 1: tr_dbg( "upnp device %s: good mapping, " "state get -> mapped", dev->host ); dev->state = UPNPDEV_STATE_MAPPED; dev->looping = 0; dev->lastcheck = tr_date(); tr_inf( "upnp successful for port %i", dev->mappedport ); break; default: assert( 0 ); break; } } else if( IGD_NO_MAPPING_EXISTS == code || IGD_GENERIC_ERROR == code || IGD_GENERIC_FAILED == code ) { tr_dbg( "upnp device %s: no mapping, state get -> add", dev->host ); dev->state = UPNPDEV_STATE_ADD; } else { tr_dbg( "upnp device %s: get failed with http code %i", dev->host, code ); } break; case UPNPDEV_STATE_DEL: dev->looping++; if( TR_HTTP_STATUS_OK( code ) || IGD_NO_MAPPING_EXISTS == code || IGD_GENERIC_ERROR == code || IGD_GENERIC_FAILED == code ) { tr_dbg( "upnp device %s: deleted, state delete -> ready", dev->host ); dev->state = UPNPDEV_STATE_READY; dev->looping = 0; } else { tr_dbg( "upnp device %s: del failed with http code %i", dev->host, code ); } break; default: assert( 0 ); break; } dev->lastrequest = tr_date(); killHttp( fdlimit, &dev->http ); if( UPNPDEV_STATE_ERROR == dev->state ) { tr_dbg( "upnp device %s: error, state %hhu -> error", dev->host, laststate ); return 0; } return 1; }
void tr_natpmpForwardPort( tr_natpmp_t * pmp, int port ) { tr_inf( "nat-pmp set port %i", port ); pmp->newport = port; }
void tr_natpmpPulse( tr_natpmp_t * pmp, int * publicPort ) { if( 0 <= pmp->mcastfd ) { mcastpulse( pmp ); } if( NULL != publicPort ) { *publicPort = -1; } if( pmp->active || PMP_STATE_DELETING == pmp->state ) { switch( pmp->state ) { case PMP_STATE_IDLE: case PMP_STATE_TMPFAIL: if( 0 < pmp->newport ) { tr_dbg( "nat-pmp state %s -> add with port %i", ( PMP_STATE_IDLE == pmp->state ? "idle" : "err" ), pmp->newport ); pmp->state = PMP_STATE_ADDING; } break; case PMP_STATE_ADDING: if( NULL == pmp->req ) { if( 0 >= pmp->newport ) { tr_dbg( "nat-pmp state add -> idle, no port" ); pmp->state = PMP_STATE_IDLE; } else if( INADDR_NONE == pmp->dest.s_addr ) { tr_dbg( "nat-pmp state add -> fail, no default route" ); pmp->state = PMP_STATE_FAILED; } else { pmp->req = newreq( 1, pmp->dest, pmp->newport ); if( NULL == pmp->req ) { pmp->state = PMP_STATE_FAILED; tr_dbg( "nat-pmp state add -> fail on req init" ); } } } if( PMP_STATE_ADDING == pmp->state ) { switch( pulsereq( pmp ) ) { case TR_NET_ERROR: if( pmp->req->nobodyhome ) { pmp->state = PMP_STATE_NOBODYHOME; tr_dbg( "nat-pmp state add -> nobodyhome on pulse" ); } else if( pmp->req->tmpfail ) { pmp->state = PMP_STATE_TMPFAIL; tr_dbg( "nat-pmp state add -> err on pulse" ); if( pmp->req->askport == pmp->newport ) { pmp->newport = 0; } } else { pmp->state = PMP_STATE_FAILED; tr_dbg( "nat-pmp state add -> fail on pulse" ); } killreq( &pmp->req ); break; case TR_NET_OK: pmp->mappedport = pmp->req->gotport; if( pmp->mappedport != pmp->newport && pmp->newport == pmp->req->askport ) { pmp->newport = pmp->req->gotport; } killreq( &pmp->req ); pmp->state = PMP_STATE_MAPPED; pmp->mapped = 1; tr_dbg( "nat-pmp state add -> mapped with port %i", pmp->mappedport); tr_inf( "nat-pmp mapped port %i", pmp->mappedport ); if( NULL != publicPort ) { *publicPort = pmp->mappedport; } break; case TR_NET_WAIT: break; } } break; case PMP_STATE_DELETING: if( NULL == pmp->req ) { assert( 0 < pmp->mappedport ); pmp->req = newreq( 0, pmp->dest, pmp->mappedport ); if( NULL == pmp->req ) { pmp->state = PMP_STATE_FAILED; tr_dbg( "nat-pmp state del -> fail on req init" ); } } if( PMP_STATE_DELETING == pmp->state ) { switch( pulsereq( pmp ) ) { case TR_NET_ERROR: if( pmp->req->nobodyhome ) { pmp->mapped = 0; pmp->state = PMP_STATE_NOBODYHOME; tr_dbg( "nat-pmp state del -> nobodyhome on pulse" ); } else if( pmp->req->tmpfail ) { pmp->mapped = 0; pmp->state = PMP_STATE_TMPFAIL; tr_dbg( "nat-pmp state del -> err on pulse" ); pmp->mappedport = -1; } else { pmp->state = PMP_STATE_FAILED; tr_dbg( "nat-pmp state del -> fail on pulse" ); } killreq( &pmp->req ); break; case TR_NET_OK: tr_dbg( "nat-pmp state del -> idle with port %i", pmp->req->askport); tr_inf( "nat-pmp unmapped port %i", pmp->req->askport ); pmp->mapped = 0; pmp->mappedport = -1; killreq( &pmp->req ); pmp->state = PMP_STATE_IDLE; break; case TR_NET_WAIT: break; } } break; case PMP_STATE_MAPPED: if( pmp->newport != pmp->mappedport ) { tr_dbg( "nat-pmp state mapped -> del, port from %i to %i", pmp->mappedport, pmp->newport ); pmp->state = PMP_STATE_DELETING; } else if( tr_date() > pmp->renew ) { pmp->state = PMP_STATE_ADDING; tr_dbg( "nat-pmp state mapped -> add for renewal" ); } break; case PMP_STATE_FAILED: case PMP_STATE_NOBODYHOME: break; default: assert( 0 ); break; } } }
static tr_tristate_t pulsereq( tr_natpmp_t * pmp ) { tr_natpmp_req_t * req = pmp->req; struct sockaddr_in sin; uint8_t buf[16]; int res; uint64_t now; tr_tristate_t ret; tr_natpmp_parse_t parse; now = tr_date(); /* check for timeout */ if( now >= req->timeout ) { tr_dbg( "nat-pmp request timed out" ); req->nobodyhome = 1; return TR_NET_ERROR; } /* send another request if it's been long enough */ if( now >= req->retry && sendreq( req ) ) { return TR_NET_ERROR; } /* check for incoming packets */ res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin ); if( TR_NET_BLOCK & res ) { return TR_NET_WAIT; } else if( TR_NET_CLOSE & res ) { if( ECONNRESET == errno || ECONNREFUSED == errno ) { tr_dbg( "nat-pmp not supported by device" ); req->nobodyhome = 1; } else { tr_inf( "error reading nat-pmp response (%s)", strerror( errno ) ); } return TR_NET_ERROR; } /* parse the packet */ tr_dbg( "nat-pmp read %i byte response", res ); ret = parseresponse( buf, res, req->askport, &parse ); req->tmpfail = parse.tmpfail; /* check for device reset */ if( checktime( &pmp->uptime, parse.seconds ) ) { pmp->renew = 0; tr_inf( "detected nat-pmp device reset" ); resetreq( req ); ret = TR_NET_WAIT; } if( TR_NET_OK == ret && req->adding ) { if( req->askport != parse.port ) { tr_dbg( "nat-pmp received %i for public port instead of %i", parse.port, req->askport ); req->gotport = parse.port; } tr_dbg( "nat-pmp set renew to half of %u", parse.lifetime ); pmp->renew = now + ( parse.lifetime / 2 * 1000 ); } return ret; }
int tr_trackerPulse( tr_tracker_t * tc ) { tr_torrent_t * tor = tc->tor; tr_info_t * inf = &tor->info; uint64_t now = tr_date(); if( ( tc->status & TC_STATUS_IDLE ) && shouldConnect( tc ) ) { tc->resolve = tr_netResolveInit( inf->trackerAddress ); tr_inf( "Tracker: connecting to %s:%d (%s)", inf->trackerAddress, inf->trackerPort, tc->started ? "sending 'started'" : ( tc->completed ? "sending 'completed'" : ( tc->stopped ? "sending 'stopped'" : ( 0 < tc->newPort ? "sending 'stopped' to change port" : "getting peers" ) ) ) ); tc->status = TC_STATUS_RESOLVE; tc->dateTry = tr_date(); } if( tc->status & TC_STATUS_RESOLVE ) { int ret; struct in_addr addr; ret = tr_netResolvePulse( tc->resolve, &addr ); if( ret == TR_RESOLVE_WAIT ) { return 0; } else { tr_netResolveClose( tc->resolve ); } if( ret == TR_RESOLVE_ERROR ) { tc->status = TC_STATUS_IDLE; return 0; } if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) ) { tc->status = TC_STATUS_IDLE; return 0; } tc->socket = tr_netOpen( addr, htons( inf->trackerPort ) ); if( tc->socket < 0 ) { tr_fdSocketClosed( tor->fdlimit, 1 ); tc->status = TC_STATUS_IDLE; return 0; } tc->status = TC_STATUS_CONNECT; } if( tc->status & TC_STATUS_CONNECT ) { /* We are connecting to the tracker. Try to send the query */ sendQuery( tc ); } if( tc->status & TC_STATUS_RECV ) { /* Try to get something */ recvAnswer( tc ); } if( tc->status > TC_STATUS_IDLE && now > tc->dateTry + 60000 ) { /* Give up if the request wasn't successful within 60 seconds */ tr_inf( "Tracker: timeout reached (60 s)" ); tr_netClose( tc->socket ); tr_fdSocketClosed( tor->fdlimit, 1 ); tc->status = TC_STATUS_IDLE; tc->dateTry = tr_date(); } return 0; }
int main( int argc, char ** argv ) { int c; const char * optarg; tr_benc settings; tr_bool boolVal; tr_bool loaded; tr_bool foreground = FALSE; tr_bool dumpSettings = FALSE; const char * configDir = NULL; const char * pid_filename; dtr_watchdir * watchdir = NULL; FILE * logfile = NULL; tr_bool pidfile_created = FALSE; signal( SIGINT, gotsig ); signal( SIGTERM, gotsig ); #ifndef WIN32 signal( SIGHUP, gotsig ); #endif /* load settings from defaults + config file */ tr_bencInitDict( &settings, 0 ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_ENABLED, TRUE ); configDir = getConfigDir( argc, (const char**)argv ); loaded = tr_sessionLoadSettings( &settings, configDir, MY_NAME ); /* overwrite settings from the comamndline */ tr_optind = 1; while(( c = tr_getopt( getUsage(), argc, (const char**)argv, options, &optarg ))) { switch( c ) { case 'a': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_WHITELIST, optarg ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, TRUE ); break; case 'b': tr_bencDictAddBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, TRUE ); break; case 'B': tr_bencDictAddBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE ); break; case 'c': tr_bencDictAddStr( &settings, PREF_KEY_DIR_WATCH, optarg ); tr_bencDictAddBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, TRUE ); break; case 'C': tr_bencDictAddBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, FALSE ); break; case 941: tr_bencDictAddStr( &settings, TR_PREFS_KEY_INCOMPLETE_DIR, optarg ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, TRUE ); break; case 942: tr_bencDictAddBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, FALSE ); break; case 'd': dumpSettings = TRUE; break; case 'e': logfile = fopen( optarg, "a+" ); if( logfile == NULL ) fprintf( stderr, "Couldn't open \"%s\": %s\n", optarg, tr_strerror( errno ) ); break; case 'f': foreground = TRUE; break; case 'g': /* handled above */ break; case 'V': /* version */ fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING); exit( 0 ); case 'o': tr_bencDictAddBool( &settings, TR_PREFS_KEY_DHT_ENABLED, TRUE ); break; case 'O': tr_bencDictAddBool( &settings, TR_PREFS_KEY_DHT_ENABLED, FALSE ); break; case 'p': tr_bencDictAddInt( &settings, TR_PREFS_KEY_RPC_PORT, atoi( optarg ) ); break; case 't': tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, TRUE ); break; case 'T': tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, FALSE ); break; case 'u': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_USERNAME, optarg ); break; case 'v': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_PASSWORD, optarg ); break; case 'w': tr_bencDictAddStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, optarg ); break; case 'P': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_PORT, atoi( optarg ) ); break; case 'm': tr_bencDictAddBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, TRUE ); break; case 'M': tr_bencDictAddBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, FALSE ); break; case 'L': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, atoi( optarg ) ); break; case 'l': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, atoi( optarg ) ); break; case 800: paused = TRUE; break; case 910: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_REQUIRED ); break; case 911: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_PREFERRED ); break; case 912: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_CLEAR_PREFERRED ); break; case 'i': tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, optarg ); break; case 'I': tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, optarg ); break; case 'r': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_BIND_ADDRESS, optarg ); break; case 953: tr_bencDictAddReal( &settings, TR_PREFS_KEY_RATIO, atof(optarg) ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, TRUE ); break; case 954: tr_bencDictAddBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, FALSE ); break; case 'x': tr_bencDictAddStr( &settings, PREF_KEY_PIDFILE, optarg ); break; case 'y': tr_bencDictAddBool( &settings, TR_PREFS_KEY_LPD_ENABLED, TRUE ); break; case 'Y': tr_bencDictAddBool( &settings, TR_PREFS_KEY_LPD_ENABLED, FALSE ); break; case 810: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_ERR ); break; case 811: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_INF ); break; case 812: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_DBG ); break; default: showUsage( ); break; } } if( foreground && !logfile ) logfile = stderr; if( !loaded ) { printMessage( logfile, TR_MSG_ERR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__ ); return -1; } if( dumpSettings ) { char * str = tr_bencToStr( &settings, TR_FMT_JSON, NULL ); fprintf( stderr, "%s", str ); tr_free( str ); return 0; } if( !foreground && tr_daemon( TRUE, FALSE ) < 0 ) { char buf[256]; tr_snprintf( buf, sizeof( buf ), "Failed to daemonize: %s", tr_strerror( errno ) ); printMessage( logfile, TR_MSG_ERR, MY_NAME, buf, __FILE__, __LINE__ ); exit( 1 ); } /* start the session */ tr_formatter_mem_init( MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR ); tr_formatter_size_init( DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR ); tr_formatter_speed_init( SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR ); mySession = tr_sessionInit( "daemon", configDir, TRUE, &settings ); tr_ninf( NULL, "Using settings from \"%s\"", configDir ); tr_sessionSaveSettings( mySession, configDir, &settings ); pid_filename = NULL; tr_bencDictFindStr( &settings, PREF_KEY_PIDFILE, &pid_filename ); if( pid_filename && *pid_filename ) { FILE * fp = fopen( pid_filename, "w+" ); if( fp != NULL ) { fprintf( fp, "%d", (int)getpid() ); fclose( fp ); tr_inf( "Saved pidfile \"%s\"", pid_filename ); pidfile_created = TRUE; } else tr_err( "Unable to save pidfile \"%s\": %s", pid_filename, strerror( errno ) ); } if( tr_bencDictFindBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, &boolVal ) && boolVal ) tr_ninf( MY_NAME, "requiring authentication" ); /* maybe add a watchdir */ { const char * dir; if( tr_bencDictFindBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, &boolVal ) && boolVal && tr_bencDictFindStr( &settings, PREF_KEY_DIR_WATCH, &dir ) && dir && *dir ) { tr_inf( "Watching \"%s\" for new .torrent files", dir ); watchdir = dtr_watchdir_new( mySession, dir, onFileAdded ); } } /* load the torrents */ { tr_torrent ** torrents; tr_ctor * ctor = tr_ctorNew( mySession ); if( paused ) tr_ctorSetPaused( ctor, TR_FORCE, TRUE ); torrents = tr_sessionLoadTorrents( mySession, ctor, NULL ); tr_free( torrents ); tr_ctorFree( ctor ); } #ifdef HAVE_SYSLOG if( !foreground ) openlog( MY_NAME, LOG_CONS|LOG_PID, LOG_DAEMON ); #endif while( !closing ) { tr_wait_msec( 1000 ); /* sleep one second */ dtr_watchdir_update( watchdir ); pumpLogMessages( logfile ); } /* shutdown */ #if HAVE_SYSLOG if( !foreground ) { syslog( LOG_INFO, "%s", "Closing session" ); closelog( ); } #endif printf( "Closing transmission session..." ); tr_sessionSaveSettings( mySession, configDir, &settings ); dtr_watchdir_free( watchdir ); tr_sessionClose( mySession ); printf( " done.\n" ); /* cleanup */ if( pidfile_created ) remove( pid_filename ); tr_bencFree( &settings ); return 0; }
static void sendQuery( tr_tracker_t * tc ) { tr_torrent_t * tor = tc->tor; tr_info_t * inf = &tor->info; char * event; uint64_t left; int ret; uint64_t down; uint64_t up; down = tor->downloaded - tc->download; up = tor->uploaded - tc->upload; if( tc->started ) { event = "&event=started"; down = up = 0; if( 0 < tc->newPort ) { tc->bindPort = tc->newPort; tc->newPort = -1; } } else if( tc->completed ) { event = "&event=completed"; } else if( tc->stopped || 0 < tc->newPort ) { event = "&event=stopped"; } else { event = ""; } left = tr_cpLeftBytes( tor->completion ); ret = snprintf( (char *) tc->buf, tc->size, "GET %s?" "info_hash=%s&" "peer_id=%s&" "port=%d&" "uploaded=%"PRIu64"&" "downloaded=%"PRIu64"&" "left=%"PRIu64"&" "compact=1&" "numwant=50&" "key=%s" "%s " "HTTP/1.1\r\n" "Host: %s\r\n" "User-Agent: Transmission/%d.%d\r\n" "Connection: close\r\n\r\n", inf->trackerAnnounce, tor->hashString, tc->id, tc->bindPort, up, down, left, tor->key, event, inf->trackerAddress, VERSION_MAJOR, VERSION_MINOR ); ret = tr_netSend( tc->socket, tc->buf, ret ); if( ret & TR_NET_CLOSE ) { tr_inf( "Tracker: connection failed" ); tr_netClose( tc->socket ); tr_fdSocketClosed( tor->fdlimit, 1 ); tc->status = TC_STATUS_IDLE; tc->dateTry = tr_date(); } else if( !( ret & TR_NET_BLOCK ) ) { // printf( "Tracker: sent %s", tc->buf ); tc->status = TC_STATUS_RECV; tc->pos = 0; } }
static void recvAnswer( tr_tracker_t * tc ) { tr_torrent_t * tor = tc->tor; int ret; int i; benc_val_t beAll; benc_val_t * bePeers, * beFoo; uint8_t * body; int bodylen; if( tc->pos == tc->size ) { tc->size *= 2; tc->buf = realloc( tc->buf, tc->size ); } ret = tr_netRecv( tc->socket, &tc->buf[tc->pos], tc->size - tc->pos ); if( ret & TR_NET_BLOCK ) { return; } if( !( ret & TR_NET_CLOSE ) ) { // printf( "got %d bytes\n", ret ); tc->pos += ret; return; } tr_netClose( tc->socket ); tr_fdSocketClosed( tor->fdlimit, 1 ); // printf( "connection closed, got total %d bytes\n", tc->pos ); tc->status = TC_STATUS_IDLE; tc->dateTry = tr_date(); if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) && 0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) ) { /* We don't have a complete HTTP status line */ tr_inf( "Tracker: incomplete HTTP status line" ); tc->lastAttempt = TC_ATTEMPT_NOREACH; return; } if( '2' != tc->buf[9] ) { /* we didn't get a 2xx status code */ tr_err( "Tracker: invalid HTTP status code: %c%c%c", tc->buf[9], tc->buf[10], tc->buf[11] ); tc->lastAttempt = TC_ATTEMPT_ERROR; return; } /* find the end of the http headers */ body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 ); if( NULL != body ) { body += 4; } /* hooray for trackers that violate the HTTP spec */ else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) || NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) ) { body += 2; } else { tr_err( "Tracker: could not find end of HTTP headers" ); tc->lastAttempt = TC_ATTEMPT_NOREACH; return; } bodylen = tc->pos - (body - tc->buf); /* Find and load the dictionary */ for( i = 0; i < bodylen; i++ ) { if( !tr_bencLoad( &body[i], bodylen - i, &beAll, NULL ) ) { break; } } if( i >= bodylen ) { if( tc->stopped || 0 < tc->newPort ) { tc->lastAttempt = TC_ATTEMPT_OK; goto nodict; } tr_err( "Tracker: no valid dictionary found in answer" ); tc->lastAttempt = TC_ATTEMPT_ERROR; return; } // tr_bencPrint( &beAll ); if( ( bePeers = tr_bencDictFind( &beAll, "failure reason" ) ) ) { tr_err( "Tracker: %s", bePeers->val.s.s ); tor->error |= TR_ETRACKER; snprintf( tor->trackerError, sizeof( tor->trackerError ), "%s", bePeers->val.s.s ); tc->lastAttempt = TC_ATTEMPT_ERROR; goto cleanup; } tor->error &= ~TR_ETRACKER; tc->lastAttempt = TC_ATTEMPT_OK; if( !tc->interval ) { /* Get the tracker interval, ignore it if it is not between 10 sec and 5 mins */ if( !( beFoo = tr_bencDictFind( &beAll, "interval" ) ) || !( beFoo->type & TYPE_INT ) ) { tr_err( "Tracker: no 'interval' field" ); goto cleanup; } tc->interval = beFoo->val.i; tc->interval = MIN( tc->interval, 300 ); tc->interval = MAX( 10, tc->interval ); tr_inf( "Tracker: interval = %d seconds", tc->interval ); } if( ( beFoo = tr_bencDictFind( &beAll, "complete" ) ) && ( beFoo->type & TYPE_INT ) ) { tc->seeders = beFoo->val.i; } if( ( beFoo = tr_bencDictFind( &beAll, "incomplete" ) ) && ( beFoo->type & TYPE_INT ) ) { tc->leechers = beFoo->val.i; } if( tc->seeders + tc->leechers >= 50 ) { tc->hasManyPeers = 1; } if( !( bePeers = tr_bencDictFind( &beAll, "peers" ) ) ) { if( tc->stopped || 0 < tc->newPort ) { goto nodict; } tr_err( "Tracker: no \"peers\" field" ); goto cleanup; } if( bePeers->type & TYPE_LIST ) { char * ip; int port; /* Original protocol */ tr_inf( "Tracker: got %d peers", bePeers->val.l.count ); for( i = 0; i < bePeers->val.l.count; i++ ) { beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "ip" ); if( !beFoo ) continue; ip = beFoo->val.s.s; beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "port" ); if( !beFoo ) continue; port = beFoo->val.i; tr_peerAddOld( tor, ip, port ); } if( bePeers->val.l.count >= 50 ) { tc->hasManyPeers = 1; } } else if( bePeers->type & TYPE_STR ) { struct in_addr addr; in_port_t port; /* "Compact" extension */ if( bePeers->val.s.i % 6 ) { tr_err( "Tracker: \"peers\" of size %d", bePeers->val.s.i ); tr_lockUnlock( &tor->lock ); goto cleanup; } tr_inf( "Tracker: got %d peers", bePeers->val.s.i / 6 ); for( i = 0; i < bePeers->val.s.i / 6; i++ ) { memcpy( &addr, &bePeers->val.s.s[6*i], 4 ); memcpy( &port, &bePeers->val.s.s[6*i+4], 2 ); tr_peerAddCompact( tor, addr, port ); } if( bePeers->val.s.i / 6 >= 50 ) { tc->hasManyPeers = 1; } } nodict: /* Success */ tc->started = 0; tc->completed = 0; tc->dateOk = tr_date(); if( tc->stopped ) { tor->status = TR_STATUS_STOPPED; tc->stopped = 0; } else if( 0 < tc->newPort ) { tc->started = 1; tc->download = tor->downloaded; tc->upload = tor->uploaded; } cleanup: tr_bencFree( &beAll ); }
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 ); }