1use prelude::Protocol;
2use ffi::{IntoI32, AF_UNSPEC, AF_INET, AF_INET6, SOCK_RAW,
3 IPPROTO_ICMP, IPPROTO_ICMPV6};
4use raw_socket::RawSocket;
5use ip::{IpProtocol, IpEndpoint, Resolver, ResolverIter, ResolverQuery};
6
7use std::io;
8use std::fmt;
9use std::mem;
10
11#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
13pub struct Icmp {
14 family: i32,
15 protocol: i32,
16}
17
18impl Protocol for Icmp {
19 type Endpoint = IpEndpoint<Self>;
20
21 fn family_type(&self) -> i32 {
22 self.family
23 }
24
25 fn socket_type(&self) -> i32 {
26 SOCK_RAW as i32
27 }
28
29 fn protocol_type(&self) -> i32 {
30 self.protocol
31 }
32
33 unsafe fn uninitialized(&self) -> Self::Endpoint {
34 mem::uninitialized()
35 }
36}
37
38impl IpProtocol for Icmp {
39 fn v4() -> Icmp {
51 Icmp { family: AF_INET as i32, protocol: IPPROTO_ICMP.i32() }
52 }
53
54 fn v6() -> Icmp {
66 Icmp { family: AF_INET6 as i32, protocol: IPPROTO_ICMPV6.i32() }
67 }
68}
69
70impl fmt::Debug for Icmp {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 if self.is_v4() {
73 write!(f, "ICMPv4")
74 } else if self.is_v6() {
75 write!(f, "ICMPv6")
76 } else {
77 unreachable!("Invalid address family ({}).", self.family);
78 }
79 }
80}
81
82impl<'a> ResolverQuery<Icmp> for &'a str {
83 fn iter(self) -> io::Result<ResolverIter<Icmp>> {
84 ResolverIter::new(&Icmp { family: AF_UNSPEC, protocol: 0 }, self.as_ref(), "", 0)
85 }
86}
87
88impl fmt::Debug for IpEndpoint<Icmp> {
89 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 write!(f, "Endpoint(ICMP/{})", self)
91 }
92}
93
94impl fmt::Debug for Resolver<Icmp, RawSocket<Icmp>> {
95 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 write!(f, "Resolver(ICMP)")
97 }
98}
99
100pub type IcmpEndpoint = IpEndpoint<Icmp>;
102
103pub type IcmpSocket = RawSocket<Icmp>;
105
106pub type IcmpResolver = Resolver<Icmp, RawSocket<Icmp>>;
108
109#[test]
110fn test_icmp() {
111 assert!(Icmp::v4() == Icmp::v4());
112 assert!(Icmp::v6() == Icmp::v6());
113 assert!(Icmp::v4() != Icmp::v6());
114}
115
116#[test]
117fn test_icmp_resolve() {
118 use core::IoContext;
119 use ip::*;
120
121 let ctx = &IoContext::new().unwrap();
122 let re = IcmpResolver::new(ctx);
123 for ep in re.resolve("127.0.0.1").unwrap() {
124 assert!(ep == IcmpEndpoint::new(IpAddrV4::loopback(), 0));
125 }
126 for ep in re.resolve("::1").unwrap() {
127 assert!(ep == IcmpEndpoint::new(IpAddrV6::loopback(), 0));
128 }
129 for ep in re.resolve(("localhost")).unwrap() {
130 assert!(ep.addr().is_loopback());
131 }
132}
133
134#[test]
135#[ignore]
136fn test_format() {
137 use core::IoContext;
138
139 let ctx = &IoContext::new().unwrap();
140 println!("{:?}", Icmp::v4());
141 println!("{:?}", IcmpEndpoint::new(Icmp::v4(), 12345));
142 println!("{:?}", IcmpSocket::new(ctx, Icmp::v4()).unwrap());
143 println!("{:?}", IcmpResolver::new(ctx));
144}