Beispiel #1
0
def peek_connection(conn, timeout=PEEK_TIMEOUT_MS):
    log = get_network_logger()
    log("peek_connection(%s, %i)", conn, timeout)
    PEEK_SIZE = 8192
    start = monotonic_time()
    peek_data = b""
    while not peek_data and int(1000*(monotonic_time()-start))<timeout:
        try:
            peek_data = conn.peek(PEEK_SIZE)
        except (OSError, IOError):
            pass
        except ValueError:
            log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True)
            break
        if not peek_data:
            sleep(timeout/4000.0)
    line1 = b""
    log("socket %s peek: got %i bytes", conn, len(peek_data))
    set_socket_timeout(conn, PEEK_TIMEOUT_MS*1000)
    if peek_data:
        line1 = peek_data.splitlines()[0]
        log("socket peek=%s", repr_ellipsized(peek_data, limit=512))
        log("socket peek hex=%s", hexstr(peek_data[:128]))
        log("socket peek line1=%s", repr_ellipsized(bytestostr(line1)))
    return peek_data, line1
Beispiel #2
0
 def _process_rfb_authenticated(self, proto, _packet):
     model = self._get_rfb_desktop_model()
     if not model:
         proto.close()
         return
     self.accept_protocol(proto)
     #use blocking sockets from now on:
     from xpra.net.bytestreams import set_socket_timeout
     set_socket_timeout(proto._conn, None)
     accepted, share_count, disconnected = self.handle_sharing(
         proto, share=proto.share)
     log("rfb handle sharing: accepted=%s, share count=%s, disconnected=%s",
         accepted, share_count, disconnected)
     if not accepted:
         return
     source = RFBSource(proto, self._get_rfb_desktop_model(), proto.share)
     if server_features.input_devices:
         source.keyboard_config = self.get_keyboard_config()
         self.set_keymap(source)
     self._server_sources[proto] = source
     w, h = model.get_dimensions()
     source.damage(self._window_to_id[model], model, 0, 0, w, h)
     #ugly weak dependency,
     #shadow servers need to be told to start the refresh timer:
     start_refresh = getattr(self, "start_refresh", None)
     if start_refresh:
         for wid in tuple(self._window_to_id.values()):
             start_refresh(wid)
Beispiel #3
0
def peek_connection(conn, timeout=PEEK_TIMEOUT_MS, size=PEEK_SIZE):
    log = get_network_logger()
    log("peek_connection(%s, %i)", conn, timeout)
    peek_data = b""
    start = monotonic_time()
    elapsed = 0
    set_socket_timeout(conn, PEEK_TIMEOUT_MS * 1000)
    while elapsed <= timeout:
        try:
            peek_data = conn.peek(size)
            if peek_data:
                break
        except OSError:
            log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True)
        except ValueError:
            log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True)
            break
        sleep(timeout / 4000.0)
        elapsed = int(1000 * (monotonic_time() - start))
        log("peek: elapsed=%s, timeout=%s", elapsed, timeout)
    line1 = b""
    log("socket %s peek: got %i bytes", conn, len(peek_data))
    if peek_data:
        line1 = peek_data.splitlines()[0]
        log("socket peek=%s", ellipsizer(peek_data, limit=512))
        log("socket peek hex=%s", hexstr(peek_data[:128]))
        log("socket peek line1=%s", ellipsizer(line1))
    return peek_data, line1
Beispiel #4
0
    def start_tcp_proxy(self, proto, data):
        proxylog("start_tcp_proxy(%s, '%s')", proto, repr_ellipsized(data))
        try:
            self._potential_protocols.remove(proto)
        except:
            pass  #might already have been removed by now
        proxylog("start_tcp_proxy: protocol state before stealing: %s",
                 proto.get_info(alias_info=False))
        #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)
        #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:
            proxylog.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        proxylog("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:
            proxylog.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:
        set_socket_timeout(client_connection, None)
        #prevent deadlocks on exit:
        sock.settimeout(1)

        proxylog("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:
                proxylog("pushing read buffer to its new destination: %s",
                         repr_ellipsized(buf))
                web_server_connection.write(buf)
        p = XpraProxy(client_connection.target, client_connection,
                      web_server_connection)
        self._tcp_proxy_clients.append(p)
        proxylog.info(
            "client connection from %s forwarded to proxy server on %s:%s",
            client_connection.target, host, port)
        p.run()
        proxylog("run_proxy() %s ended", p)
        if p in self._tcp_proxy_clients:
            self._tcp_proxy_clients.remove(p)
Beispiel #5
0
    def start_tcp_proxy(self, proto, data):
        proxylog("start_tcp_proxy(%s, '%s')", proto, repr_ellipsized(data))
        try:
            self._potential_protocols.remove(proto)
        except:
            pass        #might already have been removed by now
        proxylog("start_tcp_proxy: protocol state before stealing: %s", proto.get_info(alias_info=False))
        #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)
        #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:
            proxylog.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        proxylog("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:
            proxylog.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:
        set_socket_timeout(client_connection, None)
        #prevent deadlocks on exit:
        sock.settimeout(1)

        proxylog("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:
                proxylog("pushing read buffer to its new destination: %s", repr_ellipsized(buf))
                web_server_connection.write(buf)
        p = XpraProxy(client_connection.target, client_connection, web_server_connection)
        self._tcp_proxy_clients.append(p)
        proxylog.info("client connection from %s forwarded to proxy server on %s:%s", client_connection.target, host, port)
        p.run()
        proxylog("run_proxy() %s ended", p)
        if p in self._tcp_proxy_clients:
            self._tcp_proxy_clients.remove(p)
Beispiel #6
0
 def _process_rfb_authenticated(self, proto, _packet):
     model = self._get_rfb_desktop_model()
     if not model:
         proto.close()
         return
     self.accept_protocol(proto)
     #use blocking sockets from now on:
     set_socket_timeout(proto._conn, None)
     accepted, share_count, disconnected = self.handle_sharing(
         proto, share=proto.share)
     log("RFB handle sharing: accepted=%s, share count=%s, disconnected=%s",
         accepted, share_count, disconnected)
     if not accepted:
         return
     source = RFBSource(proto, proto.share)
     self._server_sources[proto] = source
     #continue in the UI thread:
     self.idle_add(self._accept_rfb_source, source)
Beispiel #7
0
def peek_connection(conn, timeout=PEEK_TIMEOUT_MS, size=PEEK_SIZE):
    log = get_network_logger()
    log("peek_connection(%s, %i, %i)", conn, timeout, size)
    peek_data = b""
    start = monotonic()
    elapsed = 0
    set_socket_timeout(conn, PEEK_TIMEOUT_MS / 1000)
    while elapsed <= timeout:
        try:
            peek_data = conn.peek(size)
            if peek_data:
                break
        except OSError:
            log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True)
        except ValueError:
            log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True)
            break
        sleep(timeout / 4000.0)
        elapsed = int(1000 * (monotonic() - start))
        log("peek: elapsed=%s, timeout=%s", elapsed, timeout)
    log("socket %s peek: got %i bytes", conn, len(peek_data))
    return peek_data
Beispiel #8
0
    def hello_oked(self, proto, packet, c, auth_caps):
        if self._server_sources.get(proto):
            log.warn("Warning: received another 'hello' packet")
            log.warn(" from an existing connection: %s", proto)
            return
        if ServerCore.hello_oked(self, proto, packet, c, auth_caps):
            #has been handled
            return
        if not self.sanity_checks(proto, c):
            return
        if not c.boolget("steal", True) and self._server_sources:
            self.disconnect_client(proto, SESSION_BUSY,
                                   "this session is already active")
            return
        if c.boolget("screenshot_request"):
            self.send_screenshot(proto)
            return
        #added in 2.2:
        request = c.strget("request")

        def is_req(mode):
            return request == mode or c.boolget("%s_request" % mode, False)

        if not request:
            #"normal" connection, so log welcome message:
            log.info("Handshake complete; enabling connection")
        else:
            log("handling request %s", request)
        self.server_event("handshake-complete")

        # Things are okay, we accept this connection, and may disconnect previous one(s)
        # (but only if this is going to be a UI session - control sessions can co-exist)
        ui_client = c.boolget("ui_client", True)
        share = c.boolget("share")
        uuid = c.strget("uuid")
        detach_request = is_req("detach")
        accepted, share_count, disconnected = self.handle_sharing(
            proto, ui_client, detach_request, share, uuid)
        if not accepted:
            return

        if is_req("detach"):
            self.disconnect_client(
                proto, DONE,
                "%i other clients have been disconnected" % disconnected)
            return

        if not request and ui_client:
            #a bit of explanation:
            #normally these things are synchronized using xsettings, which we handle already
            #but non-posix clients have no such thing,
            #and we don't want to expose that as an interface
            #(it's not very nice and it is very X11 specific)
            #also, clients may want to override what is in their xsettings..
            #so if the client specifies what it wants to use, we patch the xsettings with it
            #(the actual xsettings part is done in update_all_server_settings in the X11 specific subclasses)
            if share_count > 0:
                log.info("sharing with %s other client(s)", share_count)
                self.dpi = 0
                self.xdpi = 0
                self.ydpi = 0
                self.double_click_time = -1
                self.double_click_distance = -1, -1
                self.antialias = {}
                self.cursor_size = 24
            else:
                self.dpi = c.intget("dpi", 0)
                self.xdpi = c.intget("dpi.x", 0)
                self.ydpi = c.intget("dpi.y", 0)
                self.double_click_time = c.intget("double_click.time", -1)
                self.double_click_distance = c.intpair("double_click.distance",
                                                       (-1, -1))
                self.antialias = c.dictget("antialias", {})
                self.cursor_size = c.intget("cursor.size", 0)
            #FIXME: this belongs in DisplayManager!
            screenlog(
                "dpi=%s, dpi.x=%s, dpi.y=%s, antialias=%s, cursor_size=%s",
                self.dpi, self.xdpi, self.ydpi, self.antialias,
                self.cursor_size)
            log("double-click time=%s, distance=%s", self.double_click_time,
                self.double_click_distance)
            #if we're not sharing, reset all the settings:
            reset = share_count == 0
            self.update_all_server_settings(reset)

        self.accept_client(proto, c)
        #use blocking sockets from now on:
        if not WIN32:
            set_socket_timeout(proto._conn, None)

        def drop_client(reason="unknown", *args):
            self.disconnect_client(proto, reason, *args)

        cc_class = self.get_client_connection_class(c)
        ss = cc_class(
            proto,
            drop_client,
            self.session_name,
            self,
            self.idle_add,
            self.timeout_add,
            self.source_remove,
            self.setting_changed,
            self._socket_dir,
            self.unix_socket_paths,
            not request,
            self.bandwidth_limit,
            self.bandwidth_detection,
        )
        log("process_hello clientconnection=%s", ss)
        try:
            ss.parse_hello(c)
        except:
            #close it already
            ss.close()
            raise
        self._server_sources[proto] = ss
        add_work_item(self.mdns_update)
        #process ui half in ui thread:
        send_ui = ui_client and not request
        self.idle_add(self._process_hello_ui, ss, c, auth_caps, send_ui,
                      share_count)
Beispiel #9
0
    def hello_oked(self, proto, packet, c, auth_caps):
        if ServerCore.hello_oked(self, proto, packet, c, auth_caps):
            #has been handled
            return
        if not c.boolget("steal", True) and self._server_sources:
            self.disconnect_client(proto, SESSION_BUSY, "this session is already active")
            return
        if c.boolget("screenshot_request"):
            self.send_screenshot(proto)
            return
        #added in 2.2:
        generic_request = c.strget("request")
        def is_req(mode):
            return generic_request==mode or c.boolget("%s_request" % mode, False)
        detach_request  = is_req("detach")
        stop_request    = is_req("stop_request")
        exit_request    = is_req("exit_request")
        event_request   = is_req("event_request")
        print_request   = is_req("print_request")
        is_request = detach_request or stop_request or exit_request or event_request or print_request
        if not is_request:
            #"normal" connection, so log welcome message:
            log.info("Handshake complete; enabling connection")
        else:
            log("handling request %s", generic_request)
        self.server_event("handshake-complete")

        # Things are okay, we accept this connection, and may disconnect previous one(s)
        # (but only if this is going to be a UI session - control sessions can co-exist)
        ui_client = c.boolget("ui_client", True)
        share = c.boolget("share")
        uuid = c.strget("uuid")
        accepted, share_count, disconnected = self.handle_sharing(proto, ui_client, detach_request, share, uuid)
        if not accepted:
            return

        if detach_request:
            self.disconnect_client(proto, DONE, "%i other clients have been disconnected" % disconnected)
            return

        if not is_request and ui_client:
            #a bit of explanation:
            #normally these things are synchronized using xsettings, which we handle already
            #but non-posix clients have no such thing,
            #and we don't want to expose that as an interface
            #(it's not very nice and it is very X11 specific)
            #also, clients may want to override what is in their xsettings..
            #so if the client specifies what it wants to use, we patch the xsettings with it
            #(the actual xsettings part is done in update_all_server_settings in the X11 specific subclasses)
            if share_count>0:
                log.info("sharing with %s other client(s)", share_count)
                self.dpi = 0
                self.xdpi = 0
                self.ydpi = 0
                self.double_click_time = -1
                self.double_click_distance = -1, -1
                self.antialias = {}
                self.cursor_size = 24
            else:
                self.dpi = c.intget("dpi", 0)
                self.xdpi = c.intget("dpi.x", 0)
                self.ydpi = c.intget("dpi.y", 0)
                self.double_click_time = c.intget("double_click.time", -1)
                self.double_click_distance = c.intpair("double_click.distance", (-1, -1))
                self.antialias = c.dictget("antialias")
                self.cursor_size = c.intget("cursor.size", 0)
            #FIXME: this belongs in DisplayManager!
            log("dpi=%s, dpi.x=%s, dpi.y=%s, double_click_time=%s, double_click_distance=%s, antialias=%s, cursor_size=%s", self.dpi, self.xdpi, self.ydpi, self.double_click_time, self.double_click_distance, self.antialias, self.cursor_size)
            #if we're not sharing, reset all the settings:
            reset = share_count==0
            self.update_all_server_settings(reset)

        self.accept_client(proto, c)
        #use blocking sockets from now on:
        if not (PYTHON3 and WIN32):
            set_socket_timeout(proto._conn, None)

        def drop_client(reason="unknown", *args):
            self.disconnect_client(proto, reason, *args)
        get_window_id = self._window_to_id.get
        bandwidth_limit = self.get_client_bandwidth_limit(proto)
        ClientConnectionClass = self.get_server_source_class()
        ss = ClientConnectionClass(proto, drop_client,
                          self.session_name,
                          self.idle_add, self.timeout_add, self.source_remove, self.setting_changed,
                          self.idle_timeout,
                          self._socket_dir, self.unix_socket_paths, not is_request, self.dbus_control,
                          self.get_transient_for, self.get_focus, self.get_cursor_data,
                          get_window_id,
                          self.window_filters,
                          self.file_transfer,
                          self.supports_mmap, self.mmap_filename, self.min_mmap_size,
                          bandwidth_limit,
                          self.av_sync,
                          self.core_encodings, self.encodings, self.default_encoding, self.scaling_control,
                          self.webcam_enabled, self.webcam_device, self.webcam_encodings,
                          self.sound_properties,
                          self.sound_source_plugin,
                          self.supports_speaker, self.supports_microphone,
                          self.speaker_codecs, self.microphone_codecs,
                          self.default_quality, self.default_min_quality,
                          self.default_speed, self.default_min_speed)
        log("process_hello clientconnection=%s", ss)
        try:
            ss.parse_hello(c)
        except:
            #close it already
            ss.close()
            raise
        try:
            self.notify_new_user(ss)
        except Exception as e:
            notifylog("%s(%s)", self.notify_new_user, ss, exc_info=True)
            notifylog.error("Error: failed to show notification of user login:"******" %s", e)
        self._server_sources[proto] = ss
        #process ui half in ui thread:
        send_ui = ui_client and not is_request
        self.idle_add(self.parse_hello_ui, ss, c, auth_caps, send_ui, share_count)