1use std::io;
2
3use std::collections::HashMap;
4use std::net::{IpAddr, SocketAddr};
5use std::sync::Arc;
6use std::time::{Instant, Duration};
7
8use futures::{Async, Future, Poll, Stream};
9use futures::sync::oneshot;
10use rand::random;
11use parking_lot::Mutex;
12use socket2::{Domain, Protocol, Type};
13
14use tokio_executor::spawn;
15use tokio_reactor::Handle;
16use tokio_timer::Delay;
17
18use errors::{Error, ErrorKind};
19use packet::{IpV4Packet, IpV4Protocol};
20use packet::{ICMP_HEADER_SIZE, IcmpV4, IcmpV6, EchoRequest, EchoReply};
21use socket::{Socket, Send};
22
23const DEFAULT_TIMEOUT: u64 = 2;
24const TOKEN_SIZE: usize = 24;
25const ECHO_REQUEST_BUFFER_SIZE: usize = ICMP_HEADER_SIZE + TOKEN_SIZE;
26type Token = [u8; TOKEN_SIZE];
27type EchoRequestBuffer = [u8; ECHO_REQUEST_BUFFER_SIZE];
28
29#[derive(Clone)]
30struct PingState {
31 inner: Arc<Mutex<HashMap<Token, oneshot::Sender<Instant>>>>,
32}
33
34impl PingState {
35 fn new() -> Self {
36 Self {
37 inner: Arc::new(Mutex::new(HashMap::new())),
38 }
39 }
40
41 fn insert(&self, key: Token, value: oneshot::Sender<Instant>) {
42 self.inner.lock().insert(key, value);
43 }
44
45 fn remove(&self, key: &[u8]) -> Option<oneshot::Sender<Instant>> {
46 self.inner.lock().remove(key)
47 }
48}
49
50#[must_use = "futures do nothing unless polled"]
52pub struct PingFuture {
53 inner: PingFutureKind
54}
55
56enum PingFutureKind {
57 Normal(NormalPingFutureKind),
58 PacketEncodeError,
59 InvalidProtocol,
60}
61
62struct NormalPingFutureKind {
63 start_time: Instant,
64 state: PingState,
65 token: Token,
66 delay: Delay,
67 send: Option<Send<EchoRequestBuffer>>,
68 receiver: oneshot::Receiver<Instant>,
69}
70
71impl Future for PingFuture {
72 type Item = Option<Duration>;
73 type Error = Error;
74
75 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
76 match self.inner {
77 PingFutureKind::Normal(ref mut normal) => {
78 let mut swap_send = false;
79 if let Some(ref mut send) = normal.send {
80 match send.poll() {
81 Ok(Async::NotReady) => (),
82 Ok(Async::Ready(_)) => swap_send = true,
83 Err(_) => return Err(ErrorKind::InternalError.into()),
84 }
85 }
86
87 if swap_send {
88 normal.send = None;
89 }
90
91 match normal.receiver.poll() {
92 Ok(Async::NotReady) => (),
93 Ok(Async::Ready(stop_time)) => {
94 return Ok(Async::Ready(Some(stop_time - normal.start_time)))
95 },
96 Err(_) => return Err(ErrorKind::InternalError.into()),
97 }
98
99 match normal.delay.poll() {
100 Ok(Async::NotReady) => (),
101 Ok(Async::Ready(_)) => return Ok(Async::Ready(None)),
102 Err(_) => return Err(ErrorKind::InternalError.into()),
103 }
104 }
105 PingFutureKind::InvalidProtocol => {
106 return Err(ErrorKind::InvalidProtocol.into())
107 }
108 PingFutureKind::PacketEncodeError => {
109 return Err(ErrorKind::InternalError.into())
110 }
111 }
112 Ok(Async::NotReady)
113 }
114}
115
116impl Drop for PingFuture {
117 fn drop(&mut self) {
118 match self.inner {
119 PingFutureKind::Normal(ref normal) => {
120 normal.state.remove(&normal.token);
121 }
122 | PingFutureKind::InvalidProtocol
123 | PingFutureKind::PacketEncodeError => (),
124 }
125 }
126}
127
128pub struct PingChain {
130 pinger: Pinger,
131 hostname: IpAddr,
132 ident: Option<u16>,
133 seq_cnt: Option<u16>,
134 timeout: Option<Duration>,
135}
136
137impl PingChain {
138 fn new(pinger: Pinger, hostname: IpAddr) -> Self {
139 Self {
140 pinger: pinger,
141 hostname: hostname,
142 ident: None,
143 seq_cnt: None,
144 timeout: None,
145 }
146 }
147
148 pub fn ident(mut self, ident: u16) -> Self {
150 self.ident = Some(ident);
151 self
152 }
153
154 pub fn seq_cnt(mut self, seq_cnt: u16) -> Self {
157 self.seq_cnt = Some(seq_cnt);
158 self
159 }
160
161 pub fn timeout(mut self, timeout: Duration) -> Self {
163 self.timeout = Some(timeout);
164 self
165 }
166
167 pub fn send(&mut self) -> PingFuture {
169 let ident = match self.ident {
170 Some(ident) => ident,
171 None => {
172 let ident = random();
173 self.ident = Some(ident);
174 ident
175 }
176 };
177
178 let seq_cnt = match self.seq_cnt {
179 Some(seq_cnt) => {
180 self.seq_cnt = Some(seq_cnt.wrapping_add(1));
181 seq_cnt
182 }
183 None => {
184 self.seq_cnt = Some(1);
185 0
186 }
187 };
188
189 let timeout = match self.timeout {
190 Some(timeout) => timeout,
191 None => {
192 let timeout = Duration::from_secs(DEFAULT_TIMEOUT);
193 self.timeout = Some(timeout);
194 timeout
195 }
196 };
197
198 self.pinger.ping(self.hostname, ident, seq_cnt, timeout)
199 }
200
201 pub fn stream(self) -> PingChainStream {
203 PingChainStream::new(self)
204 }
205}
206
207pub struct PingChainStream {
209 chain: PingChain,
210 future: Option<PingFuture>,
211}
212
213impl PingChainStream {
214 fn new(chain: PingChain) -> Self {
215 Self {
216 chain: chain,
217 future: None,
218 }
219 }
220}
221
222impl Stream for PingChainStream {
223 type Item = Option<Duration>;
224 type Error = Error;
225
226 fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
227 let mut future = self.future.take().unwrap_or_else(|| self.chain.send());
228
229 match future.poll() {
230 Ok(Async::Ready(item)) => Ok(Async::Ready(Some(item))),
231 Ok(Async::NotReady) => {
232 self.future = Some(future);
233 Ok(Async::NotReady)
234 },
235 Err(err) => Err(err),
236 }
237 }
238}
239
240#[derive(Clone)]
242pub struct Pinger {
243 inner: Arc<PingInner>,
244}
245
246struct PingInner {
247 sockets: Sockets,
248 state: PingState,
249 _v4_finalize: Option<oneshot::Sender<()>>,
250 _v6_finalize: Option<oneshot::Sender<()>>,
251}
252
253enum Sockets {
254 V4(Socket),
255 V6(Socket),
256 Both { v4: Socket, v6: Socket },
257}
258
259impl Sockets {
260 fn new(handle: &Handle) -> io::Result<Self> {
261 let mb_v4socket = Socket::new(Domain::ipv4(), Type::raw(), Protocol::icmpv4(), handle);
262 let mb_v6socket = Socket::new(Domain::ipv6(), Type::raw(), Protocol::icmpv6(), handle);
263 match (mb_v4socket, mb_v6socket) {
264 (Ok(v4_socket), Ok(v6_socket)) => Ok(Sockets::Both {
265 v4: v4_socket,
266 v6: v6_socket,
267 }),
268 (Ok(v4_socket), Err(_)) => Ok(Sockets::V4(v4_socket)),
269 (Err(_), Ok(v6_socket)) => Ok(Sockets::V6(v6_socket)),
270 (Err(err), Err(_)) => Err(err),
271 }
272 }
273
274 fn v4(&self) -> Option<&Socket> {
275 match *self {
276 Sockets::V4(ref socket) => Some(socket),
277 Sockets::Both { ref v4, .. } => Some(v4),
278 Sockets::V6(_) => None,
279 }
280 }
281
282 fn v6(&self) -> Option<&Socket> {
283 match *self {
284 Sockets::V4(_) => None,
285 Sockets::Both { ref v6, .. } => Some(v6),
286 Sockets::V6(ref socket) => Some(socket),
287 }
288 }
289}
290
291impl Pinger {
292 pub fn new() -> impl Future<Item=Self, Error=Error> {
294 ::futures::future::lazy(||
295 Self::with_handle(&Handle::default()).map_err(From::from)
296 )
297
298 }
299
300 fn with_handle(handle: &Handle) -> io::Result<Self> {
301 let sockets = Sockets::new(handle)?;
302
303 let state = PingState::new();
304
305 let v4_finalize = if let Some(v4_socket) = sockets.v4() {
306 let (s, r) = oneshot::channel();
307 let receiver =
308 Receiver::<IcmpV4>::new(v4_socket.clone(), state.clone());
309 spawn(receiver.select(r.map_err(|_| ())).then(|_| Ok(())));
310 Some(s)
311 } else {
312 None
313 };
314
315 let v6_finalize = if let Some(v6_socket) = sockets.v6() {
316 let (s, r) = oneshot::channel();
317 let receiver =
318 Receiver::<IcmpV6>::new(v6_socket.clone(), state.clone());
319 spawn(receiver.select(r.map_err(|_| ())).then(|_| Ok(())));
320 Some(s)
321 } else {
322 None
323 };
324
325 let inner = PingInner {
326 sockets: sockets,
327 state: state,
328 _v4_finalize: v4_finalize,
329 _v6_finalize: v6_finalize,
330 };
331
332 Ok(Self {
333 inner: Arc::new(inner),
334 })
335 }
336
337 pub fn chain(&self, hostname: IpAddr) -> PingChain {
339 PingChain::new(self.clone(), hostname)
340 }
341
342 pub fn ping(
344 &self,
345 hostname: IpAddr,
346 ident: u16,
347 seq_cnt: u16,
348 timeout: Duration,
349 ) -> PingFuture {
350 let (sender, receiver) = oneshot::channel();
351
352 let deadline = Instant::now() + timeout;
353
354 let token = random();
355 self.inner.state.insert(token, sender);
356
357 let dest = SocketAddr::new(hostname, 0);
358 let mut buffer = [0; ECHO_REQUEST_BUFFER_SIZE];
359
360 let request = EchoRequest {
361 ident: ident,
362 seq_cnt: seq_cnt,
363 payload: &token,
364 };
365
366 let (encode_result, mb_socket) = {
367 if dest.is_ipv4() {
368 (
369 request.encode::<IcmpV4>(&mut buffer[..]),
370 self.inner.sockets.v4().cloned()
371 )
372 } else {
373 (
374 request.encode::<IcmpV6>(&mut buffer[..]),
375 self.inner.sockets.v6().cloned(),
376 )
377 }
378 };
379
380
381 let socket = match mb_socket {
382 Some(socket) => socket,
383 None => {
384 return PingFuture {
385 inner: PingFutureKind::InvalidProtocol
386 }
387 }
388 };
389
390 if let Err(_) = encode_result {
391 return PingFuture {
392 inner: PingFutureKind::PacketEncodeError
393 }
394 }
395
396 let send_future = socket.send_to(buffer, &dest);
397
398 PingFuture {
399 inner: PingFutureKind::Normal(NormalPingFutureKind {
400 start_time: Instant::now(),
401 state: self.inner.state.clone(),
402 token: token,
403 delay: Delay::new(deadline),
404 send: Some(send_future),
405 receiver: receiver,
406 })
407 }
408 }
409}
410
411struct Receiver<Message> {
412 socket: Socket,
413 state: PingState,
414 buffer: [u8; 2048],
415 _phantom: ::std::marker::PhantomData<Message>,
416}
417
418trait ParseReply {
419 fn reply_payload(data: &[u8]) -> Option<&[u8]>;
420}
421
422impl ParseReply for IcmpV4 {
423 fn reply_payload(data: &[u8]) -> Option<&[u8]> {
424 if let Ok(ipv4_packet) = IpV4Packet::decode(data) {
425 if ipv4_packet.protocol != IpV4Protocol::Icmp {
426 return None;
427 }
428
429 if let Ok(reply) = EchoReply::decode::<IcmpV4>(ipv4_packet.data) {
430 return Some(reply.payload);
431 }
432 }
433 None
434 }
435}
436
437impl ParseReply for IcmpV6 {
438 fn reply_payload(data: &[u8]) -> Option<&[u8]> {
439 if let Ok(reply) = EchoReply::decode::<IcmpV6>(data) {
440 return Some(reply.payload);
441 }
442 None
443 }
444}
445
446impl<Proto> Receiver<Proto> {
447 fn new(socket: Socket, state: PingState) -> Self {
448 Self {
449 socket: socket,
450 state: state,
451 buffer: [0; 2048],
452 _phantom: ::std::marker::PhantomData,
453 }
454 }
455}
456
457impl<Message: ParseReply> Future for Receiver<Message> {
458 type Item = ();
459 type Error = ();
460
461 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
462 match self.socket.recv(&mut self.buffer) {
463 Ok(Async::Ready(bytes)) => {
464 if let Some(payload) = Message::reply_payload(&self.buffer[..bytes]) {
465 let now = Instant::now();
466 if let Some(sender) = self.state.remove(payload) {
467 sender.send(now).unwrap_or_default()
468 }
469 }
470 self.poll()
471 }
472 Ok(Async::NotReady) => Ok(Async::NotReady),
473 Err(_) => Err(()),
474 }
475 }
476}