]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | use crate::os::windows::prelude::*; |
54a0048b | 2 | |
532ac7d7 | 3 | use crate::ffi::OsStr; |
48663c56 | 4 | use crate::io::{self, IoSlice, IoSliceMut}; |
532ac7d7 XL |
5 | use crate::mem; |
6 | use crate::path::Path; | |
7 | use crate::ptr; | |
8 | use crate::slice; | |
532ac7d7 | 9 | use crate::sync::atomic::AtomicUsize; |
60c5eb7d | 10 | use crate::sync::atomic::Ordering::SeqCst; |
532ac7d7 XL |
11 | use crate::sys::c; |
12 | use crate::sys::fs::{File, OpenOptions}; | |
13 | use crate::sys::handle::Handle; | |
14 | use crate::sys::hashmap_random_keys; | |
85aaf69f SL |
15 | |
16 | //////////////////////////////////////////////////////////////////////////////// | |
17 | // Anonymous pipes | |
18 | //////////////////////////////////////////////////////////////////////////////// | |
19 | ||
20 | pub struct AnonPipe { | |
9346a6ac | 21 | inner: Handle, |
85aaf69f SL |
22 | } |
23 | ||
476ff2be SL |
24 | pub struct Pipes { |
25 | pub ours: AnonPipe, | |
26 | pub theirs: AnonPipe, | |
27 | } | |
28 | ||
29 | /// Although this looks similar to `anon_pipe` in the Unix module it's actually | |
30 | /// subtly different. Here we'll return two pipes in the `Pipes` return value, | |
31 | /// but one is intended for "us" where as the other is intended for "someone | |
32 | /// else". | |
33 | /// | |
34 | /// Currently the only use case for this function is pipes for stdio on | |
35 | /// processes in the standard library, so "ours" is the one that'll stay in our | |
36 | /// process whereas "theirs" will be inherited to a child. | |
37 | /// | |
38 | /// The ours/theirs pipes are *not* specifically readable or writable. Each | |
39 | /// one only supports a read or a write, but which is which depends on the | |
532ac7d7 XL |
40 | /// boolean flag given. If `ours_readable` is `true`, then `ours` is readable and |
41 | /// `theirs` is writable. Conversely, if `ours_readable` is `false`, then `ours` | |
42 | /// is writable and `theirs` is readable. | |
476ff2be SL |
43 | /// |
44 | /// Also note that the `ours` pipe is always a handle opened up in overlapped | |
45 | /// mode. This means that technically speaking it should only ever be used | |
46 | /// with `OVERLAPPED` instances, but also works out ok if it's only ever used | |
47 | /// once at a time (which we do indeed guarantee). | |
416331ca | 48 | pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result<Pipes> { |
54a0048b SL |
49 | // Note that we specifically do *not* use `CreatePipe` here because |
50 | // unfortunately the anonymous pipes returned do not support overlapped | |
476ff2be SL |
51 | // operations. Instead, we create a "hopefully unique" name and create a |
52 | // named pipe which has overlapped operations enabled. | |
54a0048b | 53 | // |
476ff2be SL |
54 | // Once we do this, we connect do it as usual via `CreateFileW`, and then |
55 | // we return those reader/writer halves. Note that the `ours` pipe return | |
56 | // value is always the named pipe, whereas `theirs` is just the normal file. | |
57 | // This should hopefully shield us from child processes which assume their | |
58 | // stdout is a named pipe, which would indeed be odd! | |
54a0048b | 59 | unsafe { |
476ff2be | 60 | let ours; |
54a0048b SL |
61 | let mut name; |
62 | let mut tries = 0; | |
476ff2be | 63 | let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS; |
54a0048b SL |
64 | loop { |
65 | tries += 1; | |
60c5eb7d XL |
66 | name = format!( |
67 | r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}", | |
68 | c::GetCurrentProcessId(), | |
69 | random_number() | |
70 | ); | |
71 | let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::<Vec<_>>(); | |
72 | let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED; | |
476ff2be SL |
73 | if ours_readable { |
74 | flags |= c::PIPE_ACCESS_INBOUND; | |
75 | } else { | |
76 | flags |= c::PIPE_ACCESS_OUTBOUND; | |
77 | } | |
54a0048b | 78 | |
60c5eb7d XL |
79 | let handle = c::CreateNamedPipeW( |
80 | wide_name.as_ptr(), | |
81 | flags, | |
82 | c::PIPE_TYPE_BYTE | |
83 | | c::PIPE_READMODE_BYTE | |
84 | | c::PIPE_WAIT | |
85 | | reject_remote_clients_flag, | |
86 | 1, | |
87 | 4096, | |
88 | 4096, | |
89 | 0, | |
90 | ptr::null_mut(), | |
91 | ); | |
54a0048b | 92 | |
0731742a | 93 | // We pass the `FILE_FLAG_FIRST_PIPE_INSTANCE` flag above, and we're |
54a0048b | 94 | // also just doing a best effort at selecting a unique name. If |
0731742a | 95 | // `ERROR_ACCESS_DENIED` is returned then it could mean that we |
54a0048b SL |
96 | // accidentally conflicted with an already existing pipe, so we try |
97 | // again. | |
98 | // | |
99 | // Don't try again too much though as this could also perhaps be a | |
100 | // legit error. | |
0731742a XL |
101 | // If `ERROR_INVALID_PARAMETER` is returned, this probably means we're |
102 | // running on pre-Vista version where `PIPE_REJECT_REMOTE_CLIENTS` is | |
476ff2be SL |
103 | // not supported, so we continue retrying without it. This implies |
104 | // reduced security on Windows versions older than Vista by allowing | |
105 | // connections to this pipe from remote machines. | |
106 | // Proper fix would increase the number of FFI imports and introduce | |
107 | // significant amount of Windows XP specific code with no clean | |
108 | // testing strategy | |
0731742a | 109 | // For more info, see https://github.com/rust-lang/rust/pull/37677. |
54a0048b SL |
110 | if handle == c::INVALID_HANDLE_VALUE { |
111 | let err = io::Error::last_os_error(); | |
476ff2be SL |
112 | let raw_os_err = err.raw_os_error(); |
113 | if tries < 10 { | |
114 | if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) { | |
60c5eb7d XL |
115 | continue; |
116 | } else if reject_remote_clients_flag != 0 | |
117 | && raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) | |
118 | { | |
476ff2be SL |
119 | reject_remote_clients_flag = 0; |
120 | tries -= 1; | |
60c5eb7d | 121 | continue; |
476ff2be | 122 | } |
54a0048b | 123 | } |
60c5eb7d | 124 | return Err(err); |
54a0048b | 125 | } |
476ff2be | 126 | ours = Handle::new(handle); |
60c5eb7d | 127 | break; |
54a0048b SL |
128 | } |
129 | ||
476ff2be SL |
130 | // Connect to the named pipe we just created. This handle is going to be |
131 | // returned in `theirs`, so if `ours` is readable we want this to be | |
132 | // writable, otherwise if `ours` is writable we want this to be | |
133 | // readable. | |
134 | // | |
135 | // Additionally we don't enable overlapped mode on this because most | |
136 | // client processes aren't enabled to work with that. | |
54a0048b | 137 | let mut opts = OpenOptions::new(); |
476ff2be SL |
138 | opts.write(ours_readable); |
139 | opts.read(!ours_readable); | |
54a0048b | 140 | opts.share_mode(0); |
416331ca XL |
141 | let size = mem::size_of::<c::SECURITY_ATTRIBUTES>(); |
142 | let mut sa = c::SECURITY_ATTRIBUTES { | |
143 | nLength: size as c::DWORD, | |
144 | lpSecurityDescriptor: ptr::null_mut(), | |
145 | bInheritHandle: their_handle_inheritable as i32, | |
146 | }; | |
147 | opts.security_attributes(&mut sa); | |
476ff2be SL |
148 | let theirs = File::open(Path::new(&name), &opts)?; |
149 | let theirs = AnonPipe { inner: theirs.into_handle() }; | |
54a0048b | 150 | |
476ff2be SL |
151 | Ok(Pipes { |
152 | ours: AnonPipe { inner: ours }, | |
153 | theirs: AnonPipe { inner: theirs.into_handle() }, | |
154 | }) | |
54a0048b | 155 | } |
85aaf69f SL |
156 | } |
157 | ||
abe05a73 | 158 | fn random_number() -> usize { |
9fa01778 | 159 | static N: AtomicUsize = AtomicUsize::new(0); |
abe05a73 XL |
160 | loop { |
161 | if N.load(SeqCst) != 0 { | |
60c5eb7d | 162 | return N.fetch_add(1, SeqCst); |
abe05a73 XL |
163 | } |
164 | ||
165 | N.store(hashmap_random_keys().0 as usize, SeqCst); | |
166 | } | |
167 | } | |
168 | ||
85aaf69f | 169 | impl AnonPipe { |
60c5eb7d XL |
170 | pub fn handle(&self) -> &Handle { |
171 | &self.inner | |
172 | } | |
173 | pub fn into_handle(self) -> Handle { | |
174 | self.inner | |
175 | } | |
85aaf69f SL |
176 | |
177 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { | |
9346a6ac | 178 | self.inner.read(buf) |
85aaf69f SL |
179 | } |
180 | ||
48663c56 XL |
181 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
182 | self.inner.read_vectored(bufs) | |
183 | } | |
184 | ||
f9f354fc XL |
185 | #[inline] |
186 | pub fn is_read_vectored(&self) -> bool { | |
187 | self.inner.is_read_vectored() | |
188 | } | |
189 | ||
85aaf69f | 190 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
9346a6ac | 191 | self.inner.write(buf) |
85aaf69f | 192 | } |
48663c56 XL |
193 | |
194 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
195 | self.inner.write_vectored(bufs) | |
196 | } | |
f9f354fc XL |
197 | |
198 | #[inline] | |
199 | pub fn is_write_vectored(&self) -> bool { | |
200 | self.inner.is_write_vectored() | |
201 | } | |
85aaf69f | 202 | } |
54a0048b | 203 | |
60c5eb7d | 204 | pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> { |
54a0048b SL |
205 | let p1 = p1.into_handle(); |
206 | let p2 = p2.into_handle(); | |
207 | ||
208 | let mut p1 = AsyncPipe::new(p1, v1)?; | |
209 | let mut p2 = AsyncPipe::new(p2, v2)?; | |
210 | let objs = [p1.event.raw(), p2.event.raw()]; | |
211 | ||
212 | // In a loop we wait for either pipe's scheduled read operation to complete. | |
213 | // If the operation completes with 0 bytes, that means EOF was reached, in | |
214 | // which case we just finish out the other pipe entirely. | |
215 | // | |
216 | // Note that overlapped I/O is in general super unsafe because we have to | |
217 | // be careful to ensure that all pointers in play are valid for the entire | |
218 | // duration of the I/O operation (where tons of operations can also fail). | |
219 | // The destructor for `AsyncPipe` ends up taking care of most of this. | |
220 | loop { | |
60c5eb7d | 221 | let res = unsafe { c::WaitForMultipleObjects(2, objs.as_ptr(), c::FALSE, c::INFINITE) }; |
54a0048b SL |
222 | if res == c::WAIT_OBJECT_0 { |
223 | if !p1.result()? || !p1.schedule_read()? { | |
60c5eb7d | 224 | return p2.finish(); |
54a0048b SL |
225 | } |
226 | } else if res == c::WAIT_OBJECT_0 + 1 { | |
227 | if !p2.result()? || !p2.schedule_read()? { | |
60c5eb7d | 228 | return p1.finish(); |
54a0048b SL |
229 | } |
230 | } else { | |
60c5eb7d | 231 | return Err(io::Error::last_os_error()); |
54a0048b SL |
232 | } |
233 | } | |
234 | } | |
235 | ||
236 | struct AsyncPipe<'a> { | |
237 | pipe: Handle, | |
238 | event: Handle, | |
239 | overlapped: Box<c::OVERLAPPED>, // needs a stable address | |
240 | dst: &'a mut Vec<u8>, | |
241 | state: State, | |
242 | } | |
243 | ||
244 | #[derive(PartialEq, Debug)] | |
245 | enum State { | |
246 | NotReading, | |
247 | Reading, | |
248 | Read(usize), | |
249 | } | |
250 | ||
251 | impl<'a> AsyncPipe<'a> { | |
252 | fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> { | |
253 | // Create an event which we'll use to coordinate our overlapped | |
83c7162d | 254 | // operations, this event will be used in WaitForMultipleObjects |
54a0048b SL |
255 | // and passed as part of the OVERLAPPED handle. |
256 | // | |
257 | // Note that we do a somewhat clever thing here by flagging the | |
258 | // event as being manually reset and setting it initially to the | |
259 | // signaled state. This means that we'll naturally fall through the | |
260 | // WaitForMultipleObjects call above for pipes created initially, | |
261 | // and the only time an even will go back to "unset" will be once an | |
262 | // I/O operation is successfully scheduled (what we want). | |
263 | let event = Handle::new_event(true, true)?; | |
60c5eb7d | 264 | let mut overlapped: Box<c::OVERLAPPED> = unsafe { Box::new(mem::zeroed()) }; |
54a0048b | 265 | overlapped.hEvent = event.raw(); |
60c5eb7d | 266 | Ok(AsyncPipe { pipe, overlapped, event, dst, state: State::NotReading }) |
54a0048b SL |
267 | } |
268 | ||
269 | /// Executes an overlapped read operation. | |
270 | /// | |
271 | /// Must not currently be reading, and returns whether the pipe is currently | |
272 | /// at EOF or not. If the pipe is not at EOF then `result()` must be called | |
273 | /// to complete the read later on (may block), but if the pipe is at EOF | |
274 | /// then `result()` should not be called as it will just block forever. | |
275 | fn schedule_read(&mut self) -> io::Result<bool> { | |
276 | assert_eq!(self.state, State::NotReading); | |
277 | let amt = unsafe { | |
278 | let slice = slice_to_end(self.dst); | |
279 | self.pipe.read_overlapped(slice, &mut *self.overlapped)? | |
280 | }; | |
281 | ||
282 | // If this read finished immediately then our overlapped event will | |
283 | // remain signaled (it was signaled coming in here) and we'll progress | |
284 | // down to the method below. | |
285 | // | |
286 | // Otherwise the I/O operation is scheduled and the system set our event | |
287 | // to not signaled, so we flag ourselves into the reading state and move | |
288 | // on. | |
289 | self.state = match amt { | |
290 | Some(0) => return Ok(false), | |
291 | Some(amt) => State::Read(amt), | |
292 | None => State::Reading, | |
293 | }; | |
294 | Ok(true) | |
295 | } | |
296 | ||
297 | /// Wait for the result of the overlapped operation previously executed. | |
298 | /// | |
299 | /// Takes a parameter `wait` which indicates if this pipe is currently being | |
300 | /// read whether the function should block waiting for the read to complete. | |
301 | /// | |
9fa01778 | 302 | /// Returns values: |
54a0048b SL |
303 | /// |
304 | /// * `true` - finished any pending read and the pipe is not at EOF (keep | |
305 | /// going) | |
306 | /// * `false` - finished any pending read and pipe is at EOF (stop issuing | |
307 | /// reads) | |
308 | fn result(&mut self) -> io::Result<bool> { | |
309 | let amt = match self.state { | |
310 | State::NotReading => return Ok(true), | |
60c5eb7d | 311 | State::Reading => self.pipe.overlapped_result(&mut *self.overlapped, true)?, |
54a0048b SL |
312 | State::Read(amt) => amt, |
313 | }; | |
314 | self.state = State::NotReading; | |
315 | unsafe { | |
316 | let len = self.dst.len(); | |
317 | self.dst.set_len(len + amt); | |
318 | } | |
319 | Ok(amt != 0) | |
320 | } | |
321 | ||
322 | /// Finishes out reading this pipe entirely. | |
323 | /// | |
324 | /// Waits for any pending and schedule read, and then calls `read_to_end` | |
325 | /// if necessary to read all the remaining information. | |
326 | fn finish(&mut self) -> io::Result<()> { | |
327 | while self.result()? && self.schedule_read()? { | |
328 | // ... | |
329 | } | |
330 | Ok(()) | |
331 | } | |
332 | } | |
333 | ||
334 | impl<'a> Drop for AsyncPipe<'a> { | |
335 | fn drop(&mut self) { | |
336 | match self.state { | |
337 | State::Reading => {} | |
338 | _ => return, | |
339 | } | |
340 | ||
341 | // If we have a pending read operation, then we have to make sure that | |
342 | // it's *done* before we actually drop this type. The kernel requires | |
343 | // that the `OVERLAPPED` and buffer pointers are valid for the entire | |
344 | // I/O operation. | |
345 | // | |
346 | // To do that, we call `CancelIo` to cancel any pending operation, and | |
347 | // if that succeeds we wait for the overlapped result. | |
348 | // | |
349 | // If anything here fails, there's not really much we can do, so we leak | |
350 | // the buffer/OVERLAPPED pointers to ensure we're at least memory safe. | |
351 | if self.pipe.cancel_io().is_err() || self.result().is_err() { | |
416331ca | 352 | let buf = mem::take(self.dst); |
54a0048b SL |
353 | let overlapped = Box::new(unsafe { mem::zeroed() }); |
354 | let overlapped = mem::replace(&mut self.overlapped, overlapped); | |
355 | mem::forget((buf, overlapped)); | |
356 | } | |
357 | } | |
358 | } | |
359 | ||
360 | unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] { | |
361 | if v.capacity() == 0 { | |
362 | v.reserve(16); | |
363 | } | |
364 | if v.capacity() == v.len() { | |
365 | v.reserve(1); | |
366 | } | |
60c5eb7d | 367 | slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len()) |
54a0048b | 368 | } |