<commit_before>// Copyright (c) 2014 <NAME> <<EMAIL>>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::from_str;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl from_str::FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            println!("nlen {}", nlen);
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {<commit_msg>remove silly println that snuck in<commit_after>// Copyright (c) 2014 <NAME> <<EMAIL>>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::from_str;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl from_str::FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
{'fraction_non_alphanumeric': 0.16826253481894152, 'fraction_numerical': 0.027332869080779944, 'mean_word_length': 2.2704241389126105, 'pattern_counts': {'":': 4, '<': 63, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4457211', 'n_tokens_mistral': 4069, 'n_tokens_neox': 3887, 'n_words': 901}