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