1 use crate::{sys, Token}; 2 3 use std::fmt; 4 5 /// A readiness event. 6 /// 7 /// `Event` is a readiness state paired with a [`Token`]. It is returned by 8 /// [`Poll::poll`]. 9 /// 10 /// For more documentation on polling and events, see [`Poll`]. 11 /// 12 /// [`Poll::poll`]: ../struct.Poll.html#method.poll 13 /// [`Poll`]: ../struct.Poll.html 14 /// [`Token`]: ../struct.Token.html 15 #[derive(Clone)] 16 #[repr(transparent)] 17 pub struct Event { 18 inner: sys::Event, 19 } 20 21 impl Event { 22 /// Returns the event's token. token(&self) -> Token23 pub fn token(&self) -> Token { 24 sys::event::token(&self.inner) 25 } 26 27 /// Returns true if the event contains readable readiness. 28 /// 29 /// # Notes 30 /// 31 /// Out-of-band (OOB) data also triggers readable events. But most 32 /// applications don't actually read OOB data, this could leave an 33 /// application open to a Denial-of-Service (Dos) attack, see 34 /// <https://github.com/sandstorm-io/sandstorm-website/blob/58f93346028c0576e8147627667328eaaf4be9fa/_posts/2015-04-08-osx-security-bug.md>. 35 /// However because Mio uses edge-triggers it will not result in an infinite 36 /// loop as described in the article above. is_readable(&self) -> bool37 pub fn is_readable(&self) -> bool { 38 sys::event::is_readable(&self.inner) 39 } 40 41 /// Returns true if the event contains writable readiness. is_writable(&self) -> bool42 pub fn is_writable(&self) -> bool { 43 sys::event::is_writable(&self.inner) 44 } 45 46 /// Returns true if the event contains error readiness. 47 /// 48 /// Error events occur when the socket enters an error state. In this case, 49 /// the socket will also receive a readable or writable event. Reading or 50 /// writing to the socket will result in an error. 51 /// 52 /// # Notes 53 /// 54 /// Method is available on all platforms, but not all platforms trigger the 55 /// error event. 56 /// 57 /// The table below shows what flags are checked on what OS. 58 /// 59 /// | [OS selector] | Flag(s) checked | 60 /// |---------------|-----------------| 61 /// | [epoll] | `EPOLLERR` | 62 /// | [kqueue] | `EV_ERROR` and `EV_EOF` with `fflags` set to `0`. | 63 /// 64 /// [OS selector]: ../struct.Poll.html#implementation-notes 65 /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html 66 /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 is_error(&self) -> bool67 pub fn is_error(&self) -> bool { 68 sys::event::is_error(&self.inner) 69 } 70 71 /// Returns true if the event contains read closed readiness. 72 /// 73 /// # Notes 74 /// 75 /// Read closed readiness can be expected after any of the following have 76 /// occurred: 77 /// * The local stream has shutdown the read half of its socket 78 /// * The local stream has shutdown both the read half and the write half 79 /// of its socket 80 /// * The peer stream has shutdown the write half its socket; this sends a 81 /// `FIN` packet that has been received by the local stream 82 /// 83 /// Method is a best effort implementation. While some platforms may not 84 /// return readiness when read half is closed, it is guaranteed that 85 /// false-positives will not occur. 86 /// 87 /// The table below shows what flags are checked on what OS. 88 /// 89 /// | [OS selector] | Flag(s) checked | 90 /// |---------------|-----------------| 91 /// | [epoll] | `EPOLLHUP`, or | 92 /// | | `EPOLLIN` and `EPOLLRDHUP` | 93 /// | [kqueue] | `EV_EOF` | 94 /// 95 /// [OS selector]: ../struct.Poll.html#implementation-notes 96 /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html 97 /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 is_read_closed(&self) -> bool98 pub fn is_read_closed(&self) -> bool { 99 sys::event::is_read_closed(&self.inner) 100 } 101 102 /// Returns true if the event contains write closed readiness. 103 /// 104 /// # Notes 105 /// 106 /// On [epoll] this is essentially a check for `EPOLLHUP` flag as the 107 /// local stream shutting down its write half does not trigger this event. 108 /// 109 /// On [kqueue] the local stream shutting down the write half of its 110 /// socket will trigger this event. 111 /// 112 /// Method is a best effort implementation. While some platforms may not 113 /// return readiness when write half is closed, it is guaranteed that 114 /// false-positives will not occur. 115 /// 116 /// The table below shows what flags are checked on what OS. 117 /// 118 /// | [OS selector] | Flag(s) checked | 119 /// |---------------|-----------------| 120 /// | [epoll] | `EPOLLHUP`, or | 121 /// | | only `EPOLLERR`, or | 122 /// | | `EPOLLOUT` and `EPOLLERR` | 123 /// | [kqueue] | `EV_EOF` | 124 /// 125 /// [OS selector]: ../struct.Poll.html#implementation-notes 126 /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html 127 /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 is_write_closed(&self) -> bool128 pub fn is_write_closed(&self) -> bool { 129 sys::event::is_write_closed(&self.inner) 130 } 131 132 /// Returns true if the event contains priority readiness. 133 /// 134 /// # Notes 135 /// 136 /// Method is available on all platforms, but not all platforms trigger the 137 /// priority event. 138 /// 139 /// The table below shows what flags are checked on what OS. 140 /// 141 /// | [OS selector] | Flag(s) checked | 142 /// |---------------|-----------------| 143 /// | [epoll] | `EPOLLPRI` | 144 /// | [kqueue] | *Not supported* | 145 /// 146 /// [OS selector]: ../struct.Poll.html#implementation-notes 147 /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html 148 /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 149 #[inline] is_priority(&self) -> bool150 pub fn is_priority(&self) -> bool { 151 sys::event::is_priority(&self.inner) 152 } 153 154 /// Returns true if the event contains AIO readiness. 155 /// 156 /// # Notes 157 /// 158 /// Method is available on all platforms, but not all platforms support AIO. 159 /// 160 /// The table below shows what flags are checked on what OS. 161 /// 162 /// | [OS selector] | Flag(s) checked | 163 /// |---------------|-----------------| 164 /// | [epoll] | *Not supported* | 165 /// | [kqueue]<sup>1</sup> | `EVFILT_AIO` | 166 /// 167 /// 1: Only supported on DragonFly BSD, FreeBSD, iOS and macOS. 168 /// 169 /// [OS selector]: ../struct.Poll.html#implementation-notes 170 /// [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html 171 /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 is_aio(&self) -> bool172 pub fn is_aio(&self) -> bool { 173 sys::event::is_aio(&self.inner) 174 } 175 176 /// Returns true if the event contains LIO readiness. 177 /// 178 /// # Notes 179 /// 180 /// Method is available on all platforms, but only FreeBSD supports LIO. On 181 /// FreeBSD this method checks the `EVFILT_LIO` flag. is_lio(&self) -> bool182 pub fn is_lio(&self) -> bool { 183 sys::event::is_lio(&self.inner) 184 } 185 186 /// Create a reference to an `Event` from a platform specific event. from_sys_event_ref(sys_event: &sys::Event) -> &Event187 pub(crate) fn from_sys_event_ref(sys_event: &sys::Event) -> &Event { 188 unsafe { 189 // This is safe because the memory layout of `Event` is 190 // the same as `sys::Event` due to the `repr(transparent)` attribute. 191 &*(sys_event as *const sys::Event as *const Event) 192 } 193 } 194 } 195 196 /// When the [alternate] flag is enabled this will print platform specific 197 /// details, for example the fields of the `kevent` structure on platforms that 198 /// use `kqueue(2)`. Note however that the output of this implementation is 199 /// **not** consider a part of the stable API. 200 /// 201 /// [alternate]: fmt::Formatter::alternate 202 impl fmt::Debug for Event { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 204 let alternate = f.alternate(); 205 let mut d = f.debug_struct("Event"); 206 d.field("token", &self.token()) 207 .field("readable", &self.is_readable()) 208 .field("writable", &self.is_writable()) 209 .field("error", &self.is_error()) 210 .field("read_closed", &self.is_read_closed()) 211 .field("write_closed", &self.is_write_closed()) 212 .field("priority", &self.is_priority()) 213 .field("aio", &self.is_aio()) 214 .field("lio", &self.is_lio()); 215 216 if alternate { 217 struct EventDetails<'a>(&'a sys::Event); 218 219 impl<'a> fmt::Debug for EventDetails<'a> { 220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 221 sys::event::debug_details(f, self.0) 222 } 223 } 224 225 d.field("details", &EventDetails(&self.inner)).finish() 226 } else { 227 d.finish() 228 } 229 } 230 } 231