def __init__(self, conn, compression_level): gobject.GObject.__init__(self) self._window_to_id = {} self._id_to_window = {} self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) capabilities_request = dict(default_capabilities) if compression_level: capabilities_request["deflate"] = compression_level root_w, root_h = gtk.gdk.get_default_root_window().get_size() capabilities_request["desktop_size"] = [root_w, root_h] self.send(["hello", capabilities_request]) self._keymap = gtk.gdk.keymap_get_default() self._keymap.connect("keys-changed", self._keys_changed) self._keys_changed() self._xsettings_watcher = None self._root_props_watcher = None # FIXME: these should perhaps be merged. self._clipboard_helper = ClipboardProtocolHelper(self.send) self._client_extras = ClientExtras(self.send) self._focused = None
def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet, self.next_packet) self._protocol.large_packets.append("keymap-changed") self._protocol.large_packets.append("server-settings") self._protocol.set_compression_level(self.compression_level) self._protocol.start() self.have_more = self._protocol.source_has_more
def __init__(self, sock): gobject.GObject.__init__(self) self._window_to_id = {} self._id_to_window = {} root = gtk.gdk.get_default_root_window() root.set_events(root.get_events() | gtk.gdk.PROPERTY_NOTIFY) add_event_receiver(root, self) self._protocol = Protocol(sock, self.process_packet) ClientSource(self._protocol) self.send(["hello", default_capabilities]) self._keymap = gtk.gdk.keymap_get_default() self._keymap.connect("keys-changed", self._keys_changed) self._keys_changed() self._clipboard_helper = ClipboardProtocolHelper(self.send) self._focused = None
def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol)
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = { "handshake-complete": n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, opts): gobject.GObject.__init__(self) self.password_file = opts.password_file self.encoding = opts.encoding self.jpegquality = opts.jpegquality self._protocol = None self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) def init_packet_handlers(self): self._packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "hello": self._process_hello, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send(["hello", hello]) def make_hello(self, challenge_response=None): capabilities = {"__prerelease_version": xpra.__version__} capabilities["version"] = xpra.__version__ if challenge_response: capabilities["challenge_response"] = challenge_response capabilities["dynamic_compression"] = True capabilities["packet_size"] = True if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.jpegquality: capabilities["jpeg"] = self.jpegquality return capabilities def send(self, packet): self._protocol.source.queue_ordinary_packet(packet) def send_now(self, packet): self._protocol.source.queue_priority_packet(packet) def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, *args): raise Exception("override me!") def _process_disconnect(self, packet): log.error("server requested disconnect: %s" % str(packet)) self.quit() return def _process_challenge(self, packet): if not self.password_file: log.error("password is required by the server") self.quit() return import hmac passwordFile = open(self.password_file, "rU") password = passwordFile.read() salt = packet[1] challenge_response = hmac.HMAC(password, salt) self.send_hello(challenge_response.hexdigest()) def _process_hello(self, packet): pass def _process_set_deflate(self, packet): #this tell us the server has set its compressor #(the decompressor has been enabled - see protocol) log.debug("set_deflate: %s", packet[1:]) def _process_connection_lost(self, packet): log.error("Connection lost") self.quit() def _process_gibberish(self, packet): (_, data) = packet log.info("Received uninterpretable nonsense: %s", repr(data)) self.emit("received-gibberish", data) def process_packet(self, proto, packet): packet_type = packet[0] self._packet_handlers[packet_type](packet)
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = {"handshake-complete": n_arg_signal(0), "received-gibberish": n_arg_signal(1)} def __init__(self, opts): gobject.GObject.__init__(self) self.exit_code = None self.password_file = opts.password_file self.encoding = opts.encoding self.jpegquality = opts.jpegquality self._protocol = None self.server_capabilities = {} self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) self._protocol.start() def init_packet_handlers(self): self._packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "hello": self._process_hello, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send(["hello", hello]) def make_hello(self, challenge_response=None): capabilities = {"version": xpra.__version__} if challenge_response: capabilities["challenge_response"] = challenge_response if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.jpegquality: capabilities["jpeg"] = self.jpegquality capabilities["platform"] = sys.platform capabilities["raw_packets"] = True capabilities["server-window-resize"] = True capabilities["randr_notify"] = False # only client.py cares about this return capabilities def send(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_ordinary_packet(packet) def send_now(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_priority_packet(packet) def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, exit_code=0): if self.exit_code is None: self.exit_code = exit_code raise Exception("override me!") def _process_disconnect(self, packet): log.error("server requested disconnect: %s", packet[1:]) self.quit(0) def _process_connection_lost(self, packet): log.error("Connection lost") self.quit(1) def _process_challenge(self, packet): if not self.password_file: log.error("password is required by the server") self.quit(2) return import hmac try: passwordFile = open(self.password_file, "rU") password = passwordFile.read() passwordFile.close() while password.endswith("\n") or password.endswith("\r"): password = password[:-1] except IOError, e: log.error("failed to open password file %s: %s", self.password_file, e) self.quit(3) return salt = packet[1] challenge_response = hmac.HMAC(password, salt) self.send_hello(challenge_response.hexdigest())
def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) self._protocol.start()
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = { "handshake-complete": n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, opts): gobject.GObject.__init__(self) self.exit_code = None self.password_file = opts.password_file self.encoding = opts.encoding self.jpegquality = opts.jpegquality self._protocol = None self.server_capabilities = {} self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) self._protocol.start() def init_packet_handlers(self): self._packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "hello": self._process_hello, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send(["hello", hello]) def make_hello(self, challenge_response=None): capabilities = {} add_version_info(capabilities) if challenge_response: capabilities["challenge_response"] = challenge_response if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.jpegquality: capabilities["jpeg"] = self.jpegquality capabilities["platform"] = sys.platform capabilities["raw_packets"] = True capabilities["chunked_compression"] = True capabilities["rencode"] = has_rencode capabilities["server-window-resize"] = True capabilities["randr_notify"] = False #only client.py cares about this return capabilities def send(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_ordinary_packet(packet) def send_now(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_priority_packet(packet) def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, exit_code=0): if self.exit_code is None: self.exit_code = exit_code raise Exception("override me!") def _process_disconnect(self, packet): log.error("server requested disconnect: %s", packet[1:]) self.quit(0) def _process_connection_lost(self, packet): log.error("Connection lost") self.quit(1) def _process_challenge(self, packet): if not self.password_file: log.error("password is required by the server") self.quit(2) return import hmac try: passwordFile = open(self.password_file, "rU") password = passwordFile.read() passwordFile.close() while password.endswith("\n") or password.endswith("\r"): password = password[:-1] except IOError, e: log.error("failed to open password file %s: %s", self.password_file, e) self.quit(3) return salt = packet[1] challenge_response = hmac.HMAC(password, salt) self.send_hello(challenge_response.hexdigest())
class XpraClient(gobject.GObject): __gsignals__ = { "wimpiggy-property-notify-event": one_arg_signal, } def __init__(self, sock): gobject.GObject.__init__(self) self._window_to_id = {} self._id_to_window = {} root = gtk.gdk.get_default_root_window() root.set_events(root.get_events() | gtk.gdk.PROPERTY_NOTIFY) add_event_receiver(root, self) self._protocol = Protocol(sock, self.process_packet) ClientSource(self._protocol) self.send(["hello", default_capabilities]) self._keymap = gtk.gdk.keymap_get_default() self._keymap.connect("keys-changed", self._keys_changed) self._keys_changed() self._clipboard_helper = ClipboardProtocolHelper(self.send) self._focused = None def run(self): gtk_main_quit_on_fatal_exceptions_enable() gtk.main() def _keys_changed(self, *args): self._modifier_map = grok_modifier_map(gtk.gdk.display_get_default()) def update_focus(self, id, gotit): if gotit and self._focused is not id: self.send(["focus", id]) self._focused = id if not gotit and self._focused is id: self.send(["focus", 0]) self._focused = None def mask_to_names(self, mask): return mask_to_names(mask, self._modifier_map) def send(self, packet): self._protocol.source.queue_ordinary_packet(packet) def send_positional(self, packet): self._protocol.source.queue_positional_packet(packet) def send_mouse_position(self, packet): self._protocol.source.queue_mouse_position_packet(packet) def _process_hello(self, packet): (_, capabilities) = packet if "deflate" in capabilities: self._protocol.enable_deflate(capabilities["deflate"]) if capabilities.get("__prerelease_version") != xpra.__version__: log.error("sorry, I only know how to talk to v%s servers", xpra.__version__) self._clipboard_helper.send_all_tokens() def _process_new_common(self, packet, override_redirect): (_, id, x, y, w, h, metadata) = packet window = ClientWindow(self, id, x, y, w, h, metadata, override_redirect) self._id_to_window[id] = window self._window_to_id[window] = id window.show_all() def _process_new_window(self, packet): self._process_new_common(packet, False) def _process_new_override_redirect(self, packet): self._process_new_common(packet, True) def _process_draw(self, packet): (_, id, x, y, width, height, coding, data) = packet window = self._id_to_window[id] assert coding == "rgb24" window.draw(x, y, width, height, data) def _process_window_metadata(self, packet): (_, id, metadata) = packet window = self._id_to_window[id] window.update_metadata(metadata) def _process_configure_override_redirect(self, packet): (_, id, x, y, w, h) = packet window = self._id_to_window[id] window.move_resize(x, y, w, h) def _process_lost_window(self, packet): (_, id) = packet window = self._id_to_window[id] del self._id_to_window[id] del self._window_to_id[window] window.destroy() def _process_connection_lost(self, packet): log.error("Connection lost") gtk_main_quit_really() _packet_handlers = { "hello": _process_hello, "new-window": _process_new_window, "new-override-redirect": _process_new_override_redirect, "draw": _process_draw, "window-metadata": _process_window_metadata, "configure-override-redirect": _process_configure_override_redirect, "lost-window": _process_lost_window, # "clipboard-*" packets are handled by a special case below. Protocol.CONNECTION_LOST: _process_connection_lost, } def process_packet(self, proto, packet): packet_type = packet[0] if (isinstance(packet_type, str) and packet_type.startswith("clipboard-")): self._clipboard_helper.process_clipboard_packet(packet) else: self._packet_handlers[packet_type](self, packet)
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = { "handshake-complete": n_arg_signal(0), "first-ui-received" : n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, opts): gobject.GObject.__init__(self) self.exit_code = None self.compression_level = opts.compression_level self.password = None self.password_file = opts.password_file self.encoding = opts.encoding self.quality = opts.quality self._protocol = None self.server_capabilities = {} self._remote_version = None self._remote_revision = None self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) self._protocol.set_compression_level(self.compression_level) ClientSource(self._protocol) self._protocol.start() def init_packet_handlers(self): self._packet_handlers = {} self._ui_packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "hello": self._process_hello, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send(["hello", hello]) def make_hello(self, challenge_response=None): capabilities = {} add_version_info(capabilities) if challenge_response: capabilities["challenge_response"] = challenge_response if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.quality>=0: capabilities["jpeg"] = self.quality capabilities["quality"] = self.quality capabilities["platform"] = sys.platform capabilities["client_type"] = "Python/Gobject" capabilities["raw_packets"] = True capabilities["chunked_compression"] = True capabilities["rencode"] = has_rencode capabilities["server-window-resize"] = True u = hashlib.sha512() u.update(str(get_machine_id())) if os.name=="posix": u.update("/") u.update(str(os.getuid())) u.update("/") u.update(str(os.getgid())) capabilities["uuid"] = u.hexdigest() capabilities["randr_notify"] = False #only client.py cares about this capabilities["windows"] = False #only client.py cares about this return capabilities def idle_send(self, packet): gobject.idle_add(self.send, packet) def send(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_ordinary_packet(packet) def send_now(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_priority_packet(packet) def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, exit_code=0): if self.exit_code is None: self.exit_code = exit_code raise Exception("override me!") def warn_and_quit(self, exit_code, warning): log.warn(warning) self.quit(exit_code) def _process_disconnect(self, packet): if len(packet)==2: info = packet[1] else: info = packet[1:] self.warn_and_quit(EXIT_OK, "server requested disconnect: %s" % info) def _process_connection_lost(self, packet): self.warn_and_quit(EXIT_CONNECTION_LOST, "Connection lost") def _process_challenge(self, packet): if not self.password_file and not self.password: self.warn_and_quit(EXIT_PASSWORD_REQUIRED, "password is required by the server") return if not self.password: self.load_password() log("password read from file %s is %s", self.password_file, self.password) if self.password: salt = packet[1] import hmac challenge_response = hmac.HMAC(self.password, salt) self.send_hello(challenge_response.hexdigest()) def load_password(self): try: passwordFile = open(self.password_file, "rU") self.password = passwordFile.read() passwordFile.close() while self.password.endswith("\n") or self.password.endswith("\r"): self.password = self.password[:-1] except IOError, e: self.warn_and_quit(EXIT_PASSWORD_FILE_ERROR, "failed to open password file %s: %s" % (self.password_file, e))
def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) self._protocol.set_compression_level(self.compression_level) ClientSource(self._protocol) self._protocol.start()
class XpraClient(gobject.GObject): __gsignals__ = { "handshake-complete": n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, conn, compression_level): gobject.GObject.__init__(self) self._window_to_id = {} self._id_to_window = {} self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) capabilities_request = dict(default_capabilities) if compression_level: capabilities_request["deflate"] = compression_level root_w, root_h = gtk.gdk.get_default_root_window().get_size() capabilities_request["desktop_size"] = [root_w, root_h] self.send(["hello", capabilities_request]) self._keymap = gtk.gdk.keymap_get_default() self._keymap.connect("keys-changed", self._keys_changed) self._keys_changed() self._xsettings_watcher = None self._root_props_watcher = None # FIXME: these should perhaps be merged. self._clipboard_helper = ClipboardProtocolHelper(self.send) self._client_extras = ClientExtras(self.send) self._focused = None def run(self): gtk_main_quit_on_fatal_exceptions_enable() gtk.main() def _keys_changed(self, *args): self._modifier_map = grok_modifier_map(gtk.gdk.display_get_default()) def update_focus(self, id, gotit): if gotit and self._focused is not id: self.send(["focus", id]) self._focused = id if not gotit and self._focused is id: self.send(["focus", 0]) self._focused = None def mask_to_names(self, mask): return mask_to_names(mask, self._modifier_map) def send(self, packet): self._protocol.source.queue_ordinary_packet(packet) def send_positional(self, packet): self._protocol.source.queue_positional_packet(packet) def send_mouse_position(self, packet): self._protocol.source.queue_mouse_position_packet(packet) def _process_hello(self, packet): (_, capabilities) = packet if "deflate" in capabilities: self._protocol.enable_deflate(capabilities["deflate"]) if capabilities.get("__prerelease_version") != xpra.__version__: log.error("sorry, I only know how to talk to v%s servers", xpra.__version__) gtk.main_quit() return if "desktop_size" in capabilities: avail_w, avail_h = capabilities["desktop_size"] root_w, root_h = gtk.gdk.get_default_root_window().get_size() if (avail_w, avail_h) < (root_w, root_h): log.warn("Server's virtual screen is too small -- " "(server: %sx%s vs. client: %sx%s)\n" "You may see strange behavior.\n" "Please complain to " "*****@*****.**" % (avail_w, avail_h, root_w, root_h)) self._clipboard_helper.send_all_tokens() self._client_extras.handshake_complete(capabilities) self.emit("handshake-complete") def _process_new_common(self, packet, override_redirect): (_, id, x, y, w, h, metadata) = packet window = ClientWindow(self, id, x, y, w, h, metadata, override_redirect) self._id_to_window[id] = window self._window_to_id[window] = id window.show_all() def _process_new_window(self, packet): self._process_new_common(packet, False) def _process_new_override_redirect(self, packet): self._process_new_common(packet, True) def _process_draw(self, packet): (_, id, x, y, width, height, coding, data) = packet window = self._id_to_window[id] assert coding == "rgb24" window.draw(x, y, width, height, data) def _process_window_metadata(self, packet): (_, id, metadata) = packet window = self._id_to_window[id] window.update_metadata(metadata) def _process_configure_override_redirect(self, packet): (_, id, x, y, w, h) = packet window = self._id_to_window[id] window.move_resize(x, y, w, h) def _process_lost_window(self, packet): (_, id) = packet window = self._id_to_window[id] del self._id_to_window[id] del self._window_to_id[window] window.destroy() def _process_connection_lost(self, packet): log.error("Connection lost") gtk_main_quit_really() def _process_gibberish(self, packet): [_, data] = packet self.emit("received-gibberish", data) _packet_handlers = { "hello": _process_hello, "new-window": _process_new_window, "new-override-redirect": _process_new_override_redirect, "draw": _process_draw, "window-metadata": _process_window_metadata, "configure-override-redirect": _process_configure_override_redirect, "lost-window": _process_lost_window, # "clipboard-*" packets are handled by a special case below. Protocol.CONNECTION_LOST: _process_connection_lost, Protocol.GIBBERISH: _process_gibberish, } def process_packet(self, proto, packet): packet_type = packet[0] if (isinstance(packet_type, str) and packet_type.startswith("clipboard-")): self._clipboard_helper.process_clipboard_packet(packet) else: self._packet_handlers[packet_type](self, packet)
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = { "handshake-complete": n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, opts): gobject.GObject.__init__(self) self.password_file = opts.password_file self.encoding = opts.encoding self.jpegquality = opts.jpegquality self._protocol = None self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) ClientSource(self._protocol) def init_packet_handlers(self): self._packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "hello": self._process_hello, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send(["hello", hello]) def make_hello(self, challenge_response=None): capabilities = {"version": xpra.__version__} if challenge_response: capabilities["challenge_response"] = challenge_response if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.jpegquality: capabilities["jpeg"] = self.jpegquality capabilities["packet_size"] = True #will be removed (only for compatibility with old versions): capabilities["dynamic_compression"] = True capabilities["__prerelease_version"] = xpra.__version__ return capabilities def send(self, packet): self._protocol.source.queue_ordinary_packet(packet) def send_now(self, packet): self._protocol.source.queue_priority_packet(packet) def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, *args): raise Exception("override me!") def _process_disconnect(self, packet): log.error("server requested disconnect: %s", packet[1:]) self.quit() return def _process_challenge(self, packet): if not self.password_file: log.error("password is required by the server") self.quit() return import hmac try: passwordFile = open(self.password_file, "rU") password = passwordFile.read() except IOError, e: log.error("failed to open password file %s: %s", self.password_file, e) self.quit() return salt = packet[1] challenge_response = hmac.HMAC(password, salt) self.send_hello(challenge_response.hexdigest())
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = { "handshake-complete": n_arg_signal(0), "first-ui-received": n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, opts): gobject.GObject.__init__(self) self.exit_code = None self.compression_level = opts.compression_level self.password = None self.password_file = opts.password_file self.encoding = opts.encoding self.quality = opts.quality self._protocol = None self.server_capabilities = {} self._remote_version = None self._remote_revision = None self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet) self._protocol.set_compression_level(self.compression_level) ClientSource(self._protocol) self._protocol.start() def init_packet_handlers(self): self._packet_handlers = {} self._ui_packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "hello": self._process_hello, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send(["hello", hello]) def make_hello(self, challenge_response=None): capabilities = {} add_version_info(capabilities) if challenge_response: capabilities["challenge_response"] = challenge_response if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.quality >= 0: capabilities["jpeg"] = self.quality capabilities["quality"] = self.quality capabilities["platform"] = sys.platform capabilities["client_type"] = "Python/Gobject" capabilities["raw_packets"] = True capabilities["chunked_compression"] = True capabilities["rencode"] = has_rencode capabilities["server-window-resize"] = True u = hashlib.sha512() u.update(str(get_machine_id())) if os.name == "posix": u.update("/") u.update(str(os.getuid())) u.update("/") u.update(str(os.getgid())) capabilities["uuid"] = u.hexdigest() capabilities["randr_notify"] = False #only client.py cares about this capabilities["windows"] = False #only client.py cares about this return capabilities def idle_send(self, packet): gobject.idle_add(self.send, packet) def send(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_ordinary_packet(packet) def send_now(self, packet): if self._protocol and self._protocol.source: self._protocol.source.queue_priority_packet(packet) def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, exit_code=0): if self.exit_code is None: self.exit_code = exit_code raise Exception("override me!") def warn_and_quit(self, exit_code, warning): log.warn(warning) self.quit(exit_code) def _process_disconnect(self, packet): if len(packet) == 2: info = packet[1] else: info = packet[1:] self.warn_and_quit(EXIT_OK, "server requested disconnect: %s" % info) def _process_connection_lost(self, packet): self.warn_and_quit(EXIT_CONNECTION_LOST, "Connection lost") def _process_challenge(self, packet): if not self.password_file and not self.password: self.warn_and_quit(EXIT_PASSWORD_REQUIRED, "password is required by the server") return if not self.password: self.load_password() log("password read from file %s is %s", self.password_file, self.password) if self.password: salt = packet[1] import hmac challenge_response = hmac.HMAC(self.password, salt) self.send_hello(challenge_response.hexdigest()) def load_password(self): try: passwordFile = open(self.password_file, "rU") self.password = passwordFile.read() passwordFile.close() while self.password.endswith("\n") or self.password.endswith("\r"): self.password = self.password[:-1] except IOError, e: self.warn_and_quit( EXIT_PASSWORD_FILE_ERROR, "failed to open password file %s: %s" % (self.password_file, e))
class XpraClientBase(gobject.GObject): """Base class for Xpra clients. Provides the glue code for: * sending packets via Protocol * handling packets received via _process_packet """ __gsignals__ = { "handshake-complete": n_arg_signal(0), "first-ui-received" : n_arg_signal(0), "received-gibberish": n_arg_signal(1), } def __init__(self, opts): gobject.GObject.__init__(self) self.exit_code = None self.compression_level = opts.compression_level self.password = None self.password_file = opts.password_file self.password_sent = False self.encoding = opts.encoding self.encryption = opts.encryption self.quality = opts.quality self.min_quality = opts.min_quality self.speed = opts.speed self.min_speed = opts.min_speed #protocol stuff: self._protocol = None self._priority_packets = [] self._ordinary_packets = [] self._mouse_position = None #server state and caps: self.server_capabilities = {} self._remote_version = None self._remote_revision = None self.make_uuid() self.init_packet_handlers() def ready(self, conn): log.debug("ready(%s)", conn) self._protocol = Protocol(conn, self.process_packet, self.next_packet) self._protocol.large_packets.append("keymap-changed") self._protocol.large_packets.append("server-settings") self._protocol.set_compression_level(self.compression_level) self._protocol.start() self.have_more = self._protocol.source_has_more def init_packet_handlers(self): self._packet_handlers = { "hello": self._process_hello, } self._ui_packet_handlers = { "challenge": self._process_challenge, "disconnect": self._process_disconnect, "set_deflate": self._process_set_deflate, Protocol.CONNECTION_LOST: self._process_connection_lost, Protocol.GIBBERISH: self._process_gibberish, } def send_hello(self, challenge_response=None): hello = self.make_hello(challenge_response) log.debug("send_hello(%s) packet=%s", challenge_response, hello) self.send("hello", hello) def make_hello(self, challenge_response=None): capabilities = {} add_version_info(capabilities) if challenge_response: assert self.password capabilities["challenge_response"] = challenge_response if self.encryption: assert self.encryption in ENCRYPTION_CIPHERS capabilities["cipher"] = self.encryption iv = uuid.uuid4().hex[:16] capabilities["cipher.iv"] = iv key_salt = uuid.uuid4().hex capabilities["cipher.key_salt"] = key_salt iterations = 1000 capabilities["cipher.key_stretch_iterations"] = iterations self._protocol.set_cipher_in(self.encryption, iv, self.get_password(), key_salt, iterations) if self.encoding: capabilities["encoding"] = self.encoding capabilities["encodings"] = ENCODINGS if self.quality>0: capabilities["jpeg"] = self.quality capabilities["quality"] = self.quality capabilities["encoding.quality"] = self.quality if self.min_quality>0: capabilities["encoding.min-quality"] = self.min_quality if self.speed>=0: capabilities["speed"] = self.speed capabilities["encoding.speed"] = self.speed if self.min_speed>=0: capabilities["encoding.min-speed"] = self.min_speed capabilities["platform"] = sys.platform capabilities["client_type"] = "Python/Gobject" capabilities["raw_packets"] = True capabilities["chunked_compression"] = True capabilities["rencode"] = has_rencode capabilities["server-window-resize"] = True capabilities["hostname"] = socket.gethostname() capabilities["uuid"] = self.uuid capabilities["randr_notify"] = False #only client.py cares about this capabilities["windows"] = False #only client.py cares about this return capabilities def make_uuid(self): try: import hashlib u = hashlib.sha1() except: #try python2.4 variant: import sha u = sha.new() def uupdate(ustr): u.update(ustr.encode("utf-8")) uupdate(get_machine_id()) if os.name=="posix": uupdate(u"/") uupdate(str(os.getuid())) uupdate(u"/") uupdate(str(os.getgid())) self.uuid = u.hexdigest() def send(self, *parts): self._ordinary_packets.append(parts) self.have_more() def send_now(self, *parts): self._priority_packets.append(parts) self.have_more() def send_positional(self, packet): self._ordinary_packets.append(packet) self._mouse_position = None self.have_more() def send_mouse_position(self, packet): self._mouse_position = packet self.have_more() def have_more(self): #this function is overridden in ready() p = self._protocol if p and p.source: p.source_has_more() def next_packet(self): if self._priority_packets: packet = self._priority_packets.pop(0) elif self._ordinary_packets: packet = self._ordinary_packets.pop(0) elif self._mouse_position is not None: packet = self._mouse_position self._mouse_position = None else: packet = None has_more = packet is not None and \ (bool(self._priority_packets) or bool(self._ordinary_packets) \ or self._mouse_position is not None) return packet, None, None, has_more def cleanup(self): if self._protocol: self._protocol.close() self._protocol = None def run(self): raise Exception("override me!") def quit(self, exit_code=0): if self.exit_code is None: self.exit_code = exit_code raise Exception("override me!") def warn_and_quit(self, exit_code, warning): log.warn(warning) self.quit(exit_code) def _process_disconnect(self, packet): if len(packet)==2: info = packet[1] else: info = packet[1:] self.warn_and_quit(EXIT_OK, "server requested disconnect: %s" % info) def _process_connection_lost(self, packet): self.warn_and_quit(EXIT_CONNECTION_LOST, "Connection lost") def _process_challenge(self, packet): if not self.password_file and not self.password: self.warn_and_quit(EXIT_PASSWORD_REQUIRED, "password is required by the server") return if not self.password: self.load_password() assert self.password salt = packet[1] if self.encryption: assert len(packet)>=3, "challenge does not contain encryption details to use for the response" server_cipher = packet[2] self.set_server_encryption(server_cipher) import hmac challenge_response = hmac.HMAC(self.password, salt) password_hash = challenge_response.hexdigest() self.password_sent = True self.send_hello(password_hash) def set_server_encryption(self, props): cipher = props.get("cipher") cipher_iv = props.get("cipher.iv") key_salt = props.get("cipher.key_salt") iterations = props.get("cipher.key_stretch_iterations") if not cipher or not cipher_iv: self.warn_and_quit(EXIT_ENCRYPTION, "the server does not use or support encryption/password, cannot continue with %s cipher" % self.encryption) return False if cipher not in ENCRYPTION_CIPHERS: self.warn_and_quit(EXIT_ENCRYPTION, "unsupported server cipher: %s, allowed ciphers: %s" % (cipher, ", ".join(ENCRYPTION_CIPHERS))) return False self._protocol.set_cipher_out(cipher, cipher_iv, self.get_password(), key_salt, iterations) def get_password(self): if self.password is None: self.load_password() return self.password def load_password(self): try: passwordFile = open(self.password_file, "rU") self.password = passwordFile.read() passwordFile.close() while self.password.endswith("\n") or self.password.endswith("\r"): self.password = self.password[:-1] except IOError, e: self.warn_and_quit(EXIT_PASSWORD_FILE_ERROR, "failed to open password file %s: %s" % (self.password_file, e)) log("password read from file %s is %s", self.password_file, self.password)