1 : // Copyright 2015 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/safe_pipe_reader.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/location.h"
19 : #include "base/logging.h"
20 :
21 : namespace kasko {
22 : namespace testing {
23 : namespace {
24 :
25 : // Writes |size| bytes to |handle| and sets |*unblocked| to true.
26 : // Used as a crude timeout mechanism by ReadData().
27 E : void UnblockPipe(HANDLE handle, size_t size, bool* unblocked) {
28 E : std::string unblock_data(size, '\0');
29 : // Unblock the ReadFile in LocalTestServer::WaitToStart by writing to the
30 : // pipe. Make sure the call succeeded, otherwise we are very likely to hang.
31 E : DWORD bytes_written = 0;
32 E : LOG(WARNING) << "Timeout reached; unblocking pipe by writing " << size
33 : << " bytes";
34 E : *unblocked = true;
35 E : CHECK(::WriteFile(handle, unblock_data.data(), size, &bytes_written, NULL));
36 E : CHECK_EQ(size, bytes_written);
37 E : }
38 :
39 : } // namespace
40 :
41 : SafePipeReader::SafePipeReader()
42 : : thread_("SafePipeReader watcher"),
43 : write_handle_(INVALID_HANDLE_VALUE),
44 E : read_handle_(INVALID_HANDLE_VALUE) {
45 E : thread_.Start();
46 E : DCHECK(thread_.IsRunning());
47 :
48 E : if (thread_.IsRunning()) {
49 E : HANDLE child_read = NULL;
50 E : HANDLE child_write = NULL;
51 E : BOOL result = ::CreatePipe(&child_read, &child_write, NULL, 0);
52 E : DCHECK(result);
53 E : if (result) {
54 E : read_handle_ = child_read;
55 E : write_handle_ = child_write;
56 :
57 : // Make the write half inheritable.
58 : result = ::SetHandleInformation(write_handle_, HANDLE_FLAG_INHERIT,
59 E : HANDLE_FLAG_INHERIT);
60 E : DCHECK(result);
61 : }
62 : }
63 E : }
64 :
65 E : SafePipeReader::~SafePipeReader() {
66 E : if (read_handle_ != INVALID_HANDLE_VALUE)
67 E : ::CloseHandle(read_handle_);
68 E : if (write_handle_ != INVALID_HANDLE_VALUE)
69 E : ::CloseHandle(write_handle_);
70 E : }
71 :
72 : bool SafePipeReader::ReadData(base::TimeDelta timeout,
73 : size_t length,
74 E : void* buffer) {
75 E : size_t bytes_read = 0;
76 E : DCHECK(IsValid());
77 E : if (IsValid()) {
78 : // Prepare a timeout in case the server fails to start.
79 E : bool unblocked = false;
80 : thread_.message_loop()->PostDelayedTask(
81 : FROM_HERE,
82 : base::Bind(&UnblockPipe, write_handle_, length, &unblocked),
83 E : timeout);
84 :
85 E : DWORD num_bytes = 0;
86 : do {
87 E : num_bytes = 0;
88 : bool result = ::ReadFile(read_handle_,
89 : reinterpret_cast<uint8_t*>(buffer) + bytes_read,
90 E : length - bytes_read, &num_bytes, NULL);
91 E : DCHECK(result);
92 E : if (result && !unblocked)
93 E : bytes_read += num_bytes;
94 E : } while (num_bytes > 0 && bytes_read < length && !unblocked);
95 : }
96 :
97 E : return bytes_read == length;
98 E : }
99 :
100 E : bool SafePipeReader::IsValid() {
101 : return read_handle_ != INVALID_HANDLE_VALUE &&
102 E : write_handle_ != INVALID_HANDLE_VALUE && thread_.IsRunning();
103 E : }
104 :
105 : } // namespace testing
106 : } // namespace kasko
|