| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Virtual Me2Me implementation. This script runs and manages the processes | 6 # Virtual Me2Me implementation. This script runs and manages the processes |
| 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop | 7 # required for a Virtual Me2Me desktop, which are: X server, X desktop |
| 8 # session, and Host process. | 8 # session, and Host process. |
| 9 # This script is intended to run continuously as a background daemon | 9 # This script is intended to run continuously as a background daemon |
| 10 # process, running under an ordinary (non-root) user account. | 10 # process, running under an ordinary (non-root) user account. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 | 185 |
| 186 def __init__(self, sizes): | 186 def __init__(self, sizes): |
| 187 self.x_proc = None | 187 self.x_proc = None |
| 188 self.session_proc = None | 188 self.session_proc = None |
| 189 self.host_proc = None | 189 self.host_proc = None |
| 190 self.child_env = None | 190 self.child_env = None |
| 191 self.sizes = sizes | 191 self.sizes = sizes |
| 192 self.pulseaudio_pipe = None | 192 self.pulseaudio_pipe = None |
| 193 self.server_supports_exact_resize = False | 193 self.server_supports_exact_resize = False |
| 194 self.host_ready = False | 194 self.host_ready = False |
| 195 self.ssh_auth_sockname = None |
| 195 g_desktops.append(self) | 196 g_desktops.append(self) |
| 196 | 197 |
| 197 @staticmethod | 198 @staticmethod |
| 198 def get_unused_display_number(): | 199 def get_unused_display_number(): |
| 199 """Return a candidate display number for which there is currently no | 200 """Return a candidate display number for which there is currently no |
| 200 X Server lock file""" | 201 X Server lock file""" |
| 201 display = FIRST_X_DISPLAY_NUMBER | 202 display = FIRST_X_DISPLAY_NUMBER |
| 202 while os.path.exists(X_LOCK_FILE_TEMPLATE % display): | 203 while os.path.exists(X_LOCK_FILE_TEMPLATE % display): |
| 203 display += 1 | 204 display += 1 |
| 204 return display | 205 return display |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 return False | 286 return False |
| 286 | 287 |
| 287 self.child_env["PULSE_CONFIG_PATH"] = pulse_path | 288 self.child_env["PULSE_CONFIG_PATH"] = pulse_path |
| 288 self.child_env["PULSE_RUNTIME_PATH"] = pulse_path | 289 self.child_env["PULSE_RUNTIME_PATH"] = pulse_path |
| 289 self.child_env["PULSE_STATE_PATH"] = pulse_path | 290 self.child_env["PULSE_STATE_PATH"] = pulse_path |
| 290 self.child_env["PULSE_SINK"] = sink_name | 291 self.child_env["PULSE_SINK"] = sink_name |
| 291 self.pulseaudio_pipe = pipe_name | 292 self.pulseaudio_pipe = pipe_name |
| 292 | 293 |
| 293 return True | 294 return True |
| 294 | 295 |
| 296 def _setup_gnubby(self): |
| 297 self.ssh_auth_sockname = ("/tmp/chromoting.%s.ssh_auth_sock" % |
| 298 os.environ["USER"]) |
| 299 |
| 295 def _launch_x_server(self, extra_x_args): | 300 def _launch_x_server(self, extra_x_args): |
| 296 x_auth_file = os.path.expanduser("~/.Xauthority") | 301 x_auth_file = os.path.expanduser("~/.Xauthority") |
| 297 self.child_env["XAUTHORITY"] = x_auth_file | 302 self.child_env["XAUTHORITY"] = x_auth_file |
| 298 devnull = open(os.devnull, "rw") | 303 devnull = open(os.devnull, "rw") |
| 299 display = self.get_unused_display_number() | 304 display = self.get_unused_display_number() |
| 300 | 305 |
| 301 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY | 306 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY |
| 302 # file which will be used for the X session. | 307 # file which will be used for the X session. |
| 303 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, | 308 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, |
| 304 env=self.child_env, shell=True) | 309 env=self.child_env, shell=True) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 | 347 |
| 343 self.child_env["DISPLAY"] = ":%d" % display | 348 self.child_env["DISPLAY"] = ":%d" % display |
| 344 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" | 349 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" |
| 345 | 350 |
| 346 # Use a separate profile for any instances of Chrome that are started in | 351 # Use a separate profile for any instances of Chrome that are started in |
| 347 # the virtual session. Chrome doesn't support sharing a profile between | 352 # the virtual session. Chrome doesn't support sharing a profile between |
| 348 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. | 353 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. |
| 349 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") | 354 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") |
| 350 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile | 355 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile |
| 351 | 356 |
| 357 # Set SSH_AUTH_SOCK to the file name to listen on. |
| 358 if self.ssh_auth_sockname: |
| 359 self.child_env["SSH_AUTH_SOCK"] = self.ssh_auth_sockname |
| 360 |
| 352 # Wait for X to be active. | 361 # Wait for X to be active. |
| 353 for _test in range(5): | 362 for _test in range(5): |
| 354 proc = subprocess.Popen("xdpyinfo", env=self.child_env, stdout=devnull) | 363 proc = subprocess.Popen("xdpyinfo", env=self.child_env, stdout=devnull) |
| 355 _pid, retcode = os.waitpid(proc.pid, 0) | 364 _pid, retcode = os.waitpid(proc.pid, 0) |
| 356 if retcode == 0: | 365 if retcode == 0: |
| 357 break | 366 break |
| 358 time.sleep(0.5) | 367 time.sleep(0.5) |
| 359 if retcode != 0: | 368 if retcode != 0: |
| 360 raise Exception("Could not connect to Xvfb.") | 369 raise Exception("Could not connect to Xvfb.") |
| 361 else: | 370 else: |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 self.session_proc = subprocess.Popen(xsession_command, | 423 self.session_proc = subprocess.Popen(xsession_command, |
| 415 stdin=open(os.devnull, "r"), | 424 stdin=open(os.devnull, "r"), |
| 416 cwd=HOME_DIR, | 425 cwd=HOME_DIR, |
| 417 env=self.child_env) | 426 env=self.child_env) |
| 418 if not self.session_proc.pid: | 427 if not self.session_proc.pid: |
| 419 raise Exception("Could not start X session") | 428 raise Exception("Could not start X session") |
| 420 | 429 |
| 421 def launch_session(self, x_args): | 430 def launch_session(self, x_args): |
| 422 self._init_child_env() | 431 self._init_child_env() |
| 423 self._setup_pulseaudio() | 432 self._setup_pulseaudio() |
| 433 self._setup_gnubby() |
| 424 self._launch_x_server(x_args) | 434 self._launch_x_server(x_args) |
| 425 self._launch_x_session() | 435 self._launch_x_session() |
| 426 | 436 |
| 427 def launch_host(self, host_config): | 437 def launch_host(self, host_config): |
| 428 # Start remoting host | 438 # Start remoting host |
| 429 args = [locate_executable(HOST_BINARY_NAME), "--host-config=-"] | 439 args = [locate_executable(HOST_BINARY_NAME), "--host-config=-"] |
| 430 if self.pulseaudio_pipe: | 440 if self.pulseaudio_pipe: |
| 431 args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) | 441 args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) |
| 432 if self.server_supports_exact_resize: | 442 if self.server_supports_exact_resize: |
| 433 args.append("--server-supports-exact-resize") | 443 args.append("--server-supports-exact-resize") |
| 444 if self.ssh_auth_sockname: |
| 445 args.append("--ssh-auth-sockname=%s" % self.ssh_auth_sockname) |
| 434 | 446 |
| 435 # Have the host process use SIGUSR1 to signal a successful start. | 447 # Have the host process use SIGUSR1 to signal a successful start. |
| 436 def sigusr1_handler(signum, frame): | 448 def sigusr1_handler(signum, frame): |
| 437 _ = signum, frame | 449 _ = signum, frame |
| 438 logging.info("Host ready to receive connections.") | 450 logging.info("Host ready to receive connections.") |
| 439 self.host_ready = True | 451 self.host_ready = True |
| 440 if (ParentProcessLogger.instance() and | 452 if (ParentProcessLogger.instance() and |
| 441 False not in [desktop.host_ready for desktop in g_desktops]): | 453 False not in [desktop.host_ready for desktop in g_desktops]): |
| 442 ParentProcessLogger.instance().release_parent() | 454 ParentProcessLogger.instance().release_parent() |
| 443 | 455 |
| (...skipping 717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1161 else: | 1173 else: |
| 1162 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) | 1174 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) |
| 1163 elif os.WIFSIGNALED(status): | 1175 elif os.WIFSIGNALED(status): |
| 1164 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) | 1176 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) |
| 1165 | 1177 |
| 1166 | 1178 |
| 1167 if __name__ == "__main__": | 1179 if __name__ == "__main__": |
| 1168 logging.basicConfig(level=logging.DEBUG, | 1180 logging.basicConfig(level=logging.DEBUG, |
| 1169 format="%(asctime)s:%(levelname)s:%(message)s") | 1181 format="%(asctime)s:%(levelname)s:%(message)s") |
| 1170 sys.exit(main()) | 1182 sys.exit(main()) |
| OLD | NEW |