1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
use ::{ IoError, Result, InstantExt, WaitForEvent }; use ::std::{ io::Read, time::{ Duration, Instant }, io::ErrorKind as IoErrorKind }; /// A trait for reading with timeouts pub trait Reader { /// Executes _one_ `read`-operation to read up to `buffer.len()`-bytes /// /// This is especially useful in packet-based contexts where `read`-operations are atomic /// (like in UDP) or if you don't know the amount of bytes in advance /// /// _Note: This function catches all interal timeouts/interrupts and returns only if there was /// either one successful `read`-operation or the `timeout` was hit or a non-recoverable error /// occurred._ /// /// __Warning: This function makes `self` non-blocking. It's up to you to restore the previous /// state if necessary.__ /// /// Parameters: /// - `buffer`: The buffer to write the data to /// - `timeout`: The maximum time this function will wait for `self` to become readable /// /// Returns either __the amount of bytes read__ or a corresponding `IoError` fn read(&mut self, buffer: &mut[u8], timeout: Duration) -> Result<usize>; /// Reads until `buffer` has been filled completely /// /// This is especially useful in stream-based contexts where partial-`read`-calls are common /// (like in TCP) and you want to read a well-known amount of bytes /// /// _Note: This function catches all interal timeouts/interrupts and returns only if either /// `buffer` has been filled completely or the `timeout` was hit or a non-recoverable error /// occurred._ /// /// __Warning: This function makes `self` non-blocking. It's up to you to restore the previous /// state if necessary.__ /// /// Parameters: /// - `buffer`: The buffer to fill with data /// - `timeout`: The maximum time this function will block /// /// Returns either __nothing__ or a corresponding `IoError` fn read_exact(&mut self, buffer: &mut[u8], timeout: Duration) -> Result<()>; /// Read until either `pattern` has been matched or `buffer` has been filled completely /// /// _Note: This function catches all interal timeouts/interrupts and returns only if either /// `pattern` has been matched or `buffer` has been filled completely or the `timeout` was hit /// or a non-recoverable error occurred._ /// /// __Warning: This function makes `self` non-blocking. It's up to you to restore the previous /// state if necessary.__ /// /// Parameters: /// - `pattern`: The pattern up to which you want to read. /// - `buffer`: The buffer to write the data to /// - `timeout`: The maximum time this function will block /// /// Returns either /// - `Ok(bytes_read)` if the pattern was found or /// - `Err(IOError(std::io::ErrorKind::NotFound))` if the buffer was filled completely without /// a match or /// - another corresponding `IoError` fn read_until(&mut self, pattern: &[u8], buffer: &mut[u8], timeout: Duration) -> Result<usize>; } impl<T: Read + WaitForEvent> Reader for T { fn read(&mut self, buffer: &mut[u8], timeout: Duration) -> Result<usize> { // Make the socket non-blocking try_err!(self.set_blocking_mode(false)); // Immediately return if we should not read any bytes if buffer.len() == 0 { return Ok(0) } // Wait for read-event and read data try_err!(self.wait_until_readable(timeout)); loop { match self.read(buffer) { Ok(bytes_read) => if bytes_read > 0 { return Ok(bytes_read) } else { throw_err!(IoErrorKind::UnexpectedEof.into()) }, Err(error) => { let error = IoError::from(error); if error.non_recoverable { throw_err!(error) } } } } } fn read_exact(&mut self, buffer: &mut[u8], timeout: Duration) -> Result<()> { // Make the socket non-blocking try_err!(self.set_blocking_mode(false)); // Compute timeout-point and loop until buffer is filled completely let timeout_point = Instant::now() + timeout; // Read loop let mut total_read = 0; while buffer.len() - total_read > 0 { // Wait for read-event and read data try_err!(self.wait_until_readable(timeout_point.remaining())); match self.read(&mut buffer[total_read..]) { Ok(bytes_read) => if bytes_read > 0 { total_read += bytes_read } else { throw_err!(IoErrorKind::UnexpectedEof.into()) }, Err(error) => { let error = IoError::from(error); if error.non_recoverable { throw_err!(error) } } } } Ok(()) } fn read_until(&mut self, pattern: &[u8], buffer: &mut[u8], timeout: Duration) -> Result<usize> { // Compute timeout-point let timeout_point = Instant::now() + timeout; // Compute timeout-point and loop until `data` has been filled let mut total_read = 0; while buffer.len() - total_read > 0 { // Read next byte try_err!(Reader::read_exact(self, &mut buffer[total_read .. total_read + 1], timeout_point.remaining())); total_read += 1; // Check for pattern if total_read >= pattern.len() && &buffer[total_read - pattern.len() .. total_read] == pattern { return Ok(total_read) } } throw_err!(IoErrorKind::NotFound.into()) } }