use std::mem;
use {SocketOption, GetSocketOption, SetSocketOption};
use super::{IpProtocol, IpAddrV4, IpAddrV6, IpAddr, Tcp};
use backbone::{IPPROTO_IP, IPPROTO_IPV6, IPPROTO_TCP, IPV6_V6ONLY, TCP_NODELAY,
IP_TTL, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP,
IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IPV6_JOIN_GROUP, IPV6_LEAVE_GROUP,
IPV6_UNICAST_HOPS, IPV6_MULTICAST_HOPS, IP_MULTICAST_IF, IPV6_MULTICAST_IF,
c_void, in_addr, in6_addr, ip_mreq, ipv6_mreq};
fn in_addr_of(addr: IpAddrV4) -> in_addr {
let ptr = addr.as_bytes() as *const _ as *const in_addr;
unsafe { *ptr }
}
fn in6_addr_of(addr: IpAddrV6) -> in6_addr {
let ptr = addr.as_bytes() as *const _ as *const in6_addr;
unsafe { *ptr }
}
#[derive(Default, Clone)]
pub struct V6Only(i32);
impl V6Only {
pub fn new(on: bool) -> V6Only {
V6Only(on as i32)
}
pub fn get(&self) -> bool {
self.0 != 0
}
pub fn set(&mut self, on: bool) {
self.0 = on as i32
}
}
impl<P: IpProtocol> SocketOption<P> for V6Only {
type Data = i32;
fn level(&self, _: &P) -> i32 {
IPPROTO_IPV6
}
fn name(&self, _: &P) -> i32 {
IPV6_V6ONLY
}
}
impl<P: IpProtocol> GetSocketOption<P> for V6Only {
fn data_mut(&mut self) -> &mut Self::Data {
&mut self.0
}
}
impl<P: IpProtocol> SetSocketOption<P> for V6Only {
fn data(&self) -> &Self::Data {
&self.0
}
}
#[derive(Default, Clone)]
pub struct NoDelay(i32);
impl NoDelay {
pub fn new(on: bool) -> NoDelay {
NoDelay(on as i32)
}
pub fn get(&self) -> bool {
self.0 != 0
}
pub fn set(&mut self, on: bool) {
self.0 = on as i32
}
}
impl SocketOption<Tcp> for NoDelay {
type Data = i32;
fn level(&self, _: &Tcp) -> i32 {
IPPROTO_TCP
}
fn name(&self, _: &Tcp) -> i32 {
TCP_NODELAY
}
}
impl GetSocketOption<Tcp> for NoDelay {
fn data_mut(&mut self) -> &mut Self::Data {
&mut self.0
}
}
impl SetSocketOption<Tcp> for NoDelay {
fn data(&self) -> &Self::Data {
&self.0
}
}
#[derive(Default, Clone)]
pub struct UnicastHops(i32);
impl UnicastHops {
pub fn new(ttl: u8) -> UnicastHops {
UnicastHops(ttl as i32)
}
pub fn get(&self) -> u8 {
self.0 as u8
}
pub fn set(&mut self, ttl: u8) {
self.0 = ttl as i32
}
}
impl<P: IpProtocol> SocketOption<P> for UnicastHops {
type Data = i32;
fn level(&self, pro: &P) -> i32 {
if pro.is_v4() {
IPPROTO_IP
} else if pro.is_v6() {
IPPROTO_IPV6
} else {
unreachable!("Invalid ip version")
}
}
fn name(&self, pro: &P) -> i32 {
if pro.is_v4() {
IP_TTL
} else if pro.is_v6() {
IPV6_UNICAST_HOPS
} else {
unreachable!("Invalid ip version")
}
}
}
impl<P: IpProtocol> GetSocketOption<P> for UnicastHops {
fn data_mut(&mut self) -> &mut Self::Data {
&mut self.0
}
}
impl<P: IpProtocol> SetSocketOption<P> for UnicastHops {
fn data(&self) -> &Self::Data {
&self.0
}
}
#[derive(Default, Clone)]
pub struct MulticastEnableLoopback(i32);
impl MulticastEnableLoopback {
pub fn new(on: bool) -> MulticastEnableLoopback {
MulticastEnableLoopback(on as i32)
}
pub fn get(&self) -> bool {
self.0 != 0
}
pub fn set(&mut self, on: bool) {
self.0 = on as i32
}
}
impl<P: IpProtocol> SocketOption<P> for MulticastEnableLoopback {
type Data = i32;
fn level(&self, pro: &P) -> i32 {
if pro.is_v4() {
IPPROTO_IP
} else if pro.is_v6() {
IPPROTO_IPV6
} else {
unreachable!("Invalid ip version")
}
}
fn name(&self, pro: &P) -> i32 {
if pro.is_v4() {
IP_MULTICAST_LOOP
} else if pro.is_v6() {
IPV6_MULTICAST_LOOP
} else {
unreachable!("Invalid ip version")
}
}
}
impl<P: IpProtocol> GetSocketOption<P> for MulticastEnableLoopback {
fn data_mut(&mut self) -> &mut Self::Data {
&mut self.0
}
}
impl<P: IpProtocol> SetSocketOption<P> for MulticastEnableLoopback {
fn data(&self) -> &Self::Data {
&self.0
}
}
#[derive(Default, Clone)]
pub struct MulticastHops(i32);
impl MulticastHops {
pub fn new(ttl: u8) -> MulticastHops {
MulticastHops(ttl as i32)
}
pub fn get(&self) -> u8 {
self.0 as u8
}
pub fn set(&mut self, ttl: u8) {
self.0 = ttl as i32
}
}
impl<P: IpProtocol> SocketOption<P> for MulticastHops {
type Data = i32;
fn level(&self, pro: &P) -> i32 {
if pro.is_v4() {
IPPROTO_IP
} else if pro.is_v6() {
IPPROTO_IPV6
} else {
unreachable!("Invalid ip version")
}
}
fn name(&self, pro: &P) -> i32 {
if pro.is_v4() {
IP_MULTICAST_TTL
} else if pro.is_v6() {
IPV6_MULTICAST_HOPS
} else {
unreachable!("Invalid ip version")
}
}
}
impl<P: IpProtocol> GetSocketOption<P> for MulticastHops {
fn data_mut(&mut self) -> &mut Self::Data {
&mut self.0
}
}
impl<P: IpProtocol> SetSocketOption<P> for MulticastHops {
fn data(&self) -> &Self::Data {
&self.0
}
}
#[derive(Clone)]
enum Mreq {
V4(ip_mreq),
V6(ipv6_mreq),
}
#[derive(Clone)]
pub struct MulticastJoinGroup(Mreq);
impl MulticastJoinGroup {
pub fn new(multicast: IpAddr) -> MulticastJoinGroup {
match multicast {
IpAddr::V4(multicast) => Self::from_v4(multicast, IpAddrV4::any()),
IpAddr::V6(multicast) => {
let scope_id = multicast.get_scope_id();
Self::from_v6(multicast, scope_id)
}
}
}
pub fn from_v4(multicast: IpAddrV4, interface: IpAddrV4) -> MulticastJoinGroup {
MulticastJoinGroup(Mreq::V4(ip_mreq {
imr_multiaddr: in_addr_of(multicast),
imr_interface: in_addr_of(interface),
}))
}
pub fn from_v6(multicast: IpAddrV6, scope_id: u32) -> MulticastJoinGroup {
MulticastJoinGroup(Mreq::V6(ipv6_mreq {
ipv6mr_multiaddr: in6_addr_of(multicast),
ipv6mr_interface: scope_id,
}))
}
}
impl<P: IpProtocol> SocketOption<P> for MulticastJoinGroup {
type Data = c_void;
fn level(&self, pro: &P) -> i32 {
if pro.is_v4() {
IPPROTO_IP
} else if pro.is_v6() {
IPPROTO_IPV6
} else {
unreachable!("Invalid ip version")
}
}
fn name(&self, pro: &P) -> i32 {
if pro.is_v4() {
IP_ADD_MEMBERSHIP
} else if pro.is_v6() {
IPV6_JOIN_GROUP
} else {
unreachable!("Invalid ip version")
}
}
}
impl<P: IpProtocol> SetSocketOption<P> for MulticastJoinGroup {
fn data(&self) -> &Self::Data {
match &self.0 {
&Mreq::V4(ref mreq) => unsafe { mem::transmute(mreq) },
&Mreq::V6(ref mreq) => unsafe { mem::transmute(mreq) },
}
}
fn size(&self) -> usize {
match &self.0 {
&Mreq::V4(ref mreq) => mem::size_of_val(mreq),
&Mreq::V6(ref mreq) => mem::size_of_val(mreq),
}
}
}
#[derive(Clone)]
pub struct MulticastLeaveGroup(Mreq);
impl MulticastLeaveGroup {
pub fn new(multicast: IpAddr) -> MulticastLeaveGroup {
match multicast {
IpAddr::V4(multicast) => Self::from_v4(multicast, IpAddrV4::any()),
IpAddr::V6(multicast) => {
let scope_id = multicast.get_scope_id();
Self::from_v6(multicast, scope_id)
}
}
}
pub fn from_v4(multicast: IpAddrV4, interface: IpAddrV4) -> MulticastLeaveGroup {
MulticastLeaveGroup(Mreq::V4(ip_mreq {
imr_multiaddr: in_addr_of(multicast),
imr_interface: in_addr_of(interface),
}))
}
pub fn from_v6(multicast: IpAddrV6, scope_id: u32) -> MulticastLeaveGroup {
MulticastLeaveGroup(Mreq::V6(ipv6_mreq {
ipv6mr_multiaddr: in6_addr_of(multicast),
ipv6mr_interface: scope_id,
}))
}
}
impl<P: IpProtocol> SocketOption<P> for MulticastLeaveGroup {
type Data = c_void;
fn level(&self, pro: &P) -> i32 {
if pro.is_v4() {
IPPROTO_IP
} else if pro.is_v6() {
IPPROTO_IPV6
} else {
unreachable!("Invalid ip version")
}
}
fn name(&self, pro: &P) -> i32 {
if pro.is_v4() {
IP_DROP_MEMBERSHIP
} else if pro.is_v6() {
IPV6_LEAVE_GROUP
} else {
unreachable!("Invalid ip version")
}
}
}
impl<P: IpProtocol> SetSocketOption<P> for MulticastLeaveGroup {
fn data(&self) -> &Self::Data {
match &self.0 {
&Mreq::V4(ref mreq) => unsafe { mem::transmute(mreq) },
&Mreq::V6(ref mreq) => unsafe { mem::transmute(mreq) },
}
}
fn size(&self) -> usize {
match &self.0 {
&Mreq::V4(ref mreq) => mem::size_of_val(mreq),
&Mreq::V6(ref mreq) => mem::size_of_val(mreq),
}
}
}
#[derive(Clone)]
enum Iface {
V4(in_addr),
V6(u32),
}
#[derive(Clone)]
pub struct OutboundInterface(Iface);
impl OutboundInterface {
pub fn new(interface: IpAddr) -> OutboundInterface {
match interface {
IpAddr::V4(interface) => Self::from_v4(interface),
IpAddr::V6(interface) => Self::from_v6(interface),
}
}
pub fn from_v4(interface: IpAddrV4) -> OutboundInterface {
OutboundInterface(Iface::V4(in_addr_of(interface)))
}
pub fn from_v6(interface: IpAddrV6) -> OutboundInterface {
OutboundInterface(Iface::V6(interface.get_scope_id()))
}
}
impl<P: IpProtocol> SocketOption<P> for OutboundInterface {
type Data = u32;
fn level(&self, pro: &P) -> i32 {
if pro.is_v4() {
IPPROTO_IP
} else if pro.is_v6() {
IPPROTO_IPV6
} else {
unreachable!("Invalid ip version")
}
}
fn name(&self, pro: &P) -> i32 {
if pro.is_v4() {
IP_MULTICAST_IF
} else if pro.is_v6() {
IPV6_MULTICAST_IF
} else {
unreachable!("Invalid ip version")
}
}
}
impl<P: IpProtocol> SetSocketOption<P> for OutboundInterface {
fn data(&self) -> &Self::Data {
match &self.0 {
&Iface::V4(ref addr) => unsafe { mem::transmute(addr) },
&Iface::V6(ref scope_id) => &scope_id,
}
}
}
#[test]
fn test_outbound_interface() {
assert_eq!(mem::size_of::<u32>(), mem::size_of::<in_addr>());
}