def serve_forever(self, timeout=None, blocking=True, handle_exit=True): """Start serving. - (float) timeout: the timeout passed to the underlying IO loop expressed in seconds (default 1.0). - (bool) blocking: if False loop once and then return the timeout of the next scheduled call next to expire soonest (if any). - (bool) handle_exit: when True catches KeyboardInterrupt and SystemExit exceptions (generally caused by SIGTERM / SIGINT signals) and gracefully exits after cleaning up resources. Also, logs server start and stop. """ if handle_exit: log = handle_exit and blocking if log: self._log_start() try: self.ioloop.loop(timeout, blocking) except (KeyboardInterrupt, SystemExit): pass if blocking: if log: logger.info( ">>> shutting down FTP server (%s active fds) <<<", self._map_len()) self.close_all() else: self.ioloop.loop(timeout, blocking)
def _log_start(self): if (not logging.getLogger('pyftpdlib').handlers and not logging.root.handlers): # If we get to this point it means the user hasn't # configured any logger. We want logging to be on # by default (stderr). from pyftpdlib.ioloop import _config_logging _config_logging() if self.handler.passive_ports: pasv_ports = "%s->%s" % (self.handler.passive_ports[0], self.handler.passive_ports[-1]) else: pasv_ports = None addr = self.address if hasattr(self.handler, 'ssl_protocol'): proto = "FTP+SSL" else: proto = "FTP" logger.info(">>> starting %s server on %s:%s, pid=%i <<<" % (proto, addr[0], addr[1], os.getpid())) logger.info("poller: %r", self.ioloop.__class__) logger.info("masquerade (NAT) address: %s", self.handler.masquerade_address) logger.info("passive ports: %s", pasv_ports) if os.name == 'posix': logger.info("use sendfile(2): %s", self.handler.use_sendfile)
def serve_forever(self, timeout=None, blocking=True, handle_exit=True): self._exit.clear() if handle_exit: log = handle_exit and blocking == True if log: self._log_start() try: self.ioloop.loop(timeout, blocking) except (KeyboardInterrupt, SystemExit): pass if blocking: if log: logger.info(">>> shutting down FTP server (%s active " "workers) <<<", self._map_len()) self.close_all() else: self.ioloop.loop(timeout, blocking)
def serve_forever(self, timeout=None, blocking=True, handle_exit=True): self._exit.clear() if handle_exit: log = handle_exit and blocking == True if log: self._log_start() try: self.ioloop.loop(timeout, blocking) except (KeyboardInterrupt, SystemExit): pass if blocking: if log: logger.info(">>> shutting down FTP server (%s active " \ "workers) <<<", self._map_len()) self.close_all() else: self.ioloop.loop(timeout, blocking)
def serve_forever(self, timeout=None, blocking=True, handle_exit=True): if handle_exit: log = handle_exit and blocking if log: self._log_start() try: self.ioloop.loop(timeout, blocking) except (KeyboardInterrupt, SystemExit): logger.info("received interrupt signal") if blocking: if log: logger.info( ">>> shutting down FTP server (%s active socket " "fds) <<<", self._map_len()) self.close_all() else: self.ioloop.loop(timeout, blocking)
def _log_start(self): if not logging.getLogger().handlers: # If we get to this point it means the user hasn't # configured logger. We want to log by default so # we configure logging ourselves so that it will # print to stderr. from pyftpdlib.ioloop import _config_logging _config_logging() if self.handler.passive_ports: pasv_ports = "%s->%s" % (self.handler.passive_ports[0], self.handler.passive_ports[-1]) else: pasv_ports = None logger.info(">>> starting FTP server on %s:%s <<<" % self.address) logger.info("poller: %r", self.ioloop.__class__) logger.info("masquerade (NAT) address: %s", self.handler.masquerade_address) logger.info("passive ports: %s", pasv_ports) if os.name == "posix": logger.info("use sendfile(2): %s", self.handler.use_sendfile)
def _log_start(self): if not logging.getLogger().handlers: # If we get to this point it means the user hasn't # configured logger. We want to log by default so # we configure logging ourselves so that it will # print to stderr. from pyftpdlib.ioloop import _config_logging _config_logging() if self.handler.passive_ports: pasv_ports = "%s->%s" % (self.handler.passive_ports[0], self.handler.passive_ports[-1]) else: pasv_ports = None logger.info(">>> starting FTP server on %s:%s <<<" % self.address) logger.info("poller: %r", self.ioloop.__class__) logger.info("masquerade (NAT) address: %s", self.handler.masquerade_address) logger.info("passive ports: %s", pasv_ports) if os.name == 'posix': logger.info("use sendfile(2): %s", self.handler.use_sendfile)
def _log_start(self): FTPServer._log_start(self) logger.info("dispatcher: %r", self.__class__)
def _loop(self, handler): """Serve handler's IO loop in a separate thread or process.""" ioloop = IOLoop() try: handler.ioloop = ioloop try: handler.add_channel() except EnvironmentError: err = sys.exc_info()[1] if err.errno == errno.EBADF: # we might get here in case the other end quickly # disconnected (see test_quick_connect()) return else: raise # Here we localize variable access to minimize overhead. poll = ioloop.poll sched_poll = ioloop.sched.poll poll_timeout = getattr(self, 'poll_timeout', None) soonest_timeout = poll_timeout while (ioloop.socket_map or ioloop.sched._tasks) and \ not self._exit.is_set(): try: if ioloop.socket_map: poll(timeout=soonest_timeout) if ioloop.sched._tasks: soonest_timeout = sched_poll() # Handle the case where socket_map is emty but some # cancelled scheduled calls are still around causing # this while loop to hog CPU resources. # In theory this should never happen as all the sched # functions are supposed to be cancel()ed on close() # but by using threads we can incur into # synchronization issues such as this one. # https://github.com/giampaolo/pyftpdlib/issues/245 if not ioloop.socket_map: # get rid of cancel()led calls ioloop.sched.reheapify() soonest_timeout = sched_poll() if soonest_timeout: time.sleep(min(soonest_timeout, 1)) else: soonest_timeout = None except (KeyboardInterrupt, SystemExit): # note: these two exceptions are raised in all sub # processes self._exit.set() except select.error: # on Windows we can get WSAENOTSOCK if the client # rapidly connect and disconnects err = sys.exc_info()[1] if os.name == 'nt' and err.args[0] == 10038: for fd in list(ioloop.socket_map.keys()): try: select.select([fd], [], [], 0) except select.error: try: logger.info("discarding broken socket %r", ioloop.socket_map[fd]) del ioloop.socket_map[fd] except KeyError: # dict changed during iteration pass else: raise else: if poll_timeout: if (soonest_timeout is None or soonest_timeout > poll_timeout): soonest_timeout = poll_timeout finally: ioloop.close()
def log(msg): _depwarn("pyftpdlib.ftpserver.log() is deprecated") logger.info(msg)
def _loop(self, handler): """Serve handler's IO loop in a separate thread or process.""" ioloop = IOLoop() try: handler.ioloop = ioloop try: handler.add_channel() except EnvironmentError: err = sys.exc_info()[1] if err.errno == errno.EBADF: # we might get here in case the other end quickly # disconnected (see test_quick_connect()) return else: raise # Here we localize variable access to minimize overhead. poll = ioloop.poll socket_map = ioloop.socket_map tasks = ioloop.sched._tasks sched_poll = ioloop.sched.poll poll_timeout = getattr(self, 'poll_timeout', None) soonest_timeout = poll_timeout while (socket_map or tasks) and not self._exit.is_set(): try: if socket_map: poll(timeout=soonest_timeout) if tasks: soonest_timeout = sched_poll() else: soonest_timeout = None except (KeyboardInterrupt, SystemExit): # note: these two exceptions are raised in all sub # processes self._exit.set() except select.error: # on Windows we can get WSAENOTSOCK if the client # rapidly connect and disconnects err = sys.exc_info()[1] if os.name == 'nt' and err.args[0] == 10038: for fd in list(socket_map.keys()): try: select.select([fd], [], [], 0) except select.error: try: logger.info("discarding broken socket %r", socket_map[fd]) del socket_map[fd] except KeyError: # dict changed during iteration pass else: raise else: if poll_timeout: if soonest_timeout is None \ or soonest_timeout > poll_timeout: soonest_timeout = poll_timeout finally: try: self._active_tasks.remove(self._current_task()) except ValueError: pass ioloop.close()
def _loop(self, handler): """Serve handler's IO loop in a separate thread or process.""" ioloop = IOLoop() try: handler.ioloop = ioloop try: handler.add_channel() except EnvironmentError: err = sys.exc_info()[1] if err.errno == errno.EBADF: # we might get here in case the other end quickly # disconnected (see test_quick_connect()) return else: raise # Here we localize variable access to minimize overhead. poll = ioloop.poll socket_map = ioloop.socket_map tasks = ioloop.sched._tasks sched_poll = ioloop.sched.poll poll_timeout = getattr(self, "poll_timeout", None) soonest_timeout = poll_timeout while (socket_map or tasks) and not self._exit.is_set(): try: if socket_map: poll(timeout=soonest_timeout) if tasks: soonest_timeout = sched_poll() else: soonest_timeout = None except (KeyboardInterrupt, SystemExit): # note: these two exceptions are raised in all sub # processes self._exit.set() except select.error: # on Windows we can get WSAENOTSOCK if the client # rapidly connect and disconnects err = sys.exc_info()[1] if os.name == "nt" and err.args[0] == 10038: for fd in list(socket_map.keys()): try: select.select([fd], [], [], 0) except select.error: try: logger.info("discarding broken socket %r", socket_map[fd]) del socket_map[fd] except KeyError: # dict changed during iteration pass else: raise else: if poll_timeout: if soonest_timeout is None or soonest_timeout > poll_timeout: soonest_timeout = poll_timeout finally: try: self._active_tasks.remove(self._current_task()) except ValueError: pass ioloop.close()