def server_connection_established(self, caps: typedict): #the server should respond with the display chosen log("server_connection_established() exit_code=%s", self.exit_code) display = caps.strget("display") if display: mode = caps.strget("mode") session_type = { "start": "seamless ", "start-desktop": "desktop ", "shadow": "shadow ", }.get(mode, "") try: errwrite("\n%ssession now available on display %s\n" % (session_type, display)) if POSIX and not OSX and self.displayfd > 0 and display and display.startswith( b":"): from xpra.platform.displayfd import write_displayfd log("writing display %s to displayfd=%s", display, self.displayfd) write_displayfd(self.displayfd, display[1:]) except OSError: log("server_connection_established(..)", exc_info=True) if not self.exit_code: self.quit(0) return True
def process_ui_capabilities(self, c : typedict): self.server_is_desktop = c.boolget("shadow") or c.boolget("desktop") skip_vfb_size_check = False #if we decide not to use scaling, skip warnings if not fequ(self.xscale, 1.0) or not fequ(self.yscale, 1.0): #scaling is used, make sure that we need it and that the server can support it #(without rounding support, size-hints can cause resize loops) if self.server_is_desktop and not self.desktop_fullscreen: #don't honour auto mode in this case if self.desktop_scaling=="auto": log.info(" not scaling a %s server", c.strget("type", "shadow")) skip_vfb_size_check = self.xscale>1 or self.yscale>1 self.scale_change_embargo = 0 self.scalingoff() if self.can_scale: self.may_adjust_scaling() if not self.server_is_desktop and not skip_vfb_size_check and self.server_max_desktop_size: avail_w, avail_h = self.server_max_desktop_size root_w, root_h = self.get_root_size() log("validating server_max_desktop_size=%s vs root size=%s", self.server_max_desktop_size, (root_w, root_h)) if self.cx(root_w)!=root_w or self.cy(root_h)!=root_h: log(" root size scaled to %s", (self.cx(root_w), self.cy(root_h))) if self.cx(root_w)>(avail_w+1) or self.cy(root_h)>(avail_h+1): log.warn("Server's virtual screen is too small") log.warn(" server: %sx%s vs client: %sx%s", avail_w, avail_h, self.cx(root_w), self.cy(root_h)) log.warn(" you may see strange behavior,") log.warn(" please see https://github.com/Xpra-org/xpra/blob/master/docs/Usage/Xdummy.md") #now that we have the server's screen info, allow scale changes: self.scale_change_embargo = 0 self.set_max_packet_size()
def is_needed(cls, caps: typedict) -> bool: #pre 2.3 clients; if caps.strget("mmap_file"): return True v = caps.rawget("mmap") #we should be receiving a dict with mmap attributes #(but pre v4 clients also send a boolean telling us if mmap is supported by the platform..) return isinstance(v, dict)
def do_authenticate(self, caps: typedict) -> bool: if self.passed: log("invalid state: challenge has already been passed") return False if not caps: log("invalid state: no capabilities") return False if not self.challenge_sent: log("invalid state: challenge has not been sent yet!") return False challenge_response = caps.strget("challenge_response") client_salt = caps.strget("challenge_client_salt") #challenge has been sent already for this module if not challenge_response: log("invalid state: challenge already sent but no response found!") return False return self.authenticate_check(challenge_response, client_salt)
def do_command(self, caps: typedict): v = caps.strget(b"version") if not v: self.warn_and_quit( EXIT_FAILURE, "server did not provide the version information") else: sys.stdout.write("%s\n" % (v, )) self.quit(EXIT_OK)
def do_command(self, caps : typedict): if caps: ctr = caps.strget("connect_test_response") log("do_command(..) expected connect test response='%s', got '%s'", self.value, ctr) if ctr==self.value: self.quit(EXIT_OK) else: self.quit(EXIT_INTERNAL_ERROR) else: self.quit(EXIT_FAILURE)
def parse_server_capabilities(self, c : typedict) -> bool: self.server_display = c.strget("display") self.server_desktop_size = c.intpair("desktop_size") log("server desktop size=%s", self.server_desktop_size) self.server_max_desktop_size = c.intpair("max_desktop_size", (2**15, 2**15)) self.server_actual_desktop_size = c.intpair("actual_desktop_size") log("server actual desktop size=%s", self.server_actual_desktop_size) self.server_randr = c.boolget("resize_screen") log("server has randr: %s", self.server_randr) self.server_opengl = c.dictget("opengl") return True
def parse_server_capabilities(self, c: typedict) -> bool: self.server_av_sync = c.boolget("av-sync.enabled") avsynclog("av-sync: server=%s, client=%s", self.server_av_sync, self.av_sync) self.server_pulseaudio_id = c.strget("sound.pulseaudio.id") self.server_pulseaudio_server = c.strget("sound.pulseaudio.server") self.server_sound_decoders = c.strtupleget("sound.decoders") self.server_sound_encoders = c.strtupleget("sound.encoders") self.server_sound_receive = c.boolget("sound.receive") self.server_sound_send = c.boolget("sound.send") self.server_sound_bundle_metadata = c.boolget("sound.bundle-metadata") log( "pulseaudio id=%s, server=%s, sound decoders=%s, sound encoders=%s, receive=%s, send=%s", self.server_pulseaudio_id, self.server_pulseaudio_server, csv(self.server_sound_decoders), csv(self.server_sound_encoders), self.server_sound_receive, self.server_sound_send) if self.server_sound_send and self.speaker_enabled: self.start_receiving_sound() if self.server_sound_receive and self.microphone_enabled: self.start_sending_sound() return True
def parse_server_capabilities(self, c: typedict) -> bool: self.server_av_sync = c.boolget("av-sync.enabled") avsynclog("av-sync: server=%s, client=%s", self.server_av_sync, self.av_sync) self.server_pulseaudio_id = c.strget("sound.pulseaudio.id") self.server_pulseaudio_server = c.strget("sound.pulseaudio.server") self.server_sound_decoders = c.strtupleget("sound.decoders") self.server_sound_encoders = c.strtupleget("sound.encoders") self.server_sound_receive = c.boolget("sound.receive") self.server_sound_send = c.boolget("sound.send") log( "pulseaudio id=%s, server=%s, sound decoders=%s, sound encoders=%s, receive=%s, send=%s", self.server_pulseaudio_id, self.server_pulseaudio_server, csv(self.server_sound_decoders), csv(self.server_sound_encoders), self.server_sound_receive, self.server_sound_send) if self.server_sound_send and self.speaker_enabled: self.show_progress(90, "starting speaker forwarding") self.start_receiving_sound() if self.server_sound_receive and self.microphone_enabled: #call via idle_add because we may query X11 properties #to find the pulseaudio server: GLib.idle_add(self.start_sending_sound) return True
def parse_server_capabilities(self, c: typedict) -> bool: try: from xpra import clipboard assert clipboard except ImportError: log.warn("Warning: clipboard module is missing") self.clipboard_enabled = False return True self.server_clipboard = c.boolget("clipboard") self.server_clipboard_loop_uuids = c.dictget("clipboard.loop-uuids", {}) self.server_clipboard_direction = c.strget("clipboard-direction", "both") if self.server_clipboard_direction != self.client_clipboard_direction and self.server_clipboard_direction != "both": if self.client_clipboard_direction == "disabled": pass elif self.server_clipboard_direction == "disabled": log.warn( "Warning: server clipboard synchronization is currently disabled" ) self.client_clipboard_direction = "disabled" elif self.client_clipboard_direction == "both": log.warn( "Warning: server only supports '%s' clipboard transfers", self.server_clipboard_direction) self.client_clipboard_direction = self.server_clipboard_direction else: log.warn("Warning: incompatible clipboard direction settings") log.warn(" server setting: %s, client setting: %s", self.server_clipboard_direction, self.client_clipboard_direction) try: from xpra.clipboard.clipboard_core import ALL_CLIPBOARDS except ImportError: ALL_CLIPBOARDS = [] self.server_clipboards = c.strtupleget("clipboards", ALL_CLIPBOARDS) log("server clipboard: supported=%s, direction=%s", self.server_clipboard, self.server_clipboard_direction) log("client clipboard: supported=%s, direction=%s", self.client_supports_clipboard, self.client_clipboard_direction) self.clipboard_enabled = self.client_supports_clipboard and self.server_clipboard log("parse_clipboard_caps() clipboard enabled=%s", self.clipboard_enabled) self.server_clipboard_contents_slice_fix = c.boolget( "clipboard.contents-slice-fix") self.server_clipboard_preferred_targets = c.strtupleget( "clipboard.preferred-targets", ()) if not self.server_clipboard_contents_slice_fix: log.info("server clipboard does not include contents slice fix") return True
def parse_server_capabilities(self, c : typedict) -> bool: try: from xpra import clipboard assert clipboard except ImportError: log.warn("Warning: clipboard module is missing") self.clipboard_enabled = False return True self.server_clipboard = c.boolget("clipboard") self.server_clipboard_direction = c.strget("clipboard-direction", "both") if self.server_clipboard_direction!=self.client_clipboard_direction and self.server_clipboard_direction!="both": if self.client_clipboard_direction=="disabled": pass elif self.server_clipboard_direction=="disabled": log.warn("Warning: server clipboard synchronization is currently disabled") self.client_clipboard_direction = "disabled" elif self.client_clipboard_direction=="both": log.warn("Warning: server only supports '%s' clipboard transfers", self.server_clipboard_direction) self.client_clipboard_direction = self.server_clipboard_direction else: log.warn("Warning: incompatible clipboard direction settings") log.warn(" server setting: %s, client setting: %s", self.server_clipboard_direction, self.client_clipboard_direction) try: from xpra.clipboard.clipboard_core import ALL_CLIPBOARDS except ImportError: ALL_CLIPBOARDS = [] self.server_clipboards = c.strtupleget("clipboards", ALL_CLIPBOARDS) log("server clipboard: supported=%s, direction=%s", self.server_clipboard, self.server_clipboard_direction) log("client clipboard: supported=%s, direction=%s", self.client_supports_clipboard, self.client_clipboard_direction) self.clipboard_enabled = self.client_supports_clipboard and self.server_clipboard self.server_clipboard_greedy = c.boolget("clipboard.greedy") self.server_clipboard_want_targets = c.boolget("clipboard.want_targets") self.server_clipboard_selections = c.strtupleget("clipboard.selections", CLIPBOARDS) self.server_clipboard_preferred_targets = c.strtupleget("clipboard.preferred-targets", ()) log("server clipboard: greedy=%s, want_targets=%s, selections=%s", self.server_clipboard_greedy, self.server_clipboard_want_targets, self.server_clipboard_selections) log("parse_clipboard_caps() clipboard enabled=%s", self.clipboard_enabled) self.server_clipboard_preferred_targets = c.strtupleget("clipboard.preferred-targets", ()) return True
def parse_server_capabilities(self, c: typedict) -> bool: p = self._protocol if p.TYPE == "rfb": #only the xpra protocol provides the server info return True self._remote_machine_id = c.strget("machine_id") self._remote_uuid = c.strget("uuid") self._remote_version = c.strget("build.version", c.strget("version")) self._remote_revision = c.strget("build.revision", c.strget("revision")) mods = c.get("build.local_modifications") if mods and str(mods).find("dfsg") >= 0: # pragma: no cover get_util_logger().warn( "Warning: the xpra server is running a buggy Debian version") get_util_logger().warn( " those are usually out of date and unstable") else: self._remote_modifications = c.intget("build.local_modifications", 0) self._remote_commit = c.strget("build.commit") self._remote_build_date = c.strget("build.date") self._remote_build_time = c.strget("build.time") self._remote_hostname = c.strget("hostname") self._remote_display = c.strget("display") self._remote_platform = c.strget("platform") self._remote_platform_release = c.strget("platform.release") self._remote_platform_platform = c.strget("platform.platform") self._remote_python_version = c.strget("python.version") self._remote_subcommands = c.strtupleget("subcommands") self._remote_server_log = c.strget("server-log") self._remote_lib_versions = get_remote_lib_versions(c) #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug') pld = c.tupleget("platform.linux_distribution") if pld and len(pld) == 3: def san(v): if isinstance(v, int): return v return bytestostr(v) self._remote_platform_linux_distribution = [san(x) for x in pld] verr = version_compat_check(self._remote_version) if verr is not None: self.warn_and_quit( EXIT_INCOMPATIBLE_VERSION, "incompatible remote version '%s': %s" % (self._remote_version, verr)) return False return True
def parse_client_caps(self, c: typedict): import os from xpra.os_util import WIN32 from xpra.log import Logger log = Logger("mmap") self.mmap_client_namespace = c.boolget("mmap.namespace", False) sep = "." if self.mmap_client_namespace else "_" def mmapattr(k): return "mmap%s%s" % (sep, k) mmap_filename = c.strget(mmapattr("file")) if not mmap_filename: return mmap_size = c.intget(mmapattr("size"), 0) log("client supplied mmap_file=%s", mmap_filename) mmap_token = c.intget(mmapattr("token")) log("mmap supported=%s, token=%s", self.supports_mmap, mmap_token) if self.mmap_filename: log("using global server specified mmap file path: '%s'", self.mmap_filename) mmap_filename = self.mmap_filename if not self.supports_mmap: log("client enabled mmap but mmap mode is not supported", mmap_filename) elif WIN32 and mmap_filename.startswith("/"): log("mmap_file '%s' is a unix path", mmap_filename) elif not os.path.exists(mmap_filename): log("mmap_file '%s' cannot be found!", mmap_filename) else: from xpra.net.mmap_pipe import ( init_server_mmap, read_mmap_token, write_mmap_token, DEFAULT_TOKEN_INDEX, DEFAULT_TOKEN_BYTES, ) self.mmap, self.mmap_size = init_server_mmap( mmap_filename, mmap_size) log("found client mmap area: %s, %i bytes - min mmap size=%i", self.mmap, self.mmap_size, self.min_mmap_size) if self.mmap_size > 0: index = c.intget(mmapattr("token_index"), DEFAULT_TOKEN_INDEX) count = c.intget(mmapattr("token_bytes"), DEFAULT_TOKEN_BYTES) v = read_mmap_token(self.mmap, index, count) log("mmap_token=%#x, verification=%#x", mmap_token, v) if v != mmap_token: log.warn( "Warning: mmap token verification failed, not using mmap area!" ) log.warn(" expected '%#x', found '%#x'", mmap_token, v) self.mmap.close() self.mmap = None self.mmap_size = 0 elif self.mmap_size < self.min_mmap_size: log.warn( "Warning: client supplied mmap area is too small, discarding it" ) log.warn(" we need at least %iMB and this area is %iMB", self.min_mmap_size // 1024 // 1024, self.mmap_size // 1024 // 1024) self.mmap.close() self.mmap = None self.mmap_size = 0 else: from xpra.os_util import get_int_uuid self.mmap_client_token = get_int_uuid() self.mmap_client_token_bytes = DEFAULT_TOKEN_BYTES if c.intget("mmap_token_index"): #we can write the token anywhere we want and tell the client, #so write it right at the end: self.mmap_client_token_index = self.mmap_size - self.mmap_client_token_bytes else: #use the expected default for older versions: self.mmap_client_token_index = DEFAULT_TOKEN_INDEX write_mmap_token(self.mmap, self.mmap_client_token, self.mmap_client_token_index, self.mmap_client_token_bytes) if self.mmap_size > 0: from xpra.simple_stats import std_unit log.info(" mmap is enabled using %sB area in %s", std_unit(self.mmap_size, unit=1024), mmap_filename)
def parse_client_caps(self, c: typedict): self.uuid = c.strget("uuid") self.session_id = c.strget("session-id") self.machine_id = c.strget("machine_id") self.hostname = c.strget("hostname") self.username = c.strget("username") self.name = c.strget("name") self.argv = c.strtupleget("argv") self.sharing = c.boolget("share") self.client_type = c.strget("client_type", "PyGTK") self.client_platform = c.strget("platform") self.client_machine = c.strget("platform.machine") self.client_processor = c.strget("platform.processor") self.client_release = c.strget("platform.sysrelease") self.client_linux_distribution = c.strtupleget( "platform.linux_distribution") self.client_version = c.strget("version") self.client_revision = c.strget("build.revision") self.client_bits = c.intget("python.bits") self.client_proxy = c.boolget("proxy") self.client_wm_name = c.strget("wm_name") self.client_session_type = c.strget("session-type") self.client_session_type_full = c.strget("session-type.full", "") self.client_setting_change = c.boolget("setting-change") self.client_opengl = typedict(c.dictget("opengl") or {}) self.proxy_hostname = c.strget("proxy.hostname") self.proxy_platform = c.strget("proxy.platform") self.proxy_release = c.strget("proxy.platform.sysrelease") self.proxy_version = c.strget("proxy.version") self.proxy_version = c.strget("proxy.build.version", self.proxy_version) log("client uuid %s", self.uuid)
def parse_server_capabilities(self, c: typedict) -> bool: for cb in CLIENT_BASES: if not cb.parse_server_capabilities(self, c): log.info("failed to parse server capabilities in %s", cb) return False self.server_session_name = strtobytes(c.rawget("session_name", b"")).decode("utf-8") set_name("Xpra", self.session_name or self.server_session_name or "Xpra") self.server_platform = c.strget("platform") self.server_sharing = c.boolget("sharing") self.server_sharing_toggle = c.boolget("sharing-toggle") self.server_lock = c.boolget("lock") self.server_lock_toggle = c.boolget("lock-toggle") self.server_keyboard = c.boolget("keyboard", True) self.server_pointer = c.boolget("pointer", True) self.server_start_new_commands = c.boolget("start-new-commands") if self.server_start_new_commands: self.server_xdg_menu = c.dictget("xdg-menu", None) if self.start_new_commands or self.start_child_new_commands: if self.server_start_new_commands: self.after_handshake(self.send_start_new_commands) else: log.warn("Warning: cannot start new commands") log.warn(" the feature is currently disabled on the server") self.server_commands_info = c.boolget("server-commands-info") self.server_commands_signals = c.strtupleget("server-commands-signals") self.server_readonly = c.boolget("readonly") if self.server_readonly and not self.readonly: log.info("server is read only") self.readonly = True if not self.server_keyboard and self.keyboard_helper: #swallow packets: def nosend(*_args): pass self.keyboard_helper.send = nosend i = platform_name( self._remote_platform, c.strtupleget("platform.linux_distribution") or c.strget("platform.release", "")) r = self._remote_version if self._remote_revision: r += "-r%s" % self._remote_revision mode = c.strget("server.mode", "server") bits = c.intget("python.bits", 32) log.info("Xpra %s server version %s %i-bit", mode, std(r), bits) if i: log.info(" running on %s", std(i)) if c.boolget("desktop") or c.boolget("shadow"): v = c.intpair("actual_desktop_size") if v: w, h = v ss = c.tupleget("screen_sizes") if ss: log.info(" remote desktop size is %sx%s with %s screen%s:", w, h, len(ss), engs(ss)) log_screen_sizes(w, h, ss) else: log.info(" remote desktop size is %sx%s", w, h) if c.boolget("proxy"): proxy_hostname = c.strget("proxy.hostname") proxy_platform = c.strget("proxy.platform") proxy_release = c.strget("proxy.platform.release") proxy_version = c.strget("proxy.version") proxy_version = c.strget("proxy.build.version", proxy_version) proxy_distro = c.strget("proxy.linux_distribution") msg = "via: %s proxy version %s" % (platform_name( proxy_platform, proxy_distro or proxy_release), std(proxy_version or "unknown")) if proxy_hostname: msg += " on '%s'" % std(proxy_hostname) log.info(msg) return True
def caps_to_revision(caps: typedict) -> str: revision = caps.strget("revision") local_modifications = caps.intget("local_modifications") commit = caps.strget("commit") branch = caps.strget("branch") return make_revision_str(revision, local_modifications, branch, commit)
def caps_to_version(caps: typedict) -> str: return caps.strget("version") + "-" + caps_to_revision(caps)
def parse_server_capabilities(self, c : typedict) -> bool: self._remote_machine_id = c.strget("machine_id") self._remote_uuid = c.strget("uuid") self._remote_version = c.strget("build.version", c.strget("version")) self._remote_revision = c.strget("build.revision", c.strget("revision")) mods = c.rawget("build.local_modifications") if mods and str(mods).find("dfsg")>=0: get_util_logger().warn("Warning: the xpra server is running a buggy Debian version") get_util_logger().warn(" those are usually out of date and unstable") else: self._remote_modifications = c.intget("build.local_modifications", 0) self._remote_build_date = c.strget("build.date") self._remote_build_time = c.strget("build.time") self._remote_hostname = c.strget("hostname") self._remote_display = c.strget("display") self._remote_platform = c.strget("platform") self._remote_platform_release = c.strget("platform.release") self._remote_platform_platform = c.strget("platform.platform") self._remote_python_version = c.strget("python.version") self._remote_subcommands = c.strtupleget("subcommands") for x in ("glib", "gobject", "gtk", "gdk", "cairo", "pango", "sound.gst", "sound.pygst"): v = c.rawget("%s.version" % x, None) if v is not None: self._remote_lib_versions[x] = v #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug') pld = c.tupleget("platform.linux_distribution") if pld and len(pld)==3: def san(v): if isinstance(v, int): return v return bytestostr(v) self._remote_platform_linux_distribution = [san(x) for x in pld] verr = version_compat_check(self._remote_version) if verr is not None: self.warn_and_quit(EXIT_INCOMPATIBLE_VERSION, "incompatible remote version '%s': %s" % (self._remote_version, verr)) return False return True