use std::io::{self, Error, ErrorKind};
use std::net::{ToSocketAddrs, UdpSocket, SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, AddrParseError};
use std::mem;
use std::string::ToString;
use std::str::{FromStr};
#[cfg(windows)]
use std::os::windows::io::{RawSocket, FromRawSocket};
#[cfg(not(windows))]
use std::os::unix::io::{RawFd, FromRawFd};
use libc;
pub mod connector;
pub mod packet;
pub mod sender;
#[cfg(windows)]
type Socket = libc::SOCKET;
#[cfg(not(windows))]
type Socket = libc::c_int;
pub fn addr_from_trait<A: ToSocketAddrs>(addr: A) -> io::Result<SocketAddr> {
let mut sock_iter = try!(addr.to_socket_addrs());
match sock_iter.next() {
Some(n) => Ok(n),
None => Err(io::Error::new(ErrorKind::InvalidInput, "Failed To Parse SocketAddr"))
}
}
pub fn bind_reuse<A: ToSocketAddrs>(local_addr: A) -> io::Result<UdpSocket> {
try!(init_sock_api());
let local_addr = try!(addr_from_trait(local_addr));
let socket = try!(create_udp_socket(&local_addr));
try!(reuse_addr(socket));
try!(bind_addr(socket, &local_addr));
Ok(udp_socket_from_socket(socket))
}
pub fn join_multicast(sock: &UdpSocket, iface_addr: &IpAddr, mcast_addr: &IpAddr)
-> io::Result<()> {
let (iface_ip, mcast_ip) = match (iface_addr, mcast_addr) {
(&IpAddr::V4(ref i), &IpAddr::V4(ref m)) => (i, m),
(&IpAddr::V6(..), &IpAddr::V6(..)) => {
return Err(io::Error::new(ErrorKind::InvalidInput,
"Ipv6Addr Multicast Not Currently Supported"))
},
_ => return Err(io::Error::new(ErrorKind::InvalidInput,
"Multicast And Interface Addresses Are Not The Same Version"))
};
let socket = unsafe{ mem::transmute_copy::<UdpSocket, Socket>(sock) };
set_membership_ipv4(socket, iface_ip, mcast_ip, libc::IP_ADD_MEMBERSHIP)
}
#[allow(unused)]
pub fn leave_multicast(sock: &UdpSocket, iface_addr: &IpAddr, mcast_addr: &IpAddr)
-> io::Result<()> {
let (iface_ip, mcast_ip) = match (iface_addr, mcast_addr) {
(&IpAddr::V4(ref i), &IpAddr::V4(ref m)) => {
(i, m)
},
(&IpAddr::V6(..), &IpAddr::V6(..)) => {
return Err(io::Error::new(ErrorKind::InvalidInput,
"Ipv6Addr Multicast Not Currently Supported"))
},
_ => return Err(io::Error::new(ErrorKind::InvalidInput,
"Multicast And Interface Addresses Are Not The Same Version"))
};
let socket = unsafe{ mem::transmute_copy::<UdpSocket, Socket>(sock) };
set_membership_ipv4(socket, iface_ip, mcast_ip, libc::IP_DROP_MEMBERSHIP)
}
fn init_sock_api() -> io::Result<()> {
let init_facade = UdpSocket::bind(("0.0.0.0", 0));
init_facade.map(|_| ())
}
fn create_udp_socket(sock_addr: &SocketAddr) -> io::Result<Socket> {
let family = match *sock_addr {
SocketAddr::V4(..) => libc::AF_INET,
SocketAddr::V6(..) => libc::AF_INET6
};
let socket = unsafe{ libc::socket(family, libc::SOCK_DGRAM, 0) };
check_socket(socket).map(|_| socket)
}
fn reuse_addr(socket: Socket) -> io::Result<()> {
let opt: libc::c_int = 1;
let ret = unsafe {
libc::setsockopt(socket, libc::SOL_SOCKET, libc::SO_REUSEADDR,
&opt as *const libc::c_int as *const libc::c_void,
mem::size_of::<libc::c_int>() as libc::socklen_t)
};
if ret != 0 {
Err(Error::last_os_error())
} else {
Ok(())
}
}
fn bind_addr(socket: Socket, sock_addr: &SocketAddr) -> io::Result<()> {
let (sock_addr, sock_len) = match *sock_addr {
SocketAddr::V4(ref a) => {
(a as *const _ as *const _, mem::size_of_val(a) as libc::socklen_t)
},
SocketAddr::V6(ref a) => {
(a as *const _ as *const _, mem::size_of_val(a) as libc::socklen_t)
}
};
let ret = unsafe{ libc::bind(socket, sock_addr, sock_len) };
if ret != 0 {
Err(Error::last_os_error())
} else {
Ok(())
}
}
fn set_membership_ipv4(socket: Socket, iface_addr: &Ipv4Addr,
mcast_addr: &Ipv4Addr, opt: libc::c_int) -> io::Result<()> {
let mreq = libc::ip_mreq {
imr_multiaddr: ipv4addr_as_in_addr(mcast_addr),
imr_interface: ipv4addr_as_in_addr(iface_addr)
};
let ret = unsafe {
libc::setsockopt(socket, libc::IPPROTO_IP, opt,
&mreq as *const libc::ip_mreq as *const libc::c_void,
mem::size_of::<libc::ip_mreq>() as libc::socklen_t)
};
if ret != 0 {
Err(Error::last_os_error())
} else {
Ok(())
}
}
fn ipv4addr_as_in_addr(addr: &Ipv4Addr) -> libc::in_addr {
unsafe{ mem::transmute_copy::<Ipv4Addr, libc::in_addr>(addr) }
}
pub enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
pub trait SocketIp {
fn new(ip: IpAddr, port: u16) -> SocketAddr;
fn ip(&self) -> IpAddr;
}
impl SocketIp for SocketAddr {
fn new(ip: IpAddr, port: u16) -> SocketAddr {
match ip {
IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
}
}
fn ip(&self) -> IpAddr {
match *self {
SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
}
}
}
impl ToString for IpAddr {
fn to_string(&self) -> String {
match *self {
IpAddr::V4(a) => a.to_string(),
IpAddr::V6(a) => a.to_string()
}
}
}
impl FromStr for IpAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
s.parse().map(|ip| IpAddr::V4(ip)).or_else(|_| s.parse().map(|ip| IpAddr::V6(ip)))
}
}
#[cfg(windows)]
fn udp_socket_from_socket(socket: Socket) -> UdpSocket {
let raw_socket = unsafe{ mem::transmute::<Socket, RawSocket>(socket) };
unsafe{ UdpSocket::from_raw_socket(raw_socket) }
}
#[cfg(not(windows))]
fn udp_socket_from_socket(socket: Socket) -> UdpSocket {
let raw_fd = unsafe{ mem::transmute::<Socket, RawFd>(socket) };
unsafe{ UdpSocket::from_raw_fd(raw_fd) }
}
#[cfg(windows)]
fn check_socket(sock: Socket) -> io::Result<()> {
if sock == libc::INVALID_SOCKET {
Err(Error::new(ErrorKind::Other, "Error With Socket Creation"))
} else {
Ok(())
}
}
#[cfg(not(windows))]
fn check_socket(sock: Socket) -> io::Result<()> {
if sock == -1i32 {
Err(Error::last_os_error())
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
#[test]
fn positive_addr_from_trait() {
super::addr_from_trait("192.168.0.1:0").unwrap();
}
#[test]
#[should_panic]
fn negative_addr_from_trait() {
super::addr_from_trait("192.168.0.1").unwrap();
}
}