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
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)
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
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)
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)
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)
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
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)
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)