def parse_server_capabilities(self, c: typedict) -> bool: #make sure the server doesn't provide a start time in the future: import time self.server_start_time = min(time.time(), c.intget("start_time", -1)) self.server_bandwidth_limit_change = c.boolget( "network.bandwidth-limit-change") self.server_bandwidth_limit = c.intget("network.bandwidth-limit") bandwidthlog( "server_bandwidth_limit_change=%s, server_bandwidth_limit=%s", self.server_bandwidth_limit_change, self.server_bandwidth_limit) self.server_packet_encoders = tuple(x for x in ALL_ENCODERS if c.boolget(x, False)) return True
def parse_client_caps(self, c: typedict): #general features: self.info_namespace = c.boolget("info-namespace") self.share = c.boolget("share") self.lock = c.boolget("lock") self.control_commands = c.strtupleget("control_commands") self.xdg_menu = c.boolget("xdg-menu", True) self.xdg_menu_update = c.boolget("xdg-menu-update") bandwidth_limit = c.intget("bandwidth-limit", 0) server_bandwidth_limit = self.server_bandwidth_limit if self.server_bandwidth_limit is None: server_bandwidth_limit = self.get_socket_bandwidth_limit( ) or bandwidth_limit self.bandwidth_limit = min(server_bandwidth_limit, bandwidth_limit) if self.bandwidth_detection: self.bandwidth_detection = c.boolget("bandwidth-detection", True) self.client_connection_data = c.dictget("connection-data", {}) ccd = typedict(self.client_connection_data) self.adapter_type = ccd.strget("adapter-type", "") self.jitter = ccd.intget("jitter", 0) bandwidthlog( "server bandwidth-limit=%s, client bandwidth-limit=%s, value=%s, detection=%s", server_bandwidth_limit, bandwidth_limit, self.bandwidth_limit, self.bandwidth_detection) if getattr(self, "mmap_size", 0) > 0: log("mmap enabled, ignoring bandwidth-limit") self.bandwidth_limit = 0
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_client_caps(self, c: typedict): av_sync = c.boolget("av-sync") self.av_sync_enabled = self.av_sync and av_sync self.set_av_sync_delay( int(self.av_sync_enabled) * c.intget("av-sync.delay.default", DEFAULT_AV_SYNC_DELAY)) log("av-sync: server=%s, client=%s, enabled=%s, total=%s", self.av_sync, av_sync, self.av_sync_enabled, self.av_sync_delay_total)
def parse_server_capabilities(self, c : typedict) -> bool: self.server_webcam = c.boolget("webcam") self.server_webcam_encodings = c.strtupleget("webcam.encodings", ("png", "jpeg")) self.server_virtual_video_devices = c.intget("virtual-video-devices") log("webcam server support: %s (%i devices, encodings: %s)", self.server_webcam, self.server_virtual_video_devices, csv(self.server_webcam_encodings)) if self.webcam_forwarding and self.server_webcam and self.server_virtual_video_devices>0: if self.webcam_option=="on" or self.webcam_option.find("/dev/video")>=0: self.start_sending_webcam() return True
def parse_client_caps(self, c: typedict): self.vrefresh = c.intget("vrefresh", -1) self.randr_notify = c.boolget("randr_notify") self.desktop_size = c.intpair("desktop_size") if self.desktop_size is not None: w, h = self.desktop_size if w <= 0 or h <= 0 or w >= 32768 or h >= 32768: log.warn("ignoring invalid desktop dimensions: %sx%s", w, h) self.desktop_size = None self.desktop_mode_size = c.intpair("desktop_mode_size") self.desktop_size_unscaled = c.intpair("desktop_size.unscaled") self.screen_resize_bigger = c.boolget("screen-resize-bigger", True) self.set_screen_sizes(c.tupleget("screen_sizes")) desktop_names = tuple(net_utf8(x) for x in c.tupleget("desktop.names")) self.set_desktops(c.intget("desktops", 1), desktop_names) self.show_desktop_allowed = c.boolget("show-desktop") self.icc = c.dictget("icc", {}) self.display_icc = c.dictget("display-icc", {}) self.opengl_props = c.dictget("opengl", {})
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_branch = c.strget("build.branch") 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_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
def parse_client_caps(self, c: typedict): #general features: self.info_namespace = c.boolget("info-namespace") self.send_notifications = c.boolget("notifications") self.send_notifications_actions = c.boolget("notifications.actions") log("notifications=%s, actions=%s", self.send_notifications, self.send_notifications_actions) self.share = c.boolget("share") self.lock = c.boolget("lock") self.control_commands = c.strtupleget("control_commands") self.xdg_menu_update = c.boolget("xdg-menu-update") bandwidth_limit = c.intget("bandwidth-limit", 0) server_bandwidth_limit = self.server_bandwidth_limit if self.server_bandwidth_limit is None: server_bandwidth_limit = self.get_socket_bandwidth_limit( ) or bandwidth_limit self.bandwidth_limit = min(server_bandwidth_limit, bandwidth_limit) if self.bandwidth_detection: self.bandwidth_detection = c.boolget("bandwidth-detection", True) self.client_connection_data = c.dictget("connection-data", {}) self.jitter = typedict(self.client_connection_data).intget("jitter", 0) bandwidthlog( "server bandwidth-limit=%s, client bandwidth-limit=%s, value=%s, detection=%s", server_bandwidth_limit, bandwidth_limit, self.bandwidth_limit, self.bandwidth_detection) if getattr(self, "mmap_size", 0) > 0: log("mmap enabled, ignoring bandwidth-limit") self.bandwidth_limit = 0 #adjust max packet size if file transfers are enabled: #TODO: belongs in mixin: file_transfer = getattr(self, "file_transfer", None) if file_transfer: self.protocol.max_packet_size = max( self.protocol.max_packet_size, self.file_size_limit * 1024 * 1024)
def parse_client_caps(self, c : typedict): self.pointer_relative = c.boolget("pointer.relative") self.double_click_time = c.intget("double_click.time") self.double_click_distance = c.intpair("double_click.distance") self.mouse_show = c.boolget("mouse.show") self.mouse_last_position = c.intpair("mouse.initial-position")
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 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_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 parse_client_caps(self, c : typedict): #batch options: def batch_value(prop, default, minv=None, maxv=None): assert default is not None def parse_batch_int(value, varname): if value is not None: try: return int(value) except (TypeError, ValueError): log.error("Error: invalid value '%s' for batch option %s", value, varname) return None #from client caps first: cpname = "batch.%s" % prop v = parse_batch_int(c.get(cpname), cpname) #try env: if v is None: evname = "XPRA_BATCH_%s" % prop.upper() v = parse_batch_int(os.environ.get(evname), evname) #fallback to default: if v is None: v = default if minv is not None: v = max(minv, v) if maxv is not None: v = min(maxv, v) assert v is not None return v #general features: self.zlib = c.boolget("zlib", True) self.lz4 = c.boolget("lz4", False) and use("lz4") self.brotli = c.boolget("brotli", False) and use("brotli") log("compressors: zlib=%s, lz4=%s, brotli=%s", self.zlib, self.lz4, self.brotli) delay = batch_config.START_DELAY dbc = self.default_batch_config dbc.always = bool(batch_value("always", batch_config.ALWAYS)) dbc.min_delay = batch_value("min_delay", batch_config.MIN_DELAY, 0, 1000) dbc.max_delay = batch_value("max_delay", batch_config.MAX_DELAY, 1, 15000) dbc.max_events = batch_value("max_events", batch_config.MAX_EVENTS) dbc.max_pixels = batch_value("max_pixels", batch_config.MAX_PIXELS) dbc.time_unit = batch_value("time_unit", batch_config.TIME_UNIT, 1) self.vrefresh = c.intget("vrefresh", -1) dbc.match_vrefresh(self.vrefresh) dbc.delay = batch_value("delay", delay, dbc.min_delay) log("default batch config: %s", dbc) #encodings: self.encodings_packet = c.boolget("encodings.packet", False) self.encodings = c.strtupleget("encodings") self.core_encodings = c.strtupleget("encodings.core", self.encodings) log("encodings=%s, core_encodings=%s", self.encodings, self.core_encodings) #we can't assume that the window mixin is loaded, #or that the ui_client flag exists: send_ui = getattr(self, "ui_client", True) and getattr(self, "send_windows", True) if send_ui and not self.core_encodings: raise ClientException("client failed to specify any supported encodings") self.window_icon_encodings = c.strtupleget("encodings.window-icon", ("premult_argb32",)) #try both spellings for older versions: for x in ("encodings", "encoding",): self.rgb_formats = c.strtupleget(x+".rgb_formats", self.rgb_formats) #skip all other encoding related settings if we don't send pixels: if not send_ui: log("windows/pixels forwarding is disabled for this client") else: self.parse_encoding_caps(c)