Example #1
0
    def run(self):
        debug("ProxyProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(),
              os.getuid(), os.getgid())
        #change uid and gid:
        if os.getgid() != self.gid:
            os.setgid(self.gid)
        if os.getuid() != self.uid:
            os.setuid(self.uid)
        debug("ProxyProcess.run() new uid=%s, gid=%s", os.getuid(),
              os.getgid())

        if self.env_options:
            #TODO: whitelist env update?
            os.environ.update(self.env_options)

        log.info("new proxy started for client %s and server %s",
                 self.client_conn, self.server_conn)

        if not USE_THREADING:
            signal.signal(signal.SIGTERM, self.signal_quit)
            signal.signal(signal.SIGINT, self.signal_quit)
            debug("registered signal handler %s", self.signal_quit)

        make_daemon_thread(self.server_message_queue,
                           "server message queue").start()

        self.main_queue = Queue()
        #setup protocol wrappers:
        self.server_packets = Queue(PROXY_QUEUE_SIZE)
        self.client_packets = Queue(PROXY_QUEUE_SIZE)
        self.client_protocol = Protocol(self, self.client_conn,
                                        self.process_client_packet,
                                        self.get_client_packet)
        self.client_protocol.restore_state(self.client_state)
        self.server_protocol = Protocol(self, self.server_conn,
                                        self.process_server_packet,
                                        self.get_server_packet)
        #server connection tweaks:
        self.server_protocol.large_packets.append("draw")
        self.server_protocol.large_packets.append("keymap-changed")
        self.server_protocol.large_packets.append("server-settings")
        self.server_protocol.set_compression_level(
            self.session_options.get("compression_level", 0))

        debug("starting network threads")
        self.server_protocol.start()
        self.client_protocol.start()

        #forward the hello packet:
        hello_packet = ("hello", self.filter_client_caps(self.caps))
        self.queue_server_packet(hello_packet)

        try:
            try:
                self.run_queue()
            except KeyboardInterrupt, e:
                self.stop(str(e))
        finally:
            debug("ProxyProcess.run() ending %s", os.getpid())
Example #2
0
 def __init__(self, scheduler, conn, process_packet_cb, get_packet_cb=None):
     """
         You must call this constructor and source_has_more() from the main thread.
     """
     assert scheduler is not None
     assert conn is not None
     self.timeout_add = scheduler.timeout_add
     self.idle_add = scheduler.idle_add
     self._conn = conn
     if FAKE_JITTER > 0:
         from xpra.net.fake_jitter import FakeJitter
         fj = FakeJitter(self.timeout_add, process_packet_cb)
         self._process_packet_cb = fj.process_packet_cb
     else:
         self._process_packet_cb = process_packet_cb
     self._write_queue = Queue(1)
     self._read_queue = Queue(20)
     self._read_queue_put = self._read_queue.put
     # Invariant: if .source is None, then _source_has_more == False
     self._get_packet_cb = get_packet_cb
     #counters:
     self.input_stats = {}
     self.input_packetcount = 0
     self.input_raw_packetcount = 0
     self.output_stats = {}
     self.output_packetcount = 0
     self.output_raw_packetcount = 0
     #initial value which may get increased by client/server after handshake:
     self.max_packet_size = 256 * 1024
     self.abs_max_packet_size = 256 * 1024 * 1024
     self.large_packets = ["hello"]
     self.send_aliases = {}
     self.receive_aliases = {}
     self._log_stats = None  #None here means auto-detect
     self._closed = False
     self.encoder = "none"
     self._encoder = self.noencode
     self.compressor = "none"
     self._compress = compression.nocompress
     self.compression_level = 0
     self.cipher_in = None
     self.cipher_in_name = None
     self.cipher_in_block_size = 0
     self.cipher_out = None
     self.cipher_out_name = None
     self.cipher_out_block_size = 0
     self._write_lock = Lock()
     from xpra.daemon_thread import make_daemon_thread
     self._write_thread = make_daemon_thread(self._write_thread_loop,
                                             "write")
     self._read_thread = make_daemon_thread(self._read_thread_loop, "read")
     self._read_parser_thread = make_daemon_thread(
         self._read_parse_thread_loop, "parse")
     self._write_format_thread = make_daemon_thread(
         self._write_format_thread_loop, "format")
     self._source_has_more = threading.Event()
Example #3
0
    def run(self):
        debug("ProxyProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), os.getuid(), os.getgid())
        #change uid and gid:
        if os.getgid()!=self.gid:
            os.setgid(self.gid)
        if os.getuid()!=self.uid:
            os.setuid(self.uid)
        debug("ProxyProcess.run() new uid=%s, gid=%s", os.getuid(), os.getgid())

        if self.env_options:
            #TODO: whitelist env update?
            os.environ.update(self.env_options)

        log.info("new proxy started for client %s and server %s", self.client_conn, self.server_conn)

        signal.signal(signal.SIGTERM, self.signal_quit)
        signal.signal(signal.SIGINT, self.signal_quit)
        debug("registered signal handler %s", self.signal_quit)

        make_daemon_thread(self.server_message_queue, "server message queue").start()

        self.main_queue = Queue()
        #setup protocol wrappers:
        self.server_packets = Queue(PROXY_QUEUE_SIZE)
        self.client_packets = Queue(PROXY_QUEUE_SIZE)
        self.client_protocol = Protocol(self, self.client_conn, self.process_client_packet, self.get_client_packet)
        self.client_protocol.restore_state(self.client_state)
        self.server_protocol = Protocol(self, self.server_conn, self.process_server_packet, self.get_server_packet)
        #server connection tweaks:
        self.server_protocol.large_packets.append("draw")
        self.server_protocol.large_packets.append("window-icon")
        self.server_protocol.large_packets.append("keymap-changed")
        self.server_protocol.large_packets.append("server-settings")
        self.server_protocol.set_compression_level(self.session_options.get("compression_level", 0))

        self.lost_windows = set()
        self.encode_queue = Queue()
        self.encode_thread = make_daemon_thread(self.encode_loop, "encode")
        self.encode_thread.start()

        debug("starting network threads")
        self.server_protocol.start()
        self.client_protocol.start()

        #forward the hello packet:
        hello_packet = ("hello", self.filter_client_caps(self.caps))
        self.queue_server_packet(hello_packet)

        try:
            try:
                self.run_queue()
            except KeyboardInterrupt, e:
                self.stop(str(e))
        finally:
            debug("ProxyProcess.run() ending %s", os.getpid())
Example #4
0
    def __init__(self, scheduler, conn, process_packet_cb, get_packet_cb=None):
        """
            You must call this constructor and source_has_more() from the main thread.
        """
        assert scheduler is not None
        assert conn is not None
        self.timeout_add = scheduler.timeout_add
        self.idle_add = scheduler.idle_add
        self._conn = conn
        if FAKE_JITTER > 0:
            from xpra.net.fake_jitter import FakeJitter

            fj = FakeJitter(self.timeout_add, process_packet_cb)
            self._process_packet_cb = fj.process_packet_cb
        else:
            self._process_packet_cb = process_packet_cb
        self._write_queue = Queue(1)
        self._read_queue = Queue(20)
        self._read_queue_put = self._read_queue.put
        # Invariant: if .source is None, then _source_has_more == False
        self._get_packet_cb = get_packet_cb
        # counters:
        self.input_stats = {}
        self.input_packetcount = 0
        self.input_raw_packetcount = 0
        self.output_stats = {}
        self.output_packetcount = 0
        self.output_raw_packetcount = 0
        # initial value which may get increased by client/server after handshake:
        self.max_packet_size = 256 * 1024
        self.abs_max_packet_size = 256 * 1024 * 1024
        self.large_packets = ["hello"]
        self.send_aliases = {}
        self.receive_aliases = {}
        self._log_stats = None  # None here means auto-detect
        self._closed = False
        self.encoder = "none"
        self._encoder = self.noencode
        self.compressor = "none"
        self._compress = compression.nocompress
        self.compression_level = 0
        self.cipher_in = None
        self.cipher_in_name = None
        self.cipher_in_block_size = 0
        self.cipher_out = None
        self.cipher_out_name = None
        self.cipher_out_block_size = 0
        self._write_lock = Lock()
        from xpra.daemon_thread import make_daemon_thread

        self._write_thread = make_daemon_thread(self._write_thread_loop, "write")
        self._read_thread = make_daemon_thread(self._read_thread_loop, "read")
        self._read_parser_thread = make_daemon_thread(self._read_parse_thread_loop, "parse")
        self._write_format_thread = make_daemon_thread(self._write_format_thread_loop, "format")
        self._source_has_more = threading.Event()
Example #5
0
    def start_tcp_proxy(self, proto, data):
        log("start_tcp_proxy(%s, %s)", proto, data[:10])
        client_connection = proto.steal_connection()
        self._potential_protocols.remove(proto)
        #connect to web server:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        host, port = self._tcp_proxy.split(":", 1)
        try:
            web_server_connection = _socket_connect(sock, (host, int(port)),
                                                    "web-proxy-for-%s" % proto,
                                                    "tcp")
        except:
            log.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        log("proxy connected to tcp server at %s:%s : %s", host, port,
            web_server_connection)
        web_server_connection.write(data)
        p = XpraProxy(client_connection, web_server_connection)
        self._tcp_proxy_clients.append(p)

        def run_proxy():
            p.run()
            log("run_proxy() %s ended", p)
            if p in self._tcp_proxy_clients:
                self._tcp_proxy_clients.remove(p)

        t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
        t.start()
        log.info("client %s forwarded to proxy server %s:%s",
                 client_connection, host, port)
Example #6
0
 def start_tcp_proxy(self, proto, data):
     log("start_tcp_proxy(%s, %s)", proto, data[:10])
     client_connection = proto.steal_connection()
     self._potential_protocols.remove(proto)
     #connect to web server:
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.settimeout(10)
     host, port = self._tcp_proxy.split(":", 1)
     try:
         web_server_connection = _socket_connect(sock, (host, int(port)), "web-proxy-for-%s" % proto, "tcp")
     except:
         log.warn("failed to connect to proxy: %s:%s", host, port)
         proto.gibberish("invalid packet header", data)
         return
     log("proxy connected to tcp server at %s:%s : %s", host, port, web_server_connection)
     web_server_connection.write(data)
     p = XpraProxy(client_connection, web_server_connection)
     self._tcp_proxy_clients.append(p)
     def run_proxy():
         p.run()
         log("run_proxy() %s ended", p)
         if p in self._tcp_proxy_clients:
             self._tcp_proxy_clients.remove(p)
     t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
     t.start()
     log.info("client %s forwarded to proxy server %s:%s", client_connection, host, port)
Example #7
0
 def start(self):
     if self.last_UI_thread_time>0:
         log.warn("UI thread watcher already started!")
         return
     #run once to initialize:
     self.UI_thread_wakeup()
     if self.polling_timeout>0:
         make_daemon_thread(self.poll_UI_loop, "UI thread polling").start()
     else:
         log("not starting an IO polling thread")
     if FAKE_UI_LOCKUPS>0:
         #watch out: sleeping in UI thread!
         def sleep_in_ui_thread(*args):
             time.sleep(FAKE_UI_LOCKUPS)
             return True
         self.timeout_add((10+FAKE_UI_LOCKUPS)*1000, sleep_in_ui_thread)
Example #8
0
    def start_tcp_proxy(self, proto, data):
        log("start_tcp_proxy(%s, %s)", proto, data[:10])
        #any buffers read after we steal the connection will be placed in this temporary queue:
        temp_read_buffer = Queue()
        client_connection = proto.steal_connection(temp_read_buffer.put)
        try:
            self._potential_protocols.remove(proto)
        except:
            pass  #might already have been removed by now
        #connect to web server:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        host, port = self._tcp_proxy.split(":", 1)
        try:
            web_server_connection = _socket_connect(sock, (host, int(port)),
                                                    "web-proxy-for-%s" % proto,
                                                    "tcp")
        except:
            log.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        log("proxy connected to tcp server at %s:%s : %s", host, port,
            web_server_connection)
        sock.settimeout(self._socket_timeout)

        ioe = proto.wait_for_io_threads_exit(0.5 + self._socket_timeout)
        if not ioe:
            log.warn("proxy failed to stop all existing network threads!")
            self.disconnect_protocol(proto, "internal threading error")
            return
        #now that we own it, we can start it again:
        client_connection.set_active(True)
        #and we can use blocking sockets:
        self.set_socket_timeout(client_connection, None)
        #prevent deadlocks on exit:
        sock.settimeout(1)

        log("pushing initial buffer to its new destination: %s",
            repr_ellipsized(data))
        web_server_connection.write(data)
        while not temp_read_buffer.empty():
            buf = temp_read_buffer.get()
            if buf:
                log("pushing read buffer to its new destination: %s",
                    repr_ellipsized(buf))
                web_server_connection.write(buf)
        p = XpraProxy(client_connection, web_server_connection)
        self._tcp_proxy_clients.append(p)

        def run_proxy():
            p.run()
            log("run_proxy() %s ended", p)
            if p in self._tcp_proxy_clients:
                self._tcp_proxy_clients.remove(p)

        t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
        t.start()
        log.info("client %s forwarded to proxy server %s:%s",
                 client_connection, host, port)
Example #9
0
    def start(self):
        if self.last_UI_thread_time > 0:
            log.warn("UI thread watcher already started!")
            return
        #run once to initialize:
        self.UI_thread_wakeup()
        if self.polling_timeout > 0:
            make_daemon_thread(self.poll_UI_loop, "UI thread polling").start()
        else:
            log("not starting an IO polling thread")
        if FAKE_UI_LOCKUPS > 0:
            #watch out: sleeping in UI thread!
            def sleep_in_ui_thread(*args):
                time.sleep(FAKE_UI_LOCKUPS)
                return True

            self.timeout_add((10 + FAKE_UI_LOCKUPS) * 1000, sleep_in_ui_thread)
Example #10
0
 def __init__(self, conn, process_packet_cb, get_packet_cb=None):
     """
         You must call this constructor and source_has_more() from the main thread.
     """
     assert conn is not None
     self._conn = conn
     if FAKE_JITTER > 0:
         fj = FakeJitter(process_packet_cb)
         self._process_packet_cb = fj.process_packet_cb
     else:
         self._process_packet_cb = process_packet_cb
     self._write_queue = Queue(1)
     self._read_queue = Queue(20)
     # Invariant: if .source is None, then _source_has_more == False
     self._get_packet_cb = get_packet_cb
     #counters:
     self.input_packetcount = 0
     self.input_raw_packetcount = 0
     self.output_packetcount = 0
     self.output_raw_packetcount = 0
     #initial value which may get increased by client/server after handshake:
     self.max_packet_size = 32 * 1024
     self.large_packets = ["hello"]
     self.aliases = {}
     self.chunked_compression = True
     self._closed = False
     self._encoder = self.bencode
     self._decompressor = decompressobj()
     self._compression_level = 0
     self.cipher_in = None
     self.cipher_in_name = None
     self.cipher_in_block_size = 0
     self.cipher_out = None
     self.cipher_out_name = None
     self.cipher_out_block_size = 0
     self._write_lock = Lock()
     self._write_thread = make_daemon_thread(self._write_thread_loop,
                                             "write")
     self._read_thread = make_daemon_thread(self._read_thread_loop, "read")
     self._read_parser_thread = make_daemon_thread(
         self._read_parse_thread_loop, "parse")
     self._write_format_thread = make_daemon_thread(
         self._write_format_thread_loop, "format")
     self._source_has_more = threading.Event()
Example #11
0
 def __init__(self, conn, process_packet_cb, get_packet_cb=None):
     """
         You must call this constructor and source_has_more() from the main thread.
     """
     assert conn is not None
     self._conn = conn
     if FAKE_JITTER>0:
         fj = FakeJitter(process_packet_cb)
         self._process_packet_cb =  fj.process_packet_cb
     else:
         self._process_packet_cb = process_packet_cb
     self._write_queue = Queue(1)
     self._read_queue = Queue(20)
     # Invariant: if .source is None, then _source_has_more == False
     self._get_packet_cb = get_packet_cb
     #counters:
     self.input_packetcount = 0
     self.input_raw_packetcount = 0
     self.output_packetcount = 0
     self.output_raw_packetcount = 0
     #initial value which may get increased by client/server after handshake:
     self.max_packet_size = 32*1024
     self.large_packets = ["hello"]
     self.aliases = {}
     self.chunked_compression = True
     self._closed = False
     self._encoder = self.bencode
     self._decompressor = decompressobj()
     self._compression_level = 0
     self.cipher_in = None
     self.cipher_in_name = None
     self.cipher_in_block_size = 0
     self.cipher_out = None
     self.cipher_out_name = None
     self.cipher_out_block_size = 0
     self._write_lock = Lock()
     self._write_thread = make_daemon_thread(self._write_thread_loop, "write")
     self._read_thread = make_daemon_thread(self._read_thread_loop, "read")
     self._read_parser_thread = make_daemon_thread(self._read_parse_thread_loop, "parse")
     self._write_format_thread = make_daemon_thread(self._write_format_thread_loop, "format")
     self._source_has_more = threading.Event()
Example #12
0
    def start_tcp_proxy(self, proto, data):
        log("start_tcp_proxy(%s, %s)", proto, data[:10])
        #any buffers read after we steal the connection will be placed in this temporary queue:
        temp_read_buffer = Queue()
        client_connection = proto.steal_connection(temp_read_buffer.put)
        try:
            self._potential_protocols.remove(proto)
        except:
            pass        #might already have been removed by now
        #connect to web server:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        host, port = self._tcp_proxy.split(":", 1)
        try:
            web_server_connection = _socket_connect(sock, (host, int(port)), "web-proxy-for-%s" % proto, "tcp")
        except:
            log.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        log("proxy connected to tcp server at %s:%s : %s", host, port, web_server_connection)
        sock.settimeout(self._socket_timeout)

        ioe = proto.wait_for_io_threads_exit(0.5+self._socket_timeout)
        if not ioe:
            log.warn("proxy failed to stop all existing network threads!")
            self.disconnect_protocol(proto, "internal threading error")
            return
        #now that we own it, we can start it again:
        client_connection.set_active(True)
        #and we can use blocking sockets:
        self.set_socket_timeout(client_connection, None)
        #prevent deadlocks on exit:
        sock.settimeout(1)
 
        log("pushing initial buffer to its new destination: %s", repr_ellipsized(data))
        web_server_connection.write(data)
        while not temp_read_buffer.empty():
            buf = temp_read_buffer.get()
            if buf:
                log("pushing read buffer to its new destination: %s", repr_ellipsized(buf))
                web_server_connection.write(buf)
        p = XpraProxy(client_connection, web_server_connection)
        self._tcp_proxy_clients.append(p)
        def run_proxy():
            p.run()
            log("run_proxy() %s ended", p)
            if p in self._tcp_proxy_clients:
                self._tcp_proxy_clients.remove(p)
        t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
        t.start()
        log.info("client %s forwarded to proxy server %s:%s", client_connection, host, port)
Example #13
0
    def invalid_header(self, proto, data):
        netlog(
            "invalid_header(%s, %s bytes: '%s') input_packetcount=%s, tcp_proxy=%s",
            proto, len(data or ""), repr_ellipsized(data),
            proto.input_packetcount, self._tcp_proxy)
        if proto.input_packetcount == 0 and self._tcp_proxy and not proto._closed:
            #start a new proxy in a thread
            def run_proxy():
                self.start_tcp_proxy(proto, data)

            t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
            t.start()
            return
        err = "invalid packet format, not an xpra client?"
        proto.gibberish(err, data)
Example #14
0
    def invalid_header(self, proto, data):
        netlog(
            "invalid_header(%s, %s bytes: '%s') input_packetcount=%s, tcp_proxy=%s",
            proto,
            len(data or ""),
            repr_ellipsized(data),
            proto.input_packetcount,
            self._tcp_proxy,
        )
        if proto.input_packetcount == 0 and self._tcp_proxy and not proto._closed:
            # start a new proxy in a thread
            def run_proxy():
                self.start_tcp_proxy(proto, data)

            t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
            t.start()
            return
        err = "invalid packet format, not an xpra client?"
        proto.gibberish(err, data)
Example #15
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())
                process.start()
                log("process started")
                #FIXME: remove processes that have terminated
                self.processes[process] = (display, message_queue)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()

        make_daemon_thread(do_start_proxy,
                           "start_proxy(%s)" % client_conn).start()

    def reap(self):
        dead = []
        for p in self.processes.keys():
            live = p.is_alive()
            if not live:
                dead.append(p)
        for p in dead:
            del self.processes[p]

    def sigchld(self, *args):
        log("sigchld(%s)", args)
        self.idle_add(self.reap)
        log("processes: %s", self.processes)
Example #16
0
                assert uid!=0 and gid!=0
                message_queue = MQueue()
                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())
                process.start()
                log("process started")
                #FIXME: remove processes that have terminated
                self.processes[process] = (display, message_queue)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
        make_daemon_thread(do_start_proxy, "start_proxy(%s)" % client_conn).start()


    def reap(self):
        dead = []
        for p in self.processes.keys():
            live = p.is_alive()
            if not live:
                dead.append(p)
        for p in dead:
            del self.processes[p]

    def sigchld(self, *args):
        log("sigchld(%s)", args)
        self.idle_add(self.reap)
        log("processes: %s", self.processes)
Example #17
0
    def run(self):
        log("ProxyProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(),
            os.getuid(), os.getgid())
        #change uid and gid:
        if os.getgid() != self.gid:
            os.setgid(self.gid)
        if os.getuid() != self.uid:
            os.setuid(self.uid)
        log("ProxyProcess.run() new uid=%s, gid=%s", os.getuid(), os.getgid())

        if self.env_options:
            #TODO: whitelist env update?
            os.environ.update(self.env_options)
        self.video_init()

        log.info("new proxy started for client %s and server %s",
                 self.client_conn, self.server_conn)

        signal.signal(signal.SIGTERM, self.signal_quit)
        signal.signal(signal.SIGINT, self.signal_quit)
        log("registered signal handler %s", self.signal_quit)

        make_daemon_thread(self.server_message_queue,
                           "server message queue").start()

        if self.create_control_socket():
            self.control_socket_thread = make_daemon_thread(
                self.control_socket_loop, "control")
            self.control_socket_thread.start()

        self.main_queue = Queue()
        #setup protocol wrappers:
        self.server_packets = Queue(PROXY_QUEUE_SIZE)
        self.client_packets = Queue(PROXY_QUEUE_SIZE)
        self.client_protocol = Protocol(self, self.client_conn,
                                        self.process_client_packet,
                                        self.get_client_packet)
        self.client_protocol.restore_state(self.client_state)
        self.server_protocol = Protocol(self, self.server_conn,
                                        self.process_server_packet,
                                        self.get_server_packet)
        #server connection tweaks:
        self.server_protocol.large_packets.append("draw")
        self.server_protocol.large_packets.append("window-icon")
        self.server_protocol.large_packets.append("keymap-changed")
        self.server_protocol.large_packets.append("server-settings")
        self.server_protocol.set_compression_level(
            self.session_options.get("compression_level", 0))
        self.server_protocol.enable_default_encoder()

        self.lost_windows = set()
        self.encode_queue = Queue()
        self.encode_thread = make_daemon_thread(self.encode_loop, "encode")
        self.encode_thread.start()

        log("starting network threads")
        self.server_protocol.start()
        self.client_protocol.start()

        #forward the hello packet:
        hello_packet = ("hello", self.filter_client_caps(self.caps))
        self.queue_server_packet(hello_packet)
        self.timeout_add(VIDEO_TIMEOUT * 1000, self.timeout_video_encoders)

        try:
            try:
                self.run_queue()
            except KeyboardInterrupt as e:
                self.stop(str(e))
        finally:
            log("ProxyProcess.run() ending %s", os.getpid())
Example #18
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
        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")
        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 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():
            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)

        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
        debug("server connection=%s", server_conn)

        client_conn = client_proto.steal_connection()
        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)
        debug("start_proxy(..) client connection=%s", client_conn)
        debug("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            debug("do_start_proxy()")
            try:
                #stop IO in proxy:
                #(it may take up to _socket_timeout until the thread exits)
                client_conn.set_active(False)
                ioe = client_proto.wait_for_io_threads_exit(
                    0.1 + self._socket_timeout)
                if not ioe:
                    log.error("IO threads have failed to terminate!")
                    return
                #now we can go back to using blocking sockets:
                self.set_socket_timeout(client_conn, None)
                client_conn.set_active(True)

                assert uid != 0 and gid != 0
                message_queue = MQueue()
                process = ProxyProcess(uid, gid, env_options, session_options,
                                       client_conn, client_state, cipher,
                                       encryption_key, server_conn, c,
                                       message_queue)
                debug("starting %s from pid=%s", process, os.getpid())
                process.start()
                debug("process started")
                #FIXME: remove processes that have terminated
                self.processes[process] = (display, message_queue)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()

        make_daemon_thread(do_start_proxy,
                           "start_proxy(%s)" % client_conn).start()
Example #19
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)
        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()")
            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
                #now we can go back to using blocking sockets:
                self.set_socket_timeout(client_conn, None)
                client_conn.set_active(True)
                self.set_socket_timeout(server_conn, None)

                assert uid!=0 and gid!=0
                message_queue = MQueue()
                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())
                process.start()
                log("process started")
                #FIXME: remove processes that have terminated
                self.processes[process] = (display, message_queue)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
        make_daemon_thread(do_start_proxy, "start_proxy(%s)" % client_conn).start()
Example #20
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)
        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()")
            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
                #now we can go back to using blocking sockets:
                self.set_socket_timeout(client_conn, None)
                client_conn.set_active(True)
                self.set_socket_timeout(server_conn, None)

                assert uid != 0 and gid != 0
                message_queue = MQueue()
                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())
                process.start()
                log("process started")
                #FIXME: remove processes that have terminated
                self.processes[process] = (display, message_queue)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()

        make_daemon_thread(do_start_proxy,
                           "start_proxy(%s)" % client_conn).start()