示例#1
0
def main():
    import time
    import sys
    assert len(sys.argv)==2, "usage: %s :DISPLAY" % sys.argv[0]
    display = sys.argv[1]

    from xpra.scripts.config import make_defaults_struct
    opts = make_defaults_struct()
    from xpra.platform.dotxpra import DotXpra
    target = DotXpra().socket_path(display)
    print("will attempt to connect to socket: %s" % target)

    import socket
    sock = socket.socket(socket.AF_UNIX)
    sock.connect(target)

    from xpra.net.bytestreams import SocketConnection
    conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "scroll-test")
    print("socket connection=%s" % conn)

    app = ServerMessenger(conn, opts)
    window = ScrolledWindowExample()

    vscroll_events = deque(maxlen=1000)
    hscroll_events = deque(maxlen=1000)
    def vscroll(scrollbar, scrolltype, value):
        #print("vscroll(%s) n=%s" % ((scrollbar, scrolltype, value), len(vscroll_events)))
        now = time.time()
        needs_reset = False
        if len(vscroll_events)>0:
            #get the previous event
            t, _ = vscroll_events[-1]
            #print("last vscroll event was %sms ago" % (now-t))
            if now-t<1:
                #last event was less than a second ago
                print("lowering quality to jpeg @ 1%!")
                app.send("command_request", "encoding", "jpeg", "strict")
                app.send("command_request", "quality", 1, "*")
                app.send("command_request", "speed", 100, "*")
                needs_reset = True
        vscroll_events.append((now, value))
        if needs_reset:
            def may_reset_quality(*args):
                #if no new events since, reset quality:
                t, _ = vscroll_events[-1]
                if now==t:
                    print("resetting quality to h264")
                    app.send("command_request", "encoding", "h264", "nostrict")
                    app.send("command_request", "quality", -1, "*")     #means auto
                    app.send("command_request", "speed", -1, "*")       #means auto
            gobject.timeout_add(1000, may_reset_quality)
    def hscroll(scrollbar, scrolltype, value):
        print("hscroll(%s)" % (scrollbar, scrolltype, value))
        hscroll_events.append((time.time(), value))
    window.vscroll.connect("change-value", vscroll)
    window.hscroll.connect("change-value", hscroll)
    try:
        app.run()
    finally:
        app.cleanup()
示例#2
0
def main():
    target = sys.argv[1]
    opts = make_defaults_struct()
    MAX_CLIENTS = 10
    clients = []

    def start_try():
        sock = socket.socket(socket.AF_UNIX)
        sock.connect(target)
        conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(),
                                target, "trylogin")

        def stop_cb(client):
            try:
                clients.remove(client)
            except:
                pass
            if len(clients) < MAX_CLIENTS:
                start_try()

        def cracked_cb(password):
            sys.exit(0)

        tl = TryLogin(conn, opts, gen_password(), stop_cb, cracked_cb)
        clients.append(tl)
        tl.run()

    for _ in range(MAX_CLIENTS):
        glib.idle_add(start_try)
    glib_mainloop = glib.MainLoop()
    glib_mainloop.run()
示例#3
0
def main():
    from xpra.os_util import set_application_name, set_prgname
    set_prgname("OSX Shadow Test")
    set_application_name("OSX Shadow Test")

    defaults = make_defaults_struct()
    for x in ("daemon", "clipboard", "mmap", "speaker", "microphone",
              "cursors", "bell", "notifications", "system_tray", "sharing",
              "delay_tray", "opengl"):
        setattr(defaults, x, False)

    loop_exit = gtk.main_quit
    loop_run = gtk.main

    XPRA_DISPLAY = ":10"
    sp = "~/.xpra/%s-%s" % (socket.gethostname(), XPRA_DISPLAY[1:])
    sockpath = os.path.expanduser(sp)

    listener = socket.socket(socket.AF_UNIX)
    listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listener.setblocking(1)
    listener.bind(sockpath)
    sockets = [listener]

    ss = ShadowServer()
    ss.init(sockets, defaults)
    ss.run()

    gobject.timeout_add(1000 * 120, loop_exit)
    loop_run()
示例#4
0
def main():
    from xpra.os_util import set_application_name, set_prgname
    set_prgname("OSX Shadow Test")
    set_application_name("OSX Shadow Test")

    defaults = make_defaults_struct()
    for x in ("daemon", "clipboard", "mmap", "speaker", "microphone",
              "cursors", "bell", "notifications",
              "system_tray", "sharing",
              "delay_tray", "opengl"):
        setattr(defaults, x, False)

    loop_exit = gtk.main_quit
    loop_run = gtk.main


    XPRA_DISPLAY = ":10"
    sp = "~/.xpra/%s-%s" % (socket.gethostname(), XPRA_DISPLAY[1:])
    sockpath = os.path.expanduser(sp)

    listener = socket.socket(socket.AF_UNIX)
    listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listener.setblocking(1)
    listener.bind(sockpath)
    sockets = [listener]

    ss = ShadowServer()
    ss.init(sockets, defaults)
    ss.run()

    gobject.timeout_add(1000*120, loop_exit)
    loop_run()
示例#5
0
def test_DoS(client_class_constructor, args):
    """ utility method for running DoS tests
        See: test_DoS_*_client.py
    """

    assert len(args)==2, "usage: test_DoS_client :DISPLAY"
    log.enable_debug()
    opts = make_defaults_struct()
    opts.password_file = ""
    opts.encoding = "rgb24"
    opts.jpegquality = 70
    opts.quality = 70
    opts.compression_level = 1
    opts.encryption = ""
    display = sys.argv[1]
    target = DotXpra().socket_path(display)
    print("will attempt to connect to socket: %s" % target)
    sock = socket.socket(socket.AF_UNIX)
    sock.connect(target)
    conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "test_DoS")
    print("socket connection=%s" % conn)
    app = client_class_constructor(conn, opts)
    try:
        app.run()
    finally:
        app.cleanup()
    print("ended")
    print("")
    def __init__(self):
        dotxpra = DotXpra()
        display = os.environ.get("DISPLAY")
        from xpra.scripts.config import make_defaults_struct
        opts = make_defaults_struct()
        target = dotxpra.socket_path(display)
        log.info("attempting to connect to socket: %s", target)
        sock = socket.socket(socket.AF_UNIX)
        sock.connect(target)
        conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(),
                                target, "scroll-test")
        log.info("successfully created our socket connection: %s", conn)
        self.server = ServerMessenger(conn, opts)

        self.vscroll_events = deque(maxlen=1000)
        self.hscroll_events = deque(maxlen=1000)

        browser = WebBrowser()
        #hook some events:
        browser.content_tabs.connect("focus-view-title-changed",
                                     self.title_changed)
        vscroll_listeners.append(self.vscroll)
        hscroll_listeners.append(self.hscroll)
        #the things we tune:
        self.quality = -1
        self.speed = -1
        self.encoding = None
        self.strict = False
示例#7
0
def main():
    target = sys.argv[1]
    opts = make_defaults_struct()
    MAX_CLIENTS = 10
    clients = []
    def start_try():
        sock = socket.socket(socket.AF_UNIX)
        sock.connect(target)
        conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "trylogin")
        def stop_cb(client):
            try:
                clients.remove(client)
            except:
                pass
            if len(clients)<MAX_CLIENTS:
                start_try()
        def cracked_cb(password):
            sys.exit(0)
        tl = TryLogin(conn, opts, gen_password(), stop_cb, cracked_cb)
        clients.append(tl)
        tl.run()
    for _ in range(MAX_CLIENTS):
        glib.idle_add(start_try)
    glib_mainloop = glib.MainLoop()
    glib_mainloop.run()
示例#8
0
 def start_new_session(self, username, uid, gid, new_session_dict={}, displays=()):
     log("start_new_session%s", (username, uid, gid, new_session_dict, displays))
     sns = typedict(new_session_dict)
     if WIN32:
         return self.start_win32_shadow(username, new_session_dict)
     mode = sns.get("mode", "start")
     assert mode in ("start", "start-desktop", "shadow"), "invalid start-new-session mode '%s'" % mode
     display = sns.get("display")
     if display in displays:
         raise Exception("display %s is already active!" % display)
     log("starting new server subprocess: mode=%s, display=%s", mode, display)
     args = []
     if display:
         args = [display]
     #allow the client to override some options:
     opts = make_defaults_struct(username=username, uid=uid, gid=gid)
     for k,v in sns.items():
         k = bytestostr(k)
         if k in ("mode", "display"):
             continue    #those special attributes have been consumed already
         if k not in PROXY_START_OVERRIDABLE_OPTIONS:
             log.warn("Warning: ignoring invalid start override")
             log.warn(" %s=%s", k, v)
             continue
         try:
             vt = OPTION_TYPES[k]
             if vt==str:
                 v = bytestostr(v)
             elif vt==bool:
                 v = parse_bool(k, v)
             elif vt==int:
                 v = int(v)
             elif vt==list:
                 v = list(bytestostr(x) for x in v)
         except ValueError:
             log("start_new_session: override option %s", k, exc_info=True)
             log.warn("Warning: ignoring invalid value %s for %s (%s)", v, k, vt)
             continue
         log("start override: %s=%s", k, v)
         if v is not None:
             fn = k.replace("-", "_")
             setattr(opts, fn, v)
     opts.attach = False
     opts.start_via_proxy = False
     env = self.get_proxy_env()
     cwd = None
     if uid>0:
         cwd = get_home_for_uid(uid) or None
         if not cwd or not os.path.exists(cwd):
             import tempfile
             cwd = tempfile.gettempdir()
     log("starting new server subprocess: options=%s", opts)
     log("env=%s", env)
     log("args=%s", args)
     log("cwd=%s", cwd)
     proc, socket_path, display = start_server_subprocess(sys.argv[0], args, mode, opts, username, uid, gid, env, cwd)
     if proc:
         self.child_reaper.add_process(proc, "server-%s" % (display or socket_path), "xpra %s" % mode, True, True)
     log("start_new_session(..) pid=%s, socket_path=%s, display=%s, ", proc.pid, socket_path, display)
     return proc, socket_path, display
示例#9
0
    def init_ui(self, opts):
        """ initialize user interface """
        if not self.readonly:

            def noauto(v):
                if not v:
                    return None
                if str(v).lower() == "auto":
                    return None
                return v

            overrides = [
                noauto(getattr(opts, "keyboard_%s" % x)) for x in (
                    "layout",
                    "layouts",
                    "variant",
                    "variants",
                    "options",
                )
            ]

            def send_keyboard(*parts):
                self.after_handshake(self.send, *parts)

            try:
                self.keyboard_helper = self.keyboard_helper_class(
                    send_keyboard, opts.keyboard_sync, opts.shortcut_modifiers,
                    opts.key_shortcut, opts.keyboard_raw, *overrides)
            except ImportError as e:
                keylog("error instantiating %s",
                       self.keyboard_helper_class,
                       exc_info=True)
                keylog.warn("Warning: no keyboard support, %s", e)

        if mixin_features.windows:
            self.init_opengl(opts.opengl)

        if ClientExtras is not None:
            self.client_extras = ClientExtras(self, opts)  #pylint: disable=not-callable

        if opts.start or opts.start_child:
            from xpra.scripts.main import strip_defaults_start_child
            from xpra.scripts.config import make_defaults_struct
            defaults = make_defaults_struct()
            self.start_new_commands = strip_defaults_start_child(
                opts.start, defaults.start)  #pylint: disable=no-member
            self.start_child_new_commands = strip_defaults_start_child(
                opts.start_child, defaults.start_child)  #pylint: disable=no-member

        if MOUSE_DELAY_AUTO:
            try:
                v = self.get_vrefresh()
                if v <= 0:
                    #some platforms don't detect the vrefresh correctly
                    #(ie: macos in virtualbox?), so use a sane default:
                    v = 60
                self._mouse_position_delay = 1000 // v // 2
                log("mouse delay: %s", self._mouse_position_delay)
            except Exception:
                log("failed to calculate automatic delay", exc_info=True)
示例#10
0
    def __init__(self):
        dotxpra = DotXpra()
        display = os.environ.get("DISPLAY")
        from xpra.scripts.config import make_defaults_struct
        opts = make_defaults_struct()
        target = dotxpra.socket_path(display)
        log.info("attempting to connect to socket: %s", target)
        sock = socket.socket(socket.AF_UNIX)
        sock.connect(target)
        conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "scroll-test")
        log.info("successfully created our socket connection: %s", conn)
        self.server = ServerMessenger(conn, opts)

        self.vscroll_events = maxdeque(1000)
        self.hscroll_events = maxdeque(1000)

        browser = WebBrowser()
        #hook some events:
        browser.content_tabs.connect("focus-view-title-changed", self.title_changed)
        vscroll_listeners.append(self.vscroll)
        hscroll_listeners.append(self.hscroll)
        #the things we tune:
        self.quality = -1
        self.speed = -1
        self.encoding = None
        self.strict = False
示例#11
0
    def __init__(self):
        # Default connection options
        self.config = make_defaults_struct()
        self.config.ssh_port = "22"
        # what we save by default:
        self.config_keys = set(
            [
                "username",
                "password",
                "host",
                "port",
                "mode",
                "ssh_port",
                "encoding",
                "quality",
                "min-quality",
                "speed",
                "min-speed",
            ]
        )
        if is_gtk3():
            self.config.client_toolkit = "gtk3"
        else:
            self.config.client_toolkit = "gtk2"

        def raise_exception(*args):
            raise Exception(*args)

        self.client = make_client(raise_exception, self.config)
        self.client.init(self.config)
        self.exit_code = None
示例#12
0
def test_DoS(client_class_constructor, args):
    """ utility method for running DoS tests
        See: test_DoS_*_client.py
    """

    assert len(args) == 2, "usage: test_DoS_client :DISPLAY"
    log.enable_debug()
    opts = make_defaults_struct()
    opts.password_file = ""
    opts.encoding = "rgb24"
    opts.jpegquality = 70
    opts.quality = 70
    opts.compression_level = 1
    opts.encryption = ""
    display = sys.argv[1]
    target = DotXpra().socket_path(display)
    print("will attempt to connect to socket: %s" % target)
    sock = socket.socket(socket.AF_UNIX)
    sock.connect(target)
    conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(),
                            target, "test_DoS")
    print("socket connection=%s" % conn)
    app = client_class_constructor(conn, opts)
    try:
        app.run()
    finally:
        app.cleanup()
    print("ended")
    print("")
示例#13
0
def main():
    import time
    import sys
    assert len(sys.argv)==2, "usage: %s :DISPLAY" % sys.argv[0]
    display = sys.argv[1]

    from xpra.scripts.config import make_defaults_struct
    opts = make_defaults_struct()
    from xpra.dotxpra import DotXpra
    target = DotXpra().socket_path(display)
    print("will attempt to connect to socket: %s" % target)

    import socket
    sock = socket.socket(socket.AF_UNIX)
    sock.connect(target)

    from xpra.net.bytestreams import SocketConnection
    conn = SocketConnection(sock, sock.getsockname(), sock.getpeername(), target, "scroll-test")
    print("socket connection=%s" % conn)

    app = ServerMessenger(conn, opts)
    window = ScrolledWindowExample()

    vscroll_events = deque(maxlen=1000)
    hscroll_events = deque(maxlen=1000)
    def vscroll(scrollbar, scrolltype, value):
        #print("vscroll(%s) n=%s" % ((scrollbar, scrolltype, value), len(vscroll_events)))
        now = time.time()
        needs_reset = False
        if len(vscroll_events)>0:
            #get the previous event
            t, _ = vscroll_events[-1]
            #print("last vscroll event was %sms ago" % (now-t))
            if now-t<1:
                #last event was less than a second ago
                print("lowering quality to jpeg @ 1%!")
                app.send("command_request", "encoding", "jpeg", "strict")
                app.send("command_request", "quality", 1, "*")
                app.send("command_request", "speed", 100, "*")
                needs_reset = True
        vscroll_events.append((now, value))
        if needs_reset:
            def may_reset_quality(*args):
                #if no new events since, reset quality:
                t, _ = vscroll_events[-1]
                if now==t:
                    print("resetting quality to h264")
                    app.send("command_request", "encoding", "h264", "nostrict")
                    app.send("command_request", "quality", -1, "*")     #means auto
                    app.send("command_request", "speed", -1, "*")       #means auto
            gobject.timeout_add(1000, may_reset_quality)
    def hscroll(scrollbar, scrolltype, value):
        print("hscroll(%s)" % (scrollbar, scrolltype, value))
        hscroll_events.append((time.time(), value))
    window.vscroll.connect("change-value", vscroll)
    window.hscroll.connect("change-value", hscroll)
    try:
        app.run()
    finally:
        app.cleanup()
示例#14
0
 def    __init__(self):
     # Default connection options
     self.config = make_defaults_struct()
     #what we save by default:
     self.config_keys = set(["username", "password", "host", "port", "mode",
                             "encoding", "quality", "min-quality", "speed", "min-speed"])
     self.config.client_toolkit = "gtk2"
     self.client = make_client(Exception, self.config)
     self.exit_code = None
示例#15
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None

        #find the target server session:
        def disconnect(msg):
            self.send_disconnect(client_proto, msg)

        sessions = client_proto.authenticator.get_sessions()
        if sessions is None:
            disconnect("no sessions found")
            return
        debug("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
              auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #debug("unused options: %s, %s", env_options, session_options)
        if len(displays) == 0:
            disconnect("no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ["DISPLAY"]
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display == proxy_virtual_display:
            disconnect("invalid display")
            return
        if display:
            if display not in displays:
                disconnect("display not found")
                return
        else:
            if len(displays) != 1:
                disconnect(
                    "please specify a display (more than one available)")
                return
            display = displays[0]

        debug("start_proxy(%s, {..}, %s) using server display at: %s",
              client_proto, auth_caps, display)

        def parse_error(*args):
            disconnect("invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))

        opts = make_defaults_struct()
        opts.username = c.strget("username")
        disp_desc = parse_display_name(parse_error, opts, display)
        debug("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception, e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e)
            disconnect("failed to connect to display")
            return
示例#16
0
 def __init__(self):
     # Default connection options
     self.config = make_defaults_struct()
     #what we save by default:
     self.config_keys = set([
         "username", "password", "host", "port", "mode", "encoding",
         "quality", "min-quality", "speed", "min-speed"
     ])
     self.config.client_toolkit = "gtk2"
     self.client = make_client(Exception, self.config)
     self.exit_code = None
示例#17
0
 def start_new_session(self,
                       username,
                       uid,
                       gid,
                       new_session_dict={},
                       displays=()):
     log("start_new_session%s",
         (username, uid, gid, new_session_dict, displays))
     sns = typedict(new_session_dict)
     if WIN32:
         return self.start_win32_shadow(username, new_session_dict)
     mode = sns.get("mode", "start")
     assert mode in ("start", "start-desktop",
                     "shadow"), "invalid start-new-session mode '%s'" % mode
     display = sns.get("display")
     if display in displays:
         raise Exception("display %s is already active!" % display)
     log("starting new server subprocess: mode=%s, display=%s", mode,
         display)
     args = []
     if display:
         args = [display]
     #allow the client to override some options:
     opts = make_defaults_struct()
     for k, v in sns.items():
         if k in ("mode", "display"):
             continue  #those special attributes have been consumed already
         if k not in PROXY_START_OVERRIDABLE_OPTIONS:
             log.warn("Warning: ignoring invalid start override")
             log.warn(" %s=%s", k, v)
             continue
         log("start override: %s=%s", k, v)
         if v is not None:
             fn = k.replace("-", "_")
             setattr(opts, fn, v)
     opts.attach = False
     opts.start_via_proxy = False
     env = self.get_proxy_env()
     cwd = None
     if uid > 0:
         cwd = get_home_for_uid(uid) or None
     log("starting new server subprocess: options=%s", opts)
     log("env=%s", env)
     log("args=%s", args)
     log("cwd=%s", cwd)
     proc, socket_path, display = start_server_subprocess(
         sys.argv[0], args, mode, opts, uid, gid, env, cwd)
     if proc:
         self.child_reaper.add_process(
             proc, "server-%s" % (display or socket_path), "xpra %s" % mode,
             True, True)
     log("start_new_session(..)=%s, %s", display, proc)
     return proc, socket_path, display
示例#18
0
 def    __init__(self):
     # Default connection options
     self.config = make_defaults_struct(extras_defaults=LAUNCHER_DEFAULTS, extras_types=LAUNCHER_OPTION_TYPES, extras_validation=self.get_launcher_validation())
     #TODO: the fixup does not belong here?
     from xpra.scripts.main import fixup_options
     fixup_options(self.config)
     #what we save by default:
     self.config_keys = set(SAVED_FIELDS)
     def raise_exception(*args):
         raise Exception(*args)
     self.client = make_client(raise_exception, self.config)
     self.client.init(self.config)
     self.exit_code = None
示例#19
0
 def    __init__(self):
     # Default connection options
     self.config = make_defaults_struct(extras_defaults=LAUNCHER_DEFAULTS, extras_types=LAUNCHER_OPTION_TYPES, extras_validation=LAUNCHER_VALIDATION)
     #TODO: the fixup does not belong here?
     from xpra.scripts.main import fixup_options
     fixup_options(self.config)
     #what we save by default:
     self.config_keys = set(SAVED_FIELDS)
     def raise_exception(*args):
         raise Exception(*args)
     self.client = make_client(raise_exception, self.config)
     self.client.init(self.config)
     self.exit_code = None
示例#20
0
 def __init__(self):
     # Default connection options
     self.config = make_defaults_struct(extras_defaults=LAUNCHER_DEFAULTS, extras_types=LAUNCHER_OPTION_TYPES, extras_validation=self.get_launcher_validation())
     self.parse_ssh()
     #TODO: the fixup does not belong here?
     from xpra.scripts.main import fixup_options
     fixup_options(self.config)
     #what we save by default:
     self.config_keys = set(SAVED_FIELDS)
     self.client = None
     self.exit_launcher = False
     self.exit_code = None
     self.current_error = None
示例#21
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None
        #find the target server session:
        def disconnect(msg):
            self.send_disconnect(client_proto, msg)
        sessions = client_proto.authenticator.get_sessions()
        if sessions is None:
            disconnect("no sessions found")
            return
        debug("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #debug("unused options: %s, %s", env_options, session_options)
        if len(displays)==0:
            disconnect("no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ["DISPLAY"]
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display==proxy_virtual_display:
            disconnect("invalid display")
            return
        if display:
            if display not in displays:
                disconnect("display not found")
                return
        else:
            if len(displays)!=1:
                disconnect("please specify a display (more than one available)")
                return
            display = displays[0]

        debug("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            disconnect("invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct()
        opts.username = c.strget("username")
        disp_desc = parse_display_name(parse_error, opts, display)
        debug("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception, e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e)
            disconnect("failed to connect to display")
            return
示例#22
0
 def    __init__(self):
     # Default connection options
     self.config = make_defaults_struct(extras_defaults=LAUNCHER_DEFAULTS, extras_types=LAUNCHER_OPTION_TYPES, extras_validation=LAUNCHER_VALIDATION)
     #TODO: the fixup does not belong here?
     from xpra.scripts.main import fixup_video_all_or_none, fixup_encodings, fixup_compression, fixup_packetencoding
     fixup_video_all_or_none(self.config)
     fixup_encodings(self.config)
     fixup_compression(self.config)
     fixup_packetencoding(self.config)
     #what we save by default:
     self.config_keys = set(SAVED_FIELDS)
     def raise_exception(*args):
         raise Exception(*args)
     self.client = make_client(raise_exception, self.config)
     self.client.init(self.config)
     self.exit_code = None
示例#23
0
    def __init__(self):
        # Default connection options
        self.config = make_defaults_struct()
        self.config.ssh_port = "22"
        #what we save by default:
        self.config_keys = set([
            "username", "password", "host", "port", "mode", "ssh_port",
            "encoding", "quality", "min-quality", "speed", "min-speed"
        ])
        if is_gtk3():
            self.config.client_toolkit = "gtk3"
        else:
            self.config.client_toolkit = "gtk2"

        def raise_exception(*args):
            raise Exception(*args)

        self.client = make_client(raise_exception, self.config)
        self.client.init(self.config)
        self.exit_code = None
示例#24
0
 def    __init__(self):
     # Default connection options
     self.config = make_defaults_struct(extras_defaults=LAUNCHER_DEFAULTS, extras_types=LAUNCHER_OPTION_TYPES, extras_validation=LAUNCHER_VALIDATION)
     #TODO: the fixup does not belong here?
     from xpra.scripts.main import fixup_video_all_or_none, fixup_encodings, fixup_compression, fixup_packetencoding
     fixup_video_all_or_none(self.config)
     fixup_encodings(self.config)
     fixup_compression(self.config)
     fixup_packetencoding(self.config)
     #what we save by default:
     self.config_keys = set(SAVED_FIELDS)
     if is_gtk3():
         self.config.client_toolkit = "gtk3"
     else:
         self.config.client_toolkit = "gtk2"
     def raise_exception(*args):
         raise Exception(*args)
     self.client = make_client(raise_exception, self.config)
     self.client.init(self.config)
     self.exit_code = None
示例#25
0
def main():
    from xpra.scripts.config import make_defaults_struct
    opts = make_defaults_struct()
    return do_main(opts)
示例#26
0
    def proxy_session(self, client_proto, c, auth_caps, sessions):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)
        uid, gid, displays, env_options, session_options = sessions
        if POSIX:
            if getuid()==0:
                if uid==0 or gid==0:
                    log.error("Error: proxy instances cannot run as root")
                    log.error(" use a different uid and gid (ie: nobody)")
                    disconnect(AUTHENTICATION_ERROR, "cannot run proxy instances as root")
                    return
            else:
                uid = getuid()
                gid = getgid()
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            log("username(%i)=%s, groups=%s", uid, username, groups)
        else:
            #the auth module recorded the username we authenticate against
            assert client_proto.authenticators
            for authenticator in client_proto.authenticators:
                username = getattr(authenticator, "username", "")
                if username:
                    break
        #ensure we don't loop back to the proxy:
        proxy_virtual_display = os.environ.get("DISPLAY")
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        #remove proxy instance virtual displays:
        displays = [x for x in displays if not x.startswith(":proxy-")]
        #log("unused options: %s, %s", env_options, session_options)
        proc = None
        socket_path = None
        display = None
        sns = c.dictget("start-new-session")
        authlog("proxy_session: displays=%s, start_sessions=%s, start-new-session=%s", displays, self._start_sessions, sns)
        if len(displays)==0 or sns:
            if not self._start_sessions:
                disconnect(SESSION_NOT_FOUND, "no displays found")
                return
            try:
                proc, socket_path, display = self.start_new_session(username, uid, gid, sns, displays)
                log("start_new_session%s=%s", (username, uid, gid, sns, displays), (proc, socket_path, display))
            except Exception as e:
                log("start_server_subprocess failed", exc_info=True)
                log.error("Error: failed to start server subprocess:")
                log.error(" %s", e)
                disconnect(SERVER_ERROR, "failed to start a new session")
                return
        if display is None:
            display = c.strget("display")
            authlog("proxy_session: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s", proxy_virtual_display, display, displays)
            if display==proxy_virtual_display:
                disconnect(SESSION_NOT_FOUND, "invalid display")
                return
            if display:
                if display not in displays:
                    disconnect(SESSION_NOT_FOUND, "display '%s' not found" % display)
                    return
            else:
                if len(displays)!=1:
                    disconnect(SESSION_NOT_FOUND, "please specify a display, more than one is available: %s" % csv(displays))
                    return
                display = displays[0]

        connect = c.boolget("connect", True)
        #ConnectTestXpraClient doesn't want to connect to the real session either:
        ctr = c.strget("connect_test_request")
        log("connect=%s, connect_test_request=%s", connect, ctr)
        if not connect or ctr:
            log("proxy_session: not connecting to the session")
            hello = {"display" : display}
            if socket_path:
                hello["socket-path"] = socket_path
            #echo mode if present:
            mode = sns.get("mode")
            if mode:
                hello["mode"] = mode
            client_proto.send_now(("hello", hello))
            return

        def stop_server_subprocess():
            log("stop_server_subprocess() proc=%s", proc)
            if proc and proc.poll() is None:
                proc.terminate()

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            stop_server_subprocess()
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct(username=username, uid=uid, gid=gid)
        opts.username = username
        disp_desc = parse_display_name(parse_error, opts, display)
        if uid or gid:
            disp_desc["uid"] = uid
            disp_desc["gid"] = gid
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            for x in str(e).splitlines():
                log.error(" %s", x)
            log.error(" connection definition:")
            print_nested_dict(disp_desc, prefix=" ", lchar="*", pad=20, print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            stop_server_subprocess()
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn("Warning: received an unexpected packet on the proxy connection %s:", client_proto)
                log.warn(" %s", repr_ellipsized(packet))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticators, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout)
                if not ioe:
                    log.error("Error: some network IO threads have failed to terminate")
                    return
                client_conn.set_active(True)
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, disp_desc, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display, "xpra-proxy-instance", True, True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
示例#27
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None
        #find the target server session:
        def disconnect(reason, *extras):
            self.send_disconnect(client_proto, reason, *extras)
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            log.error("failed to get the list of sessions: %s", e)
            disconnect(AUTHENTICATION_ERROR)
            return
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        log("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays)==0:
            disconnect(SESSION_NOT_FOUND, "no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display==proxy_virtual_display:
            disconnect(SESSION_NOT_FOUND, "invalid display")
            return
        if display:
            if display not in displays:
                disconnect(SESSION_NOT_FOUND, "display not found")
                return
        else:
            if len(displays)!=1:
                disconnect(SESSION_NOT_FOUND, "please specify a display (more than one available)")
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception as e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e, exc_info=True)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn("received an unexpected packet on the proxy connection: %s", repr_ellipsized(packet))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout)
                if not ioe:
                    log.error("some network IO threads have failed to terminate!")
                    return
                client_conn.set_active(True)
                assert uid!=0 and gid!=0
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
            #FIXME: remove processes that have terminated
        make_thread(do_start_proxy, "start_proxy(%s)" % client_conn).start()
示例#28
0
class ProxyServer(ServerCore):
    """
        This is the proxy server you can launch with "xpra proxy",
        once authenticated, it will dispatch the connection
        to the session found using the authenticator's
        get_sessions() function.
    """
    def __init__(self):
        log("ProxyServer.__init__()")
        ServerCore.__init__(self)
        self._max_connections = MAX_CONCURRENT_CONNECTIONS
        self.main_loop = None
        #keep track of the proxy process instances
        #the display they're on and the message queue we can
        # use to communicate with them
        self.processes = {}
        self.idle_add = gobject.idle_add
        self.timeout_add = gobject.timeout_add
        self.source_remove = gobject.source_remove
        self._socket_timeout = PROXY_SOCKET_TIMEOUT
        self._socket_dir = None
        self.control_commands = ["hello", "stop"]
        #ensure we cache the platform info before intercepting SIGCHLD
        #as this will cause a fork and SIGCHLD to be emitted:
        from xpra.version_util import get_platform_info
        get_platform_info()
        signal.signal(signal.SIGCHLD, self.sigchld)

    def init(self, opts):
        log("ProxyServer.init(%s)", opts)
        if not opts.auth:
            raise Exception(
                "The proxy server requires an authentication mode (use 'none' to disable authentication)"
            )
        self._socket_dir = opts.socket_dir
        self.video_encoders = opts.video_encoders
        self.csc_modules = opts.csc_modules
        ServerCore.init(self, opts)

    def get_server_mode(self):
        return "proxy"

    def init_aliases(self):
        pass

    def do_run(self):
        self.main_loop = gobject.MainLoop()
        self.main_loop.run()

    def do_handle_command_request(self, proto, command, args):
        if command in ("help", "hello"):
            return ServerCore.do_handle_command_request(
                self, proto, command, args)
        assert command == "stop"
        if len(args) != 1:
            return ServerCore.control_command_response(
                self, proto, command, 4,
                "invalid number of arguments, usage: 'xpra control stop DISPLAY'"
            )
        display = args[0]
        log("stop command: will try to find proxy process for display %s",
            display)
        for process, v in list(self.processes.items()):
            disp, mq = v
            if disp == display:
                pid = process.pid
                log.info(
                    "stop command: found process %s with pid %s for display %s, sending it 'stop' request",
                    process, pid, display)
                mq.put("stop")
                return self.control_command_response(
                    proto, command, 0,
                    "stopped proxy process with pid %s" % pid)
        return self.control_command_response(
            proto, command, 14, "no proxy found for display %s" % display)

    def stop_all_proxies(self):
        processes = self.processes
        self.processes = {}
        log("stop_all_proxies() will stop proxy processes: %s", processes)
        for process, v in processes.items():
            if not process.is_alive():
                continue
            disp, mq = v
            log("stop_all_proxies() stopping process %s for display %s",
                process, disp)
            mq.put("stop")
        log("stop_all_proxies() done")

    def cleanup(self):
        self.stop_all_proxies()
        ServerCore.cleanup(self)

    def do_quit(self):
        self.main_loop.quit()
        log.info("Proxy Server process ended")

    def add_listen_socket(self, socktype, sock):
        sock.listen(5)
        gobject.io_add_watch(sock, gobject.IO_IN, self._new_connection, sock)
        self.socket_types[sock] = socktype

    def verify_connection_accepted(self, protocol):
        #if we start a proxy, the protocol will be closed
        #(a new one is created in the proxy process)
        if not protocol._closed:
            self.send_disconnect(protocol, "connection timeout")

    def hello_oked(self, proto, packet, c, auth_caps):
        if c.boolget("stop_request"):
            self.clean_quit()
            return
        self.accept_client(proto, c)
        self.start_proxy(proto, c, auth_caps)

    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None

        #find the target server session:
        def disconnect(msg):
            self.send_disconnect(client_proto, msg)

        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception, e:
            log.error("failed to get the list of sessions: %s", e)
            disconnect("authentication error")
            return
        if sessions is None:
            disconnect("no sessions found")
            return
        log("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
            auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays) == 0:
            disconnect("no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display == proxy_virtual_display:
            disconnect("invalid display")
            return
        if display:
            if display not in displays:
                disconnect("display not found")
                return
        else:
            if len(displays) != 1:
                disconnect(
                    "please specify a display (more than one available)")
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s",
            client_proto, auth_caps, display)

        def parse_error(*args):
            disconnect("invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))

        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception, e:
            log.error("cannot start proxy connection to %s: %s",
                      disp_desc,
                      e,
                      exc_info=True)
            disconnect("failed to connect to display")
            return
示例#29
0
文件: main.py 项目: svn2github/Xpra
def parse_cmdline(cmdline):
    #################################################################
    ## NOTE NOTE NOTE
    ##
    ## If you modify anything here, then remember to update the man page
    ## (xpra.1) as well!
    ##
    ## NOTE NOTE NOTE
    #################################################################
    command_options = [
                        "\t%prog attach [DISPLAY]\n",
                        "\t%prog detach [DISPLAY]\n",
                        "\t%prog screenshot filename [DISPLAY]\n",
                        "\t%prog info [DISPLAY]\n",
                        "\t%prog control DISPLAY command [arg1] [arg2]..\n",
                        "\t%prog version [DISPLAY]\n"
                      ]
    server_modes = []
    if supports_server:
        server_modes.append("start")
        server_modes.append("upgrade")
        command_options = ["\t%prog start DISPLAY\n",
                           "\t%prog stop [DISPLAY]\n",
                           "\t%prog exit [DISPLAY]\n",
                           "\t%prog list\n",
                           "\t%prog upgrade DISPLAY\n",
                           ] + command_options
    if supports_shadow:
        server_modes.append("shadow")
        command_options.append("\t%prog shadow [DISPLAY]\n")
    if not supports_server:
        command_options.append("(This xpra installation does not support starting local servers.)")

    parser = OptionParser(version="xpra v%s" % XPRA_VERSION,
                          usage="\n" + "".join(command_options))
    defaults = make_defaults_struct()
    hidden_options = {"display" : defaults.display}
    if len(server_modes):
        group = OptionGroup(parser, "Server Options",
                    "These options are only relevant on the server when using the %s mode." %
                    " or ".join(["'%s'" % x for x in server_modes]))
        parser.add_option_group(group)
    if supports_server:
        group.add_option("--start-child", action="append",
                          dest="start_child", metavar="CMD", default=defaults.start_child,
                          help="program to spawn in new server (may be repeated) (default: %default)")
        group.add_option("--exit-with-children", action="store_true",
                          dest="exit_with_children", default=defaults.exit_with_children,
                          help="Terminate server when --start-child command(s) exit")
        group.add_option("--tcp-proxy", action="store",
                          dest="tcp_proxy", default=defaults.tcp_proxy,
                          metavar="HOST:PORT",
                          help="The address to which non-xpra packets will be forwarded.")
    else:
        hidden_options["start_child"] = None
        hidden_options["exit_with_children"] = False
        hidden_options["tcp_proxy"] = ""
    if (supports_server or supports_shadow) and CAN_DAEMONIZE:
        group.add_option("--no-daemon", action="store_false",
                          dest="daemon", default=True,
                          help="Don't daemonize when running as a server")
        group.add_option("--log-file", action="store",
                      dest="log_file", default=defaults.log_file,
                      help="When daemonizing, this is where the log messages will go (default: %default)."
                      + " If a relative filename is specified the it is relative to --socket-dir,"
                      + " the value of '$DISPLAY' will be substituted with the actual display used"
                      )
        group.add_option("--no-mdns", action="store_false",
                          dest="mdns", default=defaults.mdns,
                          help="Don't publish session information via mDNS")
    else:
        hidden_options["daemon"] = False
        hidden_options["mdns"] = False
        hidden_options["log_file"] = defaults.log_file
    if supports_server:
        group.add_option("--use-display", action="store_true",
                          dest="use_display", default=defaults.use_display,
                          help="Use an existing display rather than starting one with xvfb")
        group.add_option("--xvfb", action="store",
                          dest="xvfb",
                          default=defaults.xvfb,
                          metavar="CMD",
                          help="How to run the headless X server (default: '%default')")
    else:
        hidden_options["use_display"] = False
        hidden_options["xvfb"] = ''
    if supports_server or supports_shadow:
        group.add_option("--bind-tcp", action="append",
                          dest="bind_tcp", default=defaults.bind_tcp,
                          metavar="[HOST]:PORT",
                          help="Listen for connections over TCP (use --password-file to secure it)."
                            + " You may specify this option multiple times with different host and port combinations")
    else:
        hidden_options["bind_tcp"] = []
    if supports_server:
        group.add_option("--no-pulseaudio", action="store_false",
                      dest="pulseaudio", default=defaults.pulseaudio,
                      help="Disable starting of a pulseaudio server for the session")
        group.add_option("--pulseaudio-command", action="store",
                      dest="pulseaudio_command", default=defaults.pulseaudio_command,
                      help="The command used to start the pulseaudio server (default: '%default')")
        group.add_option("--no-dbus-proxy", action="store",
                      dest="dbus_proxy", default=defaults.dbus_proxy,
                      help="Disallow the forwarding of dbus calls from the client (default: '%default')")
    else:
        hidden_options["pulseaudio"] = False
        hidden_options["pulseaudio_command"] = ""
        hidden_options["dbus_proxy"] = False

    group = OptionGroup(parser, "Server Controlled Features",
                "These options can be used to turn certain features on or off, "
                "they can be specified on the client or on the server, "
                "but the client cannot enable them if they are disabled on the server.")
    parser.add_option_group(group)
    group.add_option("--no-clipboard", action="store_false",
                      dest="clipboard", default=defaults.clipboard,
                      help="Disable clipboard support")
    group.add_option("--no-notifications", action="store_false",
                      dest="notifications", default=defaults.notifications,
                      help="Disable forwarding of system notifications")
    group.add_option("--no-system-tray", action="store_false",
                      dest="system_tray", default=defaults.system_tray,
                      help="Disable forwarding of system tray icons")
    group.add_option("--no-cursors", action="store_false",
                      dest="cursors", default=defaults.cursors,
                      help="Disable forwarding of custom application mouse cursors")
    group.add_option("--no-bell", action="store_false",
                      dest="bell", default=defaults.bell,
                      help="Disable forwarding of the system bell")
    if os.name=="posix":
        group.add_option("--no-xsettings", action="store_false",
                          dest="xsettings", default=defaults.xsettings,
                          help="Disable xsettings synchronization")
    else:
        hidden_options["xsettings"] =  False
    group.add_option("--no-mmap", action="store_false",
                      dest="mmap", default=defaults.mmap,
                      help="Disable memory mapped transfers for local connections")
    group.add_option("--readonly", action="store_true",
                      dest="readonly", default=defaults.readonly,
                      help="Ignore all keyboard input and mouse events from the clients")
    group.add_option("--enable-sharing", action="store_true",
                      dest="sharing", default=defaults.sharing,
                      help="Allow more than one client to connect to the same session")
    group.add_option("--no-speaker", action="store_false",
                      dest="speaker", default=defaults.speaker,
                      help="Disable forwarding of sound output to the client(s)")
    CODEC_HELP = """Specify the codec(s) to use for forwarding the %s sound output.
This parameter can be specified multiple times and the order in which the codecs
are specified defines the preferred codec order.
Use the special value 'help' to get a list of options.
When unspecified, all the available codecs are allowed and the first one is used."""
    group.add_option("--speaker-codec", action="append",
                      dest="speaker_codec", default=defaults.speaker_codec,
                      help=CODEC_HELP % "speaker")
    group.add_option("--no-microphone", action="store_false",
                      dest="microphone", default=defaults.microphone,
                      help="Disable forwarding of sound input to the server")
    group.add_option("--microphone-codec", action="append",
                      dest="microphone_codec", default=defaults.microphone_codec,
                      help=CODEC_HELP % "microphone")

    group = OptionGroup(parser, "Client Picture Encoding and Compression Options",
                "These options are used by the client to specify the desired picture and network data compression."
                "They may also be specified on the server as default values for those clients that do not set them.")
    parser.add_option_group(group)
    group.add_option("--encoding", action="store",
                      metavar="ENCODING", default=defaults.encoding,
                      dest="encoding", type="str",
                      help="What image compression algorithm to use, specify 'help' to get a list of options."
                            " Default: %default."
                      )
    group.add_option("--min-quality", action="store",
                      metavar="MIN-LEVEL",
                      dest="min_quality", type="int", default=defaults.min_quality,
                      help="Sets the minimum encoding quality allowed in automatic quality setting (from 1 to 100, 0 to leave unset). Default: %default.")
    group.add_option("--quality", action="store",
                      metavar="LEVEL",
                      dest="quality", type="int", default=defaults.quality,
                      help="Use a fixed image compression quality - only relevant to lossy encodings (1-100, 0 to use automatic setting). Default: %default.")
    group.add_option("--min-speed", action="store",
                      metavar="SPEED",
                      dest="min_speed", type="int", default=defaults.min_speed,
                      help="Sets the minimum encoding speed allowed in automatic speed setting (1-100, 0 to leave unset). Default: %default.")
    group.add_option("--speed", action="store",
                      metavar="SPEED",
                      dest="speed", type="int", default=defaults.speed,
                      help="Use image compression with the given encoding speed (1-100, 0 to use automatic setting). Default: %default.")
    group.add_option("--auto-refresh-delay", action="store",
                      dest="auto_refresh_delay", type="float", default=defaults.auto_refresh_delay,
                      metavar="DELAY",
                      help="Idle delay in seconds before doing an automatic lossless refresh."
                      + " 0.0 to disable."
                      + " Default: %default.")
    group.add_option("-z", "--compress", action="store",
                      dest="compression_level", type="int", default=defaults.compression_level,
                      metavar="LEVEL",
                      help="How hard to work on compressing data."
                      + " You generally do not need to use this option,"
                      + " the default value should be adequate,"
                      + " picture data is compressed separately (see --encoding)."
                      + " 0 to disable compression,"
                      + " 9 for maximal (slowest) compression. Default: %default.")

    group = OptionGroup(parser, "Client Features Options",
                "These options control client features that affect the appearance or the keyboard.")
    parser.add_option_group(group)
    group.add_option("--opengl", action="store",
                      dest="opengl", default=defaults.opengl,
                      help="Use OpenGL accelerated rendering, options: yes,no,auto. Default: %s." % print_bool("opengl", defaults.opengl))
    group.add_option("--no-windows", action="store_false",
                      dest="windows", default=defaults.windows,
                      help="Tells the server not to send any window data, only notifications and bell events will be forwarded (if enabled).")
    group.add_option("--session-name", action="store",
                      dest="session_name", default=defaults.session_name,
                      help="The name of this session, which may be used in notifications, menus, etc. Default: Xpra")
    group.add_option("--client-toolkit", action="store",
                      dest="client_toolkit", default=defaults.client_toolkit,
                      help="The type of client toolkit. Use the value 'help' to get a list of options. Default: %default")
    group.add_option("--window-layout", action="store",
                      dest="window_layout", default=defaults.window_layout,
                      help="The type of window layout to use, each client toolkit may provide different layouts."
                        "use the value 'help' to get a list of possible layouts. Default: %default")
    group.add_option("--title", action="store",
                      dest="title", default=defaults.title,
                      help="Text which is shown as window title, may use remote metadata variables (default: '%default')")
    group.add_option("--window-icon", action="store",
                          dest="window_icon", default=defaults.window_icon,
                          help="Path to the default image which will be used for all windows (the application may override this)")
    # let the platform specific code add its own options:
    # adds "--no-tray" for platforms that support it
    add_client_options(group)
    hidden_options["tray"] =  True
    hidden_options["delay_tray"] =  False
    group.add_option("--tray-icon", action="store",
                          dest="tray_icon", default=defaults.tray_icon,
                          help="Path to the image which will be used as icon for the system-tray or dock")
    group.add_option("--key-shortcut", action="append",
                      dest="key_shortcut", type="str", default=defaults.key_shortcut,
                      help="Define key shortcuts that will trigger specific actions."
                      + "If no shortcuts are defined, it defaults to '%s'" % (",".join(defaults.key_shortcut or [])))
    group.add_option("--no-keyboard-sync", action="store_false",
                      dest="keyboard_sync", default=defaults.keyboard_sync,
                      help="Disable keyboard state synchronization, prevents keys from repeating on high latency links but also may disrupt applications which access the keyboard directly")

    group = OptionGroup(parser, "Advanced Options",
                "These options apply to both client and server. Please refer to the man page for details.")
    parser.add_option_group(group)
    group.add_option("--password-file", action="store",
                      dest="password_file", default=defaults.password_file,
                      help="The file containing the password required to connect (useful to secure TCP mode)")
    group.add_option("--dpi", action="store",
                      dest="dpi", default=defaults.dpi,
                      help="The 'dots per inch' value that client applications should try to honour (default: %default)")
    default_socket_dir_str = defaults.socket_dir or "$XPRA_SOCKET_DIR or '~/.xpra'"
    group.add_option("--socket-dir", action="store",
                      dest="socket_dir", default=defaults.socket_dir,
                      help="Directory to place/look for the socket files in (default: %s)" % default_socket_dir_str)
    debug_default = ""
    if defaults.debug:
        debug_default = "all"
    group.add_option("-d", "--debug", action="store",
                      dest="debug", default=debug_default, metavar="FILTER1,FILTER2,...",
                      help="List of categories to enable debugging for (or \"all\")")
    group.add_option("--ssh", action="store",
                      dest="ssh", default=defaults.ssh, metavar="CMD",
                      help="How to run ssh (default: '%default')")
    group.add_option("--username", action="store",
                      dest="username", default=defaults.username,
                      help="The username supplied by the client for authentication (default: '%default')")
    group.add_option("--auth", action="store",
                      dest="auth", default=defaults.auth,
                      help="The authentication module (default: '%default')")
    group.add_option("--mmap-group", action="store_true",
                      dest="mmap_group", default=defaults.mmap_group,
                      help="When creating the mmap file with the client, set the group permission on the mmap file to the same value as the owner of the server socket file we connect to (default: '%default')")
    group.add_option("--enable-pings", action="store_true",
                      dest="pings", default=defaults.pings,
                      help="Send ping packets every second to gather latency statistics")
    group.add_option("--clipboard-filter-file", action="store",
                      dest="clipboard_filter_file", default=defaults.clipboard_filter_file,
                      help="Name of a file containing regular expressions of clipboard contents that must be filtered out")
    group.add_option("--remote-xpra", action="store",
                      dest="remote_xpra", default=defaults.remote_xpra,
                      metavar="CMD",
                      help="How to run xpra on the remote host (default: '%default')")
    if len(ENCRYPTION_CIPHERS)>0:
        group.add_option("--encryption", action="store",
                          dest="encryption", default=defaults.encryption,
                          metavar="ALGO",
                          help="Specifies the encryption cipher to use, supported algorithms are: %s (default: None)" % (", ".join(ENCRYPTION_CIPHERS)))
        group.add_option("--encryption-keyfile", action="store",
                          dest="encryption_keyfile", default=defaults.encryption_keyfile,
                          metavar="FILE",
                          help="Specifies the file containing the encryption key. (default: '%default')")
    else:
        hidden_options["encryption"] = ''
        hidden_options["encryption_keyfile"] = ''

    options, args = parser.parse_args(cmdline[1:])

    #ensure all the option fields are set even though
    #some options are not shown to the user:
    for k,v in hidden_options.items():
        if not hasattr(options, k):
            setattr(options, k, v)

    if options.encoding:
        #fix old encoding names if needed:
        from xpra.codecs.loader import ALL_OLD_ENCODING_NAMES_TO_NEW
        options.encoding = ALL_OLD_ENCODING_NAMES_TO_NEW.get(options.encoding, options.encoding)
        if options.encoding=="webp":
            #warn that webp should not be used:
            print("Warning: webp encoding may leak memory!")

    #special handling for URL mode:
    #xpra attach xpra://[mode:]host:port/?param1=value1&param2=value2
    if len(args)==2 and args[0]=="attach" and args[1].startswith("xpra://"):
        url = args[1]
        from urlparse import urlparse, parse_qs
        up = urlparse(url)
        address = up.netloc
        qpos = url.find("?")
        if qpos>0:
            params_str = url[qpos+1:]
            params = parse_qs(params_str, keep_blank_values=True)
            f_params = {}
            #print("params=%s" % str(params))
            for k,v in params.items():
                t = OPTION_TYPES.get(k)
                if t is not None and t!=list:
                    v = v[0]
                f_params[k] = v
            v_params = validate_config(f_params)
            for k,v in v_params.items():
                setattr(options, k, v)
        al = address.lower()
        if not al.startswith(":") and not al.startswith("tcp") and not al.startswith("ssh"):
            #assume tcp if not specified
            address = "tcp:%s" % address
        args[1] = address

    try:
        int(options.dpi)
    except Exception, e:
        parser.error("invalid dpi: %s" % e)
示例#30
0
    def start_proxy(self, client_proto, c, auth_caps):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)

        #find the target server session:
        if not client_proto.authenticator:
            log.error(
                "Error: the proxy server requires an authentication mode,")
            try:
                log.error(" client connection '%s' does not specify one",
                          client_proto._conn.socktype)
            except:
                pass
            log.error(" use 'none' to disable authentication")
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            authlog("failed to get the list of sessions", exc_info=True)
            authlog.error(
                "Error: failed to get the list of sessions using '%s' authenticator",
                client_proto.authenticator)
            authlog.error(" %s", e)
            disconnect(AUTHENTICATION_ERROR)
            return
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
                auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays) == 0:
            disconnect(SESSION_NOT_FOUND, "no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        authlog(
            "start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s",
            proxy_virtual_display, display, displays)
        if display == proxy_virtual_display:
            disconnect(SESSION_NOT_FOUND, "invalid display")
            return
        if display:
            if display not in displays:
                disconnect(SESSION_NOT_FOUND,
                           "display '%s' not found" % display)
                return
        else:
            if len(displays) != 1:
                disconnect(
                    SESSION_NOT_FOUND,
                    "please specify a display, more than one is available: %s"
                    % csv(displays))
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s",
            client_proto, auth_caps, display)

        def parse_error(*args):
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))

        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            log.error(" %s", e)
            log.error(" connection definition:")
            print_nested_dict(disp_desc,
                              prefix=" ",
                              lchar="*",
                              pad=20,
                              print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn(
                    "Warning: received an unexpected packet on the proxy connection %s:",
                    client_proto)
                log.warn(" %s", repr_ellipsized(packet))

        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(
                    client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(
                    5 + self._socket_timeout)
                if not ioe:
                    log.error(
                        "Error: some network IO threads have failed to terminate"
                    )
                    return
                client_conn.set_active(True)
                assert uid != 0 and gid != 0
                process = ProxyInstanceProcess(
                    uid, gid, env_options, session_options, self._socket_dir,
                    self.video_encoders, self.csc_modules, client_conn,
                    client_state, cipher, encryption_key, server_conn, c,
                    message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display,
                                              "xpra-proxy-instance", True,
                                              True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
            #FIXME: remove processes that have terminated

        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
示例#31
0
def main(_args):
    from xpra.scripts.config import make_defaults_struct
    defaults = make_defaults_struct()
    return do_main(defaults)
示例#32
0
文件: main.py 项目: svn2github/Xpra
def main(script_file, cmdline):
    platform_init()
    if os.name=="posix" and os.getuid()==0:
        warn("\nWarning: running as root")
    try:
        import glib
        glib.set_prgname("Xpra")
    except:
        pass
    #################################################################
    ## NOTE NOTE NOTE
    ##
    ## If you modify anything here, then remember to update the man page
    ## (xpra.1) as well!
    ##
    ## NOTE NOTE NOTE
    #################################################################
    supports_shadow = XPRA_SHADOW_SUPPORTED
    supports_server = XPRA_LOCAL_SERVERS_SUPPORTED
    if supports_server:
        try:
            from xpra.wait_for_x_server import wait_for_x_server    #@UnresolvedImport @UnusedImport
        except:
            supports_server = False

    command_options = [
                        "\t%prog attach [DISPLAY]\n",
                        "\t%prog detach [DISPLAY]\n",
                        "\t%prog screenshot filename [DISPLAY]\n",
                        "\t%prog info [DISPLAY]\n",
                        "\t%prog version [DISPLAY]\n"
                      ]
    if supports_server:
        command_options = ["\t%prog start DISPLAY\n",
                           "\t%prog stop [DISPLAY]\n",
                           "\t%prog list\n",
                           "\t%prog upgrade DISPLAY\n",
                           ] + command_options
    if supports_shadow:
        command_options.append("\t%prog shadow DISPLAY\n")
    if not supports_server:
        command_options.append("(This xpra installation does not support starting local servers.)")

    hidden_options = {}
    parser = OptionParser(version="xpra v%s" % xpra.__version__,
                          usage="\n" + "".join(command_options))
    defaults = make_defaults_struct()
    if supports_server or supports_shadow:
        group = OptionGroup(parser, "Server Options",
                    "These options are only relevant on the server when using the 'start', 'upgrade' or 'shadow' mode.")
        parser.add_option_group(group)
    if supports_server:
        group.add_option("--start-child", action="append",
                          dest="start_child", metavar="CMD", default=defaults.start_child,
                          help="program to spawn in new server (may be repeated) (default: %default)")
        group.add_option("--exit-with-children", action="store_true",
                          dest="exit_with_children", default=defaults.exit_with_children,
                          help="Terminate server when --start-child command(s) exit")
    else:
        hidden_options["start_child"] = None
        hidden_options["exit_with_children"] = False
    if supports_server or supports_shadow:
        group.add_option("--no-daemon", action="store_false",
                          dest="daemon", default=True,
                          help="Don't daemonize when running as a server")
        group.add_option("--log-file", action="store",
                      dest="log_file", default=defaults.log_file,
                      help="When daemonizing, this is where the log messages will go (default: %s)."
                      + " If a relative filename is specified the it is relative to --socket-dir,"
                      + " the value of '$DISPLAY' will be substituted with the actual display used"
                      )
    else:
        hidden_options["daemon"] = False
        hidden_options["log_file"] = defaults.log_file
    if supports_server:
        group.add_option("--use-display", action="store_true",
                          dest="use_display", default=defaults.use_display,
                          help="Use an existing display rather than starting one with xvfb")
        group.add_option("--xvfb", action="store",
                          dest="xvfb",
                          default=defaults.xvfb,
                          metavar="CMD",
                          help="How to run the headless X server (default: '%default')")
    else:
        hidden_options["use_display"] = False
        hidden_options["xvfb"] = ''
    if supports_server or supports_shadow:
        group.add_option("--bind-tcp", action="append",
                          dest="bind_tcp", default=defaults.bind_tcp,
                          metavar="[HOST]:PORT",
                          help="Listen for connections over TCP (use --password-file to secure it)."
                            + " You may specify this option multiple times with different host and port combinations")
    else:
        hidden_options["bind_tcp"] = []
    if supports_server:
        group.add_option("--no-pulseaudio", action="store_false",
                      dest="pulseaudio", default=defaults.pulseaudio,
                      help="Disable starting of a pulseaudio server for the session")
        group.add_option("--pulseaudio-command", action="store",
                      dest="pulseaudio_command", default=defaults.pulseaudio_command,
                      help="The command used to start the pulseaudio server (default: '%default')")
    else:
        hidden_options["pulseaudio"] = False
        hidden_options["pulseaudio_command"] = ""

    group = OptionGroup(parser, "Server Controlled Features",
                "These options can be used to turn certain features on or off, "
                "they can be specified on the client or on the server, "
                "but the client cannot enable them if they are disabled on the server.")
    parser.add_option_group(group)
    group.add_option("--no-clipboard", action="store_false",
                      dest="clipboard", default=defaults.clipboard,
                      help="Disable clipboard support")
    group.add_option("--no-notifications", action="store_false",
                      dest="notifications", default=defaults.notifications,
                      help="Disable forwarding of system notifications")
    group.add_option("--no-system-tray", action="store_false",
                      dest="system_tray", default=defaults.system_tray,
                      help="Disable forwarding of system tray icons")
    group.add_option("--no-cursors", action="store_false",
                      dest="cursors", default=defaults.cursors,
                      help="Disable forwarding of custom application mouse cursors")
    group.add_option("--no-bell", action="store_false",
                      dest="bell", default=defaults.bell,
                      help="Disable forwarding of the system bell")
    group.add_option("--no-mmap", action="store_false",
                      dest="mmap", default=defaults.mmap,
                      help="Disable memory mapped transfers for local connections")
    group.add_option("--readonly", action="store_true",
                      dest="readonly", default=defaults.readonly,
                      help="Ignore all keyboard input and mouse events from the clients")
    group.add_option("--enable-sharing", action="store_true",
                      dest="sharing", default=defaults.sharing,
                      help="Allow more than one client to connect to the same session")
    group.add_option("--no-speaker", action="store_false",
                      dest="speaker", default=defaults.speaker,
                      help="Disable forwarding of sound output to the client(s)")
    group.add_option("--speaker-codec", action="append",
                      dest="speaker_codec", default=defaults.speaker_codec,
                      help="The audio codec to use for forwarding the speaker sound output "
                      "(you may specify more than one to define the preferred order, use 'help' to get a list of options, "
                      "when unspecified all available codecs are allowed and the first one is used)")
    group.add_option("--no-microphone", action="store_false",
                      dest="microphone", default=defaults.microphone,
                      help="Disable forwarding of sound input to the server")
    group.add_option("--microphone-codec", action="append",
                      dest="microphone_codec", default=defaults.microphone_codec,
                      help="The audio codec to use for forwaring the microphone sound input "
                      "(you may specify more than one to define the preferred order, use 'help' to get a list of options, "
                      "when unspecified all available codecs are allowed and the first one is used)")

    group = OptionGroup(parser, "Client Picture Encoding and Compression Options",
                "These options are used by the client to specify the desired picture and network data compression."
                "They may also be specified on the server as default values for those clients that do not set them.")
    parser.add_option_group(group)
    group.add_option("--encoding", action="store",
                      metavar="ENCODING", default=defaults.encoding,
                      dest="encoding", type="str",
                      help="What image compression algorithm to use: %s." % (", ".join(ENCODINGS)) +
                            " Default: %default."
                      )
    if "jpeg" in ENCODINGS:
        group.add_option("-b", "--max-bandwidth", action="store",
                          dest="max_bandwidth", type="float", default=defaults.max_bandwidth, metavar="BANDWIDTH (kB/s)",
                          help="Specify the link's maximal receive speed to auto-adjust JPEG quality, 0.0 disables. (default: %default)")
    else:
        hidden_options["max_bandwidth"] = 0
    if len(set(("jpeg", "webp", "x264")).intersection(set(ENCODINGS)))>0:
        group.add_option("--min-quality", action="store",
                          metavar="MIN-LEVEL",
                          dest="min_quality", type="int", default=defaults.min_quality,
                          help="Sets the minimum x264 encoding quality allowed in automatic quality setting (from 1 to 100, 0 to leave unset). Default: %default.")
        group.add_option("--quality", action="store",
                          metavar="LEVEL",
                          dest="quality", type="int", default=defaults.quality,
                          help="Use a fixed image compression quality - only relevant to lossy encodings (1-100, 0 to use automatic setting). Default: %default.")
    else:
        hidden_options["min_quality"] = defaults.min_quality
        hidden_options["quality"] = defaults.quality
    if "x264" in ENCODINGS:
        group.add_option("--min-speed", action="store",
                          metavar="SPEED",
                          dest="min_speed", type="int", default=defaults.min_speed,
                          help="Sets the minimum x264 encoding speed allowed in automatic speed setting (1-100, 0 to leave unset). Default: %default.")
        group.add_option("--speed", action="store",
                          metavar="SPEED",
                          dest="speed", type="int", default=defaults.speed,
                          help="Use x264 image compression with the given encoding speed (1-100, 0 to use automatic setting). Default: %default.")
    else:
        hidden_options["min_speed"] = defaults.min_speed
        hidden_options["speed"] = defaults.speed
    group.add_option("--auto-refresh-delay", action="store",
                      dest="auto_refresh_delay", type="float", default=defaults.auto_refresh_delay,
                      metavar="DELAY",
                      help="Idle delay in seconds before doing an automatic lossless refresh."
                      + " 0.0 to disable."
                      + " Default: %default.")
    group.add_option("-z", "--compress", action="store",
                      dest="compression_level", type="int", default=defaults.compression_level,
                      metavar="LEVEL",
                      help="How hard to work on compressing data."
                      + " You generally do not need to use this option,"
                      + " the default value should be adequate,"
                      + " picture data is compressed separately (see --encoding)."
                      + " 0 to disable compression,"
                      + " 9 for maximal (slowest) compression. Default: %default.")

    group = OptionGroup(parser, "Client Features Options",
                "These options control client features that affect the appearance or the keyboard.")
    parser.add_option_group(group)
    group.add_option("--opengl", action="store",
                      dest="opengl", default=defaults.opengl,
                      help="Use OpenGL accelerated rendering, options: yes,no,auto. Default: %default.")
    group.add_option("--no-windows", action="store_false",
                      dest="windows", default=defaults.windows,
                      help="Tells the server not to send any window data, only notifications and bell events will be forwarded (if enabled).")
    group.add_option("--session-name", action="store",
                      dest="session_name", default=defaults.session_name,
                      help="The name of this session, which may be used in notifications, menus, etc. Default: Xpra")
    group.add_option("--title", action="store",
                      dest="title", default=defaults.title,
                      help="Text which is shown as window title, may use remote metadata variables (default: '%default')")
    group.add_option("--window-icon", action="store",
                          dest="window_icon", default=defaults.window_icon,
                          help="Path to the default image which will be used for all windows (the application may override this)")
    # let the platform specific code add its own options:
    # adds "--no-tray" for platforms that support it
    add_client_options(group)
    group.add_option("--tray-icon", action="store",
                          dest="tray_icon", default=defaults.tray_icon,
                          help="Path to the image which will be used as icon for the system-tray or dock")
    group.add_option("--key-shortcut", action="append",
                      dest="key_shortcut", type="str", default=defaults.key_shortcut,
                      help="Define key shortcuts that will trigger specific actions."
                      + " Defaults to 'Meta+Shift+F4:quit' if no shortcuts are defined.")
    group.add_option("--no-keyboard-sync", action="store_false",
                      dest="keyboard_sync", default=defaults.keyboard_sync,
                      help="Disable keyboard state synchronization, prevents keys from repeating on high latency links but also may disrupt applications which access the keyboard directly")
    parser.add_option_group(group)

    group = OptionGroup(parser, "Advanced Options",
                "These options apply to both client and server. Please refer to the man page for details.")
    parser.add_option_group(group)
    group.add_option("--password-file", action="store",
                      dest="password_file", default=defaults.password_file,
                      help="The file containing the password required to connect (useful to secure TCP mode)")
    group.add_option("--dpi", action="store",
                      dest="dpi", default=defaults.dpi,
                      help="The 'dots per inch' value that client applications should try to honour (default: %default)")
    default_socket_dir_str = defaults.socket_dir or "$XPRA_SOCKET_DIR or '~/.xpra'"
    group.add_option("--socket-dir", action="store",
                      dest="socket_dir", default=defaults.socket_dir,
                      help="Directory to place/look for the socket files in (default: %s)" % default_socket_dir_str)
    debug_default = ""
    if defaults.debug:
        debug_default = "all"
    group.add_option("-d", "--debug", action="store",
                      dest="debug", default=debug_default, metavar="FILTER1,FILTER2,...",
                      help="List of categories to enable debugging for (or \"all\")")
    group.add_option("--ssh", action="store",
                      dest="ssh", default=defaults.ssh, metavar="CMD",
                      help="How to run ssh (default: '%default')")
    group.add_option("--mmap-group", action="store_true",
                      dest="mmap_group", default=defaults.mmap_group,
                      help="When creating the mmap file with the client, set the group permission on the mmap file to the same value as the owner of the server socket file we connect to (default: '%default')")
    group.add_option("--enable-pings", action="store_true",
                      dest="pings", default=defaults.pings,
                      help="Send ping packets every second to gather latency statistics")
    group.add_option("--clipboard-filter-file", action="store",
                      dest="clipboard_filter_file", default=defaults.clipboard_filter_file,
                      help="Name of a file containing regular expressions of clipboard contents that must be filtered out")
    group.add_option("--remote-xpra", action="store",
                      dest="remote_xpra", default=defaults.remote_xpra,
                      metavar="CMD",
                      help="How to run xpra on the remote host (default: '%default')")
    if len(ENCRYPTION_CIPHERS)>0:
        group.add_option("--encryption", action="store",
                          dest="encryption", default=defaults.encryption,
                          metavar="ALGO",
                          help="Specifies the encryption cipher to use, only %s is currently supported. (default: None)" % (", ".join(ENCRYPTION_CIPHERS)))
    else:
        hidden_options["encryption"] = ''

    options, args = parser.parse_args(cmdline[1:])
    if not args:
        parser.error("need a mode")

    #ensure all the option fields are set even though
    #some options are not shown to the user:
    for k,v in hidden_options.items():
        setattr(options, k, v)
    try:
        int(options.dpi)
    except Exception, e:
        parser.error("invalid dpi: %s" % e)
示例#33
0
文件: main.py 项目: rudresh2319/Xpra
def main(script_file, cmdline):
    platform_init()
    if os.name == "posix" and os.getuid() == 0:
        warn("\nWarning: running as root")
    try:
        import glib
        glib.set_prgname("Xpra")
    except:
        pass
    #################################################################
    ## NOTE NOTE NOTE
    ##
    ## If you modify anything here, then remember to update the man page
    ## (xpra.1) as well!
    ##
    ## NOTE NOTE NOTE
    #################################################################
    supports_shadow = XPRA_SHADOW_SUPPORTED
    supports_server = XPRA_LOCAL_SERVERS_SUPPORTED
    if supports_server:
        try:
            from xpra.wait_for_x_server import wait_for_x_server  #@UnresolvedImport @UnusedImport
        except:
            supports_server = False

    command_options = [
        "\t%prog attach [DISPLAY]\n", "\t%prog detach [DISPLAY]\n",
        "\t%prog screenshot filename [DISPLAY]\n", "\t%prog info [DISPLAY]\n",
        "\t%prog version [DISPLAY]\n"
    ]
    if supports_server:
        command_options = [
            "\t%prog start DISPLAY\n",
            "\t%prog stop [DISPLAY]\n",
            "\t%prog list\n",
            "\t%prog upgrade DISPLAY\n",
        ] + command_options
    if supports_shadow:
        command_options.append("\t%prog shadow DISPLAY\n")
    if not supports_server:
        command_options.append(
            "(This xpra installation does not support starting local servers.)"
        )

    hidden_options = {}
    parser = OptionParser(version="xpra v%s" % xpra.__version__,
                          usage="\n" + "".join(command_options))
    defaults = make_defaults_struct()
    if supports_server or supports_shadow:
        group = OptionGroup(
            parser, "Server Options",
            "These options are only relevant on the server when using the 'start', 'upgrade' or 'shadow' mode."
        )
        parser.add_option_group(group)
    if supports_server:
        group.add_option(
            "--start-child",
            action="append",
            dest="start_child",
            metavar="CMD",
            default=defaults.start_child,
            help=
            "program to spawn in new server (may be repeated) (default: %default)"
        )
        group.add_option(
            "--exit-with-children",
            action="store_true",
            dest="exit_with_children",
            default=defaults.exit_with_children,
            help="Terminate server when --start-child command(s) exit")
    else:
        hidden_options["start_child"] = None
        hidden_options["exit_with_children"] = False
    if supports_server or supports_shadow:
        group.add_option("--no-daemon",
                         action="store_false",
                         dest="daemon",
                         default=True,
                         help="Don't daemonize when running as a server")
        group.add_option(
            "--log-file",
            action="store",
            dest="log_file",
            default=defaults.log_file,
            help=
            "When daemonizing, this is where the log messages will go (default: %s)."
            +
            " If a relative filename is specified the it is relative to --socket-dir,"
            +
            " the value of '$DISPLAY' will be substituted with the actual display used"
        )
    else:
        hidden_options["daemon"] = False
        hidden_options["log_file"] = defaults.log_file
    if supports_server:
        group.add_option(
            "--use-display",
            action="store_true",
            dest="use_display",
            default=defaults.use_display,
            help="Use an existing display rather than starting one with xvfb")
        group.add_option(
            "--xvfb",
            action="store",
            dest="xvfb",
            default=defaults.xvfb,
            metavar="CMD",
            help="How to run the headless X server (default: '%default')")
    else:
        hidden_options["use_display"] = False
        hidden_options["xvfb"] = ''
    if supports_server or supports_shadow:
        group.add_option(
            "--bind-tcp",
            action="append",
            dest="bind_tcp",
            default=defaults.bind_tcp,
            metavar="[HOST]:PORT",
            help=
            "Listen for connections over TCP (use --password-file to secure it)."
            +
            " You may specify this option multiple times with different host and port combinations"
        )
    else:
        hidden_options["bind_tcp"] = []
    if supports_server:
        group.add_option(
            "--no-pulseaudio",
            action="store_false",
            dest="pulseaudio",
            default=defaults.pulseaudio,
            help="Disable starting of a pulseaudio server for the session")
        group.add_option(
            "--pulseaudio-command",
            action="store",
            dest="pulseaudio_command",
            default=defaults.pulseaudio_command,
            help=
            "The command used to start the pulseaudio server (default: '%default')"
        )
    else:
        hidden_options["pulseaudio"] = False
        hidden_options["pulseaudio_command"] = ""

    group = OptionGroup(
        parser, "Server Controlled Features",
        "These options can be used to turn certain features on or off, "
        "they can be specified on the client or on the server, "
        "but the client cannot enable them if they are disabled on the server."
    )
    parser.add_option_group(group)
    group.add_option("--no-clipboard",
                     action="store_false",
                     dest="clipboard",
                     default=defaults.clipboard,
                     help="Disable clipboard support")
    group.add_option("--no-notifications",
                     action="store_false",
                     dest="notifications",
                     default=defaults.notifications,
                     help="Disable forwarding of system notifications")
    group.add_option("--no-system-tray",
                     action="store_false",
                     dest="system_tray",
                     default=defaults.system_tray,
                     help="Disable forwarding of system tray icons")
    group.add_option(
        "--no-cursors",
        action="store_false",
        dest="cursors",
        default=defaults.cursors,
        help="Disable forwarding of custom application mouse cursors")
    group.add_option("--no-bell",
                     action="store_false",
                     dest="bell",
                     default=defaults.bell,
                     help="Disable forwarding of the system bell")
    group.add_option(
        "--no-mmap",
        action="store_false",
        dest="mmap",
        default=defaults.mmap,
        help="Disable memory mapped transfers for local connections")
    group.add_option(
        "--readonly",
        action="store_true",
        dest="readonly",
        default=defaults.readonly,
        help="Ignore all keyboard input and mouse events from the clients")
    group.add_option(
        "--enable-sharing",
        action="store_true",
        dest="sharing",
        default=defaults.sharing,
        help="Allow more than one client to connect to the same session")
    group.add_option(
        "--no-speaker",
        action="store_false",
        dest="speaker",
        default=defaults.speaker,
        help="Disable forwarding of sound output to the client(s)")
    group.add_option(
        "--speaker-codec",
        action="append",
        dest="speaker_codec",
        default=defaults.speaker_codec,
        help="The audio codec to use for forwarding the speaker sound output "
        "(you may specify more than one to define the preferred order, use 'help' to get a list of options, "
        "when unspecified all available codecs are allowed and the first one is used)"
    )
    group.add_option("--no-microphone",
                     action="store_false",
                     dest="microphone",
                     default=defaults.microphone,
                     help="Disable forwarding of sound input to the server")
    group.add_option(
        "--microphone-codec",
        action="append",
        dest="microphone_codec",
        default=defaults.microphone_codec,
        help="The audio codec to use for forwaring the microphone sound input "
        "(you may specify more than one to define the preferred order, use 'help' to get a list of options, "
        "when unspecified all available codecs are allowed and the first one is used)"
    )

    group = OptionGroup(
        parser, "Client Picture Encoding and Compression Options",
        "These options are used by the client to specify the desired picture and network data compression."
        "They may also be specified on the server as default values for those clients that do not set them."
    )
    parser.add_option_group(group)
    group.add_option("--encoding",
                     action="store",
                     metavar="ENCODING",
                     default=defaults.encoding,
                     dest="encoding",
                     type="str",
                     help="What image compression algorithm to use: %s." %
                     (", ".join(ENCODINGS)) + " Default: %default.")
    if "jpeg" in ENCODINGS:
        group.add_option(
            "-b",
            "--max-bandwidth",
            action="store",
            dest="max_bandwidth",
            type="float",
            default=defaults.max_bandwidth,
            metavar="BANDWIDTH (kB/s)",
            help=
            "Specify the link's maximal receive speed to auto-adjust JPEG quality, 0.0 disables. (default: %default)"
        )
    else:
        hidden_options["max_bandwidth"] = 0
    if len(set(("jpeg", "webp", "x264")).intersection(set(ENCODINGS))) > 0:
        group.add_option(
            "--min-quality",
            action="store",
            metavar="MIN-LEVEL",
            dest="min_quality",
            type="int",
            default=defaults.min_quality,
            help=
            "Sets the minimum x264 encoding quality allowed in automatic quality setting (from 1 to 100, 0 to leave unset). Default: %default."
        )
        group.add_option(
            "--quality",
            action="store",
            metavar="LEVEL",
            dest="quality",
            type="int",
            default=defaults.quality,
            help=
            "Use a fixed image compression quality - only relevant to lossy encodings (1-100, 0 to use automatic setting). Default: %default."
        )
    else:
        hidden_options["min_quality"] = defaults.min_quality
        hidden_options["quality"] = defaults.quality
    if "x264" in ENCODINGS:
        group.add_option(
            "--min-speed",
            action="store",
            metavar="SPEED",
            dest="min_speed",
            type="int",
            default=defaults.min_speed,
            help=
            "Sets the minimum x264 encoding speed allowed in automatic speed setting (1-100, 0 to leave unset). Default: %default."
        )
        group.add_option(
            "--speed",
            action="store",
            metavar="SPEED",
            dest="speed",
            type="int",
            default=defaults.speed,
            help=
            "Use x264 image compression with the given encoding speed (1-100, 0 to use automatic setting). Default: %default."
        )
    else:
        hidden_options["min_speed"] = defaults.min_speed
        hidden_options["speed"] = defaults.speed
    group.add_option(
        "--auto-refresh-delay",
        action="store",
        dest="auto_refresh_delay",
        type="float",
        default=defaults.auto_refresh_delay,
        metavar="DELAY",
        help="Idle delay in seconds before doing an automatic lossless refresh."
        + " 0.0 to disable." + " Default: %default.")
    group.add_option(
        "-z",
        "--compress",
        action="store",
        dest="compression_level",
        type="int",
        default=defaults.compression_level,
        metavar="LEVEL",
        help="How hard to work on compressing data." +
        " You generally do not need to use this option," +
        " the default value should be adequate," +
        " picture data is compressed separately (see --encoding)." +
        " 0 to disable compression," +
        " 9 for maximal (slowest) compression. Default: %default.")

    group = OptionGroup(
        parser, "Client Features Options",
        "These options control client features that affect the appearance or the keyboard."
    )
    parser.add_option_group(group)
    group.add_option(
        "--opengl",
        action="store",
        dest="opengl",
        default=defaults.opengl,
        help=
        "Use OpenGL accelerated rendering, options: yes,no,auto. Default: %default."
    )
    group.add_option(
        "--no-windows",
        action="store_false",
        dest="windows",
        default=defaults.windows,
        help=
        "Tells the server not to send any window data, only notifications and bell events will be forwarded (if enabled)."
    )
    group.add_option(
        "--session-name",
        action="store",
        dest="session_name",
        default=defaults.session_name,
        help=
        "The name of this session, which may be used in notifications, menus, etc. Default: Xpra"
    )
    group.add_option(
        "--title",
        action="store",
        dest="title",
        default=defaults.title,
        help=
        "Text which is shown as window title, may use remote metadata variables (default: '%default')"
    )
    group.add_option(
        "--window-icon",
        action="store",
        dest="window_icon",
        default=defaults.window_icon,
        help=
        "Path to the default image which will be used for all windows (the application may override this)"
    )
    # let the platform specific code add its own options:
    # adds "--no-tray" for platforms that support it
    add_client_options(group)
    group.add_option(
        "--tray-icon",
        action="store",
        dest="tray_icon",
        default=defaults.tray_icon,
        help=
        "Path to the image which will be used as icon for the system-tray or dock"
    )
    group.add_option(
        "--key-shortcut",
        action="append",
        dest="key_shortcut",
        type="str",
        default=defaults.key_shortcut,
        help="Define key shortcuts that will trigger specific actions." +
        " Defaults to 'Meta+Shift+F4:quit' if no shortcuts are defined.")
    group.add_option(
        "--no-keyboard-sync",
        action="store_false",
        dest="keyboard_sync",
        default=defaults.keyboard_sync,
        help=
        "Disable keyboard state synchronization, prevents keys from repeating on high latency links but also may disrupt applications which access the keyboard directly"
    )
    parser.add_option_group(group)

    group = OptionGroup(
        parser, "Advanced Options",
        "These options apply to both client and server. Please refer to the man page for details."
    )
    parser.add_option_group(group)
    group.add_option(
        "--password-file",
        action="store",
        dest="password_file",
        default=defaults.password_file,
        help=
        "The file containing the password required to connect (useful to secure TCP mode)"
    )
    group.add_option(
        "--dpi",
        action="store",
        dest="dpi",
        default=defaults.dpi,
        help=
        "The 'dots per inch' value that client applications should try to honour (default: %default)"
    )
    default_socket_dir_str = defaults.socket_dir or "$XPRA_SOCKET_DIR or '~/.xpra'"
    group.add_option(
        "--socket-dir",
        action="store",
        dest="socket_dir",
        default=defaults.socket_dir,
        help="Directory to place/look for the socket files in (default: %s)" %
        default_socket_dir_str)
    debug_default = ""
    if defaults.debug:
        debug_default = "all"
    group.add_option(
        "-d",
        "--debug",
        action="store",
        dest="debug",
        default=debug_default,
        metavar="FILTER1,FILTER2,...",
        help="List of categories to enable debugging for (or \"all\")")
    group.add_option("--ssh",
                     action="store",
                     dest="ssh",
                     default=defaults.ssh,
                     metavar="CMD",
                     help="How to run ssh (default: '%default')")
    group.add_option(
        "--mmap-group",
        action="store_true",
        dest="mmap_group",
        default=defaults.mmap_group,
        help=
        "When creating the mmap file with the client, set the group permission on the mmap file to the same value as the owner of the server socket file we connect to (default: '%default')"
    )
    group.add_option(
        "--enable-pings",
        action="store_true",
        dest="pings",
        default=defaults.pings,
        help="Send ping packets every second to gather latency statistics")
    group.add_option(
        "--clipboard-filter-file",
        action="store",
        dest="clipboard_filter_file",
        default=defaults.clipboard_filter_file,
        help=
        "Name of a file containing regular expressions of clipboard contents that must be filtered out"
    )
    group.add_option(
        "--remote-xpra",
        action="store",
        dest="remote_xpra",
        default=defaults.remote_xpra,
        metavar="CMD",
        help="How to run xpra on the remote host (default: '%default')")
    if len(ENCRYPTION_CIPHERS) > 0:
        group.add_option(
            "--encryption",
            action="store",
            dest="encryption",
            default=defaults.encryption,
            metavar="ALGO",
            help=
            "Specifies the encryption cipher to use, only %s is currently supported. (default: None)"
            % (", ".join(ENCRYPTION_CIPHERS)))
    else:
        hidden_options["encryption"] = ''

    options, args = parser.parse_args(cmdline[1:])
    if not args:
        parser.error("need a mode")

    #ensure all the option fields are set even though
    #some options are not shown to the user:
    for k, v in hidden_options.items():
        setattr(options, k, v)
    try:
        int(options.dpi)
    except Exception, e:
        parser.error("invalid dpi: %s" % e)
示例#34
0
    def start_proxy(self, client_proto, c, auth_caps):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)

        #find the target server session:
        if not client_proto.authenticator:
            log.error(
                "Error: the proxy server requires an authentication mode,")
            try:
                log.error(" client connection '%s' does not specify one",
                          client_proto._conn.socktype)
            except:
                pass
            log.error(" use 'none' to disable authentication")
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            authlog("failed to get the list of sessions", exc_info=True)
            authlog.error(
                "Error: failed to get the list of sessions using '%s' authenticator",
                client_proto.authenticator)
            authlog.error(" %s", e)
            disconnect(AUTHENTICATION_ERROR, "cannot access sessions")
            return
        authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
                auth_caps, sessions)
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        uid, gid, displays, env_options, session_options = sessions
        if os.name == "posix":
            if uid == 0 or gid == 0:
                log.error("Error: proxy instances should not run as root")
                log.error(" use a different uid and gid (ie: nobody)")
                disconnect(AUTHENTICATION_ERROR,
                           "cannot run proxy instances as root")
                return
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            if "xpra" not in groups:
                log("user '%s' (uid=%i) is not in the xpra group", username,
                    uid)
                log(" it belongs to: %s", csv(groups) or None)
        #ensure we don't loop back to the proxy:
        proxy_virtual_display = os.environ.get("DISPLAY")
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        #remove proxy instance virtual displays:
        displays = [x for x in displays if not x.startswith(":proxy-")]
        #log("unused options: %s, %s", env_options, session_options)
        opts = make_defaults_struct()
        display = None
        proc = None
        sns = c.dictget("start-new-session")
        authlog("start_proxy: displays=%s, start-new-session=%s", displays,
                bool(sns))
        if len(displays) == 0 or sns:
            if self._start_sessions:
                #start a new session
                mode = sns.get("mode", "start")
                assert mode in (
                    "start", "start-desktop",
                    "shadow"), "invalid start-new-session mode '%s'" % mode
                sns = typedict(sns)
                display = sns.get("display")
                args = []
                if display:
                    args = [display]
                start = sns.strlistget("start")
                start_child = sns.strlistget("start-child")
                exit_with_children = sns.boolget("exit-with-children")
                exit_with_client = sns.boolget("exit-with-client")
                log(
                    "starting new server subprocess: mode=%s, socket-dir=%s, socket-dirs=%s, start=%s, start-child=%s, exit-with-children=%s, exit-with-client=%s, uid=%s, gid=%s",
                    mode, opts.socket_dir, opts.socket_dirs, start,
                    start_child, exit_with_children, exit_with_client, uid,
                    gid)
                try:
                    proc, socket_path = start_server_subprocess(
                        sys.argv[0],
                        args,
                        mode,
                        opts,
                        opts.socket_dir,
                        opts.socket_dirs,
                        start,
                        start_child,
                        exit_with_children,
                        exit_with_client,
                        uid=uid,
                        gid=gid)
                    display = "socket:%s" % socket_path
                except Exception as e:
                    log("start_server_subprocess failed", exc_info=True)
                    log.error("Error: failed to start server subprocess:")
                    log.error(" %s", e)
                    disconnect(SERVER_ERROR, "failed to start a new session")
                    return
                if proc:
                    self.child_reaper.add_process(proc, "server-%s" % display,
                                                  "xpra start", True, True)
            else:
                disconnect(SESSION_NOT_FOUND, "no displays found")
                return
        if display is None:
            display = c.strget("display")
            authlog(
                "start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s",
                proxy_virtual_display, display, displays)
            if display == proxy_virtual_display:
                disconnect(SESSION_NOT_FOUND, "invalid display")
                return
            if display:
                if display not in displays:
                    disconnect(SESSION_NOT_FOUND,
                               "display '%s' not found" % display)
                    return
            else:
                if len(displays) != 1:
                    disconnect(
                        SESSION_NOT_FOUND,
                        "please specify a display, more than one is available: %s"
                        % csv(displays))
                    return
                display = displays[0]

        def stop_server_subprocess():
            if proc:
                proc.terminate()

        log("start_proxy(%s, {..}, %s) using server display at: %s",
            client_proto, auth_caps, display)

        def parse_error(*args):
            stop_server_subprocess()
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))

        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        if uid or gid:
            disp_desc["uid"] = uid
            disp_desc["gid"] = gid
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            log.error(" %s", e)
            log.error(" connection definition:")
            print_nested_dict(disp_desc,
                              prefix=" ",
                              lchar="*",
                              pad=20,
                              print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            stop_server_subprocess()
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn(
                    "Warning: received an unexpected packet on the proxy connection %s:",
                    client_proto)
                log.warn(" %s", repr_ellipsized(packet))

        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(
                    client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(
                    5 + self._socket_timeout)
                if not ioe:
                    log.error(
                        "Error: some network IO threads have failed to terminate"
                    )
                    return
                client_conn.set_active(True)
                process = ProxyInstanceProcess(
                    uid, gid, env_options, session_options, self._socket_dir,
                    self.video_encoders, self.csc_modules, client_conn,
                    client_state, cipher, encryption_key, server_conn, c,
                    message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display,
                                              "xpra-proxy-instance", True,
                                              True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")

        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
示例#35
0
    def start_proxy(self, client_proto, c, auth_caps):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)

        #find the target server session:
        if not client_proto.authenticator:
            log.error("Error: the proxy server requires an authentication mode,")
            try:
                log.error(" client connection '%s' does not specify one", client_proto._conn.socktype)
            except:
                pass
            log.error(" use 'none' to disable authentication")
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            authlog("failed to get the list of sessions", exc_info=True)
            authlog.error("Error: failed to get the list of sessions using '%s' authenticator", client_proto.authenticator)
            authlog.error(" %s", e)
            disconnect(AUTHENTICATION_ERROR, "cannot access sessions")
            return
        authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        uid, gid, displays, env_options, session_options = sessions
        if os.name=="posix":
            if uid==0 or gid==0:
                log.error("Error: proxy instances should not run as root")
                log.error(" use a different uid and gid (ie: nobody)")
                disconnect(AUTHENTICATION_ERROR, "cannot run proxy instances as root")
                return
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            if "xpra" not in groups:
                log.error("Error: user '%s' (uid=%i) is not in the xpra group", username, uid)
                log.error(" it belongs to: %s", csv(groups) or None)
                disconnect(PERMISSION_ERROR, "user missing 'xpra' group membership")
                return
        #ensure we don't loop back to the proxy:
        proxy_virtual_display = os.environ.get("DISPLAY")
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        #remove proxy instance virtual displays:
        displays = [x for x in displays if not x.startswith(":proxy-")]
        #log("unused options: %s, %s", env_options, session_options)
        opts = make_defaults_struct()
        display = None
        proc = None
        sns = c.dictget("start-new-session")
        authlog("start_proxy: displays=%s, start-new-session=%s", displays, bool(sns))
        if len(displays)==0 or sns:
            if self._start_sessions:
                #start a new session
                mode = sns.get("mode", "start")
                assert mode in ("start", "start-desktop", "shadow"), "invalid start-new-session mode '%s'" % mode
                sns = typedict(sns)
                display = sns.get("display")
                args = []
                if display:
                    args = [display]
                start = sns.strlistget("start")
                start_child = sns.strlistget("start-child")
                exit_with_children = sns.boolget("exit-with-children")
                exit_with_client = sns.boolget("exit-with-client")
                log("starting new server subprocess: mode=%s, socket-dir=%s, socket-dirs=%s, start=%s, start-child=%s, exit-with-children=%s, exit-with-client=%s, uid=%s, gid=%s",
                    mode, opts.socket_dir, opts.socket_dirs, start, start_child, exit_with_children, exit_with_client, uid, gid)
                try:
                    proc, socket_path = start_server_subprocess(sys.argv[0], args, mode, opts,
                                                                opts.socket_dir, opts.socket_dirs,
                                                                start, start_child,
                                                                exit_with_children, exit_with_client,
                                                                uid=uid, gid=gid)
                    display = "socket:%s" % socket_path
                except Exception as e:
                    log("start_server_subprocess failed", exc_info=True)
                    log.error("Error: failed to start server subprocess:")
                    log.error(" %s", e)
                    disconnect(SERVER_ERROR, "failed to start a new session")
                    return
                if proc:
                    self.child_reaper.add_process(proc, "server-%s" % display, "xpra start", True, True)
            else:
                disconnect(SESSION_NOT_FOUND, "no displays found")
                return
        if display is None:
            display = c.strget("display")
            authlog("start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s", proxy_virtual_display, display, displays)
            if display==proxy_virtual_display:
                disconnect(SESSION_NOT_FOUND, "invalid display")
                return
            if display:
                if display not in displays:
                    disconnect(SESSION_NOT_FOUND, "display '%s' not found" % display)
                    return
            else:
                if len(displays)!=1:
                    disconnect(SESSION_NOT_FOUND, "please specify a display, more than one is available: %s" % csv(displays))
                    return
                display = displays[0]

        def stop_server_subprocess():
            if proc:
                proc.terminate()

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            stop_server_subprocess()
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        if uid or gid:
            disp_desc["uid"] = uid
            disp_desc["gid"] = gid
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            log.error(" %s", e)
            log.error(" connection definition:")
            print_nested_dict(disp_desc, prefix=" ", lchar="*", pad=20, print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            stop_server_subprocess()
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn("Warning: received an unexpected packet on the proxy connection %s:", client_proto)
                log.warn(" %s", repr_ellipsized(packet))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout)
                if not ioe:
                    log.error("Error: some network IO threads have failed to terminate")
                    return
                client_conn.set_active(True)
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display, "xpra-proxy-instance", True, True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
示例#36
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None
        #find the target server session:
        def disconnect(reason, *extras):
            self.send_disconnect(client_proto, reason, *extras)
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            log.error("failed to get the list of sessions: %s", e)
            disconnect(AUTHENTICATION_ERROR)
            return
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        log("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays)==0:
            disconnect(SESSION_NOT_FOUND, "no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display==proxy_virtual_display:
            disconnect(SESSION_NOT_FOUND, "invalid display")
            return
        if display:
            if display not in displays:
                disconnect(SESSION_NOT_FOUND, "display not found")
                return
        else:
            if len(displays)!=1:
                disconnect(SESSION_NOT_FOUND, "please specify a display (more than one available)")
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception as e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e, exc_info=True)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn("received an unexpected packet on the proxy connection: %s", repr_ellipsized(packet))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(0.5+self._socket_timeout)
                if not ioe:
                    log.error("some network IO threads have failed to terminate!")
                    return
                client_conn.set_active(True)
                assert uid!=0 and gid!=0
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
            #FIXME: remove processes that have terminated
        make_thread(do_start_proxy, "start_proxy(%s)" % client_conn).start()
示例#37
0
文件: main.py 项目: rudresh2319/Xpra
def main(script_file, cmdline):
    platform_init()
    if os.name == "posix" and os.getuid() == 0:
        warn("\nWarning: running as root")
    try:
        import glib
        glib.set_prgname("Xpra")
    except:
        pass
    #################################################################
    ## NOTE NOTE NOTE
    ##
    ## If you modify anything here, then remember to update the man page
    ## (xpra.1) as well!
    ##
    ## NOTE NOTE NOTE
    #################################################################
    supports_shadow = SHADOW_SUPPORTED
    supports_server = LOCAL_SERVERS_SUPPORTED
    if supports_server:
        try:
            from xpra.x11.bindings.wait_for_x_server import wait_for_x_server  #@UnresolvedImport @UnusedImport
        except:
            supports_server = False

    command_options = [
        "\t%prog attach [DISPLAY]\n", "\t%prog detach [DISPLAY]\n",
        "\t%prog screenshot filename [DISPLAY]\n", "\t%prog info [DISPLAY]\n",
        "\t%prog version [DISPLAY]\n"
    ]
    server_modes = []
    if supports_server:
        server_modes.append("start")
        server_modes.append("upgrade")
        command_options = [
            "\t%prog start DISPLAY\n",
            "\t%prog stop [DISPLAY]\n",
            "\t%prog list\n",
            "\t%prog upgrade DISPLAY\n",
        ] + command_options
    if supports_shadow:
        server_modes.append("shadow")
        command_options.append("\t%prog shadow DISPLAY\n")
    if not supports_server:
        command_options.append(
            "(This xpra installation does not support starting local servers.)"
        )

    hidden_options = {}
    parser = OptionParser(version="xpra v%s" % XPRA_VERSION,
                          usage="\n" + "".join(command_options))
    defaults = make_defaults_struct()
    if len(server_modes):
        group = OptionGroup(
            parser, "Server Options",
            "These options are only relevant on the server when using the %s mode."
            % "or".join(["'%s'" % x for x in server_modes]))
        parser.add_option_group(group)
    if supports_server:
        group.add_option(
            "--start-child",
            action="append",
            dest="start_child",
            metavar="CMD",
            default=defaults.start_child,
            help=
            "program to spawn in new server (may be repeated) (default: %default)"
        )
        group.add_option(
            "--exit-with-children",
            action="store_true",
            dest="exit_with_children",
            default=defaults.exit_with_children,
            help="Terminate server when --start-child command(s) exit")
    else:
        hidden_options["start_child"] = None
        hidden_options["exit_with_children"] = False
    if (supports_server or supports_shadow) and CAN_DAEMONIZE:
        group.add_option("--no-daemon",
                         action="store_false",
                         dest="daemon",
                         default=True,
                         help="Don't daemonize when running as a server")
        group.add_option(
            "--log-file",
            action="store",
            dest="log_file",
            default=defaults.log_file,
            help=
            "When daemonizing, this is where the log messages will go (default: %s)."
            +
            " If a relative filename is specified the it is relative to --socket-dir,"
            +
            " the value of '$DISPLAY' will be substituted with the actual display used"
        )
    else:
        hidden_options["daemon"] = False
        hidden_options["log_file"] = defaults.log_file
    if supports_server:
        group.add_option(
            "--use-display",
            action="store_true",
            dest="use_display",
            default=defaults.use_display,
            help="Use an existing display rather than starting one with xvfb")
        group.add_option(
            "--xvfb",
            action="store",
            dest="xvfb",
            default=defaults.xvfb,
            metavar="CMD",
            help="How to run the headless X server (default: '%default')")
    else:
        hidden_options["use_display"] = False
        hidden_options["xvfb"] = ''
    if supports_server or supports_shadow:
        group.add_option(
            "--bind-tcp",
            action="append",
            dest="bind_tcp",
            default=defaults.bind_tcp,
            metavar="[HOST]:PORT",
            help=
            "Listen for connections over TCP (use --password-file to secure it)."
            +
            " You may specify this option multiple times with different host and port combinations"
        )
    else:
        hidden_options["bind_tcp"] = []
    if supports_server:
        group.add_option(
            "--no-pulseaudio",
            action="store_false",
            dest="pulseaudio",
            default=defaults.pulseaudio,
            help="Disable starting of a pulseaudio server for the session")
        group.add_option(
            "--pulseaudio-command",
            action="store",
            dest="pulseaudio_command",
            default=defaults.pulseaudio_command,
            help=
            "The command used to start the pulseaudio server (default: '%default')"
        )
    else:
        hidden_options["pulseaudio"] = False
        hidden_options["pulseaudio_command"] = ""

    group = OptionGroup(
        parser, "Server Controlled Features",
        "These options can be used to turn certain features on or off, "
        "they can be specified on the client or on the server, "
        "but the client cannot enable them if they are disabled on the server."
    )
    parser.add_option_group(group)
    group.add_option("--no-clipboard",
                     action="store_false",
                     dest="clipboard",
                     default=defaults.clipboard,
                     help="Disable clipboard support")
    group.add_option("--no-notifications",
                     action="store_false",
                     dest="notifications",
                     default=defaults.notifications,
                     help="Disable forwarding of system notifications")
    group.add_option("--no-system-tray",
                     action="store_false",
                     dest="system_tray",
                     default=defaults.system_tray,
                     help="Disable forwarding of system tray icons")
    group.add_option(
        "--no-cursors",
        action="store_false",
        dest="cursors",
        default=defaults.cursors,
        help="Disable forwarding of custom application mouse cursors")
    group.add_option("--no-bell",
                     action="store_false",
                     dest="bell",
                     default=defaults.bell,
                     help="Disable forwarding of the system bell")
    group.add_option(
        "--no-mmap",
        action="store_false",
        dest="mmap",
        default=defaults.mmap,
        help="Disable memory mapped transfers for local connections")
    group.add_option(
        "--readonly",
        action="store_true",
        dest="readonly",
        default=defaults.readonly,
        help="Ignore all keyboard input and mouse events from the clients")
    group.add_option(
        "--enable-sharing",
        action="store_true",
        dest="sharing",
        default=defaults.sharing,
        help="Allow more than one client to connect to the same session")
    group.add_option(
        "--no-speaker",
        action="store_false",
        dest="speaker",
        default=defaults.speaker,
        help="Disable forwarding of sound output to the client(s)")
    CODEC_HELP = """Specify the codec(s) to use for forwarding the %s sound output.
This parameter can be specified multiple times and the order in which the codecs
are specified defines the preferred codec order.
Use the special value 'help' to get a list of options.
When unspecified, all the available codecs are allowed and the first one is used."""
    group.add_option("--speaker-codec",
                     action="append",
                     dest="speaker_codec",
                     default=defaults.speaker_codec,
                     help=CODEC_HELP % "speaker")
    group.add_option("--no-microphone",
                     action="store_false",
                     dest="microphone",
                     default=defaults.microphone,
                     help="Disable forwarding of sound input to the server")
    group.add_option("--microphone-codec",
                     action="append",
                     dest="microphone_codec",
                     default=defaults.microphone_codec,
                     help=CODEC_HELP % "microphone")

    group = OptionGroup(
        parser, "Client Picture Encoding and Compression Options",
        "These options are used by the client to specify the desired picture and network data compression."
        "They may also be specified on the server as default values for those clients that do not set them."
    )
    parser.add_option_group(group)
    group.add_option(
        "--encoding",
        action="store",
        metavar="ENCODING",
        default=defaults.encoding,
        dest="encoding",
        type="str",
        help=
        "What image compression algorithm to use, specify 'help' to get a list of options."
        " Default: %default.")
    group.add_option(
        "--min-quality",
        action="store",
        metavar="MIN-LEVEL",
        dest="min_quality",
        type="int",
        default=defaults.min_quality,
        help=
        "Sets the minimum encoding quality allowed in automatic quality setting (from 1 to 100, 0 to leave unset). Default: %default."
    )
    group.add_option(
        "--quality",
        action="store",
        metavar="LEVEL",
        dest="quality",
        type="int",
        default=defaults.quality,
        help=
        "Use a fixed image compression quality - only relevant to lossy encodings (1-100, 0 to use automatic setting). Default: %default."
    )
    group.add_option(
        "--min-speed",
        action="store",
        metavar="SPEED",
        dest="min_speed",
        type="int",
        default=defaults.min_speed,
        help=
        "Sets the minimum encoding speed allowed in automatic speed setting (1-100, 0 to leave unset). Default: %default."
    )
    group.add_option(
        "--speed",
        action="store",
        metavar="SPEED",
        dest="speed",
        type="int",
        default=defaults.speed,
        help=
        "Use image compression with the given encoding speed (1-100, 0 to use automatic setting). Default: %default."
    )
    group.add_option(
        "--auto-refresh-delay",
        action="store",
        dest="auto_refresh_delay",
        type="float",
        default=defaults.auto_refresh_delay,
        metavar="DELAY",
        help="Idle delay in seconds before doing an automatic lossless refresh."
        + " 0.0 to disable." + " Default: %default.")
    group.add_option(
        "-z",
        "--compress",
        action="store",
        dest="compression_level",
        type="int",
        default=defaults.compression_level,
        metavar="LEVEL",
        help="How hard to work on compressing data." +
        " You generally do not need to use this option," +
        " the default value should be adequate," +
        " picture data is compressed separately (see --encoding)." +
        " 0 to disable compression," +
        " 9 for maximal (slowest) compression. Default: %default.")

    group = OptionGroup(
        parser, "Client Features Options",
        "These options control client features that affect the appearance or the keyboard."
    )
    parser.add_option_group(group)
    group.add_option(
        "--opengl",
        action="store",
        dest="opengl",
        default=defaults.opengl,
        help=
        "Use OpenGL accelerated rendering, options: yes,no,auto. Default: %s."
        % print_bool("opengl", defaults.opengl))
    group.add_option(
        "--no-windows",
        action="store_false",
        dest="windows",
        default=defaults.windows,
        help=
        "Tells the server not to send any window data, only notifications and bell events will be forwarded (if enabled)."
    )
    group.add_option(
        "--session-name",
        action="store",
        dest="session_name",
        default=defaults.session_name,
        help=
        "The name of this session, which may be used in notifications, menus, etc. Default: Xpra"
    )
    group.add_option(
        "--client-toolkit",
        action="store",
        dest="client_toolkit",
        default=defaults.client_toolkit,
        help=
        "The type of client toolkit. Use the value 'help' to get a list of options. Default: %s"
    )
    group.add_option(
        "--window-layout",
        action="store",
        dest="window_layout",
        default=defaults.window_layout,
        help=
        "The type of window layout to use, each client toolkit may provide different layouts."
        "use the value 'help' to get a list of possible layouts. Default: %s")
    group.add_option(
        "--title",
        action="store",
        dest="title",
        default=defaults.title,
        help=
        "Text which is shown as window title, may use remote metadata variables (default: '%default')"
    )
    group.add_option(
        "--window-icon",
        action="store",
        dest="window_icon",
        default=defaults.window_icon,
        help=
        "Path to the default image which will be used for all windows (the application may override this)"
    )
    # let the platform specific code add its own options:
    # adds "--no-tray" for platforms that support it
    add_client_options(group)
    hidden_options["no_tray"] = False
    hidden_options["delay_tray"] = False
    group.add_option(
        "--tray-icon",
        action="store",
        dest="tray_icon",
        default=defaults.tray_icon,
        help=
        "Path to the image which will be used as icon for the system-tray or dock"
    )
    group.add_option(
        "--key-shortcut",
        action="append",
        dest="key_shortcut",
        type="str",
        default=defaults.key_shortcut,
        help="Define key shortcuts that will trigger specific actions." +
        "If no shortcuts are defined, it defaults to '%s'" %
        (",".join(defaults.key_shortcut or [])))
    group.add_option(
        "--no-keyboard-sync",
        action="store_false",
        dest="keyboard_sync",
        default=defaults.keyboard_sync,
        help=
        "Disable keyboard state synchronization, prevents keys from repeating on high latency links but also may disrupt applications which access the keyboard directly"
    )

    group = OptionGroup(
        parser, "Advanced Options",
        "These options apply to both client and server. Please refer to the man page for details."
    )
    parser.add_option_group(group)
    group.add_option(
        "--password-file",
        action="store",
        dest="password_file",
        default=defaults.password_file,
        help=
        "The file containing the password required to connect (useful to secure TCP mode)"
    )
    group.add_option(
        "--dpi",
        action="store",
        dest="dpi",
        default=defaults.dpi,
        help=
        "The 'dots per inch' value that client applications should try to honour (default: %default)"
    )
    default_socket_dir_str = defaults.socket_dir or "$XPRA_SOCKET_DIR or '~/.xpra'"
    group.add_option(
        "--socket-dir",
        action="store",
        dest="socket_dir",
        default=defaults.socket_dir,
        help="Directory to place/look for the socket files in (default: %s)" %
        default_socket_dir_str)
    debug_default = ""
    if defaults.debug:
        debug_default = "all"
    group.add_option(
        "-d",
        "--debug",
        action="store",
        dest="debug",
        default=debug_default,
        metavar="FILTER1,FILTER2,...",
        help="List of categories to enable debugging for (or \"all\")")
    group.add_option("--ssh",
                     action="store",
                     dest="ssh",
                     default=defaults.ssh,
                     metavar="CMD",
                     help="How to run ssh (default: '%default')")
    group.add_option(
        "--mmap-group",
        action="store_true",
        dest="mmap_group",
        default=defaults.mmap_group,
        help=
        "When creating the mmap file with the client, set the group permission on the mmap file to the same value as the owner of the server socket file we connect to (default: '%default')"
    )
    group.add_option(
        "--enable-pings",
        action="store_true",
        dest="pings",
        default=defaults.pings,
        help="Send ping packets every second to gather latency statistics")
    group.add_option(
        "--clipboard-filter-file",
        action="store",
        dest="clipboard_filter_file",
        default=defaults.clipboard_filter_file,
        help=
        "Name of a file containing regular expressions of clipboard contents that must be filtered out"
    )
    group.add_option(
        "--remote-xpra",
        action="store",
        dest="remote_xpra",
        default=defaults.remote_xpra,
        metavar="CMD",
        help="How to run xpra on the remote host (default: '%default')")
    if len(ENCRYPTION_CIPHERS) > 0:
        group.add_option(
            "--encryption",
            action="store",
            dest="encryption",
            default=defaults.encryption,
            metavar="ALGO",
            help=
            "Specifies the encryption cipher to use, only %s is currently supported. (default: None)"
            % (", ".join(ENCRYPTION_CIPHERS)))
    else:
        hidden_options["encryption"] = ''

    options, args = parser.parse_args(cmdline[1:])
    if not args:
        parser.error("need a mode")

    #ensure all the option fields are set even though
    #some options are not shown to the user:
    for k, v in hidden_options.items():
        if not hasattr(options, k):
            setattr(options, k, v)

    #forward compatibility for correct encoding names:
    if options.encoding == "h264":
        options.encoding = "x264"
    elif options.encoding == "vp8":
        options.encoding = "vpx"
    elif options.encoding == "webp":
        #warn that webp should not be used:
        print("Warning: webp encoding may leak memory!")

    #special handling for URL mode:
    #xpra attach xpra://[mode:]host:port/?param1=value1&param2=value2
    if len(args) == 2 and args[0] == "attach" and args[1].startswith(
            "xpra://"):
        url = args[1]
        from urlparse import urlparse, parse_qs
        up = urlparse(url)
        address = up.netloc
        qpos = url.find("?")
        if qpos > 0:
            params_str = url[qpos + 1:]
            params = parse_qs(params_str, keep_blank_values=True)
            f_params = {}
            #print("params=%s" % str(params))
            for k, v in params.items():
                t = OPTION_TYPES.get(k)
                if t is not None and t != list:
                    v = v[0]
                f_params[k] = v
            v_params = validate_config(f_params)
            for k, v in v_params.items():
                setattr(options, k, v)
        al = address.lower()
        if not al.startswith(":") and not al.startswith(
                "tcp") and not al.startswith("ssh"):
            #assume tcp if not specified
            address = "tcp:%s" % address
        args[1] = address

    try:
        int(options.dpi)
    except Exception, e:
        parser.error("invalid dpi: %s" % e)