Beispiel #1
0
    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
Beispiel #2
0
 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
Beispiel #3
0
    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
Beispiel #4
0
 def ready(self, conn):
     log.debug("ready(%s)", conn)
     self._protocol = Protocol(conn, self.process_packet)
     ClientSource(self._protocol)
Beispiel #5
0
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)
Beispiel #6
0
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())
Beispiel #7
0
 def ready(self, conn):
     log.debug("ready(%s)", conn)
     self._protocol = Protocol(conn, self.process_packet)
     ClientSource(self._protocol)
     self._protocol.start()
Beispiel #8
0
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())
Beispiel #9
0
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)
Beispiel #10
0
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))
Beispiel #11
0
 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()
Beispiel #12
0
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)
Beispiel #13
0
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())
Beispiel #14
0
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))
Beispiel #15
0
 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()
Beispiel #16
0
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)