├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "named_pipe" 3 | version = "0.4.1" 4 | authors = ["Anatoly Ikorsky "] 5 | license = "MIT OR Apache-2.0" 6 | description = "Wrapper for overlapped (asyncronous) IO of Windows's named pipes" 7 | repository = "https://github.com/blackbeam/named_pipe" 8 | documentation = "https://blackbeam.github.io/named_pipe/named_pipe/index.html" 9 | readme = "README.md" 10 | keywords = ["windows", "named", "pipes"] 11 | edition = "2018" 12 | 13 | [dependencies.winapi] 14 | version = "0.3" 15 | features = ["errhandlingapi", "handleapi", "ioapiset", "minwindef", "namedpipeapi", "synchapi", "winbase", "winerror"] 16 | 17 | [profile.test] 18 | opt-level = 0 19 | debug = true 20 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ikorsky Anatoly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # named_pipe 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/qwgjc58n6y3v23ge/branch/master?svg=true)](https://ci.appveyor.com/project/blackbeam/named-pipe/branch/master) 4 | 5 | Named-Pipe is a rust wrapper for overlapped (asyncronous) IO of Windows's named pipes. 6 | 7 | ## Install 8 | Use [cargo package](https://crates.io/crates/named_pipe). 9 | 10 | ## Documentation 11 | Hosted on [github pages](https://blackbeam.github.io/named_pipe/named_pipe/index.html). 12 | 13 | ## License 14 | Licensed under either of 15 | 16 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 17 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 18 | 19 | at your option. 20 | 21 | ### Contribution 22 | Unless you explicitly state otherwise, any contribution intentionally submitted 23 | for inclusion in the work by you, as defined in the Apache-2.0 license, 24 | shall be dual licensed as above, without any additional terms or conditions. 25 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Anatoly Ikorsky 2 | // 3 | // Licensed under the Apache License, Version 2.0 4 | // or the MIT 5 | // license , at your 6 | // option. All files in the project carrying such notice may not be copied, 7 | // modified, or distributed except according to those terms. 8 | 9 | //! Named-Pipe is a wrapper for overlapped (asyncronous) IO of Windows's named pipes. 10 | //! 11 | //! # Description 12 | //! 13 | //! You can use `wait` or `wait_all` to *select(2)*-like wait for multiple pending IO operations 14 | //! (which is read/write from/to `PipeServer`/`PipeClient` or waiting for new client). 15 | //! 16 | //! Or you can use `ConnectingServer::wait` or `io::Read` and `io::Write` implementaions for 17 | //! `PipeServer` and `PipeClient` for syncronous communication. 18 | //! 19 | //! For better understanding please refer to [Named Pipes documentation on MSDN] 20 | //! (https://www.google.com/search?q=msdn+named+pipes&ie=utf-8&oe=utf-8). 21 | //! 22 | //! # Usage 23 | //! 24 | //! To create new pipe instance use [`PipeOptions`](struct.PipeOptions.html) structure. 25 | //! 26 | //! To connect to a pipe server use [`PipeClient`](struct.PipeClient.html) structure. 27 | 28 | use winapi::{ 29 | ctypes::*, 30 | shared::{minwindef::*, ntdef::HANDLE, winerror::*}, 31 | um::{ 32 | errhandlingapi::*, fileapi::*, handleapi::*, ioapiset::*, minwinbase::*, namedpipeapi::*, 33 | synchapi::*, winbase::*, winnt::*, 34 | }, 35 | }; 36 | 37 | use std::ffi::{OsStr, OsString}; 38 | use std::fmt; 39 | use std::io; 40 | use std::marker::PhantomData; 41 | use std::mem; 42 | use std::os::windows::ffi::OsStrExt; 43 | use std::ptr; 44 | use std::sync::Arc; 45 | use std::time::Duration; 46 | 47 | #[derive(Debug)] 48 | struct Handle { 49 | value: HANDLE, 50 | } 51 | 52 | impl Drop for Handle { 53 | fn drop(&mut self) { 54 | let _ = unsafe { CloseHandle(self.value) }; 55 | } 56 | } 57 | 58 | unsafe impl Sync for Handle {} 59 | unsafe impl Send for Handle {} 60 | 61 | #[derive(Debug)] 62 | struct Event { 63 | handle: Handle, 64 | } 65 | 66 | impl Event { 67 | fn new() -> io::Result { 68 | let handle = unsafe { CreateEventW(ptr::null_mut(), 1, 0, ptr::null()) }; 69 | if handle != ptr::null_mut() { 70 | Ok(Event { 71 | handle: Handle { value: handle }, 72 | }) 73 | } else { 74 | Err(io::Error::last_os_error()) 75 | } 76 | } 77 | 78 | fn reset(&self) -> io::Result<()> { 79 | let result = unsafe { ResetEvent(self.handle.value) }; 80 | if result != 0 { 81 | Ok(()) 82 | } else { 83 | Err(io::Error::last_os_error()) 84 | } 85 | } 86 | 87 | fn set(&self) -> io::Result<()> { 88 | let result = unsafe { SetEvent(self.handle.value) }; 89 | if result != 0 { 90 | Ok(()) 91 | } else { 92 | Err(io::Error::last_os_error()) 93 | } 94 | } 95 | } 96 | 97 | struct Overlapped { 98 | ovl: Box, 99 | event: Event, 100 | } 101 | 102 | impl fmt::Debug for Overlapped { 103 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 104 | f.debug_struct("Overlapped") 105 | .field("ovl", &"OVERLAPPED") 106 | .field("event", &self.event) 107 | .finish() 108 | } 109 | } 110 | 111 | unsafe impl Send for Overlapped {} 112 | unsafe impl Sync for Overlapped {} 113 | 114 | impl Overlapped { 115 | fn new() -> io::Result { 116 | let event = Event::new()?; 117 | let mut ovl: Box = Box::new(unsafe { mem::zeroed() }); 118 | ovl.hEvent = event.handle.value; 119 | Ok(Overlapped { 120 | ovl: ovl, 121 | event: event, 122 | }) 123 | } 124 | 125 | fn clear(&mut self) -> io::Result<()> { 126 | self.event.reset()?; 127 | self.ovl = Box::new(unsafe { mem::zeroed() }); 128 | self.ovl.hEvent = self.event.handle.value; 129 | Ok(()) 130 | } 131 | 132 | fn get_mut(&mut self) -> &mut OVERLAPPED { 133 | &mut self.ovl 134 | } 135 | } 136 | 137 | #[derive(Debug, PartialEq, Eq, Clone, Hash)] 138 | pub enum OpenMode { 139 | /// Read only pipe instance 140 | Read, 141 | /// Write only pipe instance 142 | Write, 143 | /// Read-write pipe instance 144 | Duplex, 145 | } 146 | 147 | impl OpenMode { 148 | fn val(&self) -> u32 { 149 | match self { 150 | &OpenMode::Read => PIPE_ACCESS_INBOUND, 151 | &OpenMode::Write => PIPE_ACCESS_OUTBOUND, 152 | &OpenMode::Duplex => PIPE_ACCESS_DUPLEX, 153 | } 154 | } 155 | } 156 | 157 | /// Options and flags which can be used to configure how a pipe is created. 158 | /// 159 | /// This builder exposes the ability to configure how a `ConnectingServer` is created. 160 | /// 161 | /// Builder defaults: 162 | /// 163 | /// - **open_mode** - `Duplex` 164 | /// - **in_buffer** - 65536 165 | /// - **out_buffer** - 65536 166 | /// - **first** - true 167 | #[derive(Debug, PartialEq, Eq, Clone, Hash)] 168 | pub struct PipeOptions { 169 | name: Arc>, 170 | open_mode: OpenMode, 171 | out_buffer: u32, 172 | in_buffer: u32, 173 | first: bool, 174 | } 175 | 176 | impl PipeOptions { 177 | fn create_named_pipe(&self, first: bool) -> io::Result { 178 | let handle = unsafe { 179 | CreateNamedPipeW( 180 | self.name.as_ptr(), 181 | self.open_mode.val() 182 | | FILE_FLAG_OVERLAPPED 183 | | if first { 184 | FILE_FLAG_FIRST_PIPE_INSTANCE 185 | } else { 186 | 0 187 | }, 188 | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 189 | PIPE_UNLIMITED_INSTANCES, 190 | self.out_buffer, 191 | self.in_buffer, 192 | 0, 193 | ptr::null_mut(), 194 | ) 195 | }; 196 | 197 | if handle != INVALID_HANDLE_VALUE { 198 | Ok(Handle { value: handle }) 199 | } else { 200 | Err(io::Error::last_os_error()) 201 | } 202 | } 203 | 204 | pub fn new>(name: T) -> PipeOptions { 205 | let mut full_name: OsString = name.as_ref().into(); 206 | full_name.push("\x00"); 207 | let full_name = full_name.encode_wide().collect::>(); 208 | PipeOptions { 209 | name: Arc::new(full_name), 210 | open_mode: OpenMode::Duplex, 211 | out_buffer: 65536, 212 | in_buffer: 65536, 213 | first: true, 214 | } 215 | } 216 | 217 | /// Is this instance (or instances) will be first for this pipe name? Defaults to `true`. 218 | pub fn first(&mut self, val: bool) -> &mut PipeOptions { 219 | self.first = val; 220 | self 221 | } 222 | 223 | /// Open mode for pipe instance. Defaults to `Duplex`. 224 | pub fn open_mode(&mut self, val: OpenMode) -> &mut PipeOptions { 225 | self.open_mode = val; 226 | self 227 | } 228 | 229 | /// Input buffer size for pipe instance. Defaults to 65536 230 | pub fn in_buffer(&mut self, val: u32) -> &mut PipeOptions { 231 | self.in_buffer = val; 232 | self 233 | } 234 | 235 | /// Output buffer size for pipe instance. Defaults to 65536. 236 | pub fn out_buffer(&mut self, val: u32) -> &mut PipeOptions { 237 | self.out_buffer = val; 238 | self 239 | } 240 | 241 | /// Creates single instance of pipe with this options. 242 | pub fn single(&self) -> io::Result { 243 | let mut pipes = self.multiple(1)?; 244 | match pipes.pop() { 245 | Some(pipe) => Ok(pipe), 246 | None => unreachable!(), 247 | } 248 | } 249 | 250 | /// Creates multiple instances of pipe with this options. 251 | pub fn multiple(&self, num: u32) -> io::Result> { 252 | if num == 0 { 253 | return Ok(Vec::new()); 254 | } 255 | let mut out = Vec::with_capacity(num as usize); 256 | let mut first = self.first; 257 | for _ in 0..num { 258 | let handle = self.create_named_pipe(first)?; 259 | first = false; 260 | let mut ovl = Overlapped::new()?; 261 | let pending = connect_named_pipe(&handle, &mut ovl)?; 262 | out.push(ConnectingServer { 263 | handle: handle, 264 | ovl: ovl, 265 | pending: pending, 266 | }); 267 | } 268 | Ok(out) 269 | } 270 | } 271 | 272 | /// Pipe instance waiting for new client. Can be used with [`wait`](fn.wait.html) and [`wait_all`] 273 | /// (fn.wait_all.html) functions. 274 | #[derive(Debug)] 275 | pub struct ConnectingServer { 276 | handle: Handle, 277 | ovl: Overlapped, 278 | pending: bool, 279 | } 280 | 281 | impl ConnectingServer { 282 | /// Waites for client infinitely. 283 | pub fn wait(self) -> io::Result { 284 | match self.wait_ms(INFINITE)? { 285 | Ok(pipe_server) => Ok(pipe_server), 286 | Err(_) => unreachable!(), 287 | } 288 | } 289 | 290 | /// Waites for client. Note that `timeout` 0xFFFFFFFF stands for infinite waiting. 291 | pub fn wait_ms(mut self, timeout: u32) -> io::Result> { 292 | if self.pending { 293 | match wait_for_single_obj(&mut self, timeout)? { 294 | Some(_) => { 295 | let mut dummy = 0; 296 | get_ovl_result(&mut self, &mut dummy)?; 297 | self.pending = false; 298 | } 299 | None => return Ok(Err(self)), 300 | } 301 | } 302 | let ConnectingServer { 303 | handle, mut ovl, .. 304 | } = self; 305 | ovl.clear()?; 306 | Ok(Ok(PipeServer { 307 | handle: Some(handle), 308 | ovl: Some(ovl), 309 | read_timeout: None, 310 | write_timeout: None, 311 | })) 312 | } 313 | } 314 | 315 | /// Pipe server connected to a client. 316 | #[derive(Debug)] 317 | pub struct PipeServer { 318 | handle: Option, 319 | ovl: Option, 320 | read_timeout: Option, 321 | write_timeout: Option, 322 | } 323 | 324 | impl PipeServer { 325 | /// This function will flush buffers and disconnect server from client. Then will start waiting 326 | /// for a new client. 327 | pub fn disconnect(mut self) -> io::Result { 328 | let handle = self.handle.take().unwrap(); 329 | let mut ovl = self.ovl.take().unwrap(); 330 | let mut result = unsafe { FlushFileBuffers(handle.value) }; 331 | 332 | if result != 0 { 333 | result = unsafe { DisconnectNamedPipe(handle.value) }; 334 | if result != 0 { 335 | ovl.clear()?; 336 | let pending = connect_named_pipe(&handle, &mut ovl)?; 337 | Ok(ConnectingServer { 338 | handle: handle, 339 | ovl: ovl, 340 | pending: pending, 341 | }) 342 | } else { 343 | Err(io::Error::last_os_error()) 344 | } 345 | } else { 346 | Err(io::Error::last_os_error()) 347 | } 348 | } 349 | 350 | /// Initializes asyncronous read opeation. 351 | /// 352 | /// # Unsafety 353 | /// It's unsafe to leak returned handle because read operation should be cancelled 354 | /// by handle's destructor to not to write into `buf` that may be deallocated. 355 | unsafe fn read_async<'a, 'b: 'a>( 356 | &'a mut self, 357 | buf: &'b mut [u8], 358 | ) -> io::Result> { 359 | init_read(self, buf) 360 | } 361 | 362 | /// Initializes asyncronous read operation and takes ownership of buffer and server. 363 | pub fn read_async_owned(self, buf: Vec) -> io::Result> { 364 | init_read_owned(self, buf) 365 | } 366 | 367 | /// Initializes asyncronous write operation. 368 | /// 369 | /// # Unsafety 370 | /// It's unsafe to leak returned handle because write operation should be cancelled 371 | /// by handle's destructor to not to read from `buf` that may be deallocated. 372 | unsafe fn write_async<'a, 'b: 'a>( 373 | &'a mut self, 374 | buf: &'b [u8], 375 | ) -> io::Result> { 376 | init_write(self, buf) 377 | } 378 | 379 | /// Initializes asyncronous write operation and takes ownership of buffer and server. 380 | pub fn write_async_owned(self, buf: Vec) -> io::Result> { 381 | init_write_owned(self, buf) 382 | } 383 | 384 | /// Allows you to set read timeout in milliseconds. 385 | /// 386 | /// Note that zero value will return immediately and 0xFFFFFFFF will wait forever. Also note 387 | /// that nanos will be ignored and also if number of milliseconds is greater than 0xFFFFFFFF 388 | /// then it will write 0xFFFFFFFF as a timeout value. 389 | /// 390 | /// Defaults to None (infinite). 391 | pub fn set_read_timeout(&mut self, read_timeout: Option) { 392 | self.read_timeout = read_timeout.map(|dur| { 393 | let val = dur.as_millis(); 394 | if val > 0xFFFFFFFF { 395 | 0xFFFFFFFF 396 | } else { 397 | val as u32 398 | } 399 | }); 400 | } 401 | 402 | /// Allows you to set write timeout in milliseconds. 403 | /// 404 | /// Note that zero value will return immediately and 0xFFFFFFFF will wait forever.Also note 405 | /// that nanos will be ignored and also if number of milliseconds is greater than 0xFFFFFFFF 406 | /// then it will write 0xFFFFFFFF as a timeout value. 407 | /// 408 | /// Defaults to None (infinite). 409 | pub fn set_write_timeout(&mut self, write_timeout: Option) { 410 | self.write_timeout = write_timeout.map(|dur| { 411 | let val = dur.as_millis(); 412 | if val > 0xFFFFFFFF { 413 | 0xFFFFFFFF 414 | } else { 415 | val as u32 416 | } 417 | }); 418 | } 419 | 420 | pub fn get_read_timeout(&self) -> Option { 421 | self.read_timeout 422 | .clone() 423 | .map(|millis| Duration::from_millis(millis as u64)) 424 | } 425 | 426 | pub fn get_write_timeout(&self) -> Option { 427 | self.write_timeout 428 | .clone() 429 | .map(|millis| Duration::from_millis(millis as u64)) 430 | } 431 | 432 | fn get_read_timeout_ms(&self) -> Option { 433 | self.read_timeout.clone() 434 | } 435 | 436 | fn get_write_timeout_ms(&self) -> Option { 437 | self.write_timeout.clone() 438 | } 439 | } 440 | 441 | impl io::Read for PipeServer { 442 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 443 | let read_handle = unsafe { self.read_async(buf) }; 444 | let result = read_handle 445 | .and_then(|read_handle| read_handle.wait()) 446 | .map(|x| x.0); 447 | match result { 448 | Ok(x) => Ok(x), 449 | Err(err) => { 450 | if err.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) { 451 | Ok(0) 452 | } else { 453 | Err(err) 454 | } 455 | } 456 | } 457 | } 458 | } 459 | 460 | impl io::Write for PipeServer { 461 | fn write(&mut self, buf: &[u8]) -> io::Result { 462 | let write_handle = unsafe { self.write_async(buf) }; 463 | write_handle 464 | .and_then(|write_handle| write_handle.wait()) 465 | .map(|x| x.0) 466 | } 467 | 468 | fn flush(&mut self) -> io::Result<()> { 469 | match self.handle { 470 | Some(ref handle) => { 471 | let result = unsafe { FlushFileBuffers(handle.value) }; 472 | if result != 0 { 473 | Ok(()) 474 | } else { 475 | Err(io::Error::last_os_error()) 476 | } 477 | } 478 | None => unreachable!(), 479 | } 480 | } 481 | } 482 | 483 | impl Drop for PipeServer { 484 | fn drop(&mut self) { 485 | if let Some(ref handle) = self.handle { 486 | let _ = unsafe { FlushFileBuffers(handle.value) }; 487 | let _ = unsafe { DisconnectNamedPipe(handle.value) }; 488 | } 489 | } 490 | } 491 | 492 | /// Pipe client connected to a server. 493 | #[derive(Debug)] 494 | pub struct PipeClient { 495 | handle: Handle, 496 | ovl: Overlapped, 497 | read_timeout: Option, 498 | write_timeout: Option, 499 | } 500 | 501 | impl PipeClient { 502 | fn create_file(name: &Vec, mode: DWORD) -> io::Result { 503 | loop { 504 | let handle = unsafe { 505 | CreateFileW( 506 | name.as_ptr(), 507 | mode, 508 | 0, 509 | ptr::null_mut(), 510 | OPEN_EXISTING, 511 | FILE_FLAG_OVERLAPPED, 512 | ptr::null_mut(), 513 | ) 514 | }; 515 | 516 | if handle != INVALID_HANDLE_VALUE { 517 | return Ok(Handle { value: handle }); 518 | } 519 | 520 | match unsafe { GetLastError() } { 521 | ERROR_PIPE_BUSY => { 522 | unsafe { WaitNamedPipeW(name.as_ptr(), 0) }; 523 | } 524 | ERROR_ACCESS_DENIED => match mode { 525 | mode if mode == (GENERIC_READ | GENERIC_WRITE) => { 526 | return PipeClient::create_file(name, GENERIC_READ | FILE_WRITE_ATTRIBUTES); 527 | } 528 | mode if mode == (GENERIC_READ | FILE_WRITE_ATTRIBUTES) => { 529 | return PipeClient::create_file(name, GENERIC_WRITE | FILE_READ_ATTRIBUTES); 530 | } 531 | _ => { 532 | return Err(io::Error::last_os_error()); 533 | } 534 | }, 535 | _ => { 536 | return Err(io::Error::last_os_error()); 537 | } 538 | } 539 | } 540 | } 541 | 542 | /// Will wait for server infinitely. 543 | pub fn connect>(name: T) -> io::Result { 544 | PipeClient::connect_ms(name, 0xFFFFFFFF) 545 | } 546 | 547 | /// Will wait for server. Note that `timeout` 0xFFFFFFFF stands for infinite waiting. 548 | pub fn connect_ms>(name: T, timeout: u32) -> io::Result { 549 | let mut full_name: OsString = name.as_ref().into(); 550 | full_name.push("\x00"); 551 | let full_name = full_name.encode_wide().collect::>(); 552 | let mut waited = false; 553 | loop { 554 | match PipeClient::create_file(&full_name, GENERIC_READ | GENERIC_WRITE) { 555 | Ok(handle) => { 556 | let result = unsafe { 557 | let mut mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; 558 | SetNamedPipeHandleState( 559 | handle.value, 560 | &mut mode, 561 | ptr::null_mut(), 562 | ptr::null_mut(), 563 | ) 564 | }; 565 | 566 | if result != 0 { 567 | return Ok(PipeClient { 568 | handle: handle, 569 | ovl: Overlapped::new()?, 570 | read_timeout: None, 571 | write_timeout: None, 572 | }); 573 | } else { 574 | return Err(io::Error::last_os_error()); 575 | } 576 | } 577 | Err(err) => { 578 | if err.raw_os_error().unwrap() == ERROR_PIPE_BUSY as i32 { 579 | if !waited { 580 | waited = true; 581 | let result = unsafe { WaitNamedPipeW(full_name.as_ptr(), timeout) }; 582 | if result == 0 { 583 | return Err(err); 584 | } 585 | } else { 586 | return Err(err); 587 | } 588 | } else { 589 | return Err(err); 590 | } 591 | } 592 | } 593 | } 594 | } 595 | 596 | /// Initializes asyncronous read operation. 597 | /// 598 | /// # Unsafety 599 | /// It's unsafe to leak returned handle because write operation should be cancelled 600 | /// by handle's destructor to not to write into `buf` that may be deallocated. 601 | unsafe fn read_async<'a, 'b: 'a>( 602 | &'a mut self, 603 | buf: &'b mut [u8], 604 | ) -> io::Result> { 605 | init_read(self, buf) 606 | } 607 | 608 | /// Initializes asyncronous read operation and takes ownership of buffer and client. 609 | pub fn read_async_owned(self, buf: Vec) -> io::Result> { 610 | init_read_owned(self, buf) 611 | } 612 | 613 | /// Initializes asyncronous write operation. 614 | /// 615 | /// # Unsafety 616 | /// It's unsafe to leak returned handle because write operation should be cancelled 617 | /// by handle's destructor to not to read from `buf` that may be deallocated. 618 | unsafe fn write_async<'a, 'b: 'a>( 619 | &'a mut self, 620 | buf: &'b [u8], 621 | ) -> io::Result> { 622 | init_write(self, buf) 623 | } 624 | 625 | /// Initializes asyncronous write operation and takes ownership of buffer and client. 626 | pub fn write_async_owned(self, buf: Vec) -> io::Result> { 627 | init_write_owned(self, buf) 628 | } 629 | 630 | /// Allows you to set read timeout in milliseconds. 631 | /// 632 | /// Note that zero value will return immediately and 0xFFFFFFFF will wait forever. Also note 633 | /// that nanos will be ignored and also if number of milliseconds is greater than 0xFFFFFFFF 634 | /// then it will write 0xFFFFFFFF as a timeout value. 635 | /// 636 | /// Defaults to None (infinite). 637 | pub fn set_read_timeout(&mut self, read_timeout: Option) { 638 | self.read_timeout = read_timeout.map(|dur| { 639 | let val = dur.as_millis(); 640 | if val > 0xFFFFFFFF { 641 | 0xFFFFFFFF 642 | } else { 643 | val as u32 644 | } 645 | }); 646 | } 647 | 648 | /// Allows you to set write timeout in milliseconds. 649 | /// 650 | /// Note that zero value will return immediately and 0xFFFFFFFF will wait forever.Also note 651 | /// that nanos will be ignored and also if number of milliseconds is greater than 0xFFFFFFFF 652 | /// then it will write 0xFFFFFFFF as a timeout value. 653 | /// 654 | /// Defaults to None (infinite). 655 | pub fn set_write_timeout(&mut self, write_timeout: Option) { 656 | self.write_timeout = write_timeout.map(|dur| { 657 | let val = dur.as_millis(); 658 | if val > 0xFFFFFFFF { 659 | 0xFFFFFFFF 660 | } else { 661 | val as u32 662 | } 663 | }); 664 | } 665 | 666 | pub fn get_read_timeout(&self) -> Option { 667 | self.read_timeout 668 | .clone() 669 | .map(|millis| Duration::from_millis(millis as u64)) 670 | } 671 | 672 | pub fn get_write_timeout(&self) -> Option { 673 | self.write_timeout 674 | .clone() 675 | .map(|millis| Duration::from_millis(millis as u64)) 676 | } 677 | 678 | fn get_read_timeout_ms(&self) -> Option { 679 | self.read_timeout.clone() 680 | } 681 | 682 | fn get_write_timeout_ms(&self) -> Option { 683 | self.write_timeout.clone() 684 | } 685 | } 686 | 687 | unsafe impl Send for PipeClient {} 688 | 689 | impl io::Read for PipeClient { 690 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 691 | let read_handle = unsafe { self.read_async(buf) }; 692 | read_handle 693 | .and_then(|read_handle| read_handle.wait()) 694 | .map(|x| x.0) 695 | } 696 | } 697 | 698 | impl io::Write for PipeClient { 699 | fn write(&mut self, buf: &[u8]) -> io::Result { 700 | let write_handle = unsafe { self.write_async(buf) }; 701 | write_handle 702 | .and_then(|write_handle| write_handle.wait()) 703 | .map(|x| x.0) 704 | } 705 | 706 | fn flush(&mut self) -> io::Result<()> { 707 | let result = unsafe { FlushFileBuffers(self.handle.value) }; 708 | if result != 0 { 709 | Ok(()) 710 | } else { 711 | Err(io::Error::last_os_error()) 712 | } 713 | } 714 | } 715 | 716 | #[derive(Debug)] 717 | pub struct PipeIoObj<'a> { 718 | handle: HANDLE, 719 | ovl: &'a mut Overlapped, 720 | } 721 | 722 | #[allow(dead_code)] 723 | #[derive(Debug)] 724 | pub struct PipeIoHandles<'a> { 725 | pipe_handle: HANDLE, 726 | event_handle: HANDLE, 727 | _phantom: PhantomData<&'a ()>, 728 | } 729 | 730 | /// This trait used for genericity. 731 | pub trait PipeIo { 732 | fn io_obj<'a>(&'a mut self) -> PipeIoObj<'a>; 733 | fn io_handles<'a>(&'a self) -> PipeIoHandles<'a>; 734 | fn get_read_timeout(&self) -> Option; 735 | fn get_write_timeout(&self) -> Option; 736 | } 737 | 738 | impl PipeIo for PipeServer { 739 | fn io_obj<'a>(&'a mut self) -> PipeIoObj<'a> { 740 | let raw_handle = match self.handle { 741 | Some(ref handle) => handle.value, 742 | None => unreachable!(), 743 | }; 744 | let ovl = match self.ovl { 745 | Some(ref mut ovl) => ovl, 746 | None => unreachable!(), 747 | }; 748 | PipeIoObj { 749 | handle: raw_handle, 750 | ovl: ovl, 751 | } 752 | } 753 | 754 | fn io_handles<'a>(&'a self) -> PipeIoHandles<'a> { 755 | let pipe_handle = match self.handle { 756 | Some(ref handle) => handle.value, 757 | None => unreachable!(), 758 | }; 759 | let event_handle = match self.ovl { 760 | Some(ref ovl) => ovl.ovl.hEvent, 761 | None => unreachable!(), 762 | }; 763 | PipeIoHandles { 764 | pipe_handle: pipe_handle, 765 | event_handle: event_handle, 766 | _phantom: PhantomData, 767 | } 768 | } 769 | 770 | fn get_read_timeout(&self) -> Option { 771 | Self::get_read_timeout_ms(self) 772 | } 773 | 774 | fn get_write_timeout(&self) -> Option { 775 | Self::get_write_timeout_ms(self) 776 | } 777 | } 778 | 779 | impl PipeIo for PipeClient { 780 | fn io_obj<'a>(&'a mut self) -> PipeIoObj<'a> { 781 | PipeIoObj { 782 | handle: self.handle.value, 783 | ovl: &mut self.ovl, 784 | } 785 | } 786 | 787 | fn io_handles<'a>(&'a self) -> PipeIoHandles<'a> { 788 | PipeIoHandles { 789 | pipe_handle: self.handle.value, 790 | event_handle: self.ovl.ovl.hEvent, 791 | _phantom: PhantomData, 792 | } 793 | } 794 | 795 | fn get_read_timeout(&self) -> Option { 796 | Self::get_read_timeout_ms(self) 797 | } 798 | 799 | fn get_write_timeout(&self) -> Option { 800 | Self::get_write_timeout_ms(self) 801 | } 802 | } 803 | 804 | impl<'a, T: PipeIo> PipeIo for ReadHandle<'a, T> { 805 | fn io_obj<'b>(&'b mut self) -> PipeIoObj<'b> { 806 | match self.io { 807 | Some(ref mut io) => return io.io_obj(), 808 | _ => (), 809 | } 810 | match self.io_ref { 811 | Some(ref mut io) => return io.io_obj(), 812 | _ => (), 813 | } 814 | unreachable!(); 815 | } 816 | 817 | fn io_handles<'b>(&'b self) -> PipeIoHandles<'b> { 818 | match self.io { 819 | Some(ref io) => return io.io_handles(), 820 | _ => (), 821 | } 822 | match self.io_ref { 823 | Some(ref io) => return io.io_handles(), 824 | _ => (), 825 | } 826 | unreachable!(); 827 | } 828 | 829 | fn get_read_timeout(&self) -> Option { 830 | match self.io { 831 | Some(ref io) => return io.get_read_timeout(), 832 | _ => (), 833 | } 834 | match self.io_ref { 835 | Some(ref io) => return io.get_read_timeout(), 836 | _ => (), 837 | } 838 | unreachable!(); 839 | } 840 | 841 | fn get_write_timeout(&self) -> Option { 842 | match self.io { 843 | Some(ref io) => return io.get_write_timeout(), 844 | _ => (), 845 | } 846 | match self.io_ref { 847 | Some(ref io) => return io.get_write_timeout(), 848 | _ => (), 849 | } 850 | unreachable!(); 851 | } 852 | } 853 | 854 | impl<'a, T: PipeIo> PipeIo for WriteHandle<'a, T> { 855 | fn io_obj<'b>(&'b mut self) -> PipeIoObj<'b> { 856 | match self.io { 857 | Some(ref mut io) => return io.io_obj(), 858 | _ => (), 859 | } 860 | match self.io_ref { 861 | Some(ref mut io) => return io.io_obj(), 862 | _ => (), 863 | } 864 | unreachable!(); 865 | } 866 | 867 | fn io_handles<'b>(&'b self) -> PipeIoHandles<'b> { 868 | match self.io { 869 | Some(ref io) => return io.io_handles(), 870 | _ => (), 871 | } 872 | match self.io_ref { 873 | Some(ref io) => return io.io_handles(), 874 | _ => (), 875 | } 876 | unreachable!(); 877 | } 878 | 879 | fn get_read_timeout(&self) -> Option { 880 | match self.io { 881 | Some(ref io) => return io.get_read_timeout(), 882 | _ => (), 883 | } 884 | match self.io_ref { 885 | Some(ref io) => return io.get_read_timeout(), 886 | _ => (), 887 | } 888 | unreachable!(); 889 | } 890 | 891 | fn get_write_timeout(&self) -> Option { 892 | match self.io { 893 | Some(ref io) => return io.get_write_timeout(), 894 | _ => (), 895 | } 896 | match self.io_ref { 897 | Some(ref io) => return io.get_write_timeout(), 898 | _ => (), 899 | } 900 | unreachable!(); 901 | } 902 | } 903 | 904 | impl PipeIo for ConnectingServer { 905 | fn io_obj<'a>(&'a mut self) -> PipeIoObj<'a> { 906 | PipeIoObj { 907 | handle: self.handle.value, 908 | ovl: &mut self.ovl, 909 | } 910 | } 911 | 912 | fn io_handles<'a>(&'a self) -> PipeIoHandles<'a> { 913 | PipeIoHandles { 914 | pipe_handle: self.handle.value, 915 | event_handle: self.ovl.ovl.hEvent, 916 | _phantom: PhantomData, 917 | } 918 | } 919 | 920 | fn get_read_timeout(&self) -> Option { 921 | None 922 | } 923 | 924 | fn get_write_timeout(&self) -> Option { 925 | None 926 | } 927 | } 928 | 929 | /// Pending read operation. Can be used with [`wait`](fn.wait.html) and [`wait_all`] 930 | /// (fn.wait_all.html) functions. 931 | pub struct ReadHandle<'a, T: PipeIo> { 932 | io: Option, 933 | io_ref: Option<&'a mut dyn PipeIo>, 934 | bytes_read: u32, 935 | pending: bool, 936 | buffer: Option>, 937 | } 938 | 939 | impl<'a, T: fmt::Debug + PipeIo> fmt::Debug for ReadHandle<'a, T> { 940 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 941 | match self.io_ref { 942 | Some(ref io) => fmt 943 | .debug_struct("ReadHandle") 944 | .field("io", &self.io) 945 | .field("io_ref", &io.io_handles()) 946 | .field("bytes_read", &self.bytes_read) 947 | .field("pending", &self.pending) 948 | .field("buffer", &self.buffer) 949 | .finish(), 950 | None => fmt 951 | .debug_struct("ReadHandle") 952 | .field("io", &self.io) 953 | .field("io_ref", &"None") 954 | .field("bytes_read", &self.bytes_read) 955 | .field("pending", &self.pending) 956 | .field("buffer", &self.buffer) 957 | .finish(), 958 | } 959 | } 960 | } 961 | 962 | impl<'a, T: PipeIo> Drop for ReadHandle<'a, T> { 963 | fn drop(&mut self) { 964 | let timeout = self.get_read_timeout().unwrap_or(INFINITE); 965 | if self.pending && timeout > 0 { 966 | let result = unsafe { 967 | let io_obj = self.io_obj(); 968 | CancelIoEx(io_obj.handle, &mut *io_obj.ovl.ovl) 969 | }; 970 | if result == FALSE { 971 | let error = io::Error::last_os_error(); 972 | match error.raw_os_error().unwrap() as u32 { 973 | ERROR_IO_PENDING => (/* OK */), 974 | _ => panic!("CANCEL ERROR {:?}", error), 975 | } 976 | } 977 | } 978 | } 979 | } 980 | 981 | impl<'a, T: PipeIo> ReadHandle<'a, T> { 982 | fn wait_impl(&mut self) -> io::Result<()> { 983 | if self.pending { 984 | let timeout = self.get_read_timeout().unwrap_or(INFINITE); 985 | match wait_for_single_obj(self, timeout)? { 986 | Some(_) => { 987 | let mut count = 0; 988 | self.pending = false; 989 | match get_ovl_result(self, &mut count)? { 990 | 0 => Err(io::Error::last_os_error()), 991 | _ => { 992 | self.bytes_read = count; 993 | Ok(()) 994 | } 995 | } 996 | } 997 | None => Err(io::Error::new( 998 | io::ErrorKind::TimedOut, 999 | "timed out while reading from pipe", 1000 | )), 1001 | } 1002 | } else { 1003 | Ok(()) 1004 | } 1005 | } 1006 | /// Will wait for completion infinitely, or until read_timeout reached if read_timeout has been set. 1007 | /// 1008 | /// Returns (, ). Owned data is `Some((T, Vec))` if `ReadHandle` 1009 | /// was created as a result of `T::read_async_owned`. 1010 | pub fn wait(mut self) -> io::Result<(usize, Option<(T, Vec)>)> { 1011 | let result = self.wait_impl(); 1012 | let output = { 1013 | let io = self.io.take(); 1014 | let bytes_read = self.bytes_read; 1015 | let buffer = self.buffer.take(); 1016 | if let Some(buf) = buffer { 1017 | if let Some(io) = io { 1018 | Ok((bytes_read as usize, Some((io, buf)))) 1019 | } else { 1020 | unreachable!() 1021 | } 1022 | } else { 1023 | Ok((bytes_read as usize, None)) 1024 | } 1025 | }; 1026 | match result { 1027 | Ok(_) => output, 1028 | Err(err) => { 1029 | if err.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) { 1030 | output 1031 | } else { 1032 | Err(err) 1033 | } 1034 | } 1035 | } 1036 | } 1037 | } 1038 | 1039 | /// Pending write operation. Can be used with [`wait`](fn.wait.html) and [`wait_all`] 1040 | /// (fn.wait_all.html) functions. 1041 | pub struct WriteHandle<'a, T: PipeIo> { 1042 | buffer: Option>, 1043 | io: Option, 1044 | io_ref: Option<&'a mut dyn PipeIo>, 1045 | bytes_written: u32, 1046 | num_bytes: u32, 1047 | pending: bool, 1048 | } 1049 | 1050 | impl<'a, T: fmt::Debug + PipeIo> fmt::Debug for WriteHandle<'a, T> { 1051 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 1052 | match self.io_ref { 1053 | Some(ref io) => fmt 1054 | .debug_struct("WriteHandle") 1055 | .field("io", &self.io) 1056 | .field("io_ref", &io.io_handles()) 1057 | .field("bytes_written", &self.bytes_written) 1058 | .field("num_bytes", &self.num_bytes) 1059 | .field("pending", &self.pending) 1060 | .field("buffer", &self.buffer) 1061 | .finish(), 1062 | None => fmt 1063 | .debug_struct("WriteHandle") 1064 | .field("io", &self.io) 1065 | .field("io_ref", &"None") 1066 | .field("bytes_written", &self.bytes_written) 1067 | .field("num_bytes", &self.num_bytes) 1068 | .field("pending", &self.pending) 1069 | .field("buffer", &self.buffer) 1070 | .finish(), 1071 | } 1072 | } 1073 | } 1074 | 1075 | impl<'a, T: PipeIo> Drop for WriteHandle<'a, T> { 1076 | fn drop(&mut self) { 1077 | let timeout = self.get_write_timeout().unwrap_or(INFINITE); 1078 | if self.pending && timeout > 0 { 1079 | let result = unsafe { 1080 | let io_obj = self.io_obj(); 1081 | CancelIoEx(io_obj.handle, &mut *io_obj.ovl.ovl) 1082 | }; 1083 | if result == FALSE { 1084 | let error = io::Error::last_os_error(); 1085 | match error.raw_os_error().unwrap() as u32 { 1086 | ERROR_IO_PENDING => (/* OK */), 1087 | _ => panic!("CANCEL ERROR {:?}", error), 1088 | } 1089 | } 1090 | } 1091 | } 1092 | } 1093 | 1094 | impl<'a, T: PipeIo> WriteHandle<'a, T> { 1095 | fn wait_impl(&mut self) -> io::Result<()> { 1096 | if self.pending { 1097 | let timeout = self.get_write_timeout().unwrap_or(INFINITE); 1098 | match wait_for_single_obj(self, timeout)? { 1099 | Some(_) => { 1100 | let mut bytes_written = 0; 1101 | self.pending = false; 1102 | match get_ovl_result(self, &mut bytes_written)? { 1103 | x if x as u32 == self.num_bytes => { 1104 | self.bytes_written = bytes_written; 1105 | Ok(()) 1106 | } 1107 | _ => Err(io::Error::last_os_error()), 1108 | } 1109 | } 1110 | None => Err(io::Error::new( 1111 | io::ErrorKind::TimedOut, 1112 | "timed out while writing into pipe", 1113 | )), 1114 | } 1115 | } else { 1116 | Ok(()) 1117 | } 1118 | } 1119 | 1120 | /// Will wait for completion infinitely, or until write_timeout reached if write_timeout has been set. 1121 | /// 1122 | /// Returns (, ). Owned data is `Some((T, Vec))` if `WriteHandle` 1123 | /// was created as a result of `T::write_async_owned`. 1124 | pub fn wait(mut self) -> io::Result<(usize, Option<(T, Vec)>)> { 1125 | self.wait_impl()?; 1126 | let io = self.io.take(); 1127 | let bytes_written = self.bytes_written; 1128 | let buffer = self.buffer.take(); 1129 | if let Some(buf) = buffer { 1130 | if let Some(io) = io { 1131 | Ok((bytes_written as usize, Some((io, buf)))) 1132 | } else { 1133 | unreachable!() 1134 | } 1135 | } else { 1136 | Ok((bytes_written as usize, None)) 1137 | } 1138 | } 1139 | } 1140 | 1141 | /// Returns `Ok(true)` if connection is pending or `Ok(false)` if pipe is connected. 1142 | fn connect_named_pipe(handle: &Handle, ovl: &mut Overlapped) -> io::Result { 1143 | let result = unsafe { ConnectNamedPipe(handle.value, ovl.get_mut()) }; 1144 | if result == TRUE { 1145 | // Overlapped ConnectNamedPipe should return FALSE 1146 | return Err(io::Error::last_os_error()); 1147 | } else { 1148 | let err = io::Error::last_os_error(); 1149 | let mut pending = false; 1150 | match err.raw_os_error().unwrap() as u32 { 1151 | ERROR_IO_PENDING => pending = true, 1152 | ERROR_PIPE_CONNECTED => ovl.event.set()?, 1153 | _ => return Err(err), 1154 | } 1155 | Ok(pending) 1156 | } 1157 | } 1158 | 1159 | fn init_read<'a, 'b: 'a, T>(this: &'a mut T, buf: &'b mut [u8]) -> io::Result> 1160 | where 1161 | T: PipeIo, 1162 | { 1163 | let mut bytes_read = 0; 1164 | let result = unsafe { 1165 | let io_obj = this.io_obj(); 1166 | ReadFile( 1167 | io_obj.handle, 1168 | buf.as_mut_ptr() as *mut c_void, 1169 | buf.len() as u32, 1170 | &mut bytes_read, 1171 | &mut *io_obj.ovl.ovl, 1172 | ) 1173 | }; 1174 | 1175 | if result != 0 && bytes_read != 0 { 1176 | Ok(ReadHandle { 1177 | io: None, 1178 | io_ref: Some(this), 1179 | bytes_read: bytes_read, 1180 | pending: false, 1181 | buffer: None, 1182 | }) 1183 | } else { 1184 | let err = io::Error::last_os_error(); 1185 | if result == 0 && err.raw_os_error().unwrap() == ERROR_IO_PENDING as i32 { 1186 | Ok(ReadHandle { 1187 | io: None, 1188 | io_ref: Some(this), 1189 | bytes_read: 0, 1190 | pending: true, 1191 | buffer: None, 1192 | }) 1193 | } else { 1194 | Err(err) 1195 | } 1196 | } 1197 | } 1198 | 1199 | fn init_read_owned(mut this: T, mut buf: Vec) -> io::Result> { 1200 | let mut bytes_read = 0; 1201 | let result = unsafe { 1202 | let io_obj = this.io_obj(); 1203 | ReadFile( 1204 | io_obj.handle, 1205 | buf.as_mut_ptr() as *mut c_void, 1206 | buf.len() as u32, 1207 | &mut bytes_read, 1208 | &mut *io_obj.ovl.ovl, 1209 | ) 1210 | }; 1211 | 1212 | if result != 0 && bytes_read != 0 { 1213 | Ok(ReadHandle { 1214 | io: Some(this), 1215 | io_ref: None, 1216 | bytes_read: bytes_read, 1217 | pending: false, 1218 | buffer: Some(buf), 1219 | }) 1220 | } else { 1221 | let err = io::Error::last_os_error(); 1222 | if result == 0 && err.raw_os_error().unwrap() == ERROR_IO_PENDING as i32 { 1223 | Ok(ReadHandle { 1224 | io: Some(this), 1225 | io_ref: None, 1226 | bytes_read: 0, 1227 | pending: true, 1228 | buffer: Some(buf), 1229 | }) 1230 | } else { 1231 | Err(err) 1232 | } 1233 | } 1234 | } 1235 | 1236 | fn init_write<'a, 'b: 'a, T>(this: &'a mut T, buf: &'b [u8]) -> io::Result> 1237 | where 1238 | T: PipeIo, 1239 | { 1240 | assert!(buf.len() <= 0xFFFFFFFF); 1241 | let mut bytes_written = 0; 1242 | let result = unsafe { 1243 | let io_obj = this.io_obj(); 1244 | WriteFile( 1245 | io_obj.handle, 1246 | buf.as_ptr() as *mut c_void, 1247 | buf.len() as u32, 1248 | &mut bytes_written, 1249 | &mut *io_obj.ovl.ovl, 1250 | ) 1251 | }; 1252 | 1253 | if result != 0 && bytes_written == buf.len() as u32 { 1254 | Ok(WriteHandle { 1255 | io: None, 1256 | io_ref: Some(this), 1257 | buffer: None, 1258 | bytes_written: bytes_written, 1259 | num_bytes: buf.len() as u32, 1260 | pending: false, 1261 | }) 1262 | } else { 1263 | let err = io::Error::last_os_error(); 1264 | if result == 0 && err.raw_os_error().unwrap() == ERROR_IO_PENDING as i32 { 1265 | Ok(WriteHandle { 1266 | io: None, 1267 | io_ref: Some(this), 1268 | buffer: None, 1269 | bytes_written: 0, 1270 | num_bytes: buf.len() as u32, 1271 | pending: true, 1272 | }) 1273 | } else { 1274 | Err(err) 1275 | } 1276 | } 1277 | } 1278 | 1279 | fn init_write_owned<'a, 'b: 'a, T>(mut this: T, buf: Vec) -> io::Result> 1280 | where 1281 | T: PipeIo, 1282 | { 1283 | assert!(buf.len() <= 0xFFFFFFFF); 1284 | let mut bytes_written = 0; 1285 | let result = unsafe { 1286 | let io_obj = this.io_obj(); 1287 | WriteFile( 1288 | io_obj.handle, 1289 | buf.as_ptr() as *mut c_void, 1290 | buf.len() as u32, 1291 | &mut bytes_written, 1292 | &mut *io_obj.ovl.ovl, 1293 | ) 1294 | }; 1295 | 1296 | if result != 0 && bytes_written == buf.len() as u32 { 1297 | Ok(WriteHandle { 1298 | io_ref: None, 1299 | io: Some(this), 1300 | num_bytes: buf.len() as u32, 1301 | buffer: Some(buf), 1302 | bytes_written: bytes_written, 1303 | pending: false, 1304 | }) 1305 | } else { 1306 | let err = io::Error::last_os_error(); 1307 | if result == 0 && err.raw_os_error().unwrap() == ERROR_IO_PENDING as i32 { 1308 | Ok(WriteHandle { 1309 | io_ref: None, 1310 | io: Some(this), 1311 | num_bytes: buf.len() as u32, 1312 | buffer: Some(buf), 1313 | bytes_written: 0, 1314 | pending: true, 1315 | }) 1316 | } else { 1317 | Err(err) 1318 | } 1319 | } 1320 | } 1321 | 1322 | fn get_ovl_result(this: &mut T, count: &mut u32) -> io::Result { 1323 | let result = unsafe { 1324 | let io_obj = this.io_obj(); 1325 | GetOverlappedResult(io_obj.handle, &mut *io_obj.ovl.ovl, count, TRUE) 1326 | }; 1327 | if result != 0 { 1328 | Ok(*count as usize) 1329 | } else { 1330 | Err(io::Error::last_os_error()) 1331 | } 1332 | } 1333 | 1334 | fn wait_for_single_obj(this: &mut T, timeout: u32) -> io::Result> 1335 | where 1336 | T: PipeIo, 1337 | { 1338 | let result = unsafe { 1339 | let io_obj = this.io_obj(); 1340 | WaitForSingleObject(io_obj.ovl.event.handle.value, timeout) 1341 | }; 1342 | 1343 | match result { 1344 | WAIT_OBJECT_0 => Ok(Some(0)), 1345 | WAIT_TIMEOUT => Ok(None), 1346 | WAIT_FAILED => Err(io::Error::last_os_error()), 1347 | _ => unreachable!(), 1348 | } 1349 | } 1350 | 1351 | fn wait_for_multiple_obj(list: &[T], all: bool, timeout: u32) -> io::Result> 1352 | where 1353 | T: PipeIo, 1354 | { 1355 | assert!(list.len() <= MAXIMUM_WAIT_OBJECTS as usize); 1356 | if list.len() == 0 { 1357 | Ok(None) 1358 | } else { 1359 | let mut events = Vec::with_capacity(list.len()); 1360 | 1361 | for obj in list.iter() { 1362 | events.push(obj.io_handles().event_handle); 1363 | } 1364 | 1365 | let result = unsafe { 1366 | WaitForMultipleObjects( 1367 | events.len() as u32, 1368 | events.as_ptr(), 1369 | if all { TRUE } else { FALSE }, 1370 | timeout, 1371 | ) 1372 | }; 1373 | 1374 | if all { 1375 | match result { 1376 | WAIT_OBJECT_0 => Ok(Some(0)), 1377 | WAIT_TIMEOUT => Ok(None), 1378 | WAIT_FAILED => Err(io::Error::last_os_error()), 1379 | _ => unreachable!(), 1380 | } 1381 | } else { 1382 | match result { 1383 | i if i < 64 => Ok(Some(i as usize)), 1384 | WAIT_TIMEOUT => Ok(None), 1385 | WAIT_FAILED => Err(io::Error::last_os_error()), 1386 | _ => unreachable!(), 1387 | } 1388 | } 1389 | } 1390 | } 1391 | 1392 | /// This function will wait for first finished io operation and return it's index in `list`. 1393 | /// 1394 | /// # Panics 1395 | /// 1396 | /// This function will panic if `list.len() == 0` or `list.len() > MAXIMUM_WAIT_OBJECTS` 1397 | pub fn wait(list: &[T]) -> io::Result { 1398 | assert!(list.len() > 0); 1399 | 1400 | match wait_for_multiple_obj(list, false, INFINITE)? { 1401 | Some(x) => Ok(x), 1402 | None => unreachable!(), 1403 | } 1404 | } 1405 | 1406 | #[test] 1407 | fn test_io_single_thread() { 1408 | let connecting_server = PipeOptions::new(r"\\.\pipe\test_io_single_thread") 1409 | .single() 1410 | .unwrap(); 1411 | let mut client = PipeClient::connect(r"\\.\pipe\test_io_single_thread").unwrap(); 1412 | let mut server = connecting_server.wait().unwrap(); 1413 | { 1414 | let w_handle = unsafe { server.write_async(b"0123456789").unwrap() }; 1415 | { 1416 | let mut buf = [0; 5]; 1417 | { 1418 | let r_handle = unsafe { client.read_async(&mut buf[..]).unwrap() }; 1419 | r_handle.wait().unwrap(); 1420 | } 1421 | assert_eq!(&buf[..], b"01234"); 1422 | { 1423 | let r_handle = unsafe { client.read_async(&mut buf[..]).unwrap() }; 1424 | r_handle.wait().unwrap(); 1425 | } 1426 | assert_eq!(&buf[..], b"56789"); 1427 | } 1428 | w_handle.wait().unwrap(); 1429 | } 1430 | let connecting_server = server.disconnect().unwrap(); 1431 | 1432 | let mut client = PipeClient::connect(r"\\.\pipe\test_io_single_thread").unwrap(); 1433 | let mut server = connecting_server.wait().unwrap(); 1434 | { 1435 | let w_handle = unsafe { server.write_async(b"0123456789").unwrap() }; 1436 | { 1437 | let mut buf = [0; 5]; 1438 | { 1439 | let r_handle = unsafe { client.read_async(&mut buf[..]).unwrap() }; 1440 | r_handle.wait().unwrap(); 1441 | } 1442 | assert_eq!(&buf[..], b"01234"); 1443 | { 1444 | let r_handle = unsafe { client.read_async(&mut buf[..]).unwrap() }; 1445 | r_handle.wait().unwrap(); 1446 | } 1447 | assert_eq!(&buf[..], b"56789"); 1448 | } 1449 | w_handle.wait().unwrap(); 1450 | } 1451 | } 1452 | 1453 | #[test] 1454 | fn test_io_multiple_threads() { 1455 | use std::io::{Read, Write}; 1456 | use std::thread; 1457 | use std::time::Duration; 1458 | 1459 | let connecting_server = PipeOptions::new(r"\\.\pipe\test_io_multiple_threads") 1460 | .single() 1461 | .unwrap(); 1462 | let t1 = thread::spawn(move || { 1463 | let mut buf = [0; 5]; 1464 | let mut client = PipeClient::connect(r"\\.\pipe\test_io_multiple_threads").unwrap(); 1465 | client.read(&mut buf).unwrap(); 1466 | client.write(b"done").unwrap(); 1467 | buf 1468 | }); 1469 | let t2 = thread::spawn(move || { 1470 | thread::sleep(Duration::from_millis(50)); 1471 | let mut buf = [0; 5]; 1472 | let mut client = PipeClient::connect(r"\\.\pipe\test_io_multiple_threads").unwrap(); 1473 | client.read(&mut buf).unwrap(); 1474 | client.write(b"done").unwrap(); 1475 | buf 1476 | }); 1477 | 1478 | let mut buf = [0; 4]; 1479 | let mut server = connecting_server.wait().unwrap(); 1480 | server.write(b"01234").unwrap(); 1481 | server.read(&mut buf).unwrap(); 1482 | assert_eq!(b"done", &buf[..]); 1483 | 1484 | let mut buf = [0; 4]; 1485 | let mut server = server.disconnect().unwrap().wait().unwrap(); 1486 | server.write(b"56789").unwrap(); 1487 | server.read(&mut buf).unwrap(); 1488 | assert_eq!(b"done", &buf[..]); 1489 | server.disconnect().unwrap(); 1490 | 1491 | assert_eq!(b"01234", &t1.join().unwrap()[..]); 1492 | assert_eq!(b"56789", &t2.join().unwrap()[..]); 1493 | } 1494 | 1495 | #[test] 1496 | fn test_wait() { 1497 | use std::io::{Read, Write}; 1498 | use std::thread; 1499 | 1500 | let mut servers = PipeOptions::new(r"\\.\pipe\test_wait") 1501 | .multiple(16) 1502 | .unwrap(); 1503 | let t1 = thread::spawn(move || { 1504 | for _ in 0..16 { 1505 | let mut buf = [0; 10]; 1506 | let mut client = PipeClient::connect(r"\\.\pipe\test_wait").unwrap(); 1507 | client.read(&mut buf).unwrap(); 1508 | client.write(b"done").unwrap(); 1509 | assert_eq!(b"0123456789", &buf[..]); 1510 | } 1511 | }); 1512 | 1513 | while servers.len() > 0 { 1514 | let mut buf = [0; 4]; 1515 | let which = wait(servers.as_ref()).unwrap(); 1516 | let mut server = servers.remove(which).wait().unwrap(); 1517 | server.write(b"0123456789").unwrap(); 1518 | server.read(&mut buf).unwrap(); 1519 | assert_eq!(b"done", &buf[..]); 1520 | } 1521 | 1522 | t1.join().unwrap(); 1523 | } 1524 | 1525 | #[test] 1526 | fn test_timeout() { 1527 | use std::io::{self, Read, Write}; 1528 | use std::thread; 1529 | use std::time::Duration; 1530 | 1531 | let server = PipeOptions::new(r"\\.\pipe\test_timeout").single().unwrap(); 1532 | let t1 = thread::spawn(move || { 1533 | let mut buf = [0; 10]; 1534 | let mut client = PipeClient::connect(r"\\.\pipe\test_timeout").unwrap(); 1535 | client.set_read_timeout(Some(Duration::from_millis(10))); 1536 | let err = client.read(&mut buf).unwrap_err(); 1537 | assert_eq!(err.kind(), io::ErrorKind::TimedOut); 1538 | client.set_read_timeout(None); 1539 | client.read(&mut buf).unwrap(); 1540 | thread::sleep(Duration::from_millis(200)); 1541 | client.write(b"done").unwrap(); 1542 | client.flush().unwrap(); 1543 | assert_eq!(b"0123456789", &buf[..]); 1544 | }); 1545 | 1546 | let mut buf = [0; 4]; 1547 | thread::sleep(Duration::from_millis(200)); 1548 | let mut server = server.wait().unwrap(); 1549 | server.write(b"0123456789").unwrap(); 1550 | server.set_read_timeout(Some(Duration::from_millis(10))); 1551 | let err = server.read(&mut buf).unwrap_err(); 1552 | assert_eq!(err.kind(), io::ErrorKind::TimedOut); 1553 | server.set_read_timeout(None); 1554 | server.read(&mut buf).unwrap(); 1555 | 1556 | t1.join().unwrap(); 1557 | } 1558 | 1559 | #[test] 1560 | fn cancel_io_clien_read_on_timeout() { 1561 | use std::{ 1562 | io::{ErrorKind, Read, Write}, 1563 | thread, 1564 | }; 1565 | 1566 | let name = r"\\.\pipe\cancel_io_client_read_on_timeout"; 1567 | let server = PipeOptions::new(name).single().unwrap(); 1568 | 1569 | let handle = thread::spawn(move || { 1570 | let mut buf = [0; 10]; 1571 | 1572 | let mut client = PipeClient::connect(name).unwrap(); 1573 | client.set_read_timeout(Some(Duration::from_millis(10))); 1574 | 1575 | let err = client.read(&mut buf).unwrap_err(); 1576 | assert_eq!(err.kind(), ErrorKind::TimedOut); 1577 | assert_eq!(buf, [0; 10]); 1578 | thread::sleep(Duration::from_millis(100 * 2)); 1579 | assert_eq!(buf, [0; 10]); 1580 | }); 1581 | 1582 | let mut server = server.wait().unwrap(); 1583 | thread::sleep(Duration::from_millis(100)); 1584 | server.write(b"0123456789").unwrap(); 1585 | 1586 | handle.join().unwrap(); 1587 | } 1588 | 1589 | #[test] 1590 | fn cancel_io_server_read_on_timeout() { 1591 | use std::{ 1592 | io::{ErrorKind, Read, Write}, 1593 | thread, 1594 | }; 1595 | 1596 | let name = r"\\.\pipe\cancel_io_server_read_on_timeout"; 1597 | let server = PipeOptions::new(name).single().unwrap(); 1598 | 1599 | let handle = thread::spawn(move || { 1600 | let mut buf = [0; 10]; 1601 | 1602 | let mut server = server.wait().unwrap(); 1603 | server.set_read_timeout(Some(Duration::from_millis(10))); 1604 | let err = server.read(&mut buf).unwrap_err(); 1605 | assert_eq!(err.kind(), ErrorKind::TimedOut); 1606 | assert_eq!(buf, [0; 10]); 1607 | thread::sleep(Duration::from_millis(100 * 2)); 1608 | assert_eq!(buf, [0; 10]); 1609 | }); 1610 | 1611 | let mut client = PipeClient::connect(name).unwrap(); 1612 | thread::sleep(Duration::from_millis(100)); 1613 | client.write(b"0123456789").unwrap(); 1614 | 1615 | handle.join().unwrap(); 1616 | } 1617 | 1618 | #[test] 1619 | fn cancel_io_client_write_on_timeout() { 1620 | use std::{ 1621 | io::{ErrorKind, Read, Write}, 1622 | thread, 1623 | }; 1624 | let mut buf = [0; 10]; 1625 | 1626 | let name = r"\\.\pipe\cancel_io_client_write_on_timeout"; 1627 | let server = PipeOptions::new(name) 1628 | .out_buffer(0) 1629 | .in_buffer(0) 1630 | .single() 1631 | .unwrap(); 1632 | 1633 | let handle = thread::spawn(move || { 1634 | let mut client = PipeClient::connect(name).unwrap(); 1635 | 1636 | client.set_write_timeout(Some(Duration::from_millis(10))); 1637 | let err = client.write(b"0123456789").unwrap_err(); 1638 | assert_eq!(err.kind(), ErrorKind::TimedOut); 1639 | thread::sleep(Duration::from_millis(100 * 2)); 1640 | }); 1641 | 1642 | let mut server = server.wait().unwrap(); 1643 | 1644 | thread::sleep(Duration::from_millis(100)); 1645 | let n = server.read(&mut buf[..]).unwrap(); 1646 | assert_eq!(n, 0); 1647 | assert_eq!(buf, [0; 10]); 1648 | 1649 | handle.join().unwrap(); 1650 | } 1651 | 1652 | #[test] 1653 | fn cancel_io_server_write_on_timeout() { 1654 | use std::{ 1655 | io::{ErrorKind, Read, Write}, 1656 | thread, 1657 | }; 1658 | let mut buf = [0; 10]; 1659 | 1660 | let name = r"\\.\pipe\cancel_io_server_write_on_timeout"; 1661 | let server = PipeOptions::new(name) 1662 | .out_buffer(0) 1663 | .in_buffer(0) 1664 | .single() 1665 | .unwrap(); 1666 | 1667 | let handle = thread::spawn(move || { 1668 | let mut server = server.wait().unwrap(); 1669 | 1670 | server.set_write_timeout(Some(Duration::from_millis(10))); 1671 | let err = server.write(b"0123456789").unwrap_err(); 1672 | assert_eq!(err.kind(), ErrorKind::TimedOut); 1673 | thread::sleep(Duration::from_millis(100 * 3)); 1674 | }); 1675 | 1676 | let mut client = PipeClient::connect(name).unwrap(); 1677 | 1678 | thread::sleep(Duration::from_millis(100)); 1679 | let err = client.read(&mut buf[..]).unwrap_err(); 1680 | assert_eq!(err.raw_os_error().unwrap(), ERROR_PIPE_NOT_CONNECTED as i32); 1681 | 1682 | handle.join().unwrap(); 1683 | } 1684 | 1685 | #[test] 1686 | fn zero_timeout_read() { 1687 | use std::io::{BufRead, BufReader, ErrorKind, Write}; 1688 | use std::sync::{atomic::{AtomicBool, Ordering}, Arc}; 1689 | 1690 | let read_timeout = Arc::new(AtomicBool::new(false)); 1691 | 1692 | let handle = ::std::thread::spawn({ 1693 | let read_timeout = read_timeout.clone(); 1694 | move || { 1695 | let server = PipeOptions::new(r"\\.\pipe\ztimeout").single().unwrap(); 1696 | let mut server = server.wait().unwrap(); 1697 | server.set_write_timeout(Some(Duration::from_millis(0))); 1698 | loop { 1699 | match server.write(b"line\n") { 1700 | Ok(_) => (), 1701 | Err(ref err) 1702 | if err.kind() == ErrorKind::TimedOut => 1703 | { 1704 | if read_timeout.load(Ordering::Relaxed) { 1705 | server.disconnect().unwrap(); 1706 | break; 1707 | } 1708 | } 1709 | Err(err) => panic!("Write error: {:?}", err), 1710 | } 1711 | } 1712 | } 1713 | }); 1714 | 1715 | ::std::thread::sleep(Duration::from_secs(1)); 1716 | 1717 | let mut client = PipeClient::connect(r"\\.\pipe\ztimeout").unwrap(); 1718 | client.set_read_timeout(Some(Duration::from_millis(0))); 1719 | 1720 | let mut reader = BufReader::new(client); 1721 | let mut line = String::new(); 1722 | loop { 1723 | match reader.read_line(&mut line) { 1724 | Ok(_) => line.clear(), 1725 | Err(ref err) if err.kind() == ErrorKind::TimedOut => { 1726 | read_timeout.store(true, Ordering::Relaxed); 1727 | }, 1728 | Err(ref err) if err.raw_os_error() == Some(233) => break, 1729 | Err(err) => panic!("Read error: {:?}", err), 1730 | } 1731 | } 1732 | 1733 | handle.join().unwrap(); 1734 | } 1735 | --------------------------------------------------------------------------------