def do_get_resources_dir(): rsc = None RESOURCES = "/Resources/" #FUGLY warning: importing gtkosx_application causes the dock to appear, #and in some cases we don't want that.. so use the env var XPRA_SKIP_UI as workaround for such cases: if os.environ.get("XPRA_SKIP_UI", "0")=="0": try: import gtkosx_application #@UnresolvedImport try: rsc = gtkosx_application.gtkosx_application_get_resource_path() debug("get_resources_dir() gtkosx_application_get_resource_path=%s", rsc) except: #maybe we're not running from an app bundle? pass except: #delayed import to prevent cycles: from xpra.log import Logger log = Logger("util") log.error("ERROR: gtkosx_application module is missing - trying to continue anyway") else: debug("XPRA_SKIP_UI is set, not importing gtkosx_application") if rsc is None: #try using the path to this file to find the resource path: rsc = __file__ i = rsc.rfind(RESOURCES) if i<=0: #last fallback: try the default app dir from xpra.platform.paths import default_get_app_dir rsc = default_get_app_dir() debug("get_resources_dir() default_get_app_dir()=%s", rsc) i = rsc.rfind(RESOURCES) if i>0: rsc = rsc[:i+len(RESOURCES)] debug("get_resources_dir()=%s", rsc) return rsc
class console_event_catcher(object): def __init__(self, event_cb, events=CONSOLE_EXIT_EVENTS): self.event_cb = event_cb self.events = events self.result = 0 from xpra.log import Logger self.log = Logger("win32") def __enter__(self): try: self.result = win32api.SetConsoleCtrlHandler(self.handle_console_event, 1) if self.result == 0: self.log.error("could not SetConsoleCtrlHandler (error %r)", win32api.GetLastError()) except Exception as e: self.log.error("SetConsoleCtrlHandler error: %s", e) def __exit__(self, exc_type, exc_val, exc_tb): try: win32api.SetConsoleCtrlHandler(None, 0) except: pass def __repr__(self): return "console_event_catcher(%s, %s)" % (self.event_cb, self.events) def handle_console_event(self, event): self.log("handle_console_event(%s)", event) if event in self.events: self.log.info("received console event %s", event) self.event_cb(event)
def handle_socket_error(sockpath, e): from xpra.log import Logger log = Logger("network") log("socket creation error", exc_info=True) if sockpath.startswith("/var/run/xpra") or sockpath.startswith("/run/xpra"): log.warn("Warning: cannot create socket '%s'", sockpath) log.warn(" %s", e) dirname = sockpath[:sockpath.find("xpra")+len("xpra")] if not os.path.exists(dirname): log.warn(" %s does not exist", dirname) if POSIX: uid = getuid() username = get_username_for_uid(uid) groups = get_groups(username) log.warn(" user '%s' is a member of groups: %s", username, csv(groups) or "no groups!") if "xpra" not in groups: log.warn(" missing 'xpra' group membership?") for x in path_permission_info(dirname): log.warn(" %s", x) elif sockpath.startswith("/var/run/user") or sockpath.startswith("/run/user"): log.warn("Warning: cannot create socket '%s':", sockpath) log.warn(" %s", e) run_user = sockpath.split("/user")[0]+"/user" if not os.path.exists(run_user): log.warn(" %s does not exist", run_user) else: log.warn(" ($XDG_RUNTIME_DIR has not been created?)") else: log.error("Error: failed to create socket '%s':", sockpath) log.error(" %s", e) raise InitException("failed to create socket %s" % sockpath)
def err(*msg): """ log an error message and return None """ from xpra.log import Logger log = Logger("icon") log.error(*msg) return None
def get_sys_info(): info = {} try: import resource for k, constant in { "server": "RUSAGE_SELF", "children": "RUSAGE_CHILDREN", "total": "RUSAGE_BOTH" }.items(): try: v = getattr(resource, constant) except (NameError, AttributeError): continue stats = resource.getrusage(v) prefix = "memory.%s." % k for var in ("utime", "stime", "maxrss", "ixrss", "idrss", "isrss", "minflt", "majflt", "nswap", "inblock", "oublock", "msgsnd", "msgrcv", "nsignals", "nvcsw", "nivcsw"): value = getattr(stats, "ru_%s" % var) if type(value) == float: value = int(value) info[prefix + var] = value except: from xpra.log import Logger log = Logger() log.error("error getting memory usage info", exc_info=True) return info
def verify_display_ready(xvfb, display_name, shadowing): from xpra.log import Logger log = Logger("server") from xpra.x11.bindings.wait_for_x_server import wait_for_x_server #@UnresolvedImport # Whether we spawned our server or not, it is now running -- or at least # starting. First wait for it to start up: try: wait_for_x_server(display_name, 3) # 3s timeout except Exception as e: sys.stderr.write("%s\n" % e) return None # Now we can safely load gtk and connect: assert "gtk" not in sys.modules import gtk.gdk #@Reimport try: import glib glib.threads_init() except: #old versions do not have this method pass display = gtk.gdk.Display(display_name) manager = gtk.gdk.display_manager_get() default_display = manager.get_default_display() if default_display is not None: default_display.close() manager.set_default_display(display) if not shadowing and not check_xvfb_process(xvfb): #if we're here, there is an X11 server, but it isn't the one we started! log.error("There is an X11 server already running on display %s:" % display_name) log.error("You may want to use:") log.error(" 'xpra upgrade %s' if an instance of xpra is still connected to it" % display_name) log.error(" 'xpra --use-display start %s' to connect xpra to an existing X11 server only" % display_name) log.error("") return None return display
def set_initial_resolution(desktop=False): from xpra.log import Logger try: log = Logger("server") log("set_initial_resolution") if desktop: res = DEFAULT_DESKTOP_VFB_RESOLUTION else: res = DEFAULT_VFB_RESOLUTION from xpra.x11.bindings.randr_bindings import RandRBindings #@UnresolvedImport #try to set a reasonable display size: randr = RandRBindings() if not randr.has_randr(): l = log if desktop: l = log.warn l("Warning: no RandR support,") l(" default virtual display size unchanged") return sizes = randr.get_screen_sizes() size = randr.get_screen_size() log("RandR available, current size=%s, sizes available=%s", size, sizes) if res in sizes: log("RandR setting new screen size to %s", res) randr.set_screen_size(*res) except Exception as e: log("set_initial_resolution(%s)", desktop, exc_info=True) log.error("Error: failed to set the default screen size:") log.error(" %s", e)
def get_sys_info(): info = {} try: import resource for k, constant in {"server" : "RUSAGE_SELF", "children" : "RUSAGE_CHILDREN", "total" : "RUSAGE_BOTH"}.items(): try: v = getattr(resource, constant) except (NameError, AttributeError): continue stats = resource.getrusage(v) prefix = "memory.%s." % k for var in ("utime", "stime", "maxrss", "ixrss", "idrss", "isrss", "minflt", "majflt", "nswap", "inblock", "oublock", "msgsnd", "msgrcv", "nsignals", "nvcsw", "nivcsw"): value = getattr(stats, "ru_%s" % var) if type(value)==float: value = int(value) info[prefix+var] = value except: from xpra.log import Logger log = Logger() log.error("error getting memory usage info", exc_info=True) return info
class console_event_catcher(object): def __init__(self, event_cb, events=CONSOLE_EXIT_EVENTS): self.event_cb = event_cb self.events = events self.result = 0 from xpra.log import Logger self.log = Logger("win32") def __enter__(self): try: self.result = win32api.SetConsoleCtrlHandler( self.handle_console_event, 1) if self.result == 0: self.log.error("could not SetConsoleCtrlHandler (error %r)", win32api.GetLastError()) except Exception as e: self.log.error("SetConsoleCtrlHandler error: %s", e) def __exit__(self, exc_type, exc_val, exc_tb): try: win32api.SetConsoleCtrlHandler(None, 0) except: pass def __repr__(self): return "console_event_catcher(%s, %s)" % (self.event_cb, self.events) def handle_console_event(self, event): self.log("handle_console_event(%s)", event) if event in self.events: self.log.info("received console event %s", event) self.event_cb(event)
def get_sys_info(): try: from xpra.platform.xposix.info import get_sys_info as xposix_get_sys_info return xposix_get_sys_info() except: from xpra.log import Logger log = Logger("osx") log.error("error getting memory usage info", exc_info=True) return {}
def setbinarymode(fd): if sys.platform.startswith("win"): #turn on binary mode: try: import msvcrt msvcrt.setmode(fd, os.O_BINARY) #@UndefinedVariable except: from xpra.log import Logger log = Logger("util") log.error("setting stdin to binary mode failed", exc_info=True)
def setbinarymode(fd): if WIN32: #turn on binary mode: try: import msvcrt msvcrt.setmode(fd, os.O_BINARY) #@UndefinedVariable except: from xpra.log import Logger log = Logger("util") log.error("setting stdin to binary mode failed", exc_info=True)
def mdns_publish(display_name, mode, listen_on, text_dict={}): try: from xpra.net.avahi_publisher import AvahiPublishers except Exception, e: global MDNS_WARNING if not MDNS_WARNING: MDNS_WARNING = True from xpra.log import Logger log = Logger() log.error("failed to load the mdns avahi publisher: %s", e) log.error("either fix your installation or use the '--no-mdns' flag") return
def mdns_publish(display_name, mode, listen_on, text_dict={}): try: from xpra.net.avahi_publisher import AvahiPublishers except Exception, e: global MDNS_WARNING if not MDNS_WARNING: MDNS_WARNING = True from xpra.log import Logger log = Logger("mdns") log.error("failed to load the mdns avahi publisher: %s", e) log.error("either fix your installation or use the '--no-mdns' flag") return
def check_xvfb_process(xvfb=None): if xvfb is None: #we don't have a process to check return True if xvfb.poll() is None: #process is running return True from xpra.log import Logger log = Logger("server") log.error("") log.error("Xvfb command has terminated! xpra cannot continue") log.error(" if the display is already running, try a different one,") log.error(" or use the --use-display flag") log.error("") return False
def mdns_publish(display_name, mode, listen_on, text_dict={}): try: from xpra.net.avahi_publisher import AvahiPublishers except Exception as e: global MDNS_WARNING if not MDNS_WARNING: MDNS_WARNING = True from xpra.log import Logger log = Logger("mdns") log.error("failed to load the mdns avahi publisher: %s", e) log.error("either fix your installation or use the '--no-mdns' flag") return d = text_dict.copy() d["mode"] = mode ap = AvahiPublishers(listen_on, "Xpra %s %s" % (mode, display_name), text_dict=d) _when_ready.append(ap.start) _cleanups.append(ap.stop)
def do_get_resources_dir(): rsc = None RESOURCES = "/Resources/" #FUGLY warning: importing gtkosx_application causes the dock to appear, #and in some cases we don't want that.. so use the env var XPRA_SKIP_UI as workaround for such cases: if not envbool("XPRA_SKIP_UI", False): try: import gtkosx_application #@UnresolvedImport try: rsc = gtkosx_application.gtkosx_application_get_resource_path() debug( "get_resources_dir() gtkosx_application_get_resource_path=%s", rsc) except: #maybe we're not running from an app bundle? pass except: global _gtkosx_warning_ if _gtkosx_warning_ is False: _gtkosx_warning_ = True #delayed import to prevent cycles: from xpra.log import Logger log = Logger("util") log.error( "ERROR: gtkosx_application module is missing - trying to continue anyway" ) else: debug("XPRA_SKIP_UI is set, not importing gtkosx_application") if rsc is None: #try using the path to this file to find the resource path: rsc = __file__ i = rsc.rfind(RESOURCES) if i <= 0: #last fallback: try the default app dir from xpra.platform.paths import default_get_app_dir rsc = default_get_app_dir() debug("get_resources_dir() default_get_app_dir()=%s", rsc) i = rsc.rfind(RESOURCES) if i > 0: rsc = rsc[:i + len(RESOURCES)] debug("get_resources_dir()=%s", rsc) return rsc
def mdns_publish(display_name, mode, listen_on, text_dict={}): try: from xpra.net.avahi_publisher import AvahiPublishers except Exception as e: global MDNS_WARNING if not MDNS_WARNING: MDNS_WARNING = True from xpra.log import Logger log = Logger("mdns") log.error("failed to load the mdns avahi publisher: %s", e) log.error( "either fix your installation or use the '--no-mdns' flag") return d = text_dict.copy() d["mode"] = mode ap = AvahiPublishers(listen_on, "Xpra %s %s" % (mode, display_name), text_dict=d) _when_ready.append(ap.start) _cleanups.append(ap.stop)
def main(): from xpra.platform import program_context from xpra.log import enable_color, Logger, enable_debug_for log = Logger("win32") with program_context("LSA-Logon-Test", "LSA Logon Test"): enable_color() for x in ("-v", "--verbose"): if x in list(sys.argv): enable_debug_for("win32") sys.argv.remove(x) if len(sys.argv) != 2: log.warn("invalid number of arguments") log.warn("usage: %s [--verbose] username", sys.argv[0]) return 1 username = sys.argv[1] try: logon_msv1_s4u(username) return 0 except Exception as e: log.error("Logon failed: %s", e) return 1
def write_runner_shell_scripts(contents, overwrite=True): # This used to be given a display-specific name, but now we give it a # single fixed name and if multiple servers are started then the last one # will clobber the rest. This isn't great, but the tradeoff is that it # makes it possible to use bare 'ssh:hostname' display names and # autodiscover the proper numeric display name when only one xpra server # is running on the remote host. Might need to revisit this later if # people run into problems or autodiscovery turns out to be less useful # than expected. from xpra.log import Logger log = Logger("server") from xpra.platform.paths import get_script_bin_dirs for d in get_script_bin_dirs(): scriptdir = osexpand(d) if not os.path.exists(scriptdir): try: os.mkdir(scriptdir, 0o700) except Exception as e: log.warn("Warning: failed to write script file in '%s':", scriptdir) log.warn(" %s", e) if scriptdir.startswith( "/var/run/user") or scriptdir.startswith("/run/user"): log.warn(" ($XDG_RUNTIME_DIR has not been created?)") continue scriptpath = os.path.join(scriptdir, "run-xpra") if os.path.exists(scriptpath) and not overwrite: continue # Write out a shell-script so that we can start our proxy in a clean # environment: try: with open(scriptpath, "w") as scriptfile: # Unix is a little silly sometimes: umask = os.umask(0) os.umask(umask) os.fchmod(scriptfile.fileno(), 0o700 & ~umask) scriptfile.write(contents) except Exception as e: log.error("Error: failed to write script file '%s':", scriptpath) log.error(" %s\n", e)
def write_pidfile(pidfile, uid, gid): from xpra.log import Logger log = Logger("server") pidstr = str(os.getpid()) try: with open(pidfile, "w") as f: os.fchmod(f.fileno(), 0o600) f.write("%s\n" % pidstr) try: inode = os.fstat(f.fileno()).st_ino except: inode = -1 if POSIX and uid != getuid() or gid != getgid(): try: os.fchown(f.fileno(), uid, gid) except: pass log.info("wrote pid %s to '%s'", pidstr, pidfile) def cleanuppidfile(): #verify this is the right file! log("cleanuppidfile: inode=%i", inode) if inode > 0: try: i = os.stat(pidfile).st_ino log("cleanuppidfile: current inode=%i", i) if i != inode: return except: pass try: os.unlink(pidfile) except: pass add_cleanup(cleanuppidfile) except Exception as e: log.error("Error: failed to write pid %i to pidfile '%s':", os.getpid(), pidfile) log.error(" %s", e)
def verify_display_ready(xvfb, display_name, shadowing): from xpra.log import Logger log = Logger("server") from xpra.x11.bindings.wait_for_x_server import wait_for_x_server #@UnresolvedImport # Whether we spawned our server or not, it is now running -- or at least # starting. First wait for it to start up: try: wait_for_x_server(display_name, 3) # 3s timeout except Exception as e: sys.stderr.write("%s\n" % e) return None # Now we can safely load gtk and connect: no_gtk() import gtk.gdk #@Reimport try: import glib glib.threads_init() except: #old versions do not have this method pass display = gtk.gdk.Display(display_name) manager = gtk.gdk.display_manager_get() default_display = manager.get_default_display() if default_display is not None: default_display.close() manager.set_default_display(display) if not shadowing and not check_xvfb_process(xvfb): #if we're here, there is an X11 server, but it isn't the one we started! log.error("There is an X11 server already running on display %s:" % display_name) log.error("You may want to use:") log.error( " 'xpra upgrade %s' if an instance of xpra is still connected to it" % display_name) log.error( " 'xpra --use-display start %s' to connect xpra to an existing X11 server only" % display_name) log.error("") return None return display
def get_peercred(sock): from xpra.log import Logger log = Logger("network") if LINUX: SO_PEERCRED = 17 try: import socket import struct creds = sock.getsockopt(socket.SOL_SOCKET, SO_PEERCRED, struct.calcsize('3i')) pid, uid, gid = struct.unpack('3i', creds) log("peer: %s", (pid, uid, gid)) return pid, uid, gid except Exception as e: log("getsockopt", exc_info=True) log.error("Error getting peer credentials: %s", e) return None elif FREEBSD: #TODO: use getpeereid #then pwd to get the gid? pass return None
def main(): from xpra.platform import program_context from xpra.platform.gui import init as gui_init from xpra.util import print_nested_dict from xpra.log import enable_color, Logger with program_context("OpenGL Native Context Check"): gui_init() enable_color() log = Logger("opengl") verbose = "-v" in sys.argv or "--verbose" in sys.argv if verbose: log.enable_debug() if not GLContext: log.error("Error: no GLContext available on %s", sys.platform) return 1 try: props = check_support() except Exception: log.error("%s().check_support()", exc_info=True) return 1 log.info("") log.info("OpenGL properties:") print_nested_dict(props) return 0
def abort_test(action): """ if ssh dies, we don't need to try to read/write from its sockets """ e = child.poll() if e is not None: error_message = "cannot %s using %s: the SSH process has terminated with exit code=%s" % (action, display_desc["full_ssh"], e) if debug_cb: debug_cb(error_message) if ssh_fail_cb: ssh_fail_cb(error_message) if "ssh_abort" not in display_desc: display_desc["ssh_abort"] = True from xpra.log import Logger log = Logger() log.error("The SSH process has terminated with exit code %s", e) if conn.input_bytecount==0 and conn.output_bytecount==0: log.error("Connection to the xpra server via SSH failed for: %s", display_name) log.error(" the command line used was: %s", cmd) log.error(" check your username, hostname, display number, etc") raise ConnectionClosedException(error_message)
def do_print_pdf(hdc, title="PDF Print Test", pdf_data=None): assert pdf_data, "no pdf data" from xpra.log import Logger log = Logger("printing", "win32") log("pdfium=%s", pdfium) buf = c_char_p(pdf_data) log("pdf data buffer: %s", repr_ellipsized(pdf_data)) log("FPDF_InitLibraryWithConfig=%s", FPDF_InitLibraryWithConfig) config = FPDF_LIBRARY_CONFIG() config.m_pUserFontPaths = None config.version = 2 config.m_pIsolate = None config.m_v8EmbedderSlot = 0 FPDF_InitLibraryWithConfig(config) x = 0 y = 0 w = GetDeviceCaps(hdc, win32con.HORZRES) h = GetDeviceCaps(hdc, win32con.VERTRES) rotate = 0 log("printer device size: %ix%i", w, h) flags = FPDF_PRINTING | FPDF_DEBUG_INFO try: doc = FPDF_LoadMemDocument(cast(buf, c_void_p), len(pdf_data), None) if not doc: log.error("Error: FPDF_LoadMemDocument failed, error: %s", get_error()) return -1 log("FPDF_LoadMemDocument(..)=%s", doc) count = FPDF_GetPageCount(doc) log("FPDF_GetPageCount(%s)=%s", doc, count) docinfo = DOCINFO() docinfo.lpszDocName = LPCSTR("%s\0" % title) jobid = StartDocA(hdc, pointer(docinfo)) if jobid < 0: log.error("Error: StartDocA failed: %i", jobid) return jobid log("StartDocA()=%i", jobid) try: for i in range(count): page = FPDF_LoadPage(doc, i) if not page: log.error( "Error: FPDF_LoadPage failed for page %i, error: %s", i, get_error()) return -2 log("FPDF_LoadPage()=%s page %i loaded", page, i) FPDF_RenderPage(hdc, page, x, y, w, h, rotate, flags) log("FPDF_RenderPage page %i rendered", i) finally: EndDoc(hdc) finally: FPDF_DestroyLibrary() return jobid
def check_xvfb_process(xvfb=None): if xvfb is None: #we don't have a process to check return True if xvfb.poll() is None: #process is running return True from xpra.log import Logger log = Logger("server") log.error("") log.error("Xvfb command has terminated! xpra cannot continue") log.error("") return False
def setup_console_event_listener(handler, enable): try: from xpra.platform.win32.common import SetConsoleCtrlHandler, ConsoleCtrlHandler from xpra.log import Logger log = Logger("win32") log("calling SetConsoleCtrlHandler(%s, %s)", handler, enable) ctypes_handler = ConsoleCtrlHandler(handler) result = SetConsoleCtrlHandler(ctypes_handler, enable) log("SetConsoleCtrlHandler(%s, %s)=%s", handler, enable, result) if result==0: log.error("Error: could not %s console control handler:", "set" if enable else "unset") log.error(" SetConsoleCtrlHandler: %r", ctypes.GetLastError()) return False return True except Exception as e: log.error("SetConsoleCtrlHandler error: %s", e) return False
DEFAULT_SINK = "osxaudiosink" elif sys.platform.startswith("win"): SINKS.append("directsoundsink") DEFAULT_SINK = "directsoundsink" if os.name == "posix": SINKS += ["alsasink", "osssink", "oss4sink", "jackaudiosink"] # SINK_SHARED_DEFAULT_ATTRIBUTES = {"sync" : False, # "async" : True} SINK_SHARED_DEFAULT_ATTRIBUTES = {"sync": False, "async": True, "qos": True} SINK_DEFAULT_ATTRIBUTES = {0: {"pulsesink": {"client": "Xpra"}}, 1: {"pulsesink": {"client-name": "Xpra"}}} DEFAULT_SINK = os.environ.get("XPRA_SOUND_SINK", DEFAULT_SINK) if DEFAULT_SINK not in SINKS: log.error("invalid default sound sink: '%s' is not in %s, using %s instead", DEFAULT_SINK, SINKS, SINKS[0]) DEFAULT_SINK = SINKS[0] QUEUE_SILENT = 0 QUEUE_TIME = get_queue_time(450) QUEUE_MIN_TIME = get_queue_time(QUEUE_TIME // 10 // MS_TO_NS, "MIN") assert QUEUE_MIN_TIME <= QUEUE_TIME VARIABLE_MIN_QUEUE = os.environ.get("XPRA_VARIABLE_MIN_QUEUE", "1") == "1" GST_FORMAT_BUFFERS = 4 def sink_has_device_attribute(sink): return sink not in ("autoaudiosink", "jackaudiosink", "directsoundsink")
self._closed) except KeyboardInterrupt, e: raise e except ConnectionClosedException, e: if not self._closed: self._internal_error("%s connection %s closed: %s" % (name, self._conn, e)) except (OSError, IOError, socket_error), e: if not self._closed: self._internal_error("%s connection %s reset: %s" % (name, self._conn, e), exc_info=e.args[0] not in ABORT) except: #can happen during close(), in which case we just ignore: if not self._closed: log.error("%s error on %s", name, self._conn, exc_info=True) self.close() def _write_thread_loop(self): self._io_thread_loop("write", self._write) def _write(self): items = self._write_queue.get() # Used to signal that we should exit: if items is None: log("write thread: empty marker, exiting") self.close() return for buf, start_cb, end_cb in items: con = self._conn if not con:
mouselog = Logger("posix", "mouse") xinputlog = Logger("posix", "xinput") from xpra.os_util import bytestostr, hexstr from xpra.util import iround, envbool, envint, csv from xpra.gtk_common.gtk_util import get_xwindow from xpra.os_util import is_X11, is_Wayland X11WindowBindings = None X11XI2Bindings = None if is_X11(): try: from xpra.x11.bindings.window_bindings import X11WindowBindings #@UnresolvedImport from xpra.x11.bindings.xi2_bindings import X11XI2Bindings #@UnresolvedImport except Exception as e: log.error("no X11 bindings", exc_info=True) del e device_bell = None GTK_MENUS = envbool("XPRA_GTK_MENUS", False) RANDR_DPI = envbool("XPRA_RANDR_DPI", True) XSETTINGS_DPI = envbool("XPRA_XSETTINGS_DPI", True) USE_NATIVE_TRAY = envbool("XPRA_USE_NATIVE_TRAY", True) XINPUT_WHEEL_DIV = envint("XPRA_XINPUT_WHEEL_DIV", 15) DBUS_SCREENSAVER = envbool("XPRA_DBUS_SCREENSAVER", False) def gl_check(): if not is_X11() and is_Wayland(): return "disabled under wayland with GTK3 (buggy)" return None
from xpra.util import envbool from xpra.log import Logger log = Logger("events", "win32") from xpra.platform.win32.wndproc_events import WNDPROC_EVENT_NAMES from xpra.platform.win32 import constants as win32con from xpra.platform.win32.common import (WNDCLASSEX, WNDPROC, RegisterClassExW, CreateWindowExA, DestroyWindow, UnregisterClassW, DefWindowProcW, GetModuleHandleA, GetStockObject) try: wtsapi32 = ctypes.WinDLL("WtsApi32") except Exception as e: log.error( "Error: cannot load WtsApi2 DLL, session events will not be detected") log.error(" %s", e) del e wtsapi32 = None NOTIFY_FOR_THIS_SESSION = 0 KNOWN_EVENTS = {} POWER_EVENTS = {} for x in dir(win32con): if x.endswith("_EVENT"): v = getattr(win32con, x) KNOWN_EVENTS[v] = x if x.startswith("PBT_"): v = getattr(win32con, x) POWER_EVENTS[v] = x
def run_server(error_cb, opts, mode, xpra_file, extra_args): try: cwd = os.getcwd() except: cwd = os.path.expanduser("~") sys.stderr.write( "current working directory does not exist, using '%s'\n" % cwd) if opts.encoding and opts.encoding == "help": #avoid errors and warnings: opts.encoding = "" opts.clipboard = False opts.notifications = False print("xpra server supports the following encodings:") print("(please wait, encoder initialization may take a few seconds)") #disable info logging which would be confusing here from xpra.log import get_all_loggers, set_default_level import logging set_default_level(logging.WARN) logging.root.setLevel(logging.WARN) for x in get_all_loggers(): x.logger.setLevel(logging.WARN) from xpra.server.server_base import ServerBase sb = ServerBase() sb.init(opts) #ensures that the threaded video helper init has completed #(by running it again, which will block on the init lock) from xpra.codecs.video_helper import getVideoHelper getVideoHelper().init() sb.init_encodings() from xpra.codecs.loader import encoding_help for e in sb.encodings: print(" * %s" % encoding_help(e)) return 0 assert mode in ("start", "upgrade", "shadow", "proxy") starting = mode == "start" upgrading = mode == "upgrade" shadowing = mode == "shadow" proxying = mode == "proxy" clobber = upgrading or opts.use_display start_vfb = not shadowing and not proxying and not clobber if upgrading or shadowing: #there should already be one running opts.pulseaudio = False #get the display name: if shadowing and len(extra_args) == 0: if sys.platform.startswith("win") or sys.platform.startswith("darwin"): #just a virtual name for the only display available: display_name = ":0" else: from xpra.scripts.main import guess_X11_display display_name = guess_X11_display(opts.socket_dir, opts.socket_dirs) elif upgrading and len(extra_args) == 0: display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs) else: if len(extra_args) > 1: error_cb( "too many extra arguments: only expected a display number") if len(extra_args) == 1: display_name = extra_args[0] if not shadowing and not proxying: display_name_check(display_name) else: if proxying: error_cb( "you must specify a free virtual display name to use with the proxy server" ) if not opts.displayfd: error_cb( "displayfd support is not enabled on this system, you must specify the display to use" ) if opts.use_display: #only use automatic guess for xpra displays and not X11 displays: display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs) else: # We will try to find one automaticaly # Use the temporary magic value 'S' as marker: display_name = 'S' + str(os.getpid()) if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child: error_cb( "--exit-with-children specified without any children to spawn; exiting immediately" ) atexit.register(run_cleanups) #the server class will usually override those: #SIGINT breaks GTK3.. (but there are no py3k servers!) signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) # Generate the script text now, because os.getcwd() will # change if/when we daemonize: script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir) if start_vfb or opts.daemon: #we will probably need a log dir #either for the vfb, or for our own log file log_dir = os.path.expanduser(opts.log_dir) if not os.path.exists(log_dir): try: os.mkdir(log_dir, 0o700) except OSError as e: raise InitException( "failed to create the Xorg log directory '%s': %s" % (xorg_log_dir, e)) stdout = sys.stdout stderr = sys.stderr # Daemonize: if opts.daemon: #daemonize will chdir to "/", so try to use an absolute path: if opts.password_file: opts.password_file = os.path.abspath(opts.password_file) # At this point we may not know the display name, # so log_filename0 may point to a temporary file which we will rename later log_filename0 = select_log_file(log_dir, opts.log_file, display_name) logfd = open_log_file(log_filename0) assert logfd > 2 stdout, stderr = daemonize(logfd) try: stderr.write("Entering daemon mode; " + "any further errors will be reported to:\n" + (" %s\n" % log_filename0)) except: #this can happen if stderr is closed by the caller already pass if os.name == "posix": # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_script(script) from xpra.log import Logger log = Logger("server") #warn early about this: if starting: de = os.environ.get("XDG_SESSION_DESKTOP") or os.environ.get( "SESSION_DESKTOP") if de and (opts.pulseaudio or opts.notifications): log.warn( "Warning: xpra start from an existing '%s' desktop session", de) log.warn(" pulseaudio and notifications forwarding may not work") log.warn( " try using a clean environment, a dedicated user, or turn off those options" ) mdns_recs = [] sockets = [] # Initialize the TCP sockets before the display, # That way, errors won't make us kill the Xvfb # (which may not be ours to kill at that point) bind_tcp = parse_bind_tcp(opts.bind_tcp) for host, iport in bind_tcp: socket = setup_tcp_socket(host, iport) sockets.append(socket) if opts.mdns: rec = "tcp", [(host, iport)] mdns_recs.append(rec) # Do this after writing out the shell script: if display_name[0] != 'S': os.environ["DISPLAY"] = display_name sanitize_env() configure_imsettings_env(opts.input_method) # Start the Xvfb server first to get the display_name if needed xvfb = None xvfb_pid = None if start_vfb: try: xvfb, display_name = start_Xvfb(opts.xvfb, display_name) except OSError as e: log.error("Error starting Xvfb: %s\n", e) return 1 xvfb_pid = xvfb.pid #always update as we may now have the "real" display name: os.environ["DISPLAY"] = display_name if opts.daemon: log_filename1 = select_log_file(log_dir, opts.log_file, display_name) if log_filename0 != log_filename1: # we now have the correct log filename, so use it: os.rename(log_filename0, log_filename1) stderr.write("Actual log file name is now: %s\n" % log_filename1) stdout.close() stderr.close() if not check_xvfb_process(xvfb): #xvfb problem: exit now return 1 #setup unix domain socket: socket, cleanup_socket = setup_local_socket(opts.socket_dir, opts.socket_dirs, display_name, clobber, opts.mmap_group, opts.socket_permissions) if socket: #win32 returns None! sockets.append(socket) if opts.mdns: ssh_port = get_ssh_port() if ssh_port: mdns_recs.append(("ssh", [("", ssh_port)])) #publish mdns records: if opts.mdns: from xpra.platform.info import get_username mdns_info = {"display": display_name, "username": get_username()} if opts.session_name: mdns_info["session"] = opts.session_name for mode, listen_on in mdns_recs: mdns_publish(display_name, mode, listen_on, mdns_info) if not check_xvfb_process(xvfb): #xvfb problem: exit now return 1 display = None if not sys.platform.startswith("win") and not sys.platform.startswith( "darwin") and not proxying: display = verify_display_ready(xvfb, display_name, shadowing) if not display: return 1 elif not proxying: no_gtk() import gtk #@Reimport assert gtk if shadowing: from xpra.platform.shadow_server import ShadowServer app = ShadowServer() info = "shadow" elif proxying: from xpra.server.proxy.proxy_server import ProxyServer app = ProxyServer() info = "proxy" else: assert starting or upgrading from xpra.x11.gtk2 import gdk_display_source assert gdk_display_source #(now we can access the X11 server) if clobber: #get the saved pid (there should be one): xvfb_pid = get_xvfb_pid() elif xvfb_pid is not None: #save the new pid (we should have one): save_xvfb_pid(xvfb_pid) #check for an existing window manager: from xpra.x11.gtk2.wm import wm_check if not wm_check(display, opts.wm_name, upgrading): return 1 try: # This import is delayed because the module depends on gtk: from xpra.x11.server import XpraServer from xpra.x11.bindings.window_bindings import X11WindowBindings #@UnresolvedImport X11Window = X11WindowBindings() except ImportError as e: log.error( "Failed to load Xpra server components, check your installation: %s" % e) return 1 if not X11Window.displayHasXComposite(): log.error( "Xpra is a compositing manager, it cannot use a display which lacks the XComposite extension!" ) return 1 log("XShape=%s", X11Window.displayHasXShape()) app = XpraServer(clobber) info = "xpra" #we got this far so the sockets have initialized and #the server should be able to manage the display #from now on, if we exit without upgrading we will also kill the Xvfb def kill_xvfb(): # Close our display(s) first, so the server dying won't kill us. log.info("killing xvfb with pid %s" % xvfb_pid) import gtk #@Reimport for display in gtk.gdk.display_manager_get().list_displays(): display.close() os.kill(xvfb_pid, signal.SIGTERM) if xvfb_pid is not None and not opts.use_display and not shadowing: _cleanups.append(kill_xvfb) try: app.exec_cwd = cwd app.init(opts) except InitException as e: log.error("xpra server initialization error:") log.error(" %s", e) return 1 except Exception as e: log.error("Error: cannot start the %s server", info, exc_info=True) log.error(str(e)) log.info("") return 1 #honour start child, html webserver, and setup child reaper if os.name == "posix" and not proxying and not upgrading and not shadowing: # start websockify? try: start_websockify(app.child_reaper, opts, bind_tcp) #websockify overrides the tcp proxy, so we must re-set it: app._tcp_proxy = opts.tcp_proxy except Exception as e: error_cb("failed to setup websockify html server: %s" % e) if opts.exit_with_children: assert opts.start_child, "exit-with-children was specified but start-child is missing!" if opts.start: for x in opts.start: if x: app.start_child(x, x, True) if opts.start_child: for x in opts.start_child: if x: app.start_child(x, x, False) log("%s(%s)", app.init_sockets, sockets) app.init_sockets(sockets) log("%s(%s)", app.init_when_ready, _when_ready) app.init_when_ready(_when_ready) try: log("running %s", app.run) e = app.run() log("%s()=%s", app.run, e) except KeyboardInterrupt: log.info("stopping on KeyboardInterrupt") e = 0 except Exception as e: log.error("server error", exc_info=True) e = -128 if e > 0: # Upgrading/exiting, so leave X server running if kill_xvfb in _cleanups: _cleanups.remove(kill_xvfb) from xpra.server.server_core import ServerCore if e == ServerCore.EXITING_CODE: log.info("exiting: not cleaning up Xvfb") elif cleanup_socket in _cleanups: log.info("upgrading: not cleaning up Xvfb or socket") # don't delete the new socket (not ours) _cleanups.remove(cleanup_socket) log("cleanups=%s", _cleanups) e = 0 return e
def create_sockets(opts, error_cb): bind_tcp = parse_bind_ip(opts.bind_tcp) bind_udp = parse_bind_ip(opts.bind_udp) bind_ssl = parse_bind_ip(opts.bind_ssl, 443) bind_ssh = parse_bind_ip(opts.bind_ssh, 22) bind_ws = parse_bind_ip(opts.bind_ws, 80) bind_wss = parse_bind_ip(opts.bind_wss, 443) bind_rfb = parse_bind_ip(opts.bind_rfb, 5900) bind_vsock = parse_bind_vsock(opts.bind_vsock) sockets = {} min_port = int(opts.min_port) def add_tcp_socket(socktype, host_str, iport, options): if iport != 0 and iport < min_port: error_cb("invalid %s port number %i (minimum value is %i)" % (socktype, iport, min_port)) for host in hosts(host_str): sock = setup_tcp_socket(host, iport, socktype) host, iport = sock[2] sockets[sock] = options def add_udp_socket(socktype, host_str, iport, options): if iport != 0 and iport < min_port: error_cb("invalid %s port number %i (minimum value is %i)" % (socktype, iport, min_port)) for host in hosts(host_str): sock = setup_udp_socket(host, iport, socktype) host, iport = sock[2] sockets[sock] = options # Initialize the TCP sockets before the display, # That way, errors won't make us kill the Xvfb # (which may not be ours to kill at that point) ssh_upgrades = opts.ssh_upgrade if ssh_upgrades: try: from xpra.net.ssh import nogssapi_context with nogssapi_context(): import paramiko assert paramiko except ImportError as e: from xpra.log import Logger sshlog = Logger("ssh") sshlog("import paramiko", exc_info=True) sshlog.error("Error: cannot enable SSH socket upgrades:") sshlog.error(" %s", e) ssh_upgrades = False log = get_network_logger() for socktype, defs in { "tcp": bind_tcp, "ssl": bind_ssl, "ssh": bind_ssh, "ws": bind_ws, "wss": bind_wss, "rfb": bind_rfb, }.items(): log("setting up %s sockets: %s", socktype, csv(defs.items())) for (host, iport), options in defs.items(): add_tcp_socket(socktype, host, iport, options) log("setting up UDP sockets: %s", csv(bind_udp.items())) for (host, iport), options in bind_udp.items(): add_udp_socket("udp", host, iport, options) log("setting up vsock sockets: %s", csv(bind_vsock.items())) for (cid, iport), options in bind_vsock.items(): sock = setup_vsock_socket(cid, iport) sockets[sock] = options # systemd socket activation: if POSIX and not OSX: try: from xpra.platform.xposix.sd_listen import get_sd_listen_sockets except ImportError as e: log("no systemd socket activation: %s", e) else: sd_sockets = get_sd_listen_sockets() log("systemd sockets: %s", sd_sockets) for stype, sock, addr in sd_sockets: sock = setup_sd_listen_socket(stype, sock, addr) sockets[sock] = {} log("%s : %s", (stype, [addr]), sock) return sockets
def run_server(parser, opts, mode, xpra_file, extra_args): if opts.encoding and opts.encoding=="help": #avoid errors and warnings: opts.encoding = "" opts.clipboard = False opts.notifications = False print("xpra server supports the following encodings:") print("(please wait, encoder initialization may take a few seconds)") #disable info logging which would be confusing here from xpra.log import get_all_loggers, set_default_level import logging set_default_level(logging.WARN) logging.root.setLevel(logging.WARN) for x in get_all_loggers(): x.logger.setLevel(logging.WARN) from xpra.server.server_base import ServerBase sb = ServerBase() sb.init(opts) #ensures that the threaded video helper init has completed #(by running it again, which will block on the init lock) from xpra.codecs.video_helper import getVideoHelper getVideoHelper().init() sb.init_encodings() from xpra.codecs.loader import encoding_help for e in sb.encodings: print(" * %s" % encoding_help(e)) return 0 assert mode in ("start", "upgrade", "shadow", "proxy") starting = mode == "start" upgrading = mode == "upgrade" shadowing = mode == "shadow" proxying = mode == "proxy" clobber = upgrading or opts.use_display #get the display name: if shadowing and len(extra_args)==0: from xpra.scripts.main import guess_X11_display display_name = guess_X11_display() else: if len(extra_args) != 1: parser.error("need exactly 1 extra argument") display_name = extra_args.pop(0) if not shadowing and not proxying: display_name_check(display_name) if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child: sys.stderr.write("--exit-with-children specified without any children to spawn; exiting immediately") return 1 atexit.register(run_cleanups) #the server class will usually override those: signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) dotxpra = DotXpra(opts.socket_dir) # Generate the script text now, because os.getcwd() will # change if/when we daemonize: script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir) # Daemonize: if opts.daemon: #daemonize will chdir to "/", so try to use an absolute path: if opts.password_file: opts.password_file = os.path.abspath(opts.password_file) logfd = open_log_file(dotxpra, opts.log_file, display_name) assert logfd > 2 daemonize(logfd) # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_script(dotxpra, script) from xpra.log import Logger log = Logger("server") try: # Initialize the sockets before the display, # That way, errors won't make us kill the Xvfb # (which may not be ours to kill at that point) bind_tcp = parse_bind_tcp(opts.bind_tcp) sockets = [] mdns_info = {"display" : display_name, "username": getpass.getuser()} if opts.session_name: mdns_info["session"] = opts.session_name #tcp: for host, iport in bind_tcp: socket = setup_tcp_socket(host, iport) sockets.append(socket) #unix: socket, cleanup_socket = setup_local_socket(dotxpra, display_name, clobber, opts.mmap_group) if socket: #win32 returns None! sockets.append(socket) if opts.mdns: ssh_port = get_ssh_port() if ssh_port: mdns_publish(display_name, "ssh", [("", ssh_port)], mdns_info) if opts.mdns: mdns_publish(display_name, "tcp", bind_tcp, mdns_info) except Exception, e: log.error("cannot start server: failed to setup sockets: %s", e) return 1
debug = debug_if_env(log, "XPRA_NETWORK_DEBUG") from xpra.os_util import Queue, strtobytes from xpra.daemon_thread import make_daemon_thread from xpra.net.bencode import bencode, bdecode from xpra.simple_stats import std_unit, std_unit_dec rencode_dumps, rencode_loads, rencode_version = None, None, None try: try: from xpra.net.rencode import dumps as rencode_dumps #@UnresolvedImport from xpra.net.rencode import loads as rencode_loads #@UnresolvedImport from xpra.net.rencode import __version__ rencode_version = __version__ debug("found rencode version %s", rencode_version) except ImportError: log.error("rencode load error", exc_info=True) except Exception, e: log.error("xpra.rencode is missing: %s", e) has_rencode = rencode_dumps is not None and rencode_loads is not None and rencode_version is not None use_rencode = has_rencode and not os.environ.get("XPRA_USE_BENCODER", "0")=="1" #stupid python version breakage: if sys.version > '3': long = int #@ReservedAssignment unicode = str #@ReservedAssignment def zcompress(packet, level): return compress(bytes(packet, 'UTF-8'), level) else: def zcompress(packet, level): return compress(packet, level)
if not depressed: """ when the key is released, just ignore it - do NOT send it to the server! """ return True try: method = getattr(window, action) log("key_handled_as_shortcut(%s,%s,%s,%s) found shortcut=%s, will call %s%s", window, key_name, modifiers, depressed, shortcut, method, args) except AttributeError, e: log.error("key dropped, invalid method name in shortcut %s: %s", action, e) return True try: method(*args) log("key_handled_as_shortcut(%s,%s,%s,%s) has been handled: %s", window, key_name, modifiers, depressed, method) except KeyboardInterrupt: raise except Exception, e: log.error("key_handled_as_shortcut(%s,%s,%s,%s) failed to execute shortcut=%s: %s", window, key_name, modifiers, depressed, shortcut, e) return True def handle_key_action(self, window, wid, key_event): """ Intercept key shortcuts and gives the Keyboard class a chance to fire more than one send_key_action. (win32 uses this for AltGr emulation) """ if self.key_handled_as_shortcut(window, key_event.keyname, key_event.modifiers, key_event.pressed): return self.keyboard.process_key_event(self.send_key_action, wid, key_event) def send_key_action(self, wid, key_event): log("send_key_action(%s, %s)", wid, key_event)
LZ4_compress, LZ4_uncompress = None, None has_lz4 = False def lz4_compress(packet, level): raise Exception("lz4 is not supported!") use_lz4 = has_lz4 and os.environ.get("XPRA_USE_LZ4", "1")=="1" rencode_dumps, rencode_loads, rencode_version = None, None, None try: try: from xpra.net.rencode import dumps as rencode_dumps #@UnresolvedImport from xpra.net.rencode import loads as rencode_loads #@UnresolvedImport from xpra.net.rencode import __version__ as rencode_version except ImportError, e: log.warn("rencode import error: %s", e) except Exception, e: log.error("error loading rencode", exc_info=True) has_rencode = rencode_dumps is not None and rencode_loads is not None and rencode_version is not None use_rencode = has_rencode and os.environ.get("XPRA_USE_RENCODER", "1")=="1" log("protocol: has_rencode=%s, use_rencode=%s, version=%s", has_rencode, use_rencode, rencode_version) bencode, bdecode, bencode_version = None, None, None if sys.version_info[0]<3: #bencode needs porting to Python3.. try: try: from xpra.net.bencode import bencode, bdecode, __version__ as bencode_version except ImportError, e: log.warn("bencode import error: %s", e, exc_info=True) except Exception, e: log.error("error loading bencoder", exc_info=True) has_bencode = bencode is not None and bdecode is not None
__import__("xpra.client.gl", {}, {}, []) __import__("gtk.gdkgl", {}, {}, []) __import__("gtk.gtkgl", {}, {}, []) gl_check = __import__("xpra.client.gl.gl_check", {}, {}, ["check_support"]) w, h = self.get_root_size() min_texture_size = max(w, h) self.opengl_props = gl_check.check_support(min_texture_size, force_enable=(enable_opengl is True)) gl_client_window = __import__("xpra.client.gl.gl_client_window", {}, {}, ["GLClientWindow"]) self.GLClientWindowClass = gl_client_window.GLClientWindow self.client_supports_opengl = True self.opengl_enabled = True except ImportError, e: log.info("OpenGL support not enabled: %s", e) self.opengl_props["info"] = str(e) except Exception, e: log.error("Error loading OpenGL support: %s", e, exc_info=True) self.opengl_props["info"] = str(e) def get_group_leader(self, metadata, override_redirect): if not self.supports_group_leader: return None wid = metadata.get("transient-for") if wid>0: client_window = self._id_to_window.get(wid) if client_window: gdk_window = client_window.gdk_window() if gdk_window: return gdk_window pid = metadata.get("pid", -1) leader_xid = metadata.get("group-leader-xid") leader_wid = metadata.get("group-leader-wid")
log("io_thread_loop(%s, %s) loop starting", name, callback) while not self._closed: callback() log("io_thread_loop(%s, %s) loop ended, closed=%s", name, callback, self._closed) except KeyboardInterrupt, e: raise e except ConnectionClosedException, e: if not self._closed: #log it at debug level #(rely on location where we raise to provide better logging) log("%s connection closed for %s", name, self._conn) self._call_connection_lost("%s connection closed: %s" % (name, e)) except (OSError, IOError, socket_error), e: if not self._closed: if e.args[0] in ABORT: log.error("%s connection reset or aborted for %s", name, self._conn) self._call_connection_lost("%s connection reset: %s" % (name, e)) else: log.error("%s error for %s", name, self._conn, exc_info=True) self._call_connection_lost("%s error on connection: %s" % (name, e)) except Exception, e: #can happen during close(), in which case we just ignore: if not self._closed: log.error("%s error on %s", name, self._conn, exc_info=True) self.close() def _write_thread_loop(self): self._io_thread_loop("write", self._write) def _write(self): items = self._write_queue.get() # Used to signal that we should exit:
log = Logger("sound", "gstreamer") #used on the server (reversed): XPRA_PULSE_SOURCE_DEVICE_NAME = "Speaker" XPRA_PULSE_SINK_DEVICE_NAME = "Microphone" GST_QUEUE_NO_LEAK = 0 GST_QUEUE_LEAK_UPSTREAM = 1 GST_QUEUE_LEAK_DOWNSTREAM = 2 GST_QUEUE_LEAK_DEFAULT = GST_QUEUE_LEAK_DOWNSTREAM MS_TO_NS = 1000000 QUEUE_LEAK = int(os.environ.get("XPRA_SOUND_QUEUE_LEAK", GST_QUEUE_LEAK_DEFAULT)) if QUEUE_LEAK not in (GST_QUEUE_NO_LEAK, GST_QUEUE_LEAK_UPSTREAM, GST_QUEUE_LEAK_DOWNSTREAM): log.error("invalid leak option %s", QUEUE_LEAK) QUEUE_LEAK = GST_QUEUE_LEAK_DEFAULT def get_queue_time(default_value=450, prefix=""): queue_time = int(os.environ.get("XPRA_SOUND_QUEUE_%sTIME" % prefix, default_value))*MS_TO_NS queue_time = max(0, queue_time) return queue_time WIN32 = sys.platform.startswith("win") OSX = sys.platform.startswith("darwin") ALLOW_SOUND_LOOP = os.environ.get("XPRA_ALLOW_SOUND_LOOP", "0")=="1" GSTREAMER1 = os.environ.get("XPRA_GSTREAMER1", "1")=="1" PULSEAUDIO_DEVICE_NAME = os.environ.get("XPRA_PULSEAUDIO_DEVICE_NAME", "") USE_DEFAULT_DEVICE = os.environ.get("XPRA_USE_DEFAULT_DEVICE", "1")=="1"
mmap_size = os.path.getsize(mmap_filename) mmap_area = mmap.mmap(f.fileno(), mmap_size) if mmap_token: #verify the token: v = read_mmap_token(mmap_area) log("mmap_token=%s, verification=%s", mmap_token, v) if v!=mmap_token: log.warn("WARNING: mmap token verification failed, not using mmap area!") log.warn("expected '%s', found '%s'", mmap_token, v) mmap_area.close() return None, 0 if new_mmap_token: write_mmap_token(mmap_area, new_mmap_token) return mmap_area, mmap_size except Exception, e: log.error("cannot use mmap file '%s': %s", mmap_filename, e, exc_info=True) if mmap_area: mmap_area.close() return None, 0 def int_from_buffer(mmap_area, pos): return ctypes.c_uint32.from_buffer(mmap_area, pos) #@UndefinedVariable #descr_data is a list of (offset, length) #areas from the mmap region def mmap_read(mmap_area, descr_data): """ Reads data from the mmap_area as written by 'mmap_write'. The descr_data is the list of mmap chunks used. """
rencode_dumps, rencode_loads, rencode_version = None, None, None try: try: import rencode rencode_dumps = rencode.dumps rencode_loads = rencode.loads try: rencode_version = rencode.__version__ log("loaded rencode version %s from %s", rencode_version, rencode.__file__) except: log.warn("rencode at '%s' lacks versioning information", rencode.__file__) rencode_version = "unknown" except ImportError as e: log.warn("rencode import error: %s", e) except Exception as e: log.error("error loading rencode", exc_info=True) has_rencode = rencode_dumps is not None and rencode_loads is not None and rencode_version is not None use_rencode = has_rencode and os.environ.get("XPRA_USE_RENCODER", "1")=="1" log("packet encoding: has_rencode=%s, use_rencode=%s, version=%s", has_rencode, use_rencode, rencode_version) bencode, bdecode, bencode_version = None, None, None if sys.version_info[0]<3: #bencode needs porting to Python3.. try: try: from xpra.net.bencode import bencode, bdecode, __version__ as bencode_version except ImportError as e: log.warn("bencode import error: %s", e, exc_info=True) except Exception as e: log.error("error loading bencoder", exc_info=True)
if not sys.platform.startswith("win"): library = "libc.so.6" if sys.platform.startswith("darwin"): library = "/usr/lib/libc.dylib" elif sys.platform.startswith("sunos"): library = "libsocket.so.1" elif sys.platform.startswith("freebsd"): library = "/usr/lib/libc.so" elif sys.platform.startswith("openbsd"): library = "libc.so" try: from ctypes import cdll, CDLL, c_char_p, c_uint, create_string_buffer cdll.LoadLibrary(library) # <CDLL 'libc.so.6', handle 7fcac419b000 at 7fcac1ab0c10> _libc = CDLL(library) debug("successfully loaded socket C library from %s", library) except ImportError, e: log.error("library %s not found: %s", library, e) except OSError, e: log.error("error loading %s: %s", library, e) else: _libc.if_indextoname.restype = c_char_p def if_nametoindex(interfaceName): return _libc.if_nametoindex(interfaceName) def if_indextoname(index): s = create_string_buffer("\000" * 256) return _libc.if_indextoname(c_uint(index), s)
def run_server(parser, opts, mode, xpra_file, extra_args): if opts.encoding and opts.encoding=="help": from xpra.codecs.loader import encodings_help from xpra.server.server_base import ServerBase print("xpra server supports the following encodings:\n * %s" % ("\n * ".join(encodings_help(ServerBase().encodings)))) return 0 assert mode in ("start", "upgrade", "shadow", "proxy") starting = mode == "start" upgrading = mode == "upgrade" shadowing = mode == "shadow" proxying = mode == "proxy" clobber = upgrading or opts.use_display #get the display name: if shadowing and len(extra_args)==0: from xpra.scripts.main import guess_X11_display display_name = guess_X11_display() else: if len(extra_args) != 1: parser.error("need exactly 1 extra argument") display_name = extra_args.pop(0) if not shadowing and not proxying: display_name_check(display_name) if not shadowing and not proxying and opts.exit_with_children and not opts.start_child: sys.stderr.write("--exit-with-children specified without any children to spawn; exiting immediately") return 1 atexit.register(run_cleanups) #the server class will usually override those: signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) dotxpra = DotXpra(opts.socket_dir) # Generate the script text now, because os.getcwd() will # change if/when we daemonize: script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir) # Daemonize: if opts.daemon: logfd = open_log_file(dotxpra, opts.log_file, display_name) assert logfd > 2 daemonize(logfd) # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_script(dotxpra, script) from xpra.log import Logger log = Logger() try: # Initialize the sockets before the display, # That way, errors won't make us kill the Xvfb # (which may not be ours to kill at that point) bind_tcp = parse_bind_tcp(opts.bind_tcp) sockets = [] mdns_info = {"display" : display_name, "username": getpass.getuser()} if opts.session_name: mdns_info["session"] = opts.session_name #tcp: for host, iport in bind_tcp: socket = setup_tcp_socket(host, iport) sockets.append(socket) #unix: socket, cleanup_socket = setup_local_socket(dotxpra, display_name, clobber, opts.mmap_group) if socket: #win32 returns None! sockets.append(socket) if opts.mdns: ssh_port = get_ssh_port() if ssh_port: mdns_publish(display_name, "ssh", [("", ssh_port)], mdns_info) if opts.mdns: mdns_publish(display_name, "tcp", bind_tcp, mdns_info) except Exception, e: log.error("cannot start server: failed to setup sockets: %s", e) return 1
self.idle_add(self.handle_command_request, proto, command_req) return #continue processing hello packet in UI thread: self.idle_add(self.call_hello_oked, proto, packet, c, auth_caps) def call_hello_oked(self, proto, packet, c, auth_caps): try: self.hello_oked(proto, packet, c, auth_caps) except ClientException, e: log.error("error setting up connection for %s: %s", proto, e) self.disconnect_client(proto, SERVER_ERROR, str(e)) except Exception, e: #log full stack trace at debug level, #log exception as error #but don't disclose internal details to the client log.error("server error processing new connection from %s: %s", proto, e, exc_info=True) self.disconnect_client(proto, SERVER_ERROR, "error accepting new connection") def set_socket_timeout(self, conn, timeout=None): #FIXME: this is ugly, but less intrusive than the alternative? if isinstance(conn, SocketConnection): conn._socket.settimeout(timeout) def verify_hello(self, proto, c): remote_version = c.strget("version") verr = version_compat_check(remote_version) if verr is not None: self.disconnect_client(proto, VERSION_ERROR, "incompatible version: %s" % verr) proto.close() return False
DEFAULT_SINK = "osxaudiosink" elif sys.platform.startswith("win"): SINKS.append("directsoundsink") DEFAULT_SINK = "directsoundsink" if os.name=="posix": SINKS += ["alsasink", "osssink", "oss4sink", "jackaudiosink"] GST_QUEUE_NO_LEAK = 0 GST_QUEUE_LEAK_UPSTREAM = 1 GST_QUEUE_LEAK_DOWNSTREAM = 2 GST_QUEUE_LEAK_DEFAULT = GST_QUEUE_LEAK_DOWNSTREAM MS_TO_NS = 1000000 QUEUE_LEAK = int(os.environ.get("XPRA_SOUND_QUEUE_LEAK", GST_QUEUE_LEAK_DEFAULT)) if QUEUE_LEAK not in (GST_QUEUE_NO_LEAK, GST_QUEUE_LEAK_UPSTREAM, GST_QUEUE_LEAK_DOWNSTREAM): log.error("invalid leak option %s", QUEUE_LEAK) QUEUE_LEAK = GST_QUEUE_LEAK_DEFAULT QUEUE_TIME = int(os.environ.get("XPRA_SOUND_QUEUE_TIME", "450"))*MS_TO_NS QUEUE_TIME = max(0, QUEUE_TIME) DEFAULT_SINK = os.environ.get("XPRA_SOUND_SINK", DEFAULT_SINK) if DEFAULT_SINK not in SINKS: log.error("invalid default sound sink: '%s' is not in %s, using %s instead", DEFAULT_SINK, SINKS, SINKS[0]) DEFAULT_SINK = SINKS[0] QUEUE_SILENT = 0 def sink_has_device_attribute(sink): return sink not in ("autoaudiosink", "jackaudiosink", "directsoundsink") class SoundSink(SoundPipeline):
def run_server(error_cb, opts, mode, xpra_file, extra_args): try: cwd = os.getcwd() except: cwd = os.path.expanduser("~") sys.stderr.write("current working directory does not exist, using '%s'\n" % cwd) if opts.encoding and opts.encoding == "help": # avoid errors and warnings: opts.encoding = "" opts.clipboard = False opts.notifications = False print("xpra server supports the following encodings:") print("(please wait, encoder initialization may take a few seconds)") # disable info logging which would be confusing here from xpra.log import get_all_loggers, set_default_level import logging set_default_level(logging.WARN) logging.root.setLevel(logging.WARN) for x in get_all_loggers(): x.logger.setLevel(logging.WARN) from xpra.server.server_base import ServerBase sb = ServerBase() sb.init(opts) # ensures that the threaded video helper init has completed # (by running it again, which will block on the init lock) from xpra.codecs.video_helper import getVideoHelper getVideoHelper().init() sb.init_encodings() from xpra.codecs.loader import encoding_help for e in sb.encodings: print(" * %s" % encoding_help(e)) return 0 assert mode in ("start", "upgrade", "shadow", "proxy") starting = mode == "start" upgrading = mode == "upgrade" shadowing = mode == "shadow" proxying = mode == "proxy" clobber = upgrading or opts.use_display # get the display name: if shadowing and len(extra_args) == 0: if sys.platform.startswith("win") or sys.platform.startswith("darwin"): # just a virtual name for the only display available: display_name = ":0" else: from xpra.scripts.main import guess_X11_display display_name = guess_X11_display(opts.socket_dir) elif upgrading and len(extra_args) == 0: from xpra.scripts.main import guess_xpra_display display_name = guess_xpra_display(opts.socket_dir) else: if len(extra_args) > 1: error_cb("too many extra arguments: only expected a display number") if len(extra_args) == 1: display_name = extra_args[0] if not shadowing and not proxying: display_name_check(display_name) else: if proxying: error_cb("you must specify a free virtual display name to use with the proxy server") if not opts.displayfd: error_cb("displayfd support is not enabled on this system, you must specify the display to use") if opts.use_display: # only use automatic guess for xpra displays and not X11 displays: from xpra.scripts.main import guess_xpra_display # @Reimport display_name = guess_xpra_display(opts.socket_dir) else: # We will try to find one automaticaly # Use the temporary magic value 'S' as marker: display_name = "S" + str(os.getpid()) if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child: error_cb("--exit-with-children specified without any children to spawn; exiting immediately") atexit.register(run_cleanups) # the server class will usually override those: signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) dotxpra = DotXpra(opts.socket_dir) # Generate the script text now, because os.getcwd() will # change if/when we daemonize: script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir) stdout = sys.stdout stderr = sys.stderr # Daemonize: if opts.daemon: # daemonize will chdir to "/", so try to use an absolute path: if opts.password_file: opts.password_file = os.path.abspath(opts.password_file) # At this point we may not know the display name, # so log_filename0 may point to a temporary file which we will rename later log_filename0 = select_log_file(dotxpra, opts.log_file, display_name) logfd = open_log_file(log_filename0) assert logfd > 2 stdout, stderr = daemonize(logfd) try: stderr.write( "Entering daemon mode; " + "any further errors will be reported to:\n" + (" %s\n" % log_filename0) ) except: # this can happen if stderr is closed by the caller already pass # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_script(dotxpra, script) from xpra.log import Logger log = Logger("server") mdns_recs = [] sockets = [] try: # Initialize the TCP sockets before the display, # That way, errors won't make us kill the Xvfb # (which may not be ours to kill at that point) bind_tcp = parse_bind_tcp(opts.bind_tcp) for host, iport in bind_tcp: socket = setup_tcp_socket(host, iport) sockets.append(socket) if opts.mdns: mdns_recs.append(("tcp", bind_tcp)) except Exception, e: log.error("cannot start server: failed to setup sockets: %s", e) return 1
#used on the server (reversed): XPRA_PULSE_SOURCE_DEVICE_NAME = "XPRA_PULSE_SOURCE_DEVICE_NAME" XPRA_PULSE_SINK_DEVICE_NAME = "XPRA_PULSE_SINK_DEVICE_NAME" GST_QUEUE_NO_LEAK = 0 GST_QUEUE_LEAK_UPSTREAM = 1 GST_QUEUE_LEAK_DOWNSTREAM = 2 GST_QUEUE_LEAK_DEFAULT = GST_QUEUE_LEAK_DOWNSTREAM MS_TO_NS = 1000000 GST_FLOW_OK = 0 #Gst.FlowReturn.OK QUEUE_LEAK = envint("XPRA_SOUND_QUEUE_LEAK", GST_QUEUE_LEAK_DEFAULT) if QUEUE_LEAK not in (GST_QUEUE_NO_LEAK, GST_QUEUE_LEAK_UPSTREAM, GST_QUEUE_LEAK_DOWNSTREAM): log.error("invalid leak option %s", QUEUE_LEAK) QUEUE_LEAK = GST_QUEUE_LEAK_DEFAULT def get_queue_time(default_value=450, prefix=""): queue_time = int(os.environ.get("XPRA_SOUND_QUEUE_%sTIME" % prefix, default_value))*MS_TO_NS queue_time = max(0, queue_time) return queue_time ALLOW_SOUND_LOOP = envbool("XPRA_ALLOW_SOUND_LOOP", False) USE_DEFAULT_DEVICE = envbool("XPRA_USE_DEFAULT_DEVICE", True) IGNORED_INPUT_DEVICES = os.environ.get("XPRA_SOUND_IGNORED_INPUT_DEVICES", "bell.ogg,bell.wav").split(",") IGNORED_OUTPUT_DEVICES = os.environ.get("XPRA_SOUND_IGNORED_OUTPUT_DEVICES", "bell-window-system").split(",") def force_enabled(codec_name): return os.environ.get("XPRA_SOUND_CODEC_ENABLE_%s" % codec_name.upper().replace("+", "_"), "0")=="1"
log( "key_handled_as_shortcut(%s,%s,%s,%s) found shortcut=%s, will call %s%s", window, key_name, modifiers, depressed, shortcut, method, args) except AttributeError, e: log.error("key dropped, invalid method name in shortcut %s: %s", action, e) return True try: method(*args) log("key_handled_as_shortcut(%s,%s,%s,%s) has been handled: %s", window, key_name, modifiers, depressed, method) except KeyboardInterrupt: raise except Exception, e: log.error( "key_handled_as_shortcut(%s,%s,%s,%s) failed to execute shortcut=%s: %s", window, key_name, modifiers, depressed, shortcut, e) return True def handle_key_action(self, window, wid, key_event): """ Intercept key shortcuts and gives the Keyboard class a chance to fire more than one send_key_action. (win32 uses this for AltGr emulation) """ if self.key_handled_as_shortcut(window, key_event.keyname, key_event.modifiers, key_event.pressed): return self.keyboard.process_key_event(self.send_key_action, wid, key_event)
dbus.UInt16(self.port), self.text, ) log("calling %s%s", g, args) g.AddService(*args) g.Commit() self.group = g log("dbus service added") except DBusException, e: # use try+except as older versions may not have those modules? message = e.get_dbus_message() dbus_error_name = e.get_dbus_name() if dbus_error_name == "org.freedesktop.Avahi.CollisionError": log.error( "error starting publisher %s: another instance already claims this dbus name: %s, message: %s", self, e, message, ) return log.warn("failed to start %s: %s", self, e) helpmsg() def stop(self): log("%s.stop() group=%s", self, self.group) if self.group: try: self.group.Reset() self.group = None except Exception, e: log.error("error stopping publisher %s: %s", self, e)
SINKS.append("directsoundsink") DEFAULT_SINK = "directsoundsink" if os.name == "posix": SINKS += ["alsasink", "osssink", "oss4sink", "jackaudiosink"] GST_QUEUE_NO_LEAK = 0 GST_QUEUE_LEAK_UPSTREAM = 1 GST_QUEUE_LEAK_DOWNSTREAM = 2 GST_QUEUE_LEAK_DEFAULT = GST_QUEUE_LEAK_DOWNSTREAM MS_TO_NS = 1000000 QUEUE_LEAK = int( os.environ.get("XPRA_SOUND_QUEUE_LEAK", GST_QUEUE_LEAK_DEFAULT)) if QUEUE_LEAK not in (GST_QUEUE_NO_LEAK, GST_QUEUE_LEAK_UPSTREAM, GST_QUEUE_LEAK_DOWNSTREAM): log.error("invalid leak option %s", QUEUE_LEAK) QUEUE_LEAK = GST_QUEUE_LEAK_DEFAULT QUEUE_TIME = int(os.environ.get("XPRA_SOUND_QUEUE_TIME", "450")) * MS_TO_NS QUEUE_TIME = max(0, QUEUE_TIME) DEFAULT_SINK = os.environ.get("XPRA_SOUND_SINK", DEFAULT_SINK) if DEFAULT_SINK not in SINKS: log.error( "invalid default sound sink: '%s' is not in %s, using %s instead", DEFAULT_SINK, SINKS, SINKS[0]) DEFAULT_SINK = SINKS[0] QUEUE_SILENT = 0 def sink_has_device_attribute(sink): return sink not in ("autoaudiosink", "jackaudiosink", "directsoundsink")
ptime = os.stat(password_file).st_mtime except Exception, e: log.error("error accessing password file time: %s", e) if auth_data is None or ptime!=auth_data_time: auth_data = {} auth_data_time = ptime f = None try: try: f = open(password_file, mode='rb') data = f.read() finally: if f: f.close() except Exception, e: log.error("error loading %s: %s", password_file, e) data = "" i = 0 for line in data.splitlines(): i += 1 line = line.strip() if len(line)==0 or line.startswith("#"): continue debug("line %s: %s", i, line) if line.find("|")<0: #assume old style file with just the password #get all the displays for the current user: sockdir = DotXpra(socket_dir) results = sockdir.sockets() displays = [display for state, display in results if state==DotXpra.LIVE] auth_data[""] = line, os.getuid(), os.getgid(), displays, {}, {}
if has_pa(): SOURCES.append("pulsesrc") if sys.platform.startswith("darwin"): SOURCES.append("osxaudiosrc") elif sys.platform.startswith("win"): SOURCES.append("directsoundsrc") if os.name=="posix": SOURCES += ["alsasrc", "jackaudiosrc", "osssrc", "oss4src", "osxaudiosrc", "jackaudiosrc"] SOURCES.append("audiotestsrc") DEFAULT_SRC = os.environ.get("XPRA_SOUND_DEFAULT_SRC", SOURCES[0]) if DEFAULT_SRC not in SOURCES: log.error("invalid default sound source: '%s' is not in %s, using %s instead", DEFAULT_SRC, SOURCES, SOURCES[0]) DEFAULT_SRC = SOURCES[0] AUDIOCONVERT = True AUDIORESAMPLE = False class SoundSource(SoundPipeline): __gsignals__ = SoundPipeline.__generic_signals__.copy() __gsignals__.update({ "new-buffer" : n_arg_signal(2), }) def __init__(self, src_type=DEFAULT_SRC, src_options={}, codec=MP3, volume=1.0, encoder_options={}):