xpra icon
Bug tracker and wiki

Ticket #172: 0001-enable-xpra-to-select-display-automaticaly.patch

File 0001-enable-xpra-to-select-display-automaticaly.patch, 33.3 KB (added by Benoit Gschwind, 6 years ago)

patch enabling selection of DISPLAY automaticaly

  • src/xpra/dotxpra.py

    From b8b1e2f2b563edb3661e8b154ac890e95710599d Mon Sep 17 00:00:00 2001
    From: Benoit Gschwind <gschwind@gnu-log.net>
    Date: Sat, 24 May 2014 14:06:15 +0200
    Subject: [PATCH] enable xpra to select display automaticaly
    
     the patch include :
      * selecting display automaticaly (drop old method)
      * refactor display_name/display to session_id when necessary
      * refactor display_name to session_string when necessary
    ---
     src/xpra/dotxpra.py             |  37 +++++----
     src/xpra/scripts/main.py        | 172 ++++++++++++++++++++++------------------
     src/xpra/scripts/server.py      |  82 +++++++++++--------
     src/xpra/server/proxy_server.py |  17 ++--
     src/xpra/util.py                |  16 ++++
     5 files changed, 182 insertions(+), 142 deletions(-)
    
    diff --git a/src/xpra/dotxpra.py b/src/xpra/dotxpra.py
    index 6d8347c..ec2cae5 100644
    a b import errno 
    1111import stat
    1212import time
    1313import sys
     14import re
    1415
    1516o0700 = 448     #0o700
    1617
    class DotXpra(object): 
    4344    def confdir(self):
    4445        return self._confdir
    4546
    46     def normalize_local_display_name(self, local_display_name):
    47         if not local_display_name.startswith(":"):
    48             local_display_name = ":" + local_display_name
    49         if "." in local_display_name:
    50             local_display_name = local_display_name[:local_display_name.rindex(".")]
    51         assert local_display_name.startswith(":")
    52         for char in local_display_name[1:]:
    53             assert char in "0123456789", "invalid character in display name: %s" % char
    54         return local_display_name
     47    def normalize_local_session_id(self, local_session_string):
     48        assert re.match("^[1234567890]+$", local_session_string)
     49        return local_session_string
    5550
    5651    def norm_make_path(self, name, dirpath):
    5752        return os.path.join(dirpath, self._prefix + name)
    5853
    59     def socket_path(self, local_display_name):
    60         return self.norm_make_path(local_display_name[1:], self._sockdir)
     54    def socket_path(self, local_session_id):
     55        return self.norm_make_path(local_session_id, self._sockdir)
    6156
    62     def log_path(self, local_display_name):
    63         return self.norm_make_path(local_display_name[1:], self._confdir)
     57    def log_path(self, local_session_id):
     58        return self.norm_make_path("%s.log" % str(local_session_id), self._confdir)
     59
     60    def metadata_path(self, local_session_id):
     61        return self.norm_make_path("%s.display" % str(local_session_id), self._confdir)
    6462
    6563    LIVE = "LIVE"
    6664    DEAD = "DEAD"
    class DotXpra(object): 
    8987        return self.UNKNOWN
    9088
    9189    # Same as socket_path, but preps for the server:
    92     def server_socket_path(self, local_display_name, clobber, wait_for_unknown=0):
    93         socket_path = self.socket_path(local_display_name)
     90    def server_socket_path(self, local_session_id, clobber, wait_for_unknown=0):
     91        socket_path = self.socket_path(local_session_id)
     92        print socket_path
    9493        if not clobber:
    95             state = self.server_state(local_display_name)
     94            state = self.server_state(local_session_id)
    9695            counter = 0
    9796            while state==self.UNKNOWN and counter<wait_for_unknown:
    9897                if counter==0:
    class DotXpra(object): 
    101100                sys.stdout.flush()
    102101                counter += 1
    103102                time.sleep(1)
    104                 state = self.server_state(local_display_name)
     103                state = self.server_state(local_session_id)
    105104            if counter>0:
    106105                sys.stdout.write("\n")
    107106                sys.stdout.flush()
    108107            if state not in (self.DEAD, self.UNKNOWN):
    109                 raise ServerSockInUse((state, local_display_name))
     108                raise ServerSockInUse((state, local_session_id))
    110109        if os.path.exists(socket_path):
    111110            os.unlink(socket_path)
    112111        return socket_path
    class DotXpra(object): 
    123122                        #socket uid does not match
    124123                        continue
    125124                state = self.get_server_state(path)
    126                 local_display = ":"+path[len(base):]
     125                local_display = path[len(base):]
    127126                results.append((state, local_display))
    128127        return results
  • src/xpra/scripts/main.py

    diff --git a/src/xpra/scripts/main.py b/src/xpra/scripts/main.py
    index fb393ea..0056e3d 100644
    a b import logging 
    1515from subprocess import Popen, PIPE
    1616import signal
    1717import shlex
     18import re
     19
     20from xpra.util import load_display_name
    1821
    1922from xpra import __version__ as XPRA_VERSION
    2023from xpra.dotxpra import DotXpra, osexpand
    def run_mode(script_file, parser, options, args, mode): 
    636639        return 128+signal.SIGINT
    637640
    638641
    639 def parse_display_name(error_cb, opts, display_name):
    640     desc = {"display_name" : display_name}
    641     if display_name.lower().startswith("ssh:") or display_name.lower().startswith("ssh/"):
    642         separator = display_name[3] # ":" or "/"
     642def parse_session_string(error_cb, opts, session_string):
     643    desc = {"session_string" : session_string}
     644    if session_string.lower().startswith("ssh:") or session_string.lower().startswith("ssh/"):
     645        separator = session_string[3] # ":" or "/"
    643646        desc["type"] = "ssh"
    644647        desc["proxy_command"] = ["_proxy"]
    645648        desc["local"] = False
    646649        desc["exit_ssh"] = opts.exit_ssh
    647         parts = display_name.split(separator)
     650        parts = session_string.split(separator)
    648651        if len(parts)>2:
    649             #ssh:HOST:DISPLAY or ssh/HOST/DISPLAY
     652            #ssh:HOST:ID or ssh/HOST/ID
    650653            host = separator.join(parts[1:-1])
    651             display = ":" + parts[-1]
    652             desc["display"] = display
    653             opts.display = display
    654             desc["display_as_args"] = [display]
     654            session_id = parts[-1]
     655            desc["session_id"] = session_id
     656            opts.session_id = session_id
     657            desc["display_as_args"] = [session_id]
    655658        else:
    656659            #ssh:HOST or ssh/HOST
    657660            host = parts[1]
    658             desc["display"] = None
     661            desc["session_id"] = None
    659662            desc["display_as_args"] = []
    660663        #ie: ssh=["/usr/bin/ssh", "-v"]
    661664        ssh = shlex.split(opts.ssh)
    def parse_display_name(error_cb, opts, display_name): 
    719722            except Exception, e:
    720723                print("failed to read password file %s: %s", opts.password_file, e)
    721724        return desc
    722     elif display_name.startswith(":"):
    723         desc["type"] = "unix-domain"
    724         desc["local"] = True
    725         desc["display"] = display_name
    726         opts.display = display_name
    727         desc["socket_dir"] = osexpand(opts.socket_dir or get_default_socket_dir(), opts.username)
    728         return desc
    729     elif display_name.startswith("tcp:") or display_name.startswith("tcp/"):
    730         separator = display_name[3] # ":" or "/"
     725    elif session_string.startswith("tcp:") or session_string.startswith("tcp/"):
     726        separator = session_string[3] # ":" or "/"
    731727        desc["type"] = "tcp"
    732728        desc["local"] = False
    733         parts = display_name.split(separator)
     729        parts = session_string.split(separator)
    734730        if len(parts) not in (3, 4):
    735             error_cb("invalid tcp connection string, use tcp/[username@]host/port[/display] or tcp:[username@]host:port[:display]")
     731            error_cb("invalid tcp connection string, use tcp/[username@]host/port[/session_id] or tcp:[username@]host:port[:session_id]")
    736732        #display (optional):
    737733        if len(parts)==4:
    738             display = parts[3]
    739             if display:
     734            session_id = parts[3]
     735            if session_id:
    740736                try:
    741                     v = int(display)
    742                     display = ":%s" % v
     737                    v = int(session_id)
     738                    session_id = "%s" % v
    743739                except:
    744740                    pass
    745                 desc["display"] = display
    746                 opts.display = display
     741                desc["session_id"] = session_id
     742                opts.session_id = session_id
    747743        #port:
    748744        port = parts[2]
    749745        try:
    def parse_display_name(error_cb, opts, display_name): 
    764760            host = "127.0.0.1"
    765761        desc["host"] = host
    766762        return desc
     763    elif re.match('^[1234567890]+$', session_string):
     764        desc["type"] = "unix-domain"
     765        desc["local"] = True
     766        desc["session_id"] = session_string
     767        opts.session_id = session_string
     768        desc["socket_dir"] = osexpand(opts.socket_dir or get_default_socket_dir(), opts.username)
     769        return desc
    767770    else:
    768         error_cb("unknown format for display name: %s" % display_name)
     771        error_cb("unknown format for session string: %s" % session_string)
    769772
    770 def pick_display(parser, opts, extra_args):
     773def pick_session(parser, opts, extra_args):
    771774    if len(extra_args) == 0:
    772775        # Pick a default server
    773776        sockdir = DotXpra(opts.socket_dir or get_default_socket_dir())
    774777        servers = sockdir.sockets()
    775778        live_servers = [display
    776779                        for (state, display) in servers
    777                         if state is DotXpra.LIVE]
     780                        if state is DotXpra.LIVE and re.match("[1234567890]+", display)]
    778781        if len(live_servers) == 0:
    779782            if not LOCAL_SERVERS_SUPPORTED:
    780783                parser.error("this installation does not support local servers, you must specify a remote display")
    781784            parser.error("cannot find a live server to connect to")
    782785        elif len(live_servers) == 1:
    783             return parse_display_name(parser.error, opts, live_servers[0])
     786            return parse_session_string(parser.error, opts, live_servers[0])
    784787        else:
    785788            parser.error("there are multiple servers running, please specify")
    786789    elif len(extra_args) == 1:
    787         return parse_display_name(parser.error, opts, extra_args[0])
     790        return parse_session_string(parser.error, opts, extra_args[0])
    788791    else:
    789792        parser.error("too many arguments")
    790793
    def _socket_connect(sock, endpoint, description, dtype): 
    793796    sock.settimeout(None)
    794797    return SocketConnection(sock, sock.getsockname(), sock.getpeername(), description, dtype)
    795798
    796 def connect_or_fail(display_desc):
     799def connect_or_fail(session_desc):
    797800    try:
    798         return connect_to(display_desc)
     801        print "try connection to", session_desc
     802        return connect_to(session_desc)
    799803    except Exception, e:
    800804        sys.exit("connection failed: %s" % e)
    801805
    def ssh_connect_failed(message): 
    805809    from xpra.gtk_common.quit import gtk_main_quit_really
    806810    gtk_main_quit_really()
    807811
    808 def connect_to(display_desc, debug_cb=None, ssh_fail_cb=ssh_connect_failed):
    809     display_name = display_desc["display_name"]
    810     dtype = display_desc["type"]
     812def connect_to(session_desc, debug_cb=None, ssh_fail_cb=ssh_connect_failed):
     813    if session_desc.has_key("session_id"):
     814        session_id = session_desc["session_id"]
     815    else:
     816        session_id = None
     817    dtype = session_desc["type"]
    811818    conn = None
    812819    if dtype == "ssh":
    813         cmd = display_desc["full_ssh"]
    814         cmd += display_desc["remote_xpra"] + display_desc["proxy_command"] + display_desc["display_as_args"]
     820        cmd = session_desc["full_ssh"]
     821        cmd += session_desc["remote_xpra"] + session_desc["proxy_command"] + session_desc["display_as_args"]
    815822        try:
    816823            kwargs = {}
    817824            kwargs["stderr"] = sys.stderr
    818             if not display_desc.get("exit_ssh", False) and os.name=="posix" and not sys.platform.startswith("darwin"):
     825            if not session_desc.get("exit_ssh", False) and os.name=="posix" and not sys.platform.startswith("darwin"):
    819826                def setsid():
    820827                    #run in a new session
    821828                    os.setsid()
    def connect_to(display_desc, debug_cb=None, ssh_fail_cb=ssh_connect_failed): 
    835842            """ if ssh dies, we don't need to try to read/write from its sockets """
    836843            e = child.poll()
    837844            if e is not None:
    838                 error_message = "cannot %s using %s: the SSH process has terminated with exit code=%s" % (action, display_desc["full_ssh"], e)
     845                error_message = "cannot %s using %s: the SSH process has terminated with exit code=%s" % (action, session_desc["full_ssh"], e)
    839846                if debug_cb:
    840847                    debug_cb(error_message)
    841848                if ssh_fail_cb:
    842849                    ssh_fail_cb(error_message)
    843                 if "ssh_abort" not in display_desc:
    844                     display_desc["ssh_abort"] = True
     850                if "ssh_abort" not in session_desc:
     851                    session_desc["ssh_abort"] = True
    845852                    from xpra.log import Logger
    846853                    log = Logger()
    847854                    log.error("The SSH process has terminated with exit code %s", e)
    848855                    if conn.input_bytecount==0 and conn.output_bytecount==0:
    849                         log.error("Connection to the xpra server via SSH failed for: %s", display_name)
     856                        log.error("Connection to the xpra server via SSH failed for: %s", session_id)
    850857                        log.error(" the command line used was: %s", cmd)
    851858                        log.error(" check your username, hostname, display number, etc")
    852859                raise ConnectionClosedException(error_message)
    def connect_to(display_desc, debug_cb=None, ssh_fail_cb=ssh_connect_failed): 
    863870                            fd.close()
    864871                    except Exception, e:
    865872                        print("error closing ssh tunnel %s: %s" % (name, e))
    866                 if not display_desc.get("exit_ssh", False):
     873                if not session_desc.get("exit_ssh", False):
    867874                    #leave it running
    868875                    return
    869876            try:
    def connect_to(display_desc, debug_cb=None, ssh_fail_cb=ssh_connect_failed): 
    877884                        raise Exception("cannot find function to kill subprocess")
    878885            except Exception, e:
    879886                print("error trying to stop ssh tunnel process: %s" % e)
    880         conn = TwoFileConnection(child.stdin, child.stdout, abort_test, target=display_name, info=dtype, close_cb=stop_tunnel)
     887        conn = TwoFileConnection(child.stdin, child.stdout, abort_test, target=session_id, info=dtype, close_cb=stop_tunnel)
    881888
    882889    elif dtype == "unix-domain":
    883890        if not hasattr(socket, "AF_UNIX"):
    884891            return False, "unix domain sockets are not available on this operating system"
    885         sockdir = DotXpra(display_desc["socket_dir"])
     892        sockdir = DotXpra(session_desc["socket_dir"])
    886893        sock = socket.socket(socket.AF_UNIX)
    887894        sock.settimeout(SOCKET_TIMEOUT)
    888         sockfile = sockdir.socket_path(display_desc["display"])
    889         conn = _socket_connect(sock, sockfile, display_name, dtype)
     895        sockfile = sockdir.socket_path(session_desc["session_id"])
     896        conn = _socket_connect(sock, sockfile, session_id, dtype)
    890897
    891898    elif dtype == "tcp":
    892899        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    893900        sock.settimeout(SOCKET_TIMEOUT)
    894901        sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, TCP_NODELAY)
    895         tcp_endpoint = (display_desc["host"], display_desc["port"])
    896         conn = _socket_connect(sock, tcp_endpoint, display_name, dtype)
     902        tcp_endpoint = (session_desc["host"], session_desc["port"])
     903        conn = _socket_connect(sock, tcp_endpoint, session_id, dtype)
    897904
    898905    else:
    899906        assert False, "unsupported display type in connect: %s" % dtype
    def run_client(parser, opts, extra_args, mode): 
    913920        parser.error("Quality must be between 0 and 100 inclusive. (or -1 to disable)")
    914921
    915922    def connect():
    916         return connect_or_fail(pick_display(parser, opts, extra_args))
     923        return connect_or_fail(pick_session(parser, opts, extra_args))
    917924
    918925    if mode=="screenshot":
    919926        from xpra.client.gobject_client_base import ScreenshotXpraClient
    def do_run_client(app): 
    10181025
    10191026def run_remote_server(parser, opts, args, mode):
    10201027    """ Uses the regular XpraClient with patched proxy arguments to tell run_proxy to start the server """
    1021     params = parse_display_name(parser.error, opts, args[0])
     1028    params = parse_session_string(parser.error, opts, args[0])
    10221029    #add special flags to "display_as_args"
    10231030    proxy_args = []
    10241031    if params["display"] is not None:
    def run_proxy(parser, opts, script_file, args, mode): 
    10911098        if mode=="_proxy_start":
    10921099            cmd.append("start")
    10931100            assert len(args)==1, "proxy/shadow-start: expected 1 argument but got %s" % len(args)
    1094             display_name = args[0]
     1101            session_id = args[0]
    10951102        else:
    10961103            assert mode=="_shadow_start"
    10971104            cmd.append("shadow")
    1098             if len(args)==1:
    1099                 #display_name was provided:
    1100                 display_name = args[0]
     1105            if len(args)==0:
     1106                session_id = str(os.getpid())
     1107            elif len(args)==1:
     1108                #session_id was provided:
     1109                session_id = args[0]
    11011110            else:
    1102                 display_name = guess_X11_display()
     1111                session_id = guess_X11_display()
    11031112        cmd += args
    11041113        if opts.start_child and len(opts.start_child)>0:
    11051114            for x in opts.start_child:
    def run_proxy(parser, opts, script_file, args, mode): 
    11101119            cmd.append("--exit-with-client")
    11111120        def setsid():
    11121121            os.setsid()
     1122        print cmd
    11131123        proc = Popen(cmd, preexec_fn=setsid, shell=False, close_fds=True)
    11141124        dotxpra = DotXpra()
    11151125        start = time.time()
    1116         while dotxpra.server_state(display_name, 1)!=DotXpra.LIVE:
     1126        while dotxpra.server_state(session_id, 1)!=DotXpra.LIVE:
    11171127            if time.time()-start>5:
    11181128                warn("server failed to start after %.1f seconds - sorry!" % (time.time()-start))
    11191129                return
    def run_proxy(parser, opts, script_file, args, mode): 
    11241134            proc.wait()
    11251135        from xpra.daemon_thread import make_daemon_thread
    11261136        make_daemon_thread(reaper, "server-startup-reaper").start()
    1127     server_conn = connect_or_fail(pick_display(parser, opts, args))
     1137    print args
     1138    server_conn = connect_or_fail(pick_session(parser, opts, args))
    11281139    app = XpraProxy(TwoFileConnection(sys.stdout, sys.stdin, info="stdin/stdout"), server_conn)
    11291140    signal.signal(signal.SIGINT, app.quit)
    11301141    signal.signal(signal.SIGTERM, app.quit)
    def run_stopexit(mode, parser, opts, extra_args): 
    11531164            assert False, "invalid state: %s" % final_state
    11541165            return 1
    11551166
    1156     display_desc = pick_display(parser, opts, extra_args)
    1157     conn = connect_or_fail(display_desc)
     1167    session_desc = pick_session(parser, opts, extra_args)
     1168    conn = connect_or_fail(session_desc)
    11581169    e = 1
    11591170    try:
    11601171        if mode=="stop":
    def run_stopexit(mode, parser, opts, extra_args): 
    11681179        e = app.run()
    11691180    finally:
    11701181        app.cleanup()
    1171     if display_desc["local"]:
    1172         show_final_state(display_desc["display"])
     1182    if session_desc["local"]:
     1183        show_final_state(session_desc["session_id"])
    11731184    else:
    11741185        print("Sent shutdown command")
    11751186    return  e
    11761187
    11771188
    1178 def may_cleanup_socket(sockdir, state, display, clean_states=[DotXpra.DEAD]):
    1179     sys.stdout.write("\t%s session at %s" % (state, display))
     1189def may_cleanup_socket(sockdir, state, session_id, clean_states=[DotXpra.DEAD]):
     1190    display = load_display_name(sockdir, session_id)
     1191    sys.stdout.write("\t%s session at %s(%s)" % (state, session_id, display))
    11801192    if state in clean_states:
    11811193        try:
    1182             os.unlink(sockdir.socket_path(display))
     1194            os.unlink(sockdir.socket_path(session_id))
     1195            os.unlink(sockdir.metadata_path(session_id))
    11831196        except OSError:
    11841197            pass
    11851198        else:
    def run_list(parser, opts, extra_args): 
    11961209        sys.stdout.write("No xpra sessions found\n")
    11971210        return  1
    11981211    sys.stdout.write("Found the following xpra sessions:\n")
    1199     for state, display in results:
    1200         may_cleanup_socket(sockdir, state, display)
     1212    for state, session_id in results:
     1213        may_cleanup_socket(sockdir, state, session_id)
    12011214    #now, re-probe the "unknown" ones:
    1202     unknown = [display for state, display in results if state==DotXpra.UNKNOWN]
     1215    unknown = [session_id for state, session_id in results if state==DotXpra.UNKNOWN]
    12031216    if len(unknown)>0:
    12041217        sys.stdout.write("Re-probing unknown sessions: %s\n" % (", ".join(unknown)))
    12051218    counter = 0
    def run_list(parser, opts, extra_args): 
    12081221        counter += 1
    12091222        probe_list = list(unknown)
    12101223        unknown = []
    1211         for display in probe_list:
    1212             state = sockdir.server_state(display)
     1224        for session_id in probe_list:
     1225            state = sockdir.server_state(session_id)
    12131226            if state is DotXpra.DEAD:
    1214                 may_cleanup_socket(sockdir, state, display)
     1227                may_cleanup_socket(sockdir, state, session_id)
    12151228            elif state is DotXpra.UNKNOWN:
    1216                 unknown.append(display)
     1229                unknown.append(session_id)
    12171230            else:
    1218                 sys.stdout.write("\t%s session at %s\n" % (state, display))
     1231                display = load_display_name(sockdir, session_id)
     1232                sys.stdout.write("\t%s session at %s(%s)\n" % (state, session_id, display))
    12191233    #now cleanup those still unknown:
    12201234    clean_states = [DotXpra.DEAD, DotXpra.UNKNOWN]
    1221     for display in unknown:
    1222         state = sockdir.server_state(display)
    1223         may_cleanup_socket(sockdir, state, display, clean_states=clean_states)
     1235    for session_id in unknown:
     1236        state = sockdir.server_state(session_id)
     1237        may_cleanup_socket(sockdir, state, session_id, clean_states=clean_states)
    12241238    return 0
    12251239
    12261240
  • src/xpra/scripts/server.py

    diff --git a/src/xpra/scripts/server.py b/src/xpra/scripts/server.py
    index 9649ee1..acbb0ca 100644
    a b import atexit 
    1717import signal
    1818import socket
    1919import getpass
     20import select
     21
     22from xpra.util import save_display_name, load_display_name
    2023
    2124from xpra.scripts.main import TCP_NODELAY
    2225from xpra.dotxpra import DotXpra, ServerSockInUse
    def parse_bind_tcp(bind_tcp): 
    322325    return tcp_sockets
    323326
    324327
    325 def setup_local_socket(dotxpra, display_name, clobber, mmap_group):
     328def setup_local_socket(dotxpra, session_id, clobber, mmap_group):
    326329    if sys.platform.startswith("win"):
    327330        return None, None
    328331    from xpra.log import Logger
    329332    log = Logger("network")
    330333    #print("creating server socket %s" % sockpath)
    331334    try:
    332         display_name = dotxpra.normalize_local_display_name(display_name)
    333         sockpath = dotxpra.server_socket_path(display_name, clobber, wait_for_unknown=5)
     335        display_name = dotxpra.normalize_local_session_id(session_id)
     336        sockpath = dotxpra.server_socket_path(session_id, clobber, wait_for_unknown=5)
    334337    except ServerSockInUse:
    335         raise Exception("You already have an xpra server running at %s\n"
     338        raise Exception("You already have an xpra server running with session_id %s\n"
    336339                     "  (did you want 'xpra upgrade'?)"
    337                      % (display_name,))
     340                     % (session_id,))
    338341    except Exception, e:
    339342        raise Exception("socket path error: %s" % e)
    340343    sock = create_unix_domain_socket(sockpath, mmap_group)
    def close_all_fds(exceptions=[]): 
    363366            return
    364367    print("Uh-oh, can't close fds, please port me to your system...")
    365368
    366 def open_log_file(dotxpra, log_file, display_name):
     369def open_log_file(dotxpra, log_file, session_id):
    367370    if log_file:
    368371        if os.path.isabs(log_file):
    369372            logpath = log_file
    370373        else:
    371374            logpath = os.path.join(dotxpra.sockdir(), log_file)
    372         logpath = logpath.replace("$DISPLAY", display_name)
     375        logpath = logpath.replace("$DISPLAY", session_id)
    373376    else:
    374         logpath = dotxpra.log_path(display_name) + ".log"
     377        logpath = dotxpra.log_path(session_id)
     378    print "YYYY"
    375379    sys.stderr.write("Entering daemon mode; "
    376380                     + "any further errors will be reported to:\n"
    377381                     + ("  %s\n" % logpath))
    def start_pulseaudio(child_reaper, pulseaudio_command): 
    453457    _cleanups.append(cleanup_pa)
    454458
    455459
    456 def start_Xvfb(xvfb_str, display_name):
     460def start_Xvfb(xvfb_str, session_id):
    457461    # We need to set up a new server environment
    458462    xauthority = os.environ.get("XAUTHORITY", os.path.expanduser("~/.Xauthority"))
    459463    if not os.path.exists(xauthority):
    def start_Xvfb(xvfb_str, display_name): 
    464468            sys.stderr.write("Error trying to create XAUTHORITY file %s: %s\n" % (xauthority, e))
    465469    subs = {"XAUTHORITY"    : xauthority,
    466470            "USER"          : os.environ.get("USER", "unknown-user"),
    467             "HOME"          : os.environ.get("HOME", os.getcwd()),
    468             "DISPLAY"       : display_name}
     471            "HOME"          : os.environ.get("HOME", os.getcwd())}
    469472    for var,value in subs.items():
    470473        xvfb_str = xvfb_str.replace("$%s" % var, value)
    471474        xvfb_str = xvfb_str.replace("${%s}" % var, value)
    472     xvfb_cmd = xvfb_str.split()+[display_name]
    473     xvfb_executable = xvfb_cmd[0]
    474     xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name)
     475
    475476    def setsid():
    476477        #run in a new session
    477478        if os.name=="posix":
    478479            os.setsid()
    479     xvfb = subprocess.Popen(xvfb_cmd, executable=xvfb_executable, close_fds=True,
    480                                 stdin=subprocess.PIPE, preexec_fn=setsid)
     480
     481    # allocate display automaticaly
     482    r_pipe, w_pipe = os.pipe()
     483    xvfb_cmd = xvfb_str.split()+["-displayfd", str(w_pipe)]
     484    xvfb_executable = xvfb_cmd[0]
     485    xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, str(session_id))
     486    xvfb = subprocess.Popen(xvfb_cmd, executable=xvfb_executable, close_fds=False,
     487                            stdin=subprocess.PIPE, preexec_fn=setsid)
     488    # Wait to get display number from Xvfb
     489    buf = ""
     490    while True:
     491     select.select([r_pipe], [], [])
     492     buf += os.read(r_pipe, 256)
     493     # TODO: add time out to avoid infite blocking.
     494     if buf[-1] == '\n':
     495      break
     496    display_name = ":" + buf[:-1]
     497    sys.stdout.write("Dynamicaly openned display = %s\n" % display_name)
    481498    from xpra.os_util import get_hex_uuid
    482499    xauth_cmd = ["xauth", "add", display_name, "MIT-MAGIC-COOKIE-1", get_hex_uuid()]
    483500    try:
    def start_Xvfb(xvfb_str, display_name): 
    487504    except OSError, e:
    488505        #trying to continue anyway!
    489506        sys.stderr.write("Error running \"%s\": %s\n" % (" ".join(xauth_cmd), e))
    490     return xvfb
     507    return xvfb, display_name
    491508
    492509def check_xvfb_process(xvfb=None):
    493510    if xvfb is None:
    def run_server(parser, opts, mode, xpra_file, extra_args): 
    617634    proxying  = mode == "proxy"
    618635    clobber   = upgrading or opts.use_display
    619636
     637    dotxpra = DotXpra(opts.socket_dir)
     638
    620639    #get the display name:
    621640    if shadowing and len(extra_args)==0:
    622641        from xpra.scripts.main import guess_X11_display
    623642        display_name = guess_X11_display()
    624643    else:
    625         if len(extra_args) != 1:
    626             parser.error("need exactly 1 extra argument")
    627         display_name = extra_args.pop(0)
    628 
    629     if not shadowing and not proxying:
    630         display_name_check(display_name)
     644        if len(extra_args) > 0:
     645            parser.error("do not need extra arguments")
     646        display_name = None
     647        session_id = str(os.getpid())
    631648
    632649    if not shadowing and not proxying and opts.exit_with_children and not opts.start_child:
    633650        sys.stderr.write("--exit-with-children specified without any children to spawn; exiting immediately")
    def run_server(parser, opts, mode, xpra_file, extra_args): 
    638655    signal.signal(signal.SIGINT, deadly_signal)
    639656    signal.signal(signal.SIGTERM, deadly_signal)
    640657
    641     dotxpra = DotXpra(opts.socket_dir)
    642 
    643658    # Generate the script text now, because os.getcwd() will
    644659    # change if/when we daemonize:
    645660    script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir)
    def run_server(parser, opts, mode, xpra_file, extra_args): 
    650665        if opts.password_file:
    651666            opts.password_file = os.path.abspath(opts.password_file)
    652667
    653         logfd = open_log_file(dotxpra, opts.log_file, display_name)
     668        logfd = open_log_file(dotxpra, opts.log_file, session_id)
    654669        assert logfd > 2
    655670        daemonize(logfd)
    656671
    def run_server(parser, opts, mode, xpra_file, extra_args): 
    668683        bind_tcp = parse_bind_tcp(opts.bind_tcp)
    669684
    670685        sockets = []
    671         mdns_info = {"display" : display_name,
     686        mdns_info = {"session_id" : session_id,
    672687                     "username": getpass.getuser()}
    673688        if opts.session_name:
    674689            mdns_info["session"] = opts.session_name
    def run_server(parser, opts, mode, xpra_file, extra_args): 
    677692            socket = setup_tcp_socket(host, iport)
    678693            sockets.append(socket)
    679694        #unix:
    680         socket, cleanup_socket = setup_local_socket(dotxpra, display_name, clobber, opts.mmap_group)
     695        socket, cleanup_socket = setup_local_socket(dotxpra, session_id, clobber, opts.mmap_group)
    681696        if socket:      #win32 returns None!
    682697            sockets.append(socket)
    683698            if opts.mdns:
    684699                ssh_port = get_ssh_port()
    685700                if ssh_port:
    686                     mdns_publish(display_name, "ssh", [("", ssh_port)], mdns_info)
     701                    mdns_publish(session_id, "ssh", [("", ssh_port)], mdns_info)
    687702        if opts.mdns:
    688             mdns_publish(display_name, "tcp", bind_tcp, mdns_info)
     703            mdns_publish(session_id, "tcp", bind_tcp, mdns_info)
    689704    except Exception, e:
    690705        log.error("cannot start server: failed to setup sockets: %s", e)
    691706        return 1
    692707
    693708    # Do this after writing out the shell script:
    694     os.environ["DISPLAY"] = display_name
    695709    sanitize_env()
    696710
    697711    xvfb = None
    698712    xvfb_pid = None
    699713    if not shadowing and not proxying and not clobber:
    700714        try:
    701             xvfb = start_Xvfb(opts.xvfb, display_name)
     715            xvfb, display_name = start_Xvfb(opts.xvfb, session_id)
    702716        except OSError, e:
    703717            log.error("Error starting Xvfb: %s\n", e)
    704718            return  1
    705719        xvfb_pid = xvfb.pid
     720        display_name_check(display_name)
     721        save_display_name(dotxpra, session_id, display_name)
     722        # now the display it set to valid value
     723        os.environ["DISPLAY"] = display_name
    706724
    707725    if not check_xvfb_process(xvfb):
    708726        #xvfb problem: exit now
  • src/xpra/server/proxy_server.py

    diff --git a/src/xpra/server/proxy_server.py b/src/xpra/server/proxy_server.py
    index 2ed221a..96304c5 100644
    a b log = Logger("proxy") 
    1818from xpra.server.proxy_instance_process import ProxyInstanceProcess
    1919from xpra.server.server_core import ServerCore
    2020from xpra.scripts.config import make_defaults_struct
    21 from xpra.scripts.main import parse_display_name, connect_to
     21from xpra.scripts.main import parse_session_string, connect_to
    2222from xpra.daemon_thread import make_daemon_thread
    2323
    2424
    class ProxyServer(ServerCore): 
    154154            disconnect("no displays found")
    155155            return
    156156        display = c.strget("display")
    157         proxy_virtual_display = os.environ["DISPLAY"]
    158         #ensure we don't loop back to the proxy:
    159         if proxy_virtual_display in displays:
    160             displays.remove(proxy_virtual_display)
    161         if display==proxy_virtual_display:
    162             disconnect("invalid display")
    163             return
    164157        if display:
    165158            if display not in displays:
    166159                disconnect("display not found")
    class ProxyServer(ServerCore): 
    178171            raise Exception("parse error on %s: %s" % (display, args))
    179172        opts = make_defaults_struct()
    180173        opts.username = client_proto.authenticator.username
    181         disp_desc = parse_display_name(parse_error, opts, display)
    182         log("display description(%s) = %s", display, disp_desc)
     174        session_desc = parse_session_string(parse_error, opts, display)
     175        log("display description(%s) = %s", display, session_desc)
    183176        try:
    184             server_conn = connect_to(disp_desc)
     177            server_conn = connect_to(session_desc)
    185178        except Exception, e:
    186             log.error("cannot start proxy connection to %s: %s", disp_desc, e, exc_info=True)
     179            log.error("cannot start proxy connection to %s: %s", session_desc, e, exc_info=True)
    187180            disconnect("failed to connect to display")
    188181            return
    189182        log("server connection=%s", server_conn)
  • src/xpra/util.py

    diff --git a/src/xpra/util.py b/src/xpra/util.py
    index d505cd5..b025c56 100644
    a b def detect_leaks(log, detailed=[]): 
    271271        return True
    272272    return print_leaks
    273273
     274def save_display_name(dotxpra, session_id, display_name):
     275    display_name_path = dotxpra.metadata_path(session_id)
     276    f = open(display_name_path, "w")
     277    f.write(display_name)
     278    f.close()
     279
     280def load_display_name(dotxpra, session_id):
     281    try:
     282        display_name_path = dotxpra.metadata_path(session_id)
     283        f = open(display_name_path, "r")
     284        display_name = f.read()
     285        f.close()
     286        return display_name
     287    except:
     288        return None
     289        pass       
    274290
    275291def pver(v):
    276292    #print for lists with version numbers, or CSV strings