tr_watchdir_backend * tr_watchdir_kqueue_new (tr_watchdir_t handle) { const char * const path = tr_watchdir_get_path (handle); struct kevent ke; tr_watchdir_kqueue * backend; backend = tr_new0 (tr_watchdir_kqueue, 1); backend->base.free_func = &tr_watchdir_kqueue_free; backend->kq = -1; backend->dirfd = -1; if ((backend->kq = kqueue ()) == -1) { log_error ("Failed to start kqueue"); goto fail; } /* Open fd for watching */ if ((backend->dirfd = open (path, O_RDONLY | O_EVTONLY)) == -1) { log_error ("Failed to passively watch directory \"%s\": %s", path, tr_strerror (errno)); goto fail; } /* Register kevent filter with kqueue descriptor */ EV_SET (&ke, backend->dirfd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, KQUEUE_WATCH_MASK, 0, NULL); if (kevent (backend->kq, &ke, 1, NULL, 0, NULL) == -1) { log_error ("Failed to set directory event filter with fd %d: %s", backend->kq, tr_strerror (errno)); goto fail; } /* Create libevent task for event descriptor */ if ((backend->event = event_new (tr_watchdir_get_event_base (handle), backend->kq, EV_READ | EV_ET | EV_PERSIST, &tr_watchdir_kqueue_on_event, handle)) == NULL) { log_error ("Failed to create event: %s", tr_strerror (errno)); goto fail; } if (event_add (backend->event, NULL) == -1) { log_error ("Failed to add event: %s", tr_strerror (errno)); goto fail; } /* Trigger one event for the initial scan */ event_active (backend->event, EV_READ, 0); return BACKEND_DOWNCAST (backend); fail: tr_watchdir_kqueue_free (BACKEND_DOWNCAST (backend)); return NULL; }
static void tr_watchdir_inotify_on_event (struct bufferevent * event, void * context) { assert (context != NULL); const tr_watchdir_t handle = context; tr_watchdir_inotify * const backend = BACKEND_UPCAST (tr_watchdir_get_backend (handle)); struct inotify_event ev; size_t nread; size_t name_size = NAME_MAX + 1; char * name = tr_new (char, name_size); /* Read the size of the struct excluding name into buf. Guaranteed to have at least sizeof (ev) available */ while ((nread = bufferevent_read (event, &ev, sizeof (ev))) != 0) { if (nread == (size_t) -1) { log_error ("Failed to read inotify event: %s", tr_strerror (errno)); break; } if (nread != sizeof (ev)) { log_error ("Failed to read inotify event: expected %zu, got %zu bytes.", sizeof (ev), nread); break; } assert (ev.wd == backend->inwd); assert ((ev.mask & INOTIFY_WATCH_MASK) != 0); assert (ev.len > 0); if (ev.len > name_size) { name_size = ev.len; name = tr_renew (char, name, name_size); } /* Consume entire name into buffer */ if ((nread = bufferevent_read (event, name, ev.len)) == (size_t) -1) { log_error ("Failed to read inotify name: %s", tr_strerror (errno)); break; } if (nread != ev.len) { log_error ("Failed to read inotify name: expected %" PRIu32 ", got %zu bytes.", ev.len, nread); break; } tr_watchdir_process (handle, name); }
static void set_socket_buffers (int fd, int large) { int size, rbuf, sbuf, rc; socklen_t rbuf_len = sizeof (rbuf), sbuf_len = sizeof (sbuf); size = large ? RECV_BUFFER_SIZE : SMALL_BUFFER_SIZE; rc = setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)); if (rc < 0) tr_logAddNamedError ("UDP", "Failed to set receive buffer: %s", tr_strerror (errno)); size = large ? SEND_BUFFER_SIZE : SMALL_BUFFER_SIZE; rc = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)); if (rc < 0) tr_logAddNamedError ("UDP", "Failed to set send buffer: %s", tr_strerror (errno)); if (large) { rc = getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &rbuf_len); if (rc < 0) rbuf = 0; rc = getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &sbuf_len); if (rc < 0) sbuf = 0; if (rbuf < RECV_BUFFER_SIZE) { tr_logAddNamedError ("UDP", "Failed to set receive buffer: requested %d, got %d", RECV_BUFFER_SIZE, rbuf); #ifdef __linux__ tr_logAddNamedInfo ("UDP", "Please add the line " "\"net.core.rmem_max = %d\" to /etc/sysctl.conf", RECV_BUFFER_SIZE); #endif } if (sbuf < SEND_BUFFER_SIZE) { tr_logAddNamedError ("UDP", "Failed to set send buffer: requested %d, got %d", SEND_BUFFER_SIZE, sbuf); #ifdef __linux__ tr_logAddNamedInfo ("UDP", "Please add the line " "\"net.core.wmem_max = %d\" to /etc/sysctl.conf", SEND_BUFFER_SIZE); #endif } } }
static void set_system_error (tr_error ** error, int code, const char * message) { tr_error_set (error, code, "%s (%d): %s", message, code, tr_strerror (code)); }
/** * 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 void set_system_error (tr_error ** error, int code) { if (error == NULL) return; tr_error_set_literal (error, code, tr_strerror (code)); }
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 ); } }
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); }
char * tr_net_strerror (char * buf, size_t buflen, int err) { *buf = '\0'; #ifdef WIN32 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, buflen, NULL); #else tr_strlcpy (buf, tr_strerror (err), buflen); #endif return buf; }
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 maybeSetCongestionAlgorithm( int socket, const char * algorithm ) { if( algorithm && *algorithm ) { const int rc = tr_netSetCongestionControl( socket, algorithm ); if( rc < 0 ) tr_ninf( "Net", "Can't set congestion control algorithm '%s': %s", algorithm, tr_strerror( errno )); } }
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 int tr_daemon( int nochdir, int noclose ) { #if defined(USE_OS_DAEMON) return daemon( nochdir, noclose ); #elif defined(USE_TR_DAEMON) pid_t pid = fork( ); if( pid < 0 ) return -1; else if( pid > 0 ) _exit( 0 ); else { pid = setsid( ); if( pid < 0 ) return -1; pid = fork( ); if( pid < 0 ) return -1; else if( pid > 0 ) _exit( 0 ); else { if( !nochdir ) if( chdir( "/" ) < 0 ) return -1; umask( (mode_t)0 ); if( !noclose ) { /* send stdin, stdout, and stderr to /dev/null */ int i; int fd = open( "/dev/null", O_RDWR, 0 ); if( fd < 0 ) fprintf( stderr, "unable to open /dev/null: %s\n", tr_strerror(errno) ); for( i=0; i<3; ++i ) { if( close( i ) ) return -1; dup2( fd, i ); } close( fd ); } return 0; } } #else /* USE_NO_DAEMON */ return 0; #endif }
static void logVal( const char * func, int ret ) { if( ret == NATPMP_TRYAGAIN ) return; if( ret >= 0 ) tr_ninf( getKey( ), _( "%s succeeded (%d)" ), func, ret ); else tr_ndbg( getKey( ), "%s failed. Natpmp returned %d (%s); errno is %d (%s)", func, ret, strnatpmperr( ret ), errno, tr_strerror( errno ) ); }
static char* tr_getcwd( void ) { char * result; char buf[2048]; #ifdef WIN32 result = _getcwd( buf, sizeof( buf ) ); #else result = getcwd( buf, sizeof( buf ) ); #endif if( result == NULL ) { fprintf( stderr, "getcwd error: \"%s\"", tr_strerror( errno ) ); *buf = '\0'; } return tr_strdup( buf ); }
void tr_eventInit (tr_session * session) { tr_event_handle * eh; session->events = NULL; eh = tr_new0 (tr_event_handle, 1); eh->lock = tr_lockNew (); if (pipe (eh->fds) == -1) tr_logAddError ("Unable to write to pipe() in libtransmission: %s", tr_strerror(errno)); eh->session = session; eh->thread = tr_threadNew (libeventThreadFunc, eh); /* wait until the libevent thread is running */ while (session->events == NULL) tr_wait_msec (100); }
static struct UPNPDev * tr_upnpDiscover (int msec) { struct UPNPDev * ret = NULL; #if defined (HAVE_MINIUPNP_16) int err = UPNPDISCOVER_SUCCESS; ret = upnpDiscover (msec, NULL, NULL, 0, 0, &err); if (err != UPNPDISCOVER_SUCCESS) #elif defined (HAVE_MINIUPNP_15) ret = upnpDiscover (msec, NULL, NULL, 0); if (ret == NULL) #endif tr_logAddNamedDbg (getKey (), "upnpDiscover failed (errno %d - %s)", errno, tr_strerror (errno)); return ret; }
/* this is for really old versions of T and will probably be removed someday */ void tr_metainfoMigrate( tr_session * session, tr_info * inf ) { struct stat new_sb; char * name = getTorrentFilename( session, inf ); if( stat( name, &new_sb ) || ( ( new_sb.st_mode & S_IFMT ) != S_IFREG ) ) { char * old_name = getOldTorrentFilename( session, inf ); size_t contentLen; uint8_t * content; tr_mkdirp( tr_getTorrentDir( session ), 0777 ); if( ( content = tr_loadFile( old_name, &contentLen ) ) ) { FILE * out; errno = 0; out = fopen( name, "wb+" ); if( !out ) { tr_nerr( inf->name, _( "Couldn't create \"%1$s\": %2$s" ), name, tr_strerror( errno ) ); } else { if( fwrite( content, sizeof( uint8_t ), contentLen, out ) == contentLen ) { tr_free( inf->torrent ); inf->torrent = tr_strdup( name ); tr_sessionSetTorrentFile( session, inf->hashString, name ); unlink( old_name ); } fclose( out ); } } tr_free( content ); tr_free( old_name ); } tr_free( name ); }
/* returns 0 on success, or an errno on failure */ static int readOrWritePiece( tr_torrent * tor, int ioMode, tr_piece_index_t pieceIndex, uint32_t pieceOffset, uint8_t * buf, size_t buflen ) { int err = 0; tr_file_index_t fileIndex; uint64_t fileOffset; const tr_info * info = &tor->info; if( pieceIndex >= tor->info.pieceCount ) return EINVAL; //if( pieceOffset + buflen > tr_torPieceCountBytes( tor, pieceIndex ) ) // return EINVAL; tr_ioFindFileLocation( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset ); while( buflen && !err ) { const tr_file * file = &info->files[fileIndex]; const uint64_t bytesThisPass = MIN( buflen, file->length - fileOffset ); err = readOrWriteBytes( tor->session, tor, ioMode, fileIndex, fileOffset, buf, bytesThisPass ); buf += bytesThisPass; buflen -= bytesThisPass; //fprintf( stderr, "++fileIndex to %d\n", (int)fileIndex ); ++fileIndex; fileOffset = 0; if( ( err != 0 ) && (ioMode == TR_IO_WRITE ) && ( tor->error != TR_STAT_LOCAL_ERROR ) ) { char * path = tr_buildPath( tor->downloadDir, file->name, NULL ); tr_torrentSetLocalError( tor, "%s (%s)", tr_strerror( err ), path ); tr_free( path ); } } return err; }
static void tr_watchdir_kqueue_on_event (evutil_socket_t fd UNUSED, short type UNUSED, void * context) { const tr_watchdir_t handle = context; tr_watchdir_kqueue * const backend = BACKEND_UPCAST (tr_watchdir_get_backend (handle)); struct kevent ke; const struct timespec ts = { 0, 0 }; if (kevent (backend->kq, NULL, 0, &ke, 1, &ts) == -1) { log_error ("Failed to fetch kevent: %s", tr_strerror (errno)); return; } /* Read directory with generic scan */ tr_watchdir_scan (handle, &backend->dir_entries); }
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 ); }
static struct UPNPDev * tr_upnpDiscover (int msec) { struct UPNPDev * ret; bool have_err; #if (MINIUPNPC_API_VERSION >= 8) /* adds ipv6 and error args */ int err = UPNPDISCOVER_SUCCESS; ret = upnpDiscover (msec, NULL, NULL, 0, 0, &err); have_err = err != UPNPDISCOVER_SUCCESS; #else ret = upnpDiscover (msec, NULL, NULL, 0); have_err = ret == NULL; #endif if (have_err) tr_logAddNamedDbg (getKey (), "upnpDiscover failed (errno %d - %s)", errno, tr_strerror (errno)); return ret; }
int tr_fdSocketCreate( int type ) { int s = -1; tr_lockLock( gFd->lock ); if( gFd->socketCount < getSocketMax( gFd ) ) if( ( s = socket( AF_INET, type, 0 ) ) < 0 ) tr_err( _( "Couldn't create socket: %s" ), tr_strerror( sockerrno ) ); if( s > -1 ) ++gFd->socketCount; assert( gFd->socketCount >= 0 ); tr_lockUnlock( gFd->lock ); return s; }
int tr_fdSocketCreate( tr_session * session, int domain, int type ) { int s = -1; struct tr_fdInfo * gFd; assert( tr_isSession( session ) ); assert( session->fdInfo != NULL ); gFd = session->fdInfo; if( gFd->socketCount < gFd->socketLimit ) if( ( s = socket( domain, type, 0 ) ) < 0 ) { if( sockerrno != EAFNOSUPPORT ) tr_err( _( "Couldn't create socket: %s" ), tr_strerror( sockerrno ) ); } if( s > -1 ) ++gFd->socketCount; assert( gFd->socketCount >= 0 ); if( s >= 0 ) { static tr_bool buf_logged = FALSE; if( !buf_logged ) { int i; socklen_t size = sizeof( int ); buf_logged = TRUE; getsockopt( s, SOL_SOCKET, SO_SNDBUF, &i, &size ); tr_dbg( "SO_SNDBUF size is %d", i ); getsockopt( s, SOL_SOCKET, SO_RCVBUF, &i, &size ); tr_dbg( "SO_RCVBUF size is %d", i ); } } return s; }
char* tr_net_strerror(char* buf, size_t buflen, int err) { *buf = '\0'; #ifdef _WIN32 DWORD len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, buflen, NULL); while (len > 0 && buf[len - 1] >= '\0' && buf[len - 1] <= ' ') { buf[--len] = '\0'; } #else tr_strlcpy(buf, tr_strerror(err), buflen); #endif return buf; }
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); } }
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, NULL); if (err == TR_PARSE_ERR) tr_logAddError ("Error parsing .torrent file \"%s\"", file); else { bool trash = false; int test = tr_ctorGetDeleteSource (ctor, &trash); tr_logAddInfo ("Parsing .torrent file successful \"%s\"", file); if (!test && trash) { tr_logAddInfo ("Deleting input .torrent file \"%s\"", file); if (tr_remove (filename)) tr_logAddError ("Error deleting .torrent file: %s", tr_strerror (errno)); } else { char * new_filename = tr_strdup_printf ("%s.added", filename); tr_rename (filename, new_filename); tr_free (new_filename); } } } tr_ctorFree (ctor); tr_free (filename); }
static void watchdir_new_impl (dtr_watchdir * w) { int i; tr_sys_dir_t odir; w->inotify_fd = inotify_init (); if (w->inotify_fd < 0) { i = -1; } else { tr_logAddInfo ("Using inotify to watch directory \"%s\"", w->dir); i = inotify_add_watch (w->inotify_fd, w->dir, DTR_INOTIFY_MASK); } if (i < 0) { tr_logAddError ("Unable to watch \"%s\": %s", w->dir, tr_strerror (errno)); } else if ((odir = tr_sys_dir_open (w->dir, NULL)) != TR_BAD_SYS_DIR) { const char * name; while ((name = tr_sys_dir_read_name (odir, NULL)) != NULL) { if (!tr_str_has_suffix (name, ".torrent")) /* skip non-torrents */ continue; tr_logAddInfo ("Found new .torrent file \"%s\" in watchdir \"%s\"", name, w->dir); w->callback (w->session, w->dir, name); } tr_sys_dir_close (odir, NULL); } }
void tr_runInEventThread (tr_session * session, void func (void*), void * user_data) { assert (tr_isSession (session)); assert (session->events != NULL); if (tr_amInThread (session->events->thread)) { (func)(user_data); } else { int fd; char ch; ssize_t res_1; ssize_t res_2; tr_event_handle * e = session->events; struct tr_run_data data; tr_lockLock (e->lock); fd = e->fds[1]; ch = 'r'; res_1 = pipewrite (fd, &ch, 1); data.func = func; data.user_data = user_data; res_2 = pipewrite (fd, &data, sizeof (data)); tr_lockUnlock (e->lock); if ((res_1 == -1) || (res_2 == -1)) tr_logAddError ("Unable to write to libtransmisison event queue: %s", tr_strerror(errno)); } }
static void gotsig (int sig) { switch (sig) { case SIGHUP: { if (!mySession) { tr_logAddInfo ("Deferring reload until session is fully started."); seenHUP = true; } else { tr_variant settings; const char * configDir; /* reopen the logfile to allow for log rotation */ if (logfileName) { logfile = freopen (logfileName, LOGFILE_MODE_STR, logfile); if (!logfile) fprintf (stderr, "Couldn't reopen \"%s\": %s\n", logfileName, tr_strerror (errno)); } configDir = tr_sessionGetConfigDir (mySession); tr_logAddInfo ("Reloading settings from \"%s\"", configDir); tr_variantInitDict (&settings, 0); tr_variantDictAddBool (&settings, TR_KEY_rpc_enabled, true); tr_sessionLoadSettings (&settings, configDir, MY_NAME); tr_sessionSet (mySession, &settings); tr_variantFree (&settings); tr_sessionReloadBlocklists (mySession); } break; } default: tr_logAddError ("Unexpected signal (%d) in daemon, closing.", sig); /* no break */ case SIGINT: case SIGTERM: event_base_loopexit(ev_base, NULL); break; } }