1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/kasko/testing/test_server.h"
16 :
17 : #include <windows.h>
18 :
19 : #include <string>
20 : #include "base/command_line.h"
21 : #include "base/logging.h"
22 : #include "base/process/kill.h"
23 : #include "base/strings/string_number_conversions.h"
24 : #include "base/test/test_timeouts.h"
25 : #include "syzygy/kasko/testing/launch_python_process.h"
26 : #include "syzygy/kasko/testing/safe_pipe_reader.h"
27 :
28 : namespace kasko {
29 : namespace testing {
30 : namespace {
31 :
32 : base::Process LaunchServer(HANDLE socket_write_handle,
33 E : const base::FilePath& incoming_directory) {
34 E : base::CommandLine args(base::CommandLine::NO_PROGRAM);
35 : // Pass the handle on the command-line. Although HANDLE is a
36 : // pointer, truncating it on 64-bit machines is okay. See
37 : // http://msdn.microsoft.com/en-us/library/aa384203.aspx
38 : //
39 : // "64-bit versions of Windows use 32-bit handles for
40 : // interoperability. When sharing a handle between 32-bit and 64-bit
41 : // applications, only the lower 32 bits are significant, so it is
42 : // safe to truncate the handle (when passing it from 64-bit to
43 : // 32-bit) or sign-extend the handle (when passing it from 32-bit to
44 : // 64-bit)."
45 : args.AppendSwitchASCII(
46 : "--startup-pipe",
47 E : base::IntToString(reinterpret_cast<uintptr_t>(socket_write_handle)));
48 E : args.AppendSwitchPath("--incoming-directory", incoming_directory);
49 :
50 : return LaunchPythonProcess(
51 E : base::FilePath(L"syzygy/kasko/testing/test_server.py"), args);
52 E : }
53 :
54 : } // namespace
55 :
56 E : TestServer::TestServer() : port_(0) {
57 E : }
58 :
59 E : TestServer::~TestServer() {
60 E : if (process_.IsValid()) {
61 E : int exit_code = 0;
62 E : if (!process_.WaitForExitWithTimeout(base::TimeDelta(), &exit_code))
63 E : process_.Terminate(1, true);
64 : }
65 E : }
66 :
67 E : bool TestServer::Start() {
68 E : bool started = false;
69 E : incoming_directory_.CreateUniqueTempDir();
70 E : DCHECK(incoming_directory_.IsValid());
71 :
72 E : if (incoming_directory_.IsValid()) {
73 E : SafePipeReader pipe_reader;
74 E : DCHECK(pipe_reader.IsValid());
75 :
76 E : if (pipe_reader.IsValid()) {
77 : process_ = LaunchServer(pipe_reader.write_handle(),
78 E : incoming_directory_.path());
79 E : DCHECK(process_.IsValid());
80 :
81 E : if (process_.IsValid()) {
82 : started = pipe_reader.ReadData(TestTimeouts::action_max_timeout(),
83 E : sizeof(port_), &port_);
84 E : DCHECK(started);
85 : }
86 : }
87 E : }
88 :
89 E : return started;
90 E : }
91 :
92 : } // namespace testing
93 : } // namespace kasko
|