def init(self, opts): log("ProxyServer.init(%s)", opts) if not opts.tcp_auth: raise InitException("The proxy server requires an authentication mode (use 'none' to disable authentication)") self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts)
def get_info(self, proto, *args): info = ServerCore.get_info(self, proto) info.setdefault("server", {})["type"] = "Python/GLib/proxy" #only show more info if we have authenticated #as the user running the proxy server process: pa = proto.authenticator if pa: sessions = pa.get_sessions() if sessions: uid, gid = sessions[:2] if os.name != "posix" or (uid == os.getuid() and gid == os.getgid()): info.update(ServerCore.get_info(self, proto)) self.reap() i = 0 for p, v in self.processes.items(): d, _ = v info[i] = { "display": d, "live": p.is_alive(), "pid": p.pid, } i += 1 info["proxies"] = len(self.processes) return info
def __init__(self): log("ProxyServer.__init__()") ServerCore.__init__(self) self._max_connections = MAX_CONCURRENT_CONNECTIONS self._start_sessions = False self.main_loop = None #proxy servers may have to connect to remote servers, #or even start them, so allow more time before timing out: self._accept_timeout += 10 #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 = {} #connections used exclusively for requests: self._requests = set() self.idle_add = glib.idle_add self.timeout_add = glib.timeout_add self.source_remove = glib.source_remove self._socket_timeout = PROXY_SOCKET_TIMEOUT self._ws_timeout = PROXY_WS_TIMEOUT self.control_commands["stop"] = ArgsControlCommand( "stop", "stops the proxy instance on the given display", self.handle_stop_command, min_args=1, max_args=1)
def do_handle_command_request(self, proto, command, args): if command in ("help", "hello"): return ServerCore.do_handle_command_request( self, proto, command, args) assert command == "stop" if len(args) != 1: return ServerCore.control_command_response( self, proto, command, 4, "invalid number of arguments, usage: 'xpra control stop DISPLAY'" ) display = args[0] log("stop command: will try to find proxy process for display %s", display) for process, v in list(self.processes.items()): disp, mq = v if disp == display: pid = process.pid log.info( "stop command: found process %s with pid %s for display %s, sending it 'stop' request", process, pid, display) mq.put("stop") return self.control_command_response( proto, command, 0, "stopped proxy process with pid %s" % pid) return self.control_command_response( proto, command, 14, "no proxy found for display %s" % display)
def __init__(self): log("ProxyServer.__init__()") ServerCore.__init__(self) self._max_connections = MAX_CONCURRENT_CONNECTIONS self._start_sessions = False self.session_type = "proxy" self.main_loop = None #proxy servers may have to connect to remote servers, #or even start them, so allow more time before timing out: self._accept_timeout += 10 self.pings = 0 self.video_encoders = () self._start_sessions = False #keep track of the proxy process instances #the display they're on and the message queue we can # use to communicate with them self.instances = {} #connections used exclusively for requests: self._requests = set() self.idle_add = glib.idle_add self.timeout_add = glib.timeout_add self.source_remove = glib.source_remove self._socket_timeout = PROXY_SOCKET_TIMEOUT self._ws_timeout = PROXY_WS_TIMEOUT register_SIGUSR_signals(glib.idle_add)
def init_control_commands(self): ServerCore.init_control_commands(self) self.control_commands["stop"] = ArgsControlCommand( "stop", "stops the proxy instance on the given display", self.handle_stop_command, min_args=1, max_args=1)
def _log_disconnect(self, proto, *args): #skip logging of disconnection events for server sources #we have tagged during hello ("info_request", "exit_request", etc..) ss = self.get_server_source(proto) if ss and not ss.log_disconnect: #log at debug level only: netlog(*args) return ServerCore._log_disconnect(self, proto, *args)
def init(self, opts): log("ProxyServer.init(%s)", opts) self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def init(self, opts): log("ProxyServer.init(%s)", opts) self.video_encoders = opts.proxy_video_encoders self.csc_modules = opts.csc_modules self._start_sessions = opts.proxy_start_sessions ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def init(self, opts): log("ProxyServer.init(%s)", opts) if not opts.tcp_auth: raise InitException("The proxy server requires an authentication mode (use 'none' to disable authentication)") self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
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 = glib.idle_add self.timeout_add = glib.timeout_add self.source_remove = glib.source_remove self._socket_timeout = PROXY_SOCKET_TIMEOUT self.control_commands["stop"] = ArgsControlCommand("stop", "stops the proxy instance on the given display", self.handle_stop_command, min_args=1, max_args=1)
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.tcp_auth: raise InitException( "The proxy server requires an authentication mode (use 'none' to disable authentication)" ) self.video_encoders = opts.video_encoders self.csc_modules = opts.csc_modules ServerCore.init(self, opts) #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() self.child_reaper = getChildReaper()
def get_packet_handlers_info(self): info = ServerCore.get_packet_handlers_info(self) info.update({ "authenticated" : sorted(self._authenticated_packet_handlers.keys()), "ui" : sorted(self._authenticated_ui_packet_handlers.keys()), }) return info
def make_hello(self, source): capabilities = ServerCore.make_hello(self, source) for c in ServerBase.__bases__: if c!=ServerCore: merge_dicts(capabilities, c.get_caps(self)) capabilities["server_type"] = "base" if source.wants_display: capabilities.update({ "max_desktop_size" : self.get_max_screen_size(), }) if source.wants_features: capabilities.update({ "bell" : self.bell, "cursors" : self.cursors, "av-sync.enabled" : self.av_sync, "client-shutdown" : self.client_shutdown, "sharing" : self.sharing is not False, "sharing-toggle" : self.sharing is None, "lock" : self.lock is not False, "lock-toggle" : self.lock is None, }) capabilities.update(flatten_dict(self.get_server_features(source))) #this is a feature, but we would need the hello request #to know if it is really needed.. so always include it: capabilities["exit_server"] = True return capabilities
def hello_oked(self, proto, packet, c, auth_caps): if ServerCore.hello_oked(self, proto, packet, c, auth_caps): #already handled in superclass return self.accept_client(proto, c) if any( c.boolget("%s_request" % x) for x in ("screenshot", "event", "print", "exit")): self.send_disconnect(proto, "invalid request") return if c.boolget("stop_request"): self._requests.add(proto) #send a hello back and the client should then send its "shutdown-server" packet capabilities = self.make_hello() proto.send_now(("hello", capabilities)) def force_exit_request_client(): try: self._requests.remove(proto) except: pass if not proto._closed: self.send_disconnect(proto, "timeout") self.timeout_add(10 * 1000, force_exit_request_client) else: self.start_proxy(proto, c, auth_caps)
def get_info(self, proto=None, client_uuids=None): log("ServerBase.get_info%s", (proto, client_uuids)) start = monotonic_time() info = ServerCore.get_info(self, proto) server_info = info.setdefault("server", {}) if self.mem_bytes: server_info["total-memory"] = self.mem_bytes if client_uuids: sources = [ ss for ss in self._server_sources.values() if ss.uuid in client_uuids ] else: sources = tuple(self._server_sources.values()) log("info-request: sources=%s", sources) dgi = self.do_get_info(proto, sources) #ugly alert: merge nested dictionaries, #ie: do_get_info may return a dictionary for "server" and we already have one, # so we update it with the new values for k, v in dgi.items(): cval = info.get(k) if cval is None: info[k] = v continue cval.update(v) log("ServerBase.get_info took %.1fms", 1000.0 * (monotonic_time() - start)) return info
def get_info(self, proto, *_args): info = ServerCore.get_info(self, proto) info.setdefault("server", {})["type"] = "Python/GLib/proxy" #only show more info if we have authenticated #as the user running the proxy server process: if proto and proto.authenticators: sessions = [] for authenticator in proto.authenticators: auth_sessions = authenticator.get_sessions() #don't add duplicates: for x in auth_sessions: if x not in sessions: sessions.append(x) if sessions: uid, gid = sessions[:2] if not POSIX or (uid==os.getuid() and gid==os.getgid()): self.reap() i = 0 for p,v in self.processes.items(): d,_ = v info[i] = { "display" : d, "live" : p.is_alive(), "pid" : p.pid, } i += 1 info["proxies"] = len(self.processes) return info
def make_hello(self, source): capabilities = ServerCore.make_hello(self, source) for c in SERVER_BASES: if c != ServerCore: merge_dicts(capabilities, c.get_caps(self, source)) capabilities["server_type"] = "base" if source.wants_display: capabilities.update({ "max_desktop_size": self.get_max_screen_size(), }) if source.wants_features: capabilities.update({ "client-shutdown": self.client_shutdown, "sharing": self.sharing is not False, "sharing-toggle": self.sharing is None, "lock": self.lock is not False, "lock-toggle": self.lock is None, "windows": server_features.windows, "keyboard": server_features.input_devices, "pointer": server_features.input_devices, }) capabilities.update(flatten_dict(self.get_server_features(source))) #this is a feature, but we would need the hello request #to know if it is really needed.. so always include it: capabilities["exit_server"] = True return capabilities
def do_handle_command_request(self, proto, command, args): if command in ("help", "hello"): return ServerCore.do_handle_command_request(self, proto, command, args) assert command=="stop" if len(args)!=1: return ServerCore.control_command_response(self, proto, command, 4, "invalid number of arguments, usage: 'xpra control stop DISPLAY'") display = args[0] debug("stop command: will try to find proxy process for display %s", display) for process, v in list(self.processes.items()): disp,mq = v if disp==display: pid = process.pid log.info("stop command: found process %s with pid %s for display %s, sending it 'stop' request", process, pid, display) mq.put("stop") return self.control_command_response(proto, command, 0, "stopped proxy process with pid %s" % pid) return self.control_command_response(proto, command, 14, "no proxy found for display %s" % display)
def hello_oked(self, proto, packet, c, auth_caps): if ServerCore.hello_oked(self, proto, packet, c, auth_caps): #already handled in superclass return self.accept_client(proto, c) generic_request = c.strget("request") def is_req(mode): return generic_request==mode or c.boolget("%s_request" % mode) if any(is_req(x) for x in ("screenshot", "event", "print", "exit")): self.send_disconnect(proto, "invalid request") return if is_req("stop"): if not CAN_STOP_PROXY: self.send_disconnect(proto, "cannot stop proxy server") return self._requests.add(proto) #send a hello back and the client should then send its "shutdown-server" packet capabilities = self.make_hello() proto.send_now(("hello", capabilities)) def force_exit_request_client(): try: self._requests.remove(proto) except: pass if not proto._closed: self.send_disconnect(proto, "timeout") self.timeout_add(10*1000, force_exit_request_client) return self.proxy_auth(proto, c, auth_caps)
def cleanup(self): self.stop_all_proxies() ServerCore.cleanup(self) start = monotonic_time() live = True log("cleanup() proxy instances: %s", self.instances) while monotonic_time() - start < PROXY_CLEANUP_GRACE_PERIOD and live: live = tuple(x for x in tuple(self.instances.keys()) if x.is_alive()) if live: log("cleanup() still %i proxies alive: %s", len(live), live) time.sleep(0.1) if live: self.stop_all_proxies(True) log("cleanup() frames remaining:") from xpra.util import dump_all_frames dump_all_frames(log)
def __init__(self): debug("ProxyServer.__init__()") ServerCore.__init__(self) self._max_connections = MAX_CONCURRENT_CONNECTIONS self.main_loop = None #keep track of the proxy process instances #the display they're on and the message queue we can # use to communicate with them self.processes = {} self.idle_add = gobject.idle_add self.timeout_add = gobject.timeout_add self.source_remove = gobject.source_remove self._socket_timeout = PROXY_SOCKET_TIMEOUT self.control_commands = ["hello", "stop"] #ensure we cache the platform info before intercepting SIGCHLD #as this will cause a fork and SIGCHLD to be emitted: from xpra.version_util import get_platform_info get_platform_info() signal.signal(signal.SIGCHLD, self.sigchld)
def __init__(self): 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 = glib.idle_add self.timeout_add = glib.timeout_add self.source_remove = glib.source_remove self._socket_timeout = PROXY_SOCKET_TIMEOUT self.control_commands["stop"] = ArgsControlCommand( "stop", "stops the proxy instance on the given display", self.handle_stop_command, min_args=1, max_args=1)
def hello_oked(self, proto, packet, c, auth_caps): if ServerCore.hello_oked(self, proto, packet, c, auth_caps): #already handled in superclass return self.accept_client(proto, c) generic_request = c.strget("request") def is_req(mode): return generic_request == mode or c.boolget("%s_request" % mode) if any(is_req(x) for x in ("screenshot", "event", "print", "exit")): self.send_disconnect(proto, "invalid request") return if is_req("stop"): #global kill switch: if not CAN_STOP_PROXY: msg = "cannot stop proxy server" log.warn("Warning: %s", msg) self.send_disconnect(proto, msg) return #verify socket type (only local connections by default): try: socktype = proto._conn.get_info().get("type", "unknown") except: socktype = "unknown" if socktype not in STOP_PROXY_SOCKET_TYPES: msg = "cannot stop proxy server from a '%s' connection" % socktype log.warn("Warning: %s", msg) log.warn(" only from: %s", csv(STOP_PROXY_SOCKET_TYPES)) self.send_disconnect(proto, msg) return #connection must be authenticated: if not proto.authenticators: msg = "cannot stop proxy server from unauthenticated connections" log.warn("Warning: %s", msg) self.send_disconnect(proto, msg) return self._requests.add(proto) #send a hello back and the client should then send its "shutdown-server" packet capabilities = self.make_hello() proto.send_now(("hello", capabilities)) def force_exit_request_client(): try: self._requests.remove(proto) except KeyError: pass if not proto._closed: self.send_disconnect(proto, "timeout") self.timeout_add(10 * 1000, force_exit_request_client) return self.proxy_auth(proto, c, auth_caps)
def __init__(self): log("ProxyServer.__init__()") ServerCore.__init__(self) self._max_connections = MAX_CONCURRENT_CONNECTIONS self._start_sessions = False self.main_loop = None #proxy servers may have to connect to remote servers, #or even start them, so allow more time before timing out: self._accept_timeout += 10 #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 = {} #connections used exclusively for requests: self._requests = set() self.idle_add = glib.idle_add self.timeout_add = glib.timeout_add self.source_remove = glib.source_remove self._socket_timeout = PROXY_SOCKET_TIMEOUT self._ws_timeout = PROXY_WS_TIMEOUT self.control_commands["stop"] = ArgsControlCommand("stop", "stops the proxy instance on the given display", self.handle_stop_command, min_args=1, max_args=1)
def get_info(self, proto, *args): info = ServerCore.get_info(self, proto) info.setdefault("server", {})["type"] = "Python/GLib/proxy" #only show more info if we have authenticated #as the user running the proxy server process: pa = proto.authenticator if pa: sessions = pa.get_sessions() if sessions: uid, gid = sessions[:2] if os.name!="posix" or (uid==os.getuid() and gid==os.getgid()): info.update(ServerCore.get_info(self, proto)) self.reap() i = 0 for p,v in self.processes.items(): d,_ = v info[i] = { "display" : d, "live" : p.is_alive(), "pid" : p.pid, } i += 1 info["proxies"] = len(self.processes) return info
def get_info(self, proto, *args): info = {"server.type" : "Python/GLib/proxy"} #only show more info if we have authenticated #as the user running the proxy server process: sessions = proto.authenticator.get_sessions() if sessions: uid, gid = sessions[:2] if uid==os.getuid() and gid==os.getgid(): info.update(ServerCore.get_info(self, proto)) self.reap() i = 0 for p,v in self.processes.items(): d,_ = v info[i] = {"display" : d, "live" : p.is_alive(), "pid" : p.pid} i += 1 info["proxies"] = len(self.processes) return info
def get_info(self, proto, *args): info = {"server.type": "Python/GObject/proxy"} #only show more info if we have authenticated #as the user running the proxy server process: sessions = proto.authenticator.get_sessions() if sessions: uid, gid = sessions[:2] if uid == os.getuid() and gid == os.getgid(): info.update(ServerCore.get_info(self, proto)) self.reap() i = 0 for p, v in self.processes.items(): d, _ = v info["proxy[%s].display" % i] = d info["proxy[%s].live" % i] = p.is_alive() info["proxy[%s].pid" % i] = p.pid i += 1 info["proxies"] = len(self.processes) return info
def hello_oked(self, proto, packet, c, auth_caps): if ServerCore.hello_oked(self, proto, packet, c, auth_caps): #already handled in superclass return self.accept_client(proto, c) if any(c.boolget("%s_request" % x) for x in ("screenshot", "event", "print", "exit")): self.send_disconnect(proto, "invalid request") return if c.boolget("stop_request"): self._requests.add(proto) #send a hello back and the client should then send its "shutdown-server" packet capabilities = self.make_hello() proto.send_now(("hello", capabilities)) def force_exit_request_client(): try: self._requests.remove(proto) except: pass if not proto._closed: self.send_disconnect(proto, "timeout") self.timeout_add(10*1000, force_exit_request_client) else: self.start_proxy(proto, c, auth_caps)
def get_info(self, proto, *_args): info = ServerCore.get_minimal_server_info(self) info.setdefault("server", {})["type"] = "Python/GLib/proxy" #only show more info if we have authenticated #as the user running the proxy server process: if proto and proto.authenticators: sessions = [] for authenticator in proto.authenticators: auth_sessions = authenticator.get_sessions() if auth_sessions: sessions = auth_sessions break if sessions: uid, gid = sessions[:2] if not POSIX or (uid == getuid() and gid == getgid()): self.reap() i = 0 instances = dict(self.instances) instances_info = {} for proxy_instance, v in instances.items(): isprocess, d, _ = v iinfo = { "display": d, "live": proxy_instance.is_alive(), } if isprocess: iinfo.update({ "pid": proxy_instance.pid, }) else: iinfo.update(proxy_instance.get_info()) instances_info[i] = iinfo i += 1 info["instances"] = instances_info info["proxies"] = len(instances) return info
def init_packet_handlers(self): ServerCore.init_packet_handlers(self) #add shutdown handler self._default_packet_handlers["shutdown-server"] = self._process_proxy_shutdown_server
def cleanup(self): self.stop_all_proxies() ServerCore.cleanup(self)
def get_mdns_info(self) -> dict: mdns_info = ServerCore.get_mdns_info(self) if MDNS_CLIENT_COUNT: mdns_info["clients"] = len(self._server_sources) return mdns_info
def get_http_info(self) -> dict: info = ServerCore.get_http_info(self) info["clients"] = len(self._server_sources) return info
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 __init__(self): ServerCore.__init__(self) self.main_loop = None self.idle_add = gobject.idle_add self.timeout_add = gobject.timeout_add self.source_remove = gobject.source_remove
def is_timedout(self, protocol): v = ServerCore.is_timedout( self, protocol) and protocol not in self._server_sources netlog("is_timedout(%s)=%s", protocol, v) return v
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 init(self, opts): debug("ProxyServer.init(%s)", opts) if not opts.auth: raise Exception("The proxy server requires an authentication mode (use 'none' to disable authentication)") ServerCore.init(self, opts)