def pactl_output(log_errors=True, *pactl_args): pactl_bin = get_pactl_bin() if not pactl_bin: return -1, None, None #ie: "pactl list" cmd = [pactl_bin] + list(pactl_args) #force "C" locale so that we can parse the output as expected env = os.environ.copy() env["LC_ALL"] = "C" try: import subprocess log("running %s", cmd) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) from xpra.child_reaper import getChildReaper procinfo = getChildReaper().add_process(process, "pactl", cmd, True, True) log("waiting for %s output", cmd) out, err = process.communicate() getChildReaper().add_dead_process(procinfo) code = process.poll() log("pactl_output%s returned %s", pactl_args, code) return code, out, err except Exception as e: if log_errors: log.error("failed to execute %s: %s", cmd, e) else: log("failed to execute %s: %s", cmd, e) return -1, None, None
def do_process_challenge_prompt(self, packet, prompt="password"): authlog("do_process_challenge_prompt() use_tty=%s", use_tty()) if use_tty(): import getpass authlog("stdin isatty, using password prompt") password = getpass.getpass("%s :" % self.get_challenge_prompt(prompt)) authlog("password read from tty via getpass: %s", obsc(password)) self.send_challenge_reply(packet, password) return True else: from xpra.platform.paths import get_nodock_command cmd = get_nodock_command() + ["_pass", prompt] try: from subprocess import Popen, PIPE proc = Popen(cmd, stdout=PIPE) getChildReaper().add_process(proc, "password-prompt", cmd, True, True) out, err = proc.communicate(None, 60) authlog("err(%s)=%s", cmd, err) password = out.decode() self.send_challenge_reply(packet, password) return True except Exception: log("Error: failed to show GUi for password prompt", exc_info=True) return False
def exec_subprocess(self): kwargs = exec_kwargs() env = self.get_env() log("exec_subprocess() command=%s, env=%s, kwargs=%s", self.command, env, kwargs) proc = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=env, **kwargs) getChildReaper().add_process(proc, self.description, self.command, True, True, callback=self.subprocess_exit) return proc
def setup_connection(self, conn): netlog("setup_connection(%s) timeout=%s, socktype=%s", conn, conn.timeout, conn.socktype) if conn.socktype=="udp": from xpra.net.udp_protocol import UDPClientProtocol self._protocol = UDPClientProtocol(self.get_scheduler(), conn, self.process_packet, self.next_packet) #use a random uuid: import random self._protocol.uuid = random.randint(0, 2**64-1) self.set_packet_handlers(self._packet_handlers, { "udp-control" : self._process_udp_control, }) else: self._protocol = Protocol(self.get_scheduler(), conn, self.process_packet, self.next_packet) for x in (b"keymap-changed", b"server-settings", b"logging", b"input-devices"): self._protocol.large_packets.append(x) self._protocol.set_compression_level(self.compression_level) self._protocol.receive_aliases.update(self._aliases) self._protocol.enable_default_encoder() self._protocol.enable_default_compressor() if self.encryption and ENCRYPT_FIRST_PACKET: key = self.get_encryption_key() self._protocol.set_cipher_out(self.encryption, DEFAULT_IV, key, DEFAULT_SALT, DEFAULT_ITERATIONS, INITIAL_PADDING) self.have_more = self._protocol.source_has_more if conn.timeout>0: self.timeout_add((conn.timeout + EXTRA_TIMEOUT) * 1000, self.verify_connected) process = getattr(conn, "process", None) #ie: ssh is handled by anotherprocess if process: proc, name, command = process if proc: getChildReaper().add_process(proc, name, command, ignore=True, forget=False) netlog("setup_connection(%s) protocol=%s", conn, self._protocol)
def show_notify(self, dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, expire_timeout, icon): from xpra.platform.darwin import osx_notifier osx_notifier_file = osx_notifier.__file__ if osx_notifier_file.endswith("pyc"): osx_notifier_file = osx_notifier_file[:-1] import time #osx_notifier_file = "/Users/osx/osx_notifier.py" from xpra.platform.paths import get_app_dir base = get_app_dir() #python_bin = "/usr/bin/python" python_bin = os.path.join(base, "Resources", "bin", "python") cmd = [ python_bin, osx_notifier_file, "%s-%s" % (int(time.time()), nid), summary, body ] from xpra.child_reaper import getChildReaper import subprocess env = os.environ.copy() for x in ("DYLD_LIBRARY_PATH", "XDG_CONFIG_DIRS", "XDG_DATA_DIRS", "GTK_DATA_PREFIX", "GTK_EXE_PREFIX", "GTK_PATH", "GTK2_RC_FILES", "GTK_IM_MODULE_FILE", "GDK_PIXBUF_MODULE_FILE", "PANGO_RC_FILE", "PANGO_LIBDIR", "PANGO_SYSCONFDIR", "CHARSETALIASDIR", "GST_BUNDLE_CONTENTS", "PYTHON", "PYTHONHOME", "PYTHONPATH"): if x in env: del env[x] notifylog("running %s with env=%s", cmd, env) proc = subprocess.Popen(cmd, env=env) proc.wait() notifylog("returned %i", proc.poll()) getChildReaper().add_process(proc, "notifier-%s" % nid, cmd, True, True)
def exec_subprocess(self): kwargs = exec_kwargs() env = self.get_env() log("exec_subprocess() command=%s, env=%s, kwargs=%s", self.command, env, kwargs) proc = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stderr.fileno(), env=env, **kwargs) getChildReaper().add_process(proc, self.description, self.command, True, True, callback=self.subprocess_exit) return proc
def setup_connection(self, conn): netlog("setup_connection(%s) timeout=%s", conn, conn.timeout) self._protocol = Protocol(self.get_scheduler(), conn, self.process_packet, self.next_packet) self._protocol.large_packets.append("keymap-changed") self._protocol.large_packets.append("server-settings") self._protocol.large_packets.append("logging") self._protocol.large_packets.append("input-devices") self._protocol.set_compression_level(self.compression_level) self._protocol.receive_aliases.update(self._aliases) self._protocol.enable_default_encoder() self._protocol.enable_default_compressor() if self.encryption and ENCRYPT_FIRST_PACKET: key = self.get_encryption_key() self._protocol.set_cipher_out(self.encryption, DEFAULT_IV, key, DEFAULT_SALT, DEFAULT_ITERATIONS, INITIAL_PADDING) self.have_more = self._protocol.source_has_more if conn.timeout > 0: self.timeout_add((conn.timeout + EXTRA_TIMEOUT) * 1000, self.verify_connected) process = getattr(conn, "process", None) #ie: ssh is handled by anotherprocess if process: proc, name, command = process getChildReaper().add_process(proc, name, command, ignore=True, forget=False) netlog("setup_connection(%s) protocol=%s", conn, self._protocol)
def show_downloads(self, _btn): downloads = os.path.expanduser(get_download_dir()) if WIN32: os.startfile(downloads) #@UndefinedVariable pylint: disable=no-member return if OSX: cmd = ["open", downloads] else: cmd = ["xdg-open", downloads] proc = subprocess.Popen(cmd) getChildReaper().add_process(proc, "show-downloads", cmd, ignore=True, forget=True)
def new_stream(self, sound_source, codec): if NEW_STREAM_SOUND: try: from xpra.platform.paths import get_resources_dir sample = os.path.join(get_resources_dir(), "bell.wav") log("new_stream(%s, %s) sample=%s, exists=%s", sound_source, codec, sample, os.path.exists(sample)) if os.path.exists(sample): if POSIX: sink = "alsasink" else: sink = "autoaudiosink" cmd = [ "gst-launch-1.0", "-q", "filesrc", "location=%s" % sample, "!", "decodebin", "!", "audioconvert", "!", sink ] import subprocess proc = subprocess.Popen(cmd, close_fds=True) log("Popen(%s)=%s", cmd, proc) from xpra.child_reaper import getChildReaper getChildReaper().add_process(proc, "new-stream-sound", cmd, ignore=True, forget=True) except Exception: pass log("new_stream(%s, %s)", sound_source, codec) if self.sound_source != sound_source: log( "dropping new-stream signal (current source=%s, signal source=%s)", self.sound_source, sound_source) return codec = codec or sound_source.codec sound_source.codec = codec #tell the client this is the start: self.send( "sound-data", codec, "", { "start-of-stream": True, "codec": codec, "sequence": sound_source.sequence, }) update_av_sync = getattr(self, "update_av_sync_delay_total", None) if update_av_sync: update_av_sync() #pylint: disable=not-callable #run it again after 10 seconds, #by that point the source info will actually be populated: if PYTHON3: from gi.repository import GLib as glib else: import glib glib.timeout_add(10 * 1000, update_av_sync)
def defaults_init(self): #skip warning when running the client from xpra import child_reaper child_reaper.POLL_WARNING = False getChildReaper() log("XpraClientBase.defaults_init() os.environ:") for k,v in os.environ.items(): log(" %s=%s", k, nonl(v)) #client state: self.exit_code = None self.exit_on_signal = False self.display_desc = {} #connection attributes: self.hello_extra = {} self.compression_level = 0 self.display = None self.username = None self.password = None self.password_file = None self.password_sent = False self.bandwidth_limit = 0 self.encryption = None self.encryption_keyfile = None self.server_padding_options = [DEFAULT_PADDING] self.quality = -1 self.min_quality = 0 self.speed = 0 self.min_speed = -1 self.printer_attributes = [] self.send_printers_timer = None self.exported_printers = None self.can_shutdown_server = True #protocol stuff: self._protocol = None self._priority_packets = [] self._ordinary_packets = [] self._mouse_position = None self._aliases = {} self._reverse_aliases = {} #server state and caps: self.server_capabilities = None self.completed_startup = False self._remote_machine_id = None self._remote_uuid = None self._remote_version = None self._remote_revision = None self._remote_platform = None self._remote_platform_release = None self._remote_platform_platform = None self._remote_platform_linux_distribution = None self.uuid = get_user_uuid() self.init_packet_handlers() sanity_checks()
def defaults_init(self): #skip warning when running the client from xpra import child_reaper child_reaper.POLL_WARNING = False getChildReaper() log("XpraClientBase.defaults_init() os.environ:") for k,v in os.environ.items(): log(" %s=%r", k, v) #client state: self.exit_code = None self.exit_on_signal = False self.display_desc = {} self.progress_process = None self.progress_timer = None #connection attributes: self.hello_extra = {} self.compression_level = 0 self.display = None self.challenge_handlers = [] self.username = None self.password = None self.password_file = () self.password_index = 0 self.password_sent = False self.encryption = None self.encryption_keyfile = None self.server_padding_options = [DEFAULT_PADDING] self.server_client_shutdown = True self.server_compressors = [] #protocol stuff: self._protocol = None self._priority_packets = [] self._ordinary_packets = [] self._mouse_position = None self._mouse_position_pending = None self._mouse_position_send_time = 0 self._mouse_position_delay = MOUSE_DELAY self._mouse_position_timer = 0 self._aliases = {} #server state and caps: self.connection_established = False self.completed_startup = False self.uuid = get_user_uuid() self.session_id = uuid.uuid4().hex self.init_packet_handlers() def noop(): """ until we hook up the real protocol instance, do nothing when have_more() is called """ self.have_more = noop
def defaults_init(self): # skip warning when running the client from xpra import child_reaper child_reaper.POLL_WARNING = False getChildReaper() log("XpraClientBase.defaults_init() os.environ:") for k, v in os.environ.items(): log(" %s=%s", k, nonl(v)) # client state: self.exit_code = None self.exit_on_signal = False self.display_desc = {} # connection attributes: self.hello_extra = {} self.compression_level = 0 self.display = None self.username = None self.password = None self.password_file = None self.password_sent = False self.encryption = None self.encryption_keyfile = None self.server_padding_options = [DEFAULT_PADDING] self.quality = -1 self.min_quality = 0 self.speed = 0 self.min_speed = -1 self.printer_attributes = [] self.send_printers_timer = None self.exported_printers = None # protocol stuff: self._protocol = None self._priority_packets = [] self._ordinary_packets = [] self._mouse_position = None self._aliases = {} self._reverse_aliases = {} # server state and caps: self.server_capabilities = None self._remote_machine_id = None self._remote_uuid = None self._remote_version = None self._remote_revision = None self._remote_platform = None self._remote_platform_release = None self._remote_platform_platform = None self._remote_platform_linux_distribution = None self.uuid = get_user_uuid() self.init_packet_handlers() sanity_checks()
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 exec_lpadmin(args): command = shlex.split(LPADMIN) + args def preexec(): os.setsid() log("exec_lpadmin(%s) command=%s", args, command) proc = subprocess.Popen(command, stdin=None, stdout=None, stderr=None, shell=False, close_fds=True, preexec_fn=preexec) #use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper cr = getChildReaper() def check_returncode(proc): returncode = proc.returncode if returncode is not None and returncode != 0: log.warn("lpadmin failed and returned error code: %s", returncode) log.warn( "you may want to check that this user has the required permissions for using this command" ) cr.add_process(proc, "lpadmin", command, ignore=True, forget=True, callback=check_returncode) assert proc.poll() in (None, 0)
def exec_lpadmin(args, success_cb=None): command = shlex.split(LPADMIN) + args log("exec_lpadmin(%s) command=%s", args, command) proc = Popen(command, start_new_session=True) #use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper cr = getChildReaper() def check_returncode(_proc_cb): returncode = proc.poll() log("returncode(%s)=%s", command, returncode) if returncode != 0: log.warn("lpadmin failed and returned error code: %s", returncode) from xpra.platform import get_username log.warn(" verify that user '%s' has all the required permissions", get_username()) log.warn(" for running: '%s'", LPADMIN) log.warn(" full command: %s", " ".join("'%s'" % x for x in command)) elif success_cb: success_cb() cr.add_process(proc, "lpadmin", command, ignore=True, forget=True, callback=check_returncode) if proc.poll() not in (None, 0): raise Exception("lpadmin command '%s' failed and returned %s" % (command, proc.poll()))
def authenticate(self, _challenge_response=None, _client_salt=None): info = "Connection request from %s" % self.connection_str cmd = [self.command, info, str(self.timeout)] self.proc = Popen(cmd, close_fds=True, shell=False) log("authenticate(..) Popen(%s)=%s", cmd, self.proc) #if required, make sure we kill the command when it times out: if self.timeout > 0: self.timer = glib.timeout_add(self.timeout * 1000, self.command_timedout) getChildReaper().add_process(self.proc, "exec auth", cmd, True, True, self.command_ended) v = self.proc.wait() log("authenticate(..) returncode(%s)=%s", cmd, v) if self.timeout and self.timeout_event: return False return v == 0
def exec_open_command(self, url): filelog("exec_open_command(%s)", url) try: import shlex command = shlex.split(self.open_command) + [url] except ImportError as e: filelog("exec_open_command(%s) no shlex: %s", url, e) command = self.open_command.split(" ") filelog("exec_open_command(%s) command=%s", url, command) try: proc = subprocess.Popen(command, env=self.get_open_env(), shell=WIN32) except Exception as e: filelog("exec_open_command(%s)", url, exc_info=True) filelog.error("Error: cannot open '%s': %s", url, e) return filelog("exec_open_command(%s) Popen(%s)=%s", url, command, proc) def open_done(*_args): returncode = proc.poll() filelog("open_file: command %s has ended, returncode=%s", command, returncode) if returncode != 0: filelog.warn("Warning: failed to open the downloaded content") filelog.warn(" '%s' returned %s", " ".join(command), returncode) cr = getChildReaper() cr.add_process(proc, "Open file %s" % url, command, True, True, open_done)
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 make_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() make_thread(watch_lpinfo, "lpinfo watcher", daemon=True).start() 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 exec_lpadmin(args, success_cb=None): command = shlex.split(LPADMIN) + args def preexec(): os.setsid() log("exec_lpadmin(%s) command=%s", args, command) proc = subprocess.Popen( command, stdin=None, stdout=None, stderr=None, shell=False, close_fds=True, preexec_fn=preexec ) # use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper cr = getChildReaper() def check_returncode(proc_cb): returncode = proc.poll() log("returncode(%s)=%s", command, returncode) if returncode != 0: log.warn("lpadmin failed and returned error code: %s", returncode) from xpra.platform import get_username log.warn(" verify that user '%s' has all the required permissions", get_username()) log.warn(" for running: '%s'", LPADMIN) elif success_cb: success_cb() cr.add_process(proc, "lpadmin", command, ignore=True, forget=True, callback=check_returncode) if proc.poll() not in (None, 0): raise Exception("lpadmin command '%s' failed and returned %s" % (command, proc.poll()))
def __init__(self, options, title="Xpra Session Browser"): gtk.Window.__init__(self) self.exit_code = 0 self.set_title(title) self.set_border_width(20) self.set_resizable(True) self.set_decorated(True) icon = self.get_pixbuf("xpra") if icon: self.set_icon(icon) add_close_accel(self, self.quit) self.connect("delete_event", self.quit) self.child_reaper = getChildReaper() self.vbox = gtk.VBox(False, 20) self.add(self.vbox) title_label = gtk.Label(title) title_label.modify_font(pango.FontDescription("sans 14")) self.vbox.add(title_label) self.warning = gtk.Label(" ") red = color_parse("red") self.warning.modify_fg(STATE_NORMAL, red) self.vbox.add(self.warning) hbox = gtk.HBox(False, 10) al = gtk.Alignment(xalign=1, yalign=0.5) al.add(gtk.Label("Password:"******"" #log.info("options=%s (%s)", options, type(options)) self.local_info_cache = {} self.dotxpra = DotXpra(options.socket_dir, options.socket_dirs, username) self.poll_local_sessions() glib.timeout_add(5 * 1000, self.poll_local_sessions) self.populate_table() import signal signal.signal(signal.SIGINT, self.app_signal) signal.signal(signal.SIGTERM, self.app_signal) self.show_all()
def show_downloads(self, _btn): downloads = os.path.expanduser(get_download_dir()) if WIN32: os.startfile(downloads) #@UndefinedVariable pylint: disable=no-member return if OSX: cmd = ["open", downloads] else: cmd = ["xdg-open", downloads] try: proc = subprocess.Popen(cmd) except Exception as e: log("show_downloads()", exc_info=True) log.error("Error: failed to open 'Downloads' folder:") log.error(" %s", e) else: getChildReaper().add_process(proc, "show-downloads", cmd, ignore=True, forget=True)
def do_test_child_reaper(self): #force reset singleton: child_reaper.singleton = None #no-op: reaper_cleanup() log.logger.setLevel(logging.ERROR) cr = getChildReaper() #one that exits before we add the process, one that takes longer: TEST_CHILDREN = (["echo"], ["sleep", "0.5"]) count = 0 for cmd in TEST_CHILDREN: cmd_info = " ".join(cmd) proc = subprocess.Popen(cmd) cr.add_process(proc, cmd_info, cmd_info, False, False, None) count += 1 for _ in range(10): if not cr.check(): break time.sleep(0.1) #we can't check the returncode because it may not be set yet! #assert proc.poll() is not None, "%s process did not terminate?" % cmd_info assert cr.check() is False, "reaper did not notice that the '%s' process has terminated" % cmd_info i = cr.get_info() children = i.get("children").get("total") assert children==count, "expected %s children recorded, but got %s" % (count, children) #now check for the forget option: proc = subprocess.Popen(["sleep", "60"]) procinfo = cr.add_process(proc, "sleep 60", "sleep 60", False, True, None) assert repr(procinfo) count +=1 assert cr.check() is True, "sleep process terminated too quickly" i = cr.get_info() children = i.get("children").get("total") assert children==count, "expected %s children recorded, but got %s" % (count, children) #trying to claim it is dead when it is not: #(this will print some warnings) cr.add_dead_pid(proc.pid) proc.terminate() #now wait for the sleep process to exit: for _ in range(10): if proc.poll() is not None: break time.sleep(0.1) assert proc.poll() is not None assert cr.check() is False, "sleep process did not terminate?" count -= 1 i = cr.get_info() children = i.get("children").get("total") if children!=count: raise Exception("expected the sleep process to have been forgotten (%s children)" % count + "but got %s children instead in the reaper records" % children) reaper_cleanup() #can run again: reaper_cleanup() #nothing for an invalid pid: assert cr.get_proc_info(-1) is None
def new_stream(self, sound_source, codec): if NEW_STREAM_SOUND: try: from xpra.platform.paths import get_resources_dir sample = os.path.join(get_resources_dir(), "bell.wav") log("new_stream(%s, %s) sample=%s, exists=%s", sound_source, codec, sample, os.path.exists(sample)) if os.path.exists(sample): if POSIX: sink = "alsasink" else: sink = "autoaudiosink" cmd = [ "gst-launch-1.0", "-q", "filesrc", "location=%s" % sample, "!", "decodebin", "!", "audioconvert", "!", sink ] import subprocess proc = subprocess.Popen(cmd, close_fds=True) log("Popen(%s)=%s", cmd, proc) from xpra.child_reaper import getChildReaper getChildReaper().add_process(proc, "new-stream-sound", cmd, ignore=True, forget=True) except: pass log("new_stream(%s, %s)", sound_source, codec) if self.sound_source != sound_source: log( "dropping new-stream signal (current source=%s, signal source=%s)", self.sound_source, sound_source) return codec = codec or sound_source.codec sound_source.codec = codec #tell the client this is the start: self.send( "sound-data", codec, "", { "start-of-stream": True, "codec": codec, "sequence": sound_source.sequence, }) self.update_av_sync_delay_total()
def defaults_init(self): #skip warning when running the client from xpra import child_reaper child_reaper.POLL_WARNING = False getChildReaper() log("XpraClientBase.defaults_init() os.environ:") for k,v in os.environ.items(): log(" %s=%s", k, nonl(v)) #client state: self.exit_code = None self.exit_on_signal = False self.display_desc = {} #connection attributes: self.hello_extra = {} self.compression_level = 0 self.display = None self.challenge_handlers = OrderedDict() self.username = None self.password = None self.password_file = () self.password_index = 0 self.password_sent = False self.encryption = None self.encryption_keyfile = None self.server_padding_options = [DEFAULT_PADDING] self.server_client_shutdown = True self.server_compressors = [] #protocol stuff: self._protocol = None self._priority_packets = [] self._ordinary_packets = [] self._mouse_position = None self._mouse_position_pending = None self._mouse_position_send_time = 0 self._mouse_position_delay = MOUSE_DELAY self._mouse_position_timer = 0 self._aliases = {} self._reverse_aliases = {} #server state and caps: self.server_capabilities = None self.completed_startup = False self.uuid = get_user_uuid() self.init_packet_handlers() sanity_checks()
def defaults_init(self): getChildReaper() log("XpraClientBase.defaults_init() os.environ:") for k, v in os.environ.items(): log(" %s=%s", k, nonl(v)) #client state: self.exit_code = None self.exit_on_signal = False #connection attributes: self.compression_level = 0 self.display = None self.username = None self.password_file = None self.password_sent = False self.encryption = None self.encryption_keyfile = None self.server_padding_options = [DEFAULT_PADDING] self.quality = -1 self.min_quality = 0 self.speed = 0 self.min_speed = -1 self.printer_attributes = [] self.send_printers_pending = False self.exported_printers = None #protocol stuff: self._protocol = None self._priority_packets = [] self._ordinary_packets = [] self._mouse_position = None self._aliases = {} self._reverse_aliases = {} #server state and caps: self.server_capabilities = None self._remote_machine_id = None self._remote_uuid = None self._remote_version = None self._remote_revision = None self._remote_platform = None self._remote_platform_release = None self._remote_platform_platform = None self._remote_platform_linux_distribution = None self.uuid = get_user_uuid() self.init_packet_handlers() sanity_checks()
def init(self, opts): log("ProxyServer.init(%s)", opts) self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def authenticate(self, _challenge_response=None, _client_salt=None): info = "Connection request from %s" % self.connection_str cmd = [self.command, info, str(self.timeout)] proc = Popen(cmd, close_fds=True, shell=False) self.proc = proc log("authenticate(..) Popen(%s)=%s", cmd, proc) #if required, make sure we kill the command when it times out: if self.timeout>0: self.timer = glib.timeout_add(self.timeout*1000, self.command_timedout) if not OSX: #python on macos may set a 0 returncode when we use poll() #so we cannot use the ChildReaper on macos, #and we can't cancel the timer getChildReaper().add_process(proc, "exec auth", cmd, True, True, self.command_ended) v = proc.wait() log("authenticate(..) returncode(%s)=%s", cmd, v) if self.timeout_event: return False return v==0
def authenticate(self, caps : typedict) -> bool: info = "Connection request from %s" % self.connection_str cmd = [self.command, info, str(self.timeout)] with Popen(cmd) as proc: self.proc = proc log("authenticate(..) Popen(%s)=%s", cmd, proc) #if required, make sure we kill the command when it times out: if self.timeout>0: self.timer = GLib.timeout_add(self.timeout*1000, self.command_timedout) if not OSX: #python on macos may set a 0 returncode when we use poll() #so we cannot use the ChildReaper on macos, #and we can't cancel the timer getChildReaper().add_process(proc, "exec auth", cmd, True, True, self.command_ended) v = proc.returncode log("authenticate(..) returncode(%s)=%s", cmd, v) if self.timeout_event: return False return v==0
def init(self, opts): log("ProxyServer.init(%s)", opts) self.pings = int(opts.pings) self.video_encoders = opts.proxy_video_encoders self._start_sessions = opts.proxy_start_sessions super().init(opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def init(self, opts): log("ProxyServer.init(%s)", opts) self.video_encoders = opts.proxy_video_encoders self.csc_modules = opts.csc_modules self._start_sessions = opts.proxy_start_sessions ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def init(self, opts): log("ProxyServer.init(%s)", opts) if not opts.tcp_auth: raise InitException("The proxy server requires an authentication mode (use 'none' to disable authentication)") self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def init(self, opts): log("ProxyServer.init(%s)", opts) if not opts.tcp_auth: raise InitException( "The proxy server requires an authentication mode (use 'none' to disable authentication)" ) self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def setup_connection(self, conn): netlog("setup_connection(%s) timeout=%s", conn, conn.timeout) self._protocol = Protocol(self.get_scheduler(), conn, self.process_packet, self.next_packet) self._protocol.large_packets.append("keymap-changed") self._protocol.large_packets.append("server-settings") self._protocol.large_packets.append("logging") self._protocol.set_compression_level(self.compression_level) self._protocol.receive_aliases.update(self._aliases) self._protocol.enable_default_encoder() self._protocol.enable_default_compressor() if self.encryption and ENCRYPT_FIRST_PACKET: key = self.get_encryption_key() self._protocol.set_cipher_out( self.encryption, DEFAULT_IV, key, DEFAULT_SALT, DEFAULT_ITERATIONS, INITIAL_PADDING ) self.have_more = self._protocol.source_has_more if conn.timeout > 0: self.timeout_add((conn.timeout + EXTRA_TIMEOUT) * 1000, self.verify_connected) process = getattr(conn, "process", None) # ie: ssh is handled by anotherprocess if process: proc, name, command = process getChildReaper().add_process(proc, name, command, ignore=True, forget=False) netlog("setup_connection(%s) protocol=%s", conn, self._protocol)
def init(self, opts): self.exit_with_children = opts.exit_with_children self.terminate_children = opts.terminate_children self.start_new_commands = opts.start_new_commands self.start_commands = opts.start self.start_child_commands = opts.start_child self.start_after_connect = opts.start_after_connect self.start_child_after_connect = opts.start_child_after_connect self.start_on_connect = opts.start_on_connect self.start_child_on_connect = opts.start_child_on_connect if opts.exec_wrapper: import shlex self.exec_wrapper = shlex.split(opts.exec_wrapper) self.child_reaper = getChildReaper() self.start_env = parse_env(opts.start_env)
def exec_lpadmin(args): command = shlex.split(LPADMIN)+args def preexec(): os.setsid() log("exec_lpadmin(%s) command=%s", args, command) proc = subprocess.Popen(command, stdin=None, stdout=None, stderr=None, shell=False, close_fds=True, preexec_fn=preexec) #use the global child reaper to make sure this doesn't end up as a zombie from xpra.child_reaper import getChildReaper cr = getChildReaper() def check_returncode(proc): returncode = proc.returncode if returncode is not None and returncode!=0: log.warn("lpadmin failed and returned error code: %s", returncode) log.warn("you may want to check that this user has the required permissions for using this command") cr.add_process(proc, "lpadmin", command, ignore=True, forget=True, callback=check_returncode) assert proc.poll() in (None, 0)
def _open_file(self, filename): if not self.open_files: filelog.warn("Warning: opening files automatically is disabled,") filelog.warn(" ignoring uploaded file:") filelog.warn(" '%s'", filename) return command = shlex.split(self.open_command)+[filename] proc = subprocess.Popen(command) cr = getChildReaper() def open_done(*args): returncode = proc.poll() filelog("open_done: command %s has ended, returncode=%s", command, returncode) if returncode!=0: filelog.warn("Warning: failed to open the downloaded file") filelog.warn(" '%s %s' returned %s", self.open_command, filename, returncode) cr.add_process(proc, "Open File %s" % filename, command, True, True, open_done)
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 make_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() make_thread(watch_lpinfo, "lpinfo watcher", daemon=True).start() 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_sigchld(self): import logging log.logger.setLevel(logging.ERROR) cr = getChildReaper() #one that exits before we add the process, one that takes longer: TEST_CHILDREN = (["echo"], ["sleep", "0.5"]) count = 0 for cmd in TEST_CHILDREN: cmd_info = " ".join(cmd) proc = subprocess.Popen(cmd) cr.add_process(proc, cmd_info, cmd_info, False, False, None) count += 1 for _ in range(10): if not cr.check(): break time.sleep(0.1) #we can't check the returncode because it may not be set yet! #assert proc.poll() is not None, "%s process did not terminate?" % cmd_info assert cr.check() is False, "reaper did not notice that the '%s' process has terminated" % cmd_info i = cr.get_info() children = i.get("children").get("total") assert children==count, "expected %s children recorded, but got %s" % (count, children) #now check for the forget option: proc = subprocess.Popen(["sleep", "60"]) cr.add_process(proc, "sleep 60", "sleep 60", False, True, None) count +=1 assert cr.check() is True, "sleep process terminated too quickly" i = cr.get_info() children = i.get("children").get("total") assert children==count, "expected %s children recorded, but got %s" % (count, children) proc.terminate() #now wait for the sleep process to exit: for _ in range(10): if proc.poll() is not None: break time.sleep(0.1) assert proc.poll() is not None assert cr.check() is False, "sleep process did not terminate?" count -= 1 i = cr.get_info() children = i.get("children").get("total") assert children==count, "expected the sleep process to have been forgotten (%s children), but got %s children instead in the reaper records" % (count, children) reaper_cleanup()
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) proc = subprocess.Popen( command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, close_fds=True, preexec_fn=preexec, ) # 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) out, err = proc.communicate() if proc.wait() != 0: log.warn("Warning: lpinfo command failed and returned %s", proc.returncode) log.warn(" command used: '%s'", 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 _open_file(self, filename): if not self.open_files: filelog.warn("Warning: opening files automatically is disabled,") filelog.warn(" ignoring uploaded file:") filelog.warn(" '%s'", filename) return command = shlex.split(self.open_command) + [filename] proc = subprocess.Popen(command) cr = getChildReaper() def open_done(*_args): returncode = proc.poll() filelog("open_done: command %s has ended, returncode=%s", command, returncode) if returncode != 0: filelog.warn("Warning: failed to open the downloaded file") filelog.warn(" '%s %s' returned %s", self.open_command, filename, returncode) cr.add_process(proc, "Open File %s" % filename, command, True, True, open_done)