def get_lpinfo_drv(make_and_model): if not LPINFO: log.error("Error: lpinfo command is not defined") return None command = shlex.split(LPINFO) + ["--make-and-model", make_and_model, "-m"] log("get_lpinfo_drv(%s) command=%s", make_and_model, command) try: proc = Popen(command, stdout=PIPE, stderr=PIPE, start_new_session=True) except Exception as e: log("get_lp_info_drv(%s) lpinfo command %s failed", make_and_model, command, exc_info=True) log.error("Error: lpinfo command failed to run") log.error(" %s", e) log.error(" command used: '%s'", " ".join(command)) return None #use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper cr = getChildReaper() cr.add_process(proc, "lpinfo", command, ignore=True, forget=True) from xpra.make_thread import start_thread def watch_lpinfo(): #give it 15 seconds to run: for _ in range(15): if proc.poll() is not None: return #finished already time.sleep(1) if proc.poll() is not None: return log.warn("Warning: lpinfo command is taking too long,") log.warn(" is the cups server running?") try: proc.terminate() except Exception as e: log("%s.terminate()", proc, exc_info=True) log.error("Error: failed to terminate lpinfo command") log.error(" %s", e) start_thread(watch_lpinfo, "lpinfo watcher", daemon=True) out, err = proc.communicate() if proc.wait() != 0: log.warn("Warning: lpinfo command failed and returned %s", proc.returncode) log.warn(" command used: '%s'", " ".join(command)) return None try: out = out.decode() except Exception: out = str(out) log("lpinfo out=%r", out) log("lpinfo err=%r", err) if err: log.warn("Warning: lpinfo command produced some warnings:") log.warn(" %r", err) for line in out.splitlines(): if line.startswith("drv://"): return line.split(" ")[0] return None
def late_start(self): def do_late_start(): #wait for all threaded init to complete self.wait_for_threaded_init() self.exec_start_late_commands() start_thread(do_late_start, "command-late-start", daemon=True)
def do_run(self, attach=False): self.hide() cmd = self.get_run_command(attach) log("do_run(%s) cmd=%s", attach, cmd) proc = exec_command(cmd) if proc: start_thread(self.wait_for_subprocess, "wait-%i" % proc.pid, daemon=True, args=(proc,))
def run(self): log("ProxyProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), getuid(), getgid()) setuidgid(self.uid, self.gid) if self.env_options: #TODO: whitelist env update? os.environ.update(self.env_options) self.video_init() log.info("new proxy instance started") log.info(" for client %s", self.client_conn) log.info(" and server %s", self.server_conn) signal.signal(signal.SIGTERM, self.signal_quit) signal.signal(signal.SIGINT, self.signal_quit) log("registered signal handler %s", self.signal_quit) start_thread(self.server_message_queue, "server message queue") if not self.create_control_socket(): #TODO: should send a message to the client return self.control_socket_thread = start_thread(self.control_socket_loop, "control") self.main_queue = Queue() #setup protocol wrappers: self.server_packets = Queue(PROXY_QUEUE_SIZE) self.client_packets = Queue(PROXY_QUEUE_SIZE) self.client_protocol = Protocol(self, self.client_conn, self.process_client_packet, self.get_client_packet) self.client_protocol.restore_state(self.client_state) self.server_protocol = Protocol(self, self.server_conn, self.process_server_packet, self.get_server_packet) #server connection tweaks: self.server_protocol.large_packets.append("draw") self.server_protocol.large_packets.append("window-icon") self.server_protocol.large_packets.append("keymap-changed") self.server_protocol.large_packets.append("server-settings") if self.caps.boolget("file-transfer"): self.client_protocol.large_packets.append("send-file") self.client_protocol.large_packets.append("send-file-chunk") self.server_protocol.large_packets.append("send-file") self.server_protocol.large_packets.append("send-file-chunk") self.server_protocol.set_compression_level(self.session_options.get("compression_level", 0)) self.server_protocol.enable_default_encoder() self.lost_windows = set() self.encode_queue = Queue() self.encode_thread = start_thread(self.encode_loop, "encode") log("starting network threads") self.server_protocol.start() self.client_protocol.start() self.send_hello() self.timeout_add(VIDEO_TIMEOUT*1000, self.timeout_video_encoders) try: self.run_queue() except KeyboardInterrupt as e: self.stop(str(e)) finally: log("ProxyProcess.run() ending %s", os.getpid())
def cleanup(): for source in tuple(sources): GLib.source_remove(source) sources.remove(source) for c in upnp_cleanup: if c: start_thread(c, "pnp-cleanup-%s" % c, daemon=True)
def check(self): if self.progress: return self.newer_version = None glib.timeout_add(1000, self.update_label) from xpra.make_thread import start_thread start_thread(self.do_check, "version check", daemon=True)
def close(self): log("%s.close() close callback=%s, readable=%s, writeable=%s", self, self._close_cb, self._readable, self._writeable) super().close() cc = self._close_cb if cc: self._close_cb = None log("%s.close() calling %s", self, cc) try: cc() except Exception: log.error("%s.close() error on callback %s", self, cc, exc_info=True) def close_files_thread(): log("close_files_thread() _readable=%s", self._readable) log("close_files_thread() calling %s", self._readable.close) try: self._readable.close() except IOError as e: log("close_files_thread() %s", self._readable, e) log("close_files_thread() _writeable=%s", self._writeable) log("close_files_thread() calling %s", self._writeable.close) try: self._writeable.close() except IOError as e: log("close_files_thread() %s", self._writeable, e) start_thread(close_files_thread, "close-files-thread", daemon=True) log("%s.close() done", self)
def check_for_end(*_args): qtime = ss.queue.get_property("current-level-time") // MS_TO_NS if qtime <= 0: log.info("underrun (end of stream)") start_thread(ss.stop, "stop", daemon=True) GLib.timeout_add(500, glib_mainloop.quit) return False return True
def send_initial_data(self, ss, caps, send_ui, share_count): if not getattr(ss, "xdg_menu", False): return if ss.xdg_menu_update: #this method may block if the menus are still being loaded, #so do it in a throw-away thread: start_thread(self.send_xdg_menu_data, "send-xdg-menu-data", True, (ss, ))
def load_menu_data(self, force_reload=False): #start loading in a thread, #as this may take a while and #so server startup can complete: def load(): self.get_menu_data(force_reload) self.get_desktop_sessions() start_thread(load, "load-menu-data", True)
def do_run(self, attach=False): self.hide() cmd = self.get_run_command(attach) proc = exec_command(cmd) if proc: from xpra.make_thread import start_thread start_thread(self.wait_for_subprocess, "wait-%i" % proc.pid, daemon=True, args=(proc, ))
def __init__(self, *args): super().__init__(*args) self.log_file = None if CURSES_LOG: self.log_file = open(CURSES_LOG, "ab") self.paused = False self.stdscr = None self.modified = False self.psprocess = {} start_thread(self.input_thread, "input-thread", daemon=True)
def run(self): from xpra.make_thread import start_thread start_thread(self.read_stdin, "read-stdin", True) self.show_all() force_focus() self.present() self.timeout_timer = GLib.timeout_add(TIMEOUT*1000, self.timeout) self.pulse_timer = GLib.timeout_add(100, self.pulse) Gtk.main() return self.exit_code or 0
def show_html5(*_args): from xpra.scripts.main import run_html5 from xpra.make_thread import start_thread url_options = {} try: for k in ("port", "host", "username", "mode", "display"): v = self.client.display_desc.get(k) if v is not None: url_options[k] = v except Exception: pass start_thread(run_html5, "open HTML5 client", True, args=(url_options, ))
def run(self): register_SIGUSR_signals(self.idle_add) client_protocol_class = get_client_protocol_class(self.client_conn.socktype) server_protocol_class = get_server_protocol_class(self.server_conn.socktype) self.client_protocol = client_protocol_class(self, self.client_conn, self.process_client_packet, self.get_client_packet) self.client_protocol.restore_state(self.client_state) self.server_protocol = server_protocol_class(self, self.server_conn, self.process_server_packet, self.get_server_packet) self.log_start() log("ProxyProcessProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), getuid(), getgid()) set_proc_title("Xpra Proxy Instance for %s" % self.server_conn) if POSIX and (getuid()!=self.uid or getgid()!=self.gid): #do we need a valid XDG_RUNTIME_DIR for the socket-dir? username = get_username_for_uid(self.uid) socket_dir = osexpand(self.socket_dir, username, self.uid, self.gid) if not os.path.exists(socket_dir): log("the socket directory '%s' does not exist, checking for $XDG_RUNTIME_DIR path", socket_dir) for prefix in ("/run/user/", "/var/run/user/"): if socket_dir.startswith(prefix): from xpra.scripts.server import create_runtime_dir xrd = os.path.join(prefix, str(self.uid)) #ie: /run/user/99 log("creating XDG_RUNTIME_DIR=%s for uid=%i, gid=%i", xrd, self.uid, self.gid) create_runtime_dir(xrd, self.uid, self.gid) break #change uid or gid: setuidgid(self.uid, self.gid) if self.env_options: #TODO: whitelist env update? os.environ.update(self.env_options) signal.signal(signal.SIGTERM, self.signal_quit) signal.signal(signal.SIGINT, self.signal_quit) log("registered signal handler %s", self.signal_quit) start_thread(self.server_message_queue, "server message queue") if not self.create_control_socket(): return self.control_socket_thread = start_thread(self.control_socket_loop, "control", daemon=True) self.main_queue = Queue() ProxyInstance.run(self) try: QueueScheduler.run(self) except KeyboardInterrupt as e: self.stop(None, str(e)) finally: log("ProxyProcess.run() ending %s", os.getpid())
def exec_dialog_subprocess(cmd): try: log("exec_dialog_subprocess(%s)", cmd) kwargs = {} if POSIX: kwargs["close_fds"] = True else: #win32 platform code would create a log file for the command's output, #tell it not to do that: env = os.environ.copy() env["XPRA_LOG_TO_FILE"] = "0" kwargs["env"] = env proc = Popen(cmd, stdout=PIPE, stderr=PIPE, **kwargs) stdout = [] stderr = [] from xpra.gtk_common.gobject_compat import import_gtk gtk = import_gtk() def read_thread(fd, out): while proc.poll() is None: try: v = fd.read() if v: out.append(v) except: time.sleep(0.1) try: gtk.main_quit() except: pass from xpra.make_thread import start_thread start_thread(read_thread, "dialog-stdout-reader", True, (proc.stdout, stdout)) start_thread(read_thread, "dialog-stderr-reader", True, (proc.stderr, stderr)) if is_WSL(): #WSL needs to wait before calling communicate, #is this still needed now that we read using threads? proc.wait() gtk.main() log("exec_dialog_subprocess(%s) returncode=%s", cmd, proc.poll()) if stderr: log.warn("Warning: dialog process error output:") for x in (b"".join(stderr)).decode().splitlines(): log.warn(" %s", x) return proc.returncode, (b"".join(stdout)).decode() except Exception as e: log("exec_dialog_subprocess(..)", exc_info=True) log.error("Error: failed to execute the dialog subcommand") log.error(" %s", e) return -1, None
def __init__(self, client, _opts): self.client = client self._kh_warning = False self._console_handler_added = False self._screensaver_state = False self._screensaver_timer = 0 self._exit = False if SCREENSAVER_LISTENER_POLL_DELAY > 0: def log_screensaver(): v = bool( GetIntSystemParametersInfo( win32con.SPI_GETSCREENSAVERRUNNING)) log("SPI_GETSCREENSAVERRUNNING=%s", v) if self._screensaver_state != v: self._screensaver_state = v if v: self.client.suspend() else: self.client.resume() return True self._screensaver_timer = client.timeout_add( SCREENSAVER_LISTENER_POLL_DELAY * 1000, log_screensaver) if CONSOLE_EVENT_LISTENER: self._console_handler_added = setup_console_event_listener( self.handle_console_event, True) from xpra.platform.win32.win32_events import get_win32_event_listener try: el = get_win32_event_listener(True) self._el = el if el: el.add_event_callback(win32con.WM_ACTIVATEAPP, self.activateapp) el.add_event_callback(win32con.WM_POWERBROADCAST, self.power_broadcast_event) el.add_event_callback(win32con.WM_MOVE, self.wm_move) el.add_event_callback(WM_WTSSESSION_CHANGE, self.session_change_event) el.add_event_callback(win32con.WM_INPUTLANGCHANGE, self.inputlangchange) el.add_event_callback(win32con.WM_WININICHANGE, self.inichange) el.add_event_callback(win32con.WM_ENDSESSION, self.end_session) except Exception as e: log.error("Error: cannot register focus and power callbacks:") log.error(" %s", e) self.keyboard_hook_id = None if FORWARD_WINDOWS_KEY and mixin_features.windows: from xpra.make_thread import start_thread start_thread(self.init_keyboard_listener, "keyboard-listener", daemon=True)
def __init__(self, *args): super().__init__(*args) self.log_file = None if CURSES_LOG: self.log_file = open(CURSES_LOG, "ab") self.info_request_pending = False self.server_last_info = typedict() self.server_last_info_time = 0 self.info_timer = 0 self.paused = False self.stdscr = None self.psprocess = {} self.setup() start_thread(self.input_thread, "input-thread", daemon=True)
def get_lpinfo_drv(make_and_model): command = shlex.split(LPINFO)+["--make-and-model", make_and_model, "-m"] def preexec(): os.setsid() log("get_lpinfo_drv(%s) command=%s", make_and_model, command) try: proc = subprocess.Popen(command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, close_fds=True, preexec_fn=preexec) except Exception as e: log("get_lp_info_drv(%s) lpinfo command %s failed", make_and_model, command, exc_info=True) log.error("Error: lpinfo command failed to run") log.error(" %s", e) log.error(" command used: '%s'", " ".join(command)) return None #use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper from xpra.util import nonl cr = getChildReaper() cr.add_process(proc, "lpinfo", command, ignore=True, forget=True) from xpra.make_thread import start_thread def watch_lpinfo(): #give it 15 seconds to run: for _ in range(15): if proc.poll() is not None: return #finished already time.sleep(1) log.warn("Warning: lpinfo command is taking too long,") log.warn(" is the cups server running?") proc.terminate() start_thread(watch_lpinfo, "lpinfo watcher", daemon=True) out, err = proc.communicate() if proc.wait()!=0: log.warn("Warning: lpinfo command failed and returned %s", proc.returncode) log.warn(" command used: '%s'", " ".join(command)) return None if sys.version_info[0]>=3: try: out = out.decode() except: out = str(out) log("lpinfo out=%s", nonl(out)) log("lpinfo err=%s", nonl(err)) if err: log.warn("Warning: lpinfo command produced some warnings:") log.warn(" '%s'", nonl(err)) for line in out.splitlines(): if line.startswith("drv://"): return line.split(" ")[0] return None
def test_all(self): set_default_name("platform info test", "platform-info-test") init() t = start_thread(threaded_server_init, "server-init") t.join() with program_context() as p: assert repr(p) assert get_application_name() == "platform-info-test" assert get_prgname() == "platform info test" if WIN32: # pragma: no cover #we can check for command_error and command_info #on win32 because those trigger dialogs return calls = [] def ccall(*args): calls.append(args) xpra_main.error = ccall xpra_main.info = ccall command_error("error") command_info("info") assert len(calls) == 2, "expected 2 messages but got: %s" % (calls, ) set_prgname(None) clean()
def run(self): log.info("started %s", self) log.info(" for client %s", self.client_protocol._conn) log.info(" and server %s", self.server_protocol._conn) self.video_init() #setup protocol wrappers: self.server_packets = Queue(PROXY_QUEUE_SIZE) self.client_packets = Queue(PROXY_QUEUE_SIZE) #server connection tweaks: for x in (b"input-devices", b"draw", b"window-icon", b"keymap-changed", b"server-settings"): self.server_protocol.large_packets.append(x) if self.caps.boolget("file-transfer"): for x in (b"send-file", b"send-file-chunk"): self.server_protocol.large_packets.append(x) self.client_protocol.large_packets.append(x) self.server_protocol.set_compression_level( self.session_options.get("compression_level", 0)) self.server_protocol.enable_default_encoder() self.lost_windows = set() self.encode_queue = Queue() self.encode_thread = start_thread(self.encode_loop, "encode") self.start_network_threads() if self.caps.boolget("ping-echo-sourceid"): self.schedule_client_ping() self.send_hello()
def __init__(self, core_encodings, encodings, default_encoding, scaling_control, default_quality, default_min_quality, default_speed, default_min_speed): log("ServerSource%s", (core_encodings, encodings, default_encoding, scaling_control, default_quality, default_min_quality, default_speed, default_min_speed)) self.server_core_encodings = core_encodings self.server_encodings = encodings self.default_encoding = default_encoding self.scaling_control = scaling_control self.default_quality = default_quality #default encoding quality for lossy encodings self.default_min_quality = default_min_quality #default minimum encoding quality self.default_speed = default_speed #encoding speed (only used by x264) self.default_min_speed = default_min_speed #default minimum encoding speed self.default_batch_config = DamageBatchConfig( ) #contains default values, some of which may be supplied by the client self.global_batch_config = self.default_batch_config.clone( ) #global batch config self.vrefresh = -1 self.supports_transparency = False self.encoding = None #the default encoding for all windows self.encodings = () #all the encodings supported by the client self.core_encodings = () self.window_icon_encodings = ["premult_argb32"] self.rgb_formats = ("RGB", ) self.encoding_options = typedict() self.icons_encoding_options = typedict() self.default_encoding_options = typedict() self.auto_refresh_delay = 0 self.zlib = True self.lz4 = use_lz4 self.lzo = use_lzo #for managing the recalculate_delays work: self.calculate_window_pixels = {} self.calculate_window_ids = set() self.calculate_timer = 0 self.calculate_last_time = 0 #if we "proxy video", we will modify the video helper to add #new encoders, so we must make a deep copy to preserve the original #which may be used by other clients (other ServerSource instances) self.video_helper = getVideoHelper().clone() # the queues of damage requests we work through: self.encode_work_queue = Queue( ) #holds functions to call to compress data (pixels, clipboard) #items placed in this queue are picked off by the "encode" thread, #the functions should add the packets they generate to the 'packet_queue' self.packet_queue = deque( ) #holds actual packets ready for sending (already encoded) #these packets are picked off by the "protocol" via 'next_packet()' #format: packet, wid, pixels, start_send_cb, end_send_cb #(only packet is required - the rest can be 0/None for clipboard packets) self.encode_thread = start_thread(self.encode_loop, "encode")
def _process_send_file_chunk(self, packet): chunk_id, chunk, file_data, has_more = packet[1:5] filelog("_process_send_file_chunk%s", (chunk_id, chunk, "%i bytes" % len(file_data), has_more)) chunk_state = self.receive_chunks_in_progress.get(chunk_id) if not chunk_state: filelog.error("Error: cannot find the file transfer id '%s'", nonl(bytestostr(chunk_id))) self.send("ack-file-chunk", chunk_id, False, "file transfer id not found", chunk) return fd = chunk_state[1] if chunk_state[-1]+1!=chunk: filelog.error("Error: chunk number mismatch, expected %i but got %i", chunk_state[-1]+1, chunk) self.send("ack-file-chunk", chunk_id, False, "chunk number mismatch", chunk) del self.receive_chunks_in_progress[chunk_id] os.close(fd) return #update chunk number: chunk_state[-1] = chunk digest = chunk_state[8] written = chunk_state[9] try: os.write(fd, file_data) digest.update(file_data) written += len(file_data) chunk_state[9] = written except OSError as e: filelog.error("Error: cannot write file chunk") filelog.error(" %s", e) self.send("ack-file-chunk", chunk_id, False, "write error: %s" % e, chunk) del self.receive_chunks_in_progress[chunk_id] try: os.close(fd) except (OSError, IOError): pass return self.send("ack-file-chunk", chunk_id, True, "", chunk) if has_more: timer = chunk_state[-2] if timer: self.source_remove(timer) #remote end will send more after receiving the ack timer = self.timeout_add(CHUNK_TIMEOUT, self._check_chunk_receiving, chunk_id, chunk) chunk_state[-2] = timer return del self.receive_chunks_in_progress[chunk_id] os.close(fd) #check file size and digest then process it: filename, mimetype, printit, openit, filesize, options = chunk_state[2:8] if written!=filesize: filelog.error("Error: expected a file of %i bytes, got %i", filesize, written) return expected_digest = options.get("sha1") if expected_digest: self.check_digest(filename, digest.hexdigest(), expected_digest) start_time = chunk_state[0] elapsed = monotonic_time()-start_time mimetype = bytestostr(mimetype) filelog("%i bytes received in %i chunks, took %ims", filesize, chunk, elapsed*1000) t = start_thread(self.do_process_downloaded_file, "process-download", daemon=False, args=(filename, mimetype, printit, openit, filesize, options)) filelog("started process-download thread: %s", t)
def get_lpinfo_drv(make_and_model): command = shlex.split(LPINFO)+["--make-and-model", make_and_model, "-m"] def preexec(): os.setsid() log("get_lpinfo_drv(%s) command=%s", make_and_model, command) try: proc = subprocess.Popen(command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, close_fds=True, preexec_fn=preexec) except Exception as e: log("get_lp_info_drv(%s) lpinfo command %s failed", make_and_model, command, exc_info=True) log.error("Error: lpinfo command failed to run") log.error(" %s", e) log.error(" command used: '%s'", " ".join(command)) return None #use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper from xpra.util import nonl cr = getChildReaper() cr.add_process(proc, "lpinfo", command, ignore=True, forget=True) from xpra.make_thread import start_thread def watch_lpinfo(): #give it 15 seconds to run: for _ in range(15): if proc.poll() is not None: return #finished already time.sleep(1) log.warn("Warning: lpinfo command is taking too long") proc.terminate() start_thread(watch_lpinfo, "lpinfo watcher", daemon=True) out, err = proc.communicate() if proc.wait()!=0: log.warn("Warning: lpinfo command failed and returned %s", proc.returncode) log.warn(" command used: '%s'", " ".join(command)) return None if sys.version_info[0]>=3: try: out = out.decode() except: out = str(out) log("lpinfo out=%s", nonl(out)) log("lpinfo err=%s", nonl(err)) if err: log.warn("Warning: lpinfo command produced some warnings:") log.warn(" '%s'", nonl(err)) for line in out.splitlines(): if line.startswith("drv://"): return line.split(" ")[0] return None
def __init__(self, sock, process_packet_cb): assert sock is not None self._closed = False self._socket = sock self._process_packet_cb = process_packet_cb self._read_thread = start_thread(self._read_thread_loop, "read", daemon=True)
def threaded_setup(self): self.exec_start_commands() def set_reaper_callback(): self.child_reaper.set_quit_callback(self.reaper_exit) self.child_reaper.check() self.idle_add(set_reaper_callback) if POSIX and not OSX and self.start_new_commands and EXPORT_XDG_MENU_DATA: try: self.setup_menu_watcher() except Exception as e: log("threaded_setup()", exc_info=True) log.error("Error setting up menu watcher:") log.error(" %s", e) from xpra.platform.xposix.xdg_helper import load_xdg_menu_data #start loading in a thread, #so server startup can complete: start_thread(load_xdg_menu_data, "load-xdg-menu-data", True)
def process_downloaded_file(self, filename, mimetype, printit, openit, filesize, options): filelog.info("downloaded %s bytes to %s file%s:", filesize, (mimetype or "temporary"), ["", " for printing"][int(printit)]) filelog.info(" '%s'", filename) if printit or openit: t = start_thread(self.do_process_downloaded_file, "process-download", daemon=False, args=(filename, mimetype, printit, openit, filesize, options)) filelog("started process-download thread: %s", t)
def process_downloaded_file(self, filename, mimetype, printit, openit, filesize, options): t = start_thread(self.do_process_downloaded_file, "process-download", daemon=False, args=(filename, mimetype, printit, openit, filesize, options)) filelog("started process-download thread: %s", t)
def start(self): if self.last_UI_thread_time>0: log.warn("UI thread watcher already started!") return #run once to initialize: self.UI_thread_wakeup() if self.polling_timeout>0: start_thread(self.poll_UI_loop, "UI thread polling") else: log("not starting an IO polling thread") if FAKE_UI_LOCKUPS>0: #watch out: sleeping in UI thread! def sleep_in_ui_thread(*args): t = threading.current_thread() log.warn("sleep_in_ui_thread%s pausing %s for %ims", args, t, FAKE_UI_LOCKUPS) time.sleep(FAKE_UI_LOCKUPS/1000.0) return True self.timeout_add(10*1000+FAKE_UI_LOCKUPS, sleep_in_ui_thread)
def run(self): from xpra.make_thread import start_thread start_thread(self.read_stdin, "read-stdin", True) self.show_all() force_focus() self.present() self.timeout_timer = GLib.timeout_add(TIMEOUT * 1000, self.timeout) self.pulse_timer = GLib.timeout_add(100, self.pulse) scrash = envint("XPRA_SPLASH_CRASH", -1) if scrash >= 0: def crash(): import ctypes #pylint: disable=import-outside-toplevel ctypes.string_at(0) GLib.timeout_add(scrash, crash) Gtk.main() return self.exit_code or 0
def start_queue_encode(self, item): #start the encode work queue: #holds functions to call to compress data (pixels, clipboard) #items placed in this queue are picked off by the "encode" thread, #the functions should add the packets they generate to the 'packet_queue' self.encode_work_queue = Queue() self.queue_encode = self.encode_work_queue.put self.queue_encode(item) self.encode_thread = start_thread(self.encode_loop, "encode")
def __init__(self): self.exit_code = None super().__init__() self.set_border_width(20) self.set_title("Start Desktop Environment") self.set_position(Gtk.WindowPosition.CENTER) self.set_size_request(640, 300) icon = get_icon_pixbuf("xpra.png") if icon: self.set_icon(icon) self.connect("delete-event", self.quit) add_close_accel(self, self.quit) vbox = Gtk.VBox(False, 0) vbox.set_spacing(10) #self.entry_label = l("Command:") #vbox.add(self.entry_label) self.desktop_combo = sf(Gtk.ComboBoxText()) vbox.add(self.desktop_combo) # Action buttons: hbox = Gtk.HBox(False, 20) vbox.pack_start(hbox, False, True, 20) def btn(label, tooltip, callback, default=False): ib = imagebutton(label, tooltip=tooltip, clicked_callback=callback, icon_size=32, default=default, label_font=Pango.FontDescription("sans 16")) hbox.pack_start(ib) return ib self.cancel_btn = btn("Exit", "", self.quit) self.run_btn = btn("Start", "Start the desktop environment", self.run_command) vbox.show_all() self.add(vbox) start_thread(self.load_desktop_session, "load-desktop-sessions", daemon=True)
def start_proxy(self, client_proto, c, auth_caps): def disconnect(reason, *extras): log("disconnect(%s, %s)", reason, extras) self.send_disconnect(client_proto, reason, *extras) #find the target server session: if not client_proto.authenticator: log.error("Error: the proxy server requires an authentication mode,") try: log.error(" client connection '%s' does not specify one", client_proto._conn.socktype) except: pass log.error(" use 'none' to disable authentication") disconnect(SESSION_NOT_FOUND, "no sessions found") return try: sessions = client_proto.authenticator.get_sessions() except Exception as e: authlog("failed to get the list of sessions", exc_info=True) authlog.error("Error: failed to get the list of sessions using '%s' authenticator", client_proto.authenticator) authlog.error(" %s", e) disconnect(AUTHENTICATION_ERROR, "cannot access sessions") return authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions) if sessions is None: disconnect(SESSION_NOT_FOUND, "no sessions found") return uid, gid, displays, env_options, session_options = sessions if os.name=="posix": if uid==0 or gid==0: log.error("Error: proxy instances should not run as root") log.error(" use a different uid and gid (ie: nobody)") disconnect(AUTHENTICATION_ERROR, "cannot run proxy instances as root") return username = get_username_for_uid(uid) groups = get_groups(username) if "xpra" not in groups: log.error("Error: user '%s' (uid=%i) is not in the xpra group", username, uid) log.error(" it belongs to: %s", csv(groups) or None) disconnect(PERMISSION_ERROR, "user missing 'xpra' group membership") return #ensure we don't loop back to the proxy: proxy_virtual_display = os.environ.get("DISPLAY") if proxy_virtual_display in displays: displays.remove(proxy_virtual_display) #remove proxy instance virtual displays: displays = [x for x in displays if not x.startswith(":proxy-")] #log("unused options: %s, %s", env_options, session_options) opts = make_defaults_struct() display = None proc = None sns = c.dictget("start-new-session") authlog("start_proxy: displays=%s, start-new-session=%s", displays, bool(sns)) if len(displays)==0 or sns: if self._start_sessions: #start a new session mode = sns.get("mode", "start") assert mode in ("start", "start-desktop", "shadow"), "invalid start-new-session mode '%s'" % mode sns = typedict(sns) display = sns.get("display") args = [] if display: args = [display] start = sns.strlistget("start") start_child = sns.strlistget("start-child") exit_with_children = sns.boolget("exit-with-children") exit_with_client = sns.boolget("exit-with-client") log("starting new server subprocess: mode=%s, socket-dir=%s, socket-dirs=%s, start=%s, start-child=%s, exit-with-children=%s, exit-with-client=%s, uid=%s, gid=%s", mode, opts.socket_dir, opts.socket_dirs, start, start_child, exit_with_children, exit_with_client, uid, gid) try: proc, socket_path = start_server_subprocess(sys.argv[0], args, mode, opts, opts.socket_dir, opts.socket_dirs, start, start_child, exit_with_children, exit_with_client, uid=uid, gid=gid) display = "socket:%s" % socket_path except Exception as e: log("start_server_subprocess failed", exc_info=True) log.error("Error: failed to start server subprocess:") log.error(" %s", e) disconnect(SERVER_ERROR, "failed to start a new session") return if proc: self.child_reaper.add_process(proc, "server-%s" % display, "xpra start", True, True) else: disconnect(SESSION_NOT_FOUND, "no displays found") return if display is None: display = c.strget("display") authlog("start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s", proxy_virtual_display, display, displays) if display==proxy_virtual_display: disconnect(SESSION_NOT_FOUND, "invalid display") return if display: if display not in displays: disconnect(SESSION_NOT_FOUND, "display '%s' not found" % display) return else: if len(displays)!=1: disconnect(SESSION_NOT_FOUND, "please specify a display, more than one is available: %s" % csv(displays)) return display = displays[0] def stop_server_subprocess(): if proc: proc.terminate() log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display) def parse_error(*args): stop_server_subprocess() disconnect(SESSION_NOT_FOUND, "invalid display string") log.warn("Error: parsing failed for display string '%s':", display) for arg in args: log.warn(" %s", arg) raise Exception("parse error on %s: %s" % (display, args)) opts.username = client_proto.authenticator.username disp_desc = parse_display_name(parse_error, opts, display) if uid or gid: disp_desc["uid"] = uid disp_desc["gid"] = gid log("display description(%s) = %s", display, disp_desc) try: server_conn = connect_to(disp_desc, opts) except Exception as e: log("cannot connect", exc_info=True) log.error("Error: cannot start proxy connection:") log.error(" %s", e) log.error(" connection definition:") print_nested_dict(disp_desc, prefix=" ", lchar="*", pad=20, print_fn=log.error) disconnect(SESSION_NOT_FOUND, "failed to connect to display") stop_server_subprocess() return log("server connection=%s", server_conn) #no other packets should be arriving until the proxy instance responds to the initial hello packet def unexpected_packet(packet): if packet: log.warn("Warning: received an unexpected packet on the proxy connection %s:", client_proto) log.warn(" %s", repr_ellipsized(packet)) client_conn = client_proto.steal_connection(unexpected_packet) client_state = client_proto.save_state() cipher = None encryption_key = None if auth_caps: cipher = auth_caps.get("cipher") if cipher: encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile) log("start_proxy(..) client connection=%s", client_conn) log("start_proxy(..) client state=%s", client_state) #this may block, so run it in a thread: def do_start_proxy(): log("do_start_proxy()") message_queue = MQueue() try: ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout) if not ioe: log.error("Error: some network IO threads have failed to terminate") return client_conn.set_active(True) process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir, self.video_encoders, self.csc_modules, client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue) log("starting %s from pid=%s", process, os.getpid()) self.processes[process] = (display, message_queue) process.start() log("process started") popen = process._popen assert popen #when this process dies, run reap to update our list of proxy processes: self.child_reaper.add_process(popen, "xpra-proxy-%s" % display, "xpra-proxy-instance", True, True, self.reap) finally: #now we can close our handle on the connection: client_conn.close() server_conn.close() message_queue.put("socket-handover-complete") start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)