use std::io;
use std::mem;
use {Protocol, Endpoint, DgramSocket, Handler};
use backbone::{AF_UNSPEC, AF_INET, AF_INET6, SOCK_DGRAM, AI_PASSIVE, AI_NUMERICSERV};
use super::{IpProtocol, IpEndpoint, Resolver, ResolverIter, ResolverQuery, Passive};
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Udp {
family: i32,
}
impl Udp {
pub fn v4() -> Udp {
Udp { family: AF_INET as i32 }
}
pub fn v6() -> Udp {
Udp { family: AF_INET6 as i32 }
}
}
impl Protocol for Udp {
type Endpoint = IpEndpoint<Self>;
fn family_type(&self) -> i32 {
self.family
}
fn socket_type(&self) -> i32 {
SOCK_DGRAM as i32
}
fn protocol_type(&self) -> i32 {
0
}
unsafe fn uninitialized(&self) -> Self::Endpoint {
mem::uninitialized()
}
}
impl IpProtocol for Udp {
fn is_v4(&self) -> bool {
self == &Udp::v4()
}
fn is_v6(&self) -> bool {
self == &Udp::v6()
}
fn v4() -> Udp {
Udp::v4()
}
fn v6() -> Udp {
Udp::v6()
}
type Socket = UdpSocket;
fn connect(soc: &Self::Socket, ep: &IpEndpoint<Self>) -> io::Result<()> {
soc.connect(ep)
}
fn async_connect<F: Handler<()>>(soc: &Self::Socket, ep: &IpEndpoint<Self>, handler: F) {
soc.async_connect(ep, handler)
}
}
impl Endpoint<Udp> for IpEndpoint<Udp> {
fn protocol(&self) -> Udp {
if self.is_v4() {
Udp::v4()
} else if self.is_v6() {
Udp::v6()
} else {
unreachable!("Invalid address family ({}).", self.ss.ss_family);
}
}
}
impl ResolverQuery<Udp> for (Passive, u16) {
fn iter(self) -> io::Result<ResolverIter<Udp>> {
let port = self.1.to_string();
ResolverIter::new(Udp { family: AF_UNSPEC }, "", &port, AI_PASSIVE | AI_NUMERICSERV)
}
}
impl<'a> ResolverQuery<Udp> for (Passive, &'a str) {
fn iter(self) -> io::Result<ResolverIter<Udp>> {
ResolverIter::new(Udp { family: AF_UNSPEC }, "", self.1, AI_PASSIVE)
}
}
impl<'a, 'b> ResolverQuery<Udp> for (&'a str, &'b str) {
fn iter(self) -> io::Result<ResolverIter<Udp>> {
ResolverIter::new(Udp { family: AF_UNSPEC }, self.0, self.1, 0)
}
}
pub type UdpEndpoint = IpEndpoint<Udp>;
pub type UdpSocket = DgramSocket<Udp>;
pub type UdpResolver = Resolver<Udp>;
#[test]
fn test_udp() {
assert!(Udp::v4() == Udp::v4());
assert!(Udp::v6() == Udp::v6());
assert!(Udp::v4() != Udp::v6());
}
#[test]
fn test_udp_resolve() {
use IoService;
use super::*;
let io = IoService::new();
let re = UdpResolver::new(&io);
for ep in re.resolve(("127.0.0.1", "80")).unwrap() {
assert!(ep == UdpEndpoint::new(IpAddrV4::loopback(), 80));
}
for ep in re.resolve(("::1", "80")).unwrap() {
assert!(ep == UdpEndpoint::new(IpAddrV6::loopback(), 80));
}
for ep in re.resolve(("localhost", "http")).unwrap() {
assert!(ep.addr().is_loopback());
assert!(ep.port() == 80);
}
}