def child_recycler(): while True: try: pid, status = os.waitpid(-1, 0) logger.debug("Child %r ended with status=%d", pid, status) except OSError as e: if e.errno != errno.ECHILD: raise time.sleep(3)
def copy_files(solard_context, stream_reader, paths, total_size): # total_size not used for now for _to, _size in paths: logger.debug("Starting %s size=%d", _to, _size) f = SolardIface.file_start(solard_context, _to) if _size > 0: rdr = stream_reader(_size) for data in rdr: f.write(data) SolardIface.file_end(solard_context, _to) logger.debug("Done %s size=%d", _to, _size) return True
def handle(self): sock = self.request address = self.client_address h = SolardTCPHandler(sock, address) try: logger.debug("New from %s:%d" % address) auth_state = h.make_auth() if auth_state is False: logger.debug("Failed auth") return if auth_state is None: # child forked # we don't wait there, but in recycler return while True: if not h.process(): logger.debug("End from %s:%d" % address) break else: logger.debug("Waiting for more from %s:%d" % address) try: sock.shutdown(socket.SHUT_RDWR) except Exception: pass finally: sock.close() if h.forked: # if forked we can safely exit now os._exit(0)
def make_auth(self): # it's responsible for: # - checking auth # - forking if needed auth_data = self._read() if not auth_data: self._write_ok(False) return False req_user = auth_data.get('user') if not req_user: self._write_ok(False) return False proc_user = pwd.getpwuid(os.getuid())[0] logger.debug("Requested user %r", req_user) # TODO: # we may add there anything we want, checking in file etc # for now it's just `password` valid = auth_data.get('auth') == 'password' if not valid: self._write_ok(False) return False if req_user == proc_user: self._write_ok(True) return True # TODO: very naive if auth_data.get('sudo'): self._write_ok(True) return True # fork there child_pid = os.fork() if child_pid == 0: pw_uid = pwd.getpwnam(req_user).pw_uid pw_gid = pwd.getpwuid(pw_uid).pw_gid os.setgid(pw_gid) os.setuid(pw_uid) logger.debug("Child forked %d", os.getpid()) self._fix_env(pw_uid) self.forked = True self._write_ok(True) return True return None
def process(self): try: known_type = INT_DEFAULT_REPLY_TYPE input_data = self._read() if not input_data: return False method = input_data['m'] meth = getattr(SolardIface, method) is_stream = input_data.get('s', False) logger.debug("Going to run %r", method) if is_stream: res = meth(self.ctx, self._read_stream, *input_data.get('args', ()), **input_data.get('kwargs', {})) else: res = meth(self.ctx, *input_data.get('args', ()), **input_data.get('kwargs', {})) if isinstance(res, GeneratorType): known_type = INT_GENERATOR_REPLY_TYPE try: for curr in res: self._wrote = False self._write_ok_gen(curr) except: raise finally: try: self._wrote = False self._write_gen_end() except Exception: # ignore if eng gen couldn't be send pass self._wrote = True else: # if not input_data.get('empty_ok_resp', False): self._write_ok(res) except ReadFailure: return False except Exception as ex: if self._wrote: if known_type == INT_GENERATOR_REPLY_TYPE: errno_ = getattr(ex, 'errno', None) if errno_ in (errno.EPIPE, errno.ECONNRESET): logger.debug( "Client disconnected during generator based reply") else: logger.debug("Error during generator based reply") raise else: logger.error("Already wrote data, but got exception") raise else: logger.exception("Got exception") self.handle_exception() return True