| 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 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 | 197 |
| 198 def __init__(self, sizes): | 198 def __init__(self, sizes): |
| 199 self.x_proc = None | 199 self.x_proc = None |
| 200 self.session_proc = None | 200 self.session_proc = None |
| 201 self.host_proc = None | 201 self.host_proc = None |
| 202 self.child_env = None | 202 self.child_env = None |
| 203 self.sizes = sizes | 203 self.sizes = sizes |
| 204 self.pulseaudio_pipe = None | 204 self.pulseaudio_pipe = None |
| 205 self.server_supports_exact_resize = False | 205 self.server_supports_exact_resize = False |
| 206 self.host_ready = False | 206 self.host_ready = False |
| 207 self.ssh_auth_sockname = None |
| 207 g_desktops.append(self) | 208 g_desktops.append(self) |
| 208 | 209 |
| 209 @staticmethod | 210 @staticmethod |
| 210 def get_unused_display_number(): | 211 def get_unused_display_number(): |
| 211 """Return a candidate display number for which there is currently no | 212 """Return a candidate display number for which there is currently no |
| 212 X Server lock file""" | 213 X Server lock file""" |
| 213 display = FIRST_X_DISPLAY_NUMBER | 214 display = FIRST_X_DISPLAY_NUMBER |
| 214 while os.path.exists(X_LOCK_FILE_TEMPLATE % display): | 215 while os.path.exists(X_LOCK_FILE_TEMPLATE % display): |
| 215 display += 1 | 216 display += 1 |
| 216 return display | 217 return display |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 return False | 298 return False |
| 298 | 299 |
| 299 self.child_env["PULSE_CONFIG_PATH"] = pulse_path | 300 self.child_env["PULSE_CONFIG_PATH"] = pulse_path |
| 300 self.child_env["PULSE_RUNTIME_PATH"] = pulse_path | 301 self.child_env["PULSE_RUNTIME_PATH"] = pulse_path |
| 301 self.child_env["PULSE_STATE_PATH"] = pulse_path | 302 self.child_env["PULSE_STATE_PATH"] = pulse_path |
| 302 self.child_env["PULSE_SINK"] = sink_name | 303 self.child_env["PULSE_SINK"] = sink_name |
| 303 self.pulseaudio_pipe = pipe_name | 304 self.pulseaudio_pipe = pipe_name |
| 304 | 305 |
| 305 return True | 306 return True |
| 306 | 307 |
| 308 def _setup_gnubby(self): |
| 309 self.ssh_auth_sockname = ("/tmp/chromoting.%s.ssh_auth_sock" % |
| 310 os.environ["USER"]) |
| 311 |
| 307 def _launch_x_server(self, extra_x_args): | 312 def _launch_x_server(self, extra_x_args): |
| 308 x_auth_file = os.path.expanduser("~/.Xauthority") | 313 x_auth_file = os.path.expanduser("~/.Xauthority") |
| 309 self.child_env["XAUTHORITY"] = x_auth_file | 314 self.child_env["XAUTHORITY"] = x_auth_file |
| 310 devnull = open(os.devnull, "rw") | 315 devnull = open(os.devnull, "rw") |
| 311 display = self.get_unused_display_number() | 316 display = self.get_unused_display_number() |
| 312 | 317 |
| 313 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY | 318 # Run "xauth add" with |child_env| so that it modifies the same XAUTHORITY |
| 314 # file which will be used for the X session. | 319 # file which will be used for the X session. |
| 315 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, | 320 ret_code = subprocess.call("xauth add :%d . `mcookie`" % display, |
| 316 env=self.child_env, shell=True) | 321 env=self.child_env, shell=True) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 | 359 |
| 355 self.child_env["DISPLAY"] = ":%d" % display | 360 self.child_env["DISPLAY"] = ":%d" % display |
| 356 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" | 361 self.child_env["CHROME_REMOTE_DESKTOP_SESSION"] = "1" |
| 357 | 362 |
| 358 # Use a separate profile for any instances of Chrome that are started in | 363 # Use a separate profile for any instances of Chrome that are started in |
| 359 # the virtual session. Chrome doesn't support sharing a profile between | 364 # the virtual session. Chrome doesn't support sharing a profile between |
| 360 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. | 365 # multiple DISPLAYs, but Chrome Sync allows for a reasonable compromise. |
| 361 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") | 366 chrome_profile = os.path.join(CONFIG_DIR, "chrome-profile") |
| 362 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile | 367 self.child_env["CHROME_USER_DATA_DIR"] = chrome_profile |
| 363 | 368 |
| 369 # Set SSH_AUTH_SOCK to the file name to listen on. |
| 370 if self.ssh_auth_sockname: |
| 371 self.child_env["SSH_AUTH_SOCK"] = self.ssh_auth_sockname |
| 372 |
| 364 # Wait for X to be active. | 373 # Wait for X to be active. |
| 365 for _test in range(5): | 374 for _test in range(5): |
| 366 proc = subprocess.Popen("xdpyinfo", env=self.child_env, stdout=devnull) | 375 proc = subprocess.Popen("xdpyinfo", env=self.child_env, stdout=devnull) |
| 367 _pid, retcode = os.waitpid(proc.pid, 0) | 376 _pid, retcode = os.waitpid(proc.pid, 0) |
| 368 if retcode == 0: | 377 if retcode == 0: |
| 369 break | 378 break |
| 370 time.sleep(0.5) | 379 time.sleep(0.5) |
| 371 if retcode != 0: | 380 if retcode != 0: |
| 372 raise Exception("Could not connect to Xvfb.") | 381 raise Exception("Could not connect to Xvfb.") |
| 373 else: | 382 else: |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 self.session_proc = subprocess.Popen(xsession_command, | 435 self.session_proc = subprocess.Popen(xsession_command, |
| 427 stdin=open(os.devnull, "r"), | 436 stdin=open(os.devnull, "r"), |
| 428 cwd=HOME_DIR, | 437 cwd=HOME_DIR, |
| 429 env=self.child_env) | 438 env=self.child_env) |
| 430 if not self.session_proc.pid: | 439 if not self.session_proc.pid: |
| 431 raise Exception("Could not start X session") | 440 raise Exception("Could not start X session") |
| 432 | 441 |
| 433 def launch_session(self, x_args): | 442 def launch_session(self, x_args): |
| 434 self._init_child_env() | 443 self._init_child_env() |
| 435 self._setup_pulseaudio() | 444 self._setup_pulseaudio() |
| 445 self._setup_gnubby() |
| 436 self._launch_x_server(x_args) | 446 self._launch_x_server(x_args) |
| 437 self._launch_x_session() | 447 self._launch_x_session() |
| 438 | 448 |
| 439 def launch_host(self, host_config): | 449 def launch_host(self, host_config): |
| 440 # Start remoting host | 450 # Start remoting host |
| 441 args = [locate_executable(HOST_BINARY_NAME), "--host-config=-"] | 451 args = [locate_executable(HOST_BINARY_NAME), "--host-config=-"] |
| 442 if self.pulseaudio_pipe: | 452 if self.pulseaudio_pipe: |
| 443 args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) | 453 args.append("--audio-pipe-name=%s" % self.pulseaudio_pipe) |
| 444 if self.server_supports_exact_resize: | 454 if self.server_supports_exact_resize: |
| 445 args.append("--server-supports-exact-resize") | 455 args.append("--server-supports-exact-resize") |
| 456 if self.ssh_auth_sockname: |
| 457 args.append("--ssh-auth-sockname=%s" % self.ssh_auth_sockname) |
| 446 | 458 |
| 447 # Have the host process use SIGUSR1 to signal a successful start. | 459 # Have the host process use SIGUSR1 to signal a successful start. |
| 448 def sigusr1_handler(signum, frame): | 460 def sigusr1_handler(signum, frame): |
| 449 _ = signum, frame | 461 _ = signum, frame |
| 450 logging.info("Host ready to receive connections.") | 462 logging.info("Host ready to receive connections.") |
| 451 self.host_ready = True | 463 self.host_ready = True |
| 452 if (ParentProcessLogger.instance() and | 464 if (ParentProcessLogger.instance() and |
| 453 False not in [desktop.host_ready for desktop in g_desktops]): | 465 False not in [desktop.host_ready for desktop in g_desktops]): |
| 454 ParentProcessLogger.instance().release_parent() | 466 ParentProcessLogger.instance().release_parent() |
| 455 | 467 |
| (...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1189 else: | 1201 else: |
| 1190 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) | 1202 logging.info("Host exited with status %s." % os.WEXITSTATUS(status)) |
| 1191 elif os.WIFSIGNALED(status): | 1203 elif os.WIFSIGNALED(status): |
| 1192 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) | 1204 logging.info("Host terminated by signal %s." % os.WTERMSIG(status)) |
| 1193 | 1205 |
| 1194 | 1206 |
| 1195 if __name__ == "__main__": | 1207 if __name__ == "__main__": |
| 1196 logging.basicConfig(level=logging.DEBUG, | 1208 logging.basicConfig(level=logging.DEBUG, |
| 1197 format="%(asctime)s:%(levelname)s:%(message)s") | 1209 format="%(asctime)s:%(levelname)s:%(message)s") |
| 1198 sys.exit(main()) | 1210 sys.exit(main()) |
| OLD | NEW |