提交 a1056360 编写于 作者: A Alex Crichton

rollup merge of #22015: alexcrichton/netv2

This commit is an implementation of [RFC 807][rfc] which adds a `std::net`
module for basic neworking based on top of `std::io`. This module serves as a
replacement for the `std::old_io::net` module and networking primitives in
`old_io`.

[rfc]: fillmein

The major focus of this redesign is to cut back on the level of abstraction to
the point that each of the networking types is just a bare socket. To this end
functionality such as timeouts and cloning has been removed (although cloning
can be done through `duplicate`, it may just yield an error).

With this `net` module comes a new implementation of `SocketAddr` and `IpAddr`.
This work is entirely based on #20785 and the only changes were to alter the
in-memory representation to match the `libc`-expected variants and to move from
public fields to accessors.
......@@ -253,6 +253,7 @@
pub mod old_io;
pub mod io;
pub mod fs;
pub mod net;
pub mod os;
pub mod env;
pub mod path;
......
此差异已折叠。
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
use prelude::v1::*;
use cmp::Ordering;
use hash;
use fmt;
use libc;
use sys_common::{AsInner, FromInner};
use net::{hton, ntoh};
/// Representation of an IPv4 address.
#[derive(Copy)]
pub struct Ipv4Addr {
inner: libc::in_addr,
}
/// Representation of an IPv6 address.
#[derive(Copy)]
pub struct Ipv6Addr {
inner: libc::in6_addr,
}
#[allow(missing_docs)]
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
pub enum Ipv6MulticastScope {
InterfaceLocal,
LinkLocal,
RealmLocal,
AdminLocal,
SiteLocal,
OrganizationLocal,
Global
}
/// Enumeration of possible IP addresses
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
pub enum IpAddr {
/// An IPv4 address.
V4(Ipv4Addr),
/// An IPv6 address.
V6(Ipv6Addr)
}
impl IpAddr {
/// Create a new IpAddr that contains an IPv4 address.
///
/// The result will represent the IP address a.b.c.d
pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
IpAddr::V4(Ipv4Addr::new(a, b, c, d))
}
/// Create a new IpAddr that contains an IPv6 address.
///
/// The result will represent the IP address a:b:c:d:e:f
pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
h: u16) -> IpAddr {
IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for IpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
IpAddr::V4(v4) => v4.fmt(f),
IpAddr::V6(v6) => v6.fmt(f)
}
}
}
impl Ipv4Addr {
/// Create a new IPv4 address from four eight-bit octets.
///
/// The result will represent the IP address a.b.c.d
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
Ipv4Addr {
inner: libc::in_addr {
s_addr: hton(((a as u32) << 24) |
((b as u32) << 16) |
((c as u32) << 8) |
(d as u32)),
}
}
}
/// Returns the four eight-bit integers that make up this address
pub fn octets(&self) -> [u8; 4] {
let bits = ntoh(self.inner.s_addr);
[(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
}
/// Returns true for the special 'unspecified' address 0.0.0.0
pub fn is_unspecified(&self) -> bool {
self.inner.s_addr == 0
}
/// Returns true if this is a loopback address (127.0.0.0/8)
pub fn is_loopback(&self) -> bool {
self.octets()[0] == 127
}
/// Returns true if this is a private address.
///
/// The private address ranges are defined in RFC1918 and include:
///
/// - 10.0.0.0/8
/// - 172.16.0.0/12
/// - 192.168.0.0/16
pub fn is_private(&self) -> bool {
match (self.octets()[0], self.octets()[1]) {
(10, _) => true,
(172, b) if b >= 16 && b <= 31 => true,
(192, 168) => true,
_ => false
}
}
/// Returns true if the address is link-local (169.254.0.0/16)
pub fn is_link_local(&self) -> bool {
self.octets()[0] == 169 && self.octets()[1] == 254
}
/// Returns true if the address appears to be globally routable.
///
/// Non-globally-routable networks include the private networks (10.0.0.0/8,
/// 172.16.0.0/12 and 192.168.0.0/16), the loopback network (127.0.0.0/8),
/// and the link-local network (169.254.0.0/16).
pub fn is_global(&self) -> bool {
!self.is_private() && !self.is_loopback() && !self.is_link_local()
}
/// Returns true if this is a multicast address.
///
/// Multicast addresses have a most significant octet between 224 and 239.
pub fn is_multicast(&self) -> bool {
self.octets()[0] >= 224 && self.octets()[0] <= 239
}
/// Convert this address to an IPv4-compatible IPv6 address
///
/// a.b.c.d becomes ::a.b.c.d
pub fn to_ipv6_compatible(&self) -> Ipv6Addr {
Ipv6Addr::new(0, 0, 0, 0, 0, 0,
((self.octets()[0] as u16) << 8) | self.octets()[1] as u16,
((self.octets()[2] as u16) << 8) | self.octets()[3] as u16)
}
/// Convert this address to an IPv4-mapped IPv6 address
///
/// a.b.c.d becomes ::ffff:a.b.c.d
pub fn to_ipv6_mapped(&self) -> Ipv6Addr {
Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff,
((self.octets()[0] as u16) << 8) | self.octets()[1] as u16,
((self.octets()[2] as u16) << 8) | self.octets()[3] as u16)
}
}
impl fmt::Display for Ipv4Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let octets = self.octets();
write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
}
}
impl fmt::Debug for Ipv4Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, fmt)
}
}
impl Clone for Ipv4Addr {
fn clone(&self) -> Ipv4Addr { *self }
}
impl PartialEq for Ipv4Addr {
fn eq(&self, other: &Ipv4Addr) -> bool {
self.inner.s_addr == other.inner.s_addr
}
}
impl Eq for Ipv4Addr {}
impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Ipv4Addr {
fn hash(&self, s: &mut S) {
self.inner.s_addr.hash(s)
}
}
impl PartialOrd for Ipv4Addr {
fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Ipv4Addr {
fn cmp(&self, other: &Ipv4Addr) -> Ordering {
self.inner.s_addr.cmp(&other.inner.s_addr)
}
}
impl AsInner<libc::in_addr> for Ipv4Addr {
fn as_inner(&self) -> &libc::in_addr { &self.inner }
}
impl FromInner<libc::in_addr> for Ipv4Addr {
fn from_inner(addr: libc::in_addr) -> Ipv4Addr {
Ipv4Addr { inner: addr }
}
}
impl Ipv6Addr {
/// Create a new IPv6 address from eight 16-bit segments.
///
/// The result will represent the IP address a:b:c:d:e:f
pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
h: u16) -> Ipv6Addr {
Ipv6Addr {
inner: libc::in6_addr {
s6_addr: [hton(a), hton(b), hton(c), hton(d),
hton(e), hton(f), hton(g), hton(h)]
}
}
}
/// Return the eight 16-bit segments that make up this address
pub fn segments(&self) -> [u16; 8] {
[ntoh(self.inner.s6_addr[0]),
ntoh(self.inner.s6_addr[1]),
ntoh(self.inner.s6_addr[2]),
ntoh(self.inner.s6_addr[3]),
ntoh(self.inner.s6_addr[4]),
ntoh(self.inner.s6_addr[5]),
ntoh(self.inner.s6_addr[6]),
ntoh(self.inner.s6_addr[7])]
}
/// Returns true for the special 'unspecified' address ::
pub fn is_unspecified(&self) -> bool {
self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
}
/// Returns true if this is a loopback address (::1)
pub fn is_loopback(&self) -> bool {
self.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
}
/// Returns true if the address appears to be globally routable.
///
/// Non-globally-routable networks include the loopback address; the
/// link-local, site-local, and unique local unicast addresses; and the
/// interface-, link-, realm-, admin- and site-local multicast addresses.
pub fn is_global(&self) -> bool {
match self.multicast_scope() {
Some(Ipv6MulticastScope::Global) => true,
None => self.is_unicast_global(),
_ => false
}
}
/// Returns true if this is a unique local address (IPv6)
///
/// Unique local addresses are defined in RFC4193 and have the form fc00::/7
pub fn is_unique_local(&self) -> bool {
(self.segments()[0] & 0xfe00) == 0xfc00
}
/// Returns true if the address is unicast and link-local (fe80::/10)
pub fn is_unicast_link_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
}
/// Returns true if this is a deprecated unicast site-local address (IPv6
/// fec0::/10)
pub fn is_unicast_site_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfec0
}
/// Returns true if the address is a globally routable unicast address
///
/// Non-globally-routable unicast addresses include the loopback address,
/// the link-local addresses, the deprecated site-local addresses and the
/// unique local addresses.
pub fn is_unicast_global(&self) -> bool {
!self.is_multicast()
&& !self.is_loopback() && !self.is_unicast_link_local()
&& !self.is_unicast_site_local() && !self.is_unique_local()
}
/// Returns the address's multicast scope if the address is multicast.
pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
match self.segments()[0] & 0x000f {
1 => Some(Ipv6MulticastScope::InterfaceLocal),
2 => Some(Ipv6MulticastScope::LinkLocal),
3 => Some(Ipv6MulticastScope::RealmLocal),
4 => Some(Ipv6MulticastScope::AdminLocal),
5 => Some(Ipv6MulticastScope::SiteLocal),
8 => Some(Ipv6MulticastScope::OrganizationLocal),
14 => Some(Ipv6MulticastScope::Global),
_ => None
}
} else {
None
}
}
/// Returns true if this is a multicast address.
///
/// Multicast addresses have the form ff00::/8.
pub fn is_multicast(&self) -> bool {
(self.segments()[0] & 0xff00) == 0xff00
}
/// Convert this address to an IPv4 address. Returns None if this address is
/// neither IPv4-compatible or IPv4-mapped.
///
/// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
match self.segments() {
[0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => {
Some(Ipv4Addr::new((g >> 8) as u8, g as u8,
(h >> 8) as u8, h as u8))
},
_ => None
}
}
}
impl fmt::Display for Ipv6Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.segments() {
// We need special cases for :: and ::1, otherwise they're formatted
// as ::0.0.0.[01]
[0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"),
[0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"),
// Ipv4 Compatible address
[0, 0, 0, 0, 0, 0, g, h] => {
write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
(h >> 8) as u8, h as u8)
}
// Ipv4-Mapped address
[0, 0, 0, 0, 0, 0xffff, g, h] => {
write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
(h >> 8) as u8, h as u8)
},
_ => {
fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
let mut longest_span_len = 0;
let mut longest_span_at = 0;
let mut cur_span_len = 0;
let mut cur_span_at = 0;
for i in range(0, 8) {
if segments[i] == 0 {
if cur_span_len == 0 {
cur_span_at = i;
}
cur_span_len += 1;
if cur_span_len > longest_span_len {
longest_span_len = cur_span_len;
longest_span_at = cur_span_at;
}
} else {
cur_span_len = 0;
cur_span_at = 0;
}
}
(longest_span_at, longest_span_len)
}
let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
if zeros_len > 1 {
fn fmt_subslice(segments: &[u16]) -> String {
segments
.iter()
.map(|&seg| format!("{:x}", seg))
.collect::<Vec<String>>()
.as_slice()
.connect(":")
}
write!(fmt, "{}::{}",
fmt_subslice(&self.segments()[..zeros_at]),
fmt_subslice(&self.segments()[zeros_at + zeros_len..]))
} else {
let &[a, b, c, d, e, f, g, h] = &self.segments();
write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
a, b, c, d, e, f, g, h)
}
}
}
}
}
impl fmt::Debug for Ipv6Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, fmt)
}
}
impl Clone for Ipv6Addr {
fn clone(&self) -> Ipv6Addr { *self }
}
impl PartialEq for Ipv6Addr {
fn eq(&self, other: &Ipv6Addr) -> bool {
self.inner.s6_addr == other.inner.s6_addr
}
}
impl Eq for Ipv6Addr {}
impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Ipv6Addr {
fn hash(&self, s: &mut S) {
self.inner.s6_addr.hash(s)
}
}
impl PartialOrd for Ipv6Addr {
fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Ipv6Addr {
fn cmp(&self, other: &Ipv6Addr) -> Ordering {
self.inner.s6_addr.cmp(&other.inner.s6_addr)
}
}
impl AsInner<libc::in6_addr> for Ipv6Addr {
fn as_inner(&self) -> &libc::in6_addr { &self.inner }
}
impl FromInner<libc::in6_addr> for Ipv6Addr {
fn from_inner(addr: libc::in6_addr) -> Ipv6Addr {
Ipv6Addr { inner: addr }
}
}
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
//! Networking primitives for TCP/UDP communication
//!
//! > **NOTE**: This module is very much a work in progress and is under active
//! > development. At this time it is still recommended to use the `old_io`
//! > module while the details of this module shake out.
#![unstable(feature = "net")]
use prelude::v1::*;
use io::{self, Error, ErrorKind};
use num::Int;
use sys_common::net2 as net_imp;
pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;
/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq)]
pub enum Shutdown {
/// Indicates that the reading portion of this stream/socket should be shut
/// down. All currently blocked and future reads will return `Ok(0)`.
Read,
/// Indicates that the writing portion of this stream/socket should be shut
/// down. All currently blocked and future writes will return an error.
Write,
/// Shut down both the reading and writing portions of this stream.
///
/// See `Shutdown::Read` and `Shutdown::Write` for more information.
Both
}
fn hton<I: Int>(i: I) -> I { i.to_be() }
fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<T>
where F: FnMut(&SocketAddr) -> io::Result<T>
{
let mut last_err = None;
for addr in try!(addr.to_socket_addrs()) {
match f(&addr) {
Ok(l) => return Ok(l),
Err(e) => last_err = Some(e),
}
}
Err(last_err.unwrap_or_else(|| {
Error::new(ErrorKind::InvalidInput,
"could not resolve to any addresses", None)
}))
}
/// An iterator over `SocketAddr` values returned from a host lookup operation.
pub struct LookupHost(net_imp::LookupHost);
impl Iterator for LookupHost {
type Item = io::Result<SocketAddr>;
fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}
/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Example
///
/// ```no_run
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
/// println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
net_imp::lookup_host(host).map(LookupHost)
}
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
//! A private parser implementation of IPv4, IPv6, and socket addresses.
//!
//! This module is "publicly exported" through the `FromStr` implementations
//! below.
use prelude::v1::*;
use str::FromStr;
use net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
struct Parser<'a> {
// parsing as ASCII, so can use byte array
s: &'a [u8],
pos: usize,
}
impl<'a> Parser<'a> {
fn new(s: &'a str) -> Parser<'a> {
Parser {
s: s.as_bytes(),
pos: 0,
}
}
fn is_eof(&self) -> bool {
self.pos == self.s.len()
}
// Commit only if parser returns Some
fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
F: FnOnce(&mut Parser) -> Option<T>,
{
let pos = self.pos;
let r = cb(self);
if r.is_none() {
self.pos = pos;
}
r
}
// Commit only if parser read till EOF
fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
F: FnOnce(&mut Parser) -> Option<T>,
{
self.read_atomically(move |p| {
match cb(p) {
Some(x) => if p.is_eof() {Some(x)} else {None},
None => None,
}
})
}
// Return result of first successful parser
fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>])
-> Option<T> {
for pf in parsers.iter_mut() {
match self.read_atomically(|p: &mut Parser| pf(p)) {
Some(r) => return Some(r),
None => {}
}
}
None
}
// Apply 3 parsers sequentially
fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
pa: PA,
pb: PB,
pc: PC)
-> Option<(A, B, C)> where
PA: FnOnce(&mut Parser) -> Option<A>,
PB: FnOnce(&mut Parser) -> Option<B>,
PC: FnOnce(&mut Parser) -> Option<C>,
{
self.read_atomically(move |p| {
let a = pa(p);
let b = if a.is_some() { pb(p) } else { None };
let c = if b.is_some() { pc(p) } else { None };
match (a, b, c) {
(Some(a), Some(b), Some(c)) => Some((a, b, c)),
_ => None
}
})
}
// Read next char
fn read_char(&mut self) -> Option<char> {
if self.is_eof() {
None
} else {
let r = self.s[self.pos] as char;
self.pos += 1;
Some(r)
}
}
// Return char and advance iff next char is equal to requested
fn read_given_char(&mut self, c: char) -> Option<char> {
self.read_atomically(|p| {
match p.read_char() {
Some(next) if next == c => Some(next),
_ => None,
}
})
}
// Read digit
fn read_digit(&mut self, radix: u8) -> Option<u8> {
fn parse_digit(c: char, radix: u8) -> Option<u8> {
let c = c as u8;
// assuming radix is either 10 or 16
if c >= b'0' && c <= b'9' {
Some(c - b'0')
} else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
Some(c - b'a' + 10)
} else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
Some(c - b'A' + 10)
} else {
None
}
}
self.read_atomically(|p| {
p.read_char().and_then(|c| parse_digit(c, radix))
})
}
fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
let mut r = 0u32;
let mut digit_count = 0;
loop {
match self.read_digit(radix) {
Some(d) => {
r = r * (radix as u32) + (d as u32);
digit_count += 1;
if digit_count > max_digits || r >= upto {
return None
}
}
None => {
if digit_count == 0 {
return None
} else {
return Some(r)
}
}
};
}
}
// Read number, failing if max_digits of number value exceeded
fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
}
fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
let mut bs = [0u8; 4];
let mut i = 0;
while i < 4 {
if i != 0 && self.read_given_char('.').is_none() {
return None;
}
let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
match octet {
Some(d) => bs[i] = d,
None => return None,
};
i += 1;
}
Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
}
// Read IPv4 address
fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
self.read_atomically(|p| p.read_ipv4_addr_impl())
}
fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
assert!(head.len() + tail.len() <= 8);
let mut gs = [0u16; 8];
gs.clone_from_slice(head);
gs[(8 - tail.len()) .. 8].clone_from_slice(tail);
Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
}
fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
-> (usize, bool) {
let mut i = 0;
while i < limit {
if i < limit - 1 {
let ipv4 = p.read_atomically(|p| {
if i == 0 || p.read_given_char(':').is_some() {
p.read_ipv4_addr()
} else {
None
}
});
if let Some(v4_addr) = ipv4 {
let octets = v4_addr.octets();
groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
return (i + 2, true);
}
}
let group = p.read_atomically(|p| {
if i == 0 || p.read_given_char(':').is_some() {
p.read_number(16, 4, 0x10000).map(|n| n as u16)
} else {
None
}
});
match group {
Some(g) => groups[i] = g,
None => return (i, false)
}
i += 1;
}
(i, false)
}
let mut head = [0u16; 8];
let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
if head_size == 8 {
return Some(Ipv6Addr::new(
head[0], head[1], head[2], head[3],
head[4], head[5], head[6], head[7]))
}
// IPv4 part is not allowed before `::`
if head_ipv4 {
return None
}
// read `::` if previous code parsed less than 8 groups
if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
return None;
}
let mut tail = [0u16; 8];
let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
}
fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
self.read_atomically(|p| p.read_ipv6_addr_impl())
}
fn read_ip_addr(&mut self) -> Option<IpAddr> {
let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4));
let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6));
self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
let ip_addr = |p: &mut Parser| {
let ipv4_p = |p: &mut Parser| p.read_ip_addr();
let ipv6_p = |p: &mut Parser| {
let open_br = |p: &mut Parser| p.read_given_char('[');
let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
let clos_br = |p: &mut Parser| p.read_given_char(']');
p.read_seq_3::<char, Ipv6Addr, char, _, _, _>(open_br, ip_addr, clos_br)
.map(|t| match t { (_, ip, _) => IpAddr::V6(ip) })
};
p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)])
};
let colon = |p: &mut Parser| p.read_given_char(':');
let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
// host, colon, port
self.read_seq_3::<IpAddr, char, u16, _, _, _>(ip_addr, colon, port)
.map(|t| match t { (ip, _, port) => SocketAddr::new(ip, port) })
}
}
impl FromStr for IpAddr {
type Err = ParseError;
fn from_str(s: &str) -> Result<IpAddr, ParseError> {
match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
Some(s) => Ok(s),
None => Err(ParseError),
}
}
}
impl FromStr for Ipv4Addr {
type Err = ParseError;
fn from_str(s: &str) -> Result<Ipv4Addr, ParseError> {
match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
Some(s) => Ok(s),
None => Err(ParseError)
}
}
}
impl FromStr for Ipv6Addr {
type Err = ParseError;
fn from_str(s: &str) -> Result<Ipv6Addr, ParseError> {
match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
Some(s) => Ok(s),
None => Err(ParseError)
}
}
}
impl FromStr for SocketAddr {
type Err = ParseError;
fn from_str(s: &str) -> Result<SocketAddr, ParseError> {
match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
Some(s) => Ok(s),
None => Err(ParseError),
}
}
}
#[derive(Debug, Clone, PartialEq, Copy)]
pub struct ParseError;
此差异已折叠。
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
use prelude::v1::*;
use env;
use net::{SocketAddr, IpAddr};
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
pub fn next_test_ip4() -> SocketAddr {
static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1),
PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
}
pub fn next_test_ip6() -> SocketAddr {
static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0, 1),
PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
}
// The bots run multiple builds at the same time, and these builds
// all want to use ports. This function figures out which workspace
// it is running in and assigns a port range based on it.
fn base_port() -> u16 {
let cwd = env::current_dir().unwrap();
let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg",
"all-opt", "snap3", "dist"];
dirs.iter().enumerate().find(|&(i, dir)| {
cwd.as_str().unwrap().contains(dir)
}).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
}
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
use prelude::v1::*;
use io::{self, Error, ErrorKind};
use net::{ToSocketAddrs, SocketAddr, IpAddr};
use sys_common::net2 as net_imp;
use sys_common::AsInner;
/// A User Datagram Protocol socket.
///
/// This is an implementation of a bound UDP socket. This supports both IPv4 and
/// IPv6 addresses, and there is no corresponding notion of a server because UDP
/// is a datagram protocol.
///
/// # Example
///
/// ```no_run
/// use std::net::UdpSocket;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut socket = try!(UdpSocket::bind("127.0.0.1:34254"));
///
/// let mut buf = [0; 10];
/// let (amt, src) = try!(socket.recv_from(&mut buf));
///
/// // Send a reply to the socket we received data from
/// let buf = &mut buf[..amt];
/// buf.reverse();
/// try!(socket.send_to(buf, &src));
///
/// drop(socket); // close the socket
/// # Ok(())
/// # }
/// ```
pub struct UdpSocket(net_imp::UdpSocket);
impl UdpSocket {
/// Creates a UDP socket from the given address.
///
/// Address type can be any implementor of `ToSocketAddr` trait. See its
/// documentation for concrete examples.
pub fn bind<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<UdpSocket> {
super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
}
/// Receives data from the socket. On success, returns the number of bytes
/// read and the address from whence the data came.
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.recv_from(buf)
}
/// Sends data on the socket to the given address. Returns nothing on
/// success.
///
/// Address type can be any implementor of `ToSocketAddrs` trait. See its
/// documentation for concrete examples.
pub fn send_to<A: ToSocketAddrs + ?Sized>(&self, buf: &[u8], addr: &A)
-> io::Result<usize> {
match try!(addr.to_socket_addrs()).next() {
Some(addr) => self.0.send_to(buf, &addr),
None => Err(Error::new(ErrorKind::InvalidInput,
"no addresses to send data to", None)),
}
}
/// Returns the socket address that this socket was created from.
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
self.0.socket_addr()
}
/// Create a new independently owned handle to the underlying socket.
///
/// The returned `UdpSocket` is a reference to the same socket that this
/// object references. Both handles will read and write the same port, and
/// options set on one socket will be propagated to the other.
pub fn try_clone(&self) -> io::Result<UdpSocket> {
self.0.duplicate().map(UdpSocket)
}
/// Sets the broadcast flag on or off
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
self.0.set_broadcast(on)
}
/// Set the multicast loop flag to the specified value
///
/// This lets multicast packets loop back to local sockets (if enabled)
pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
self.0.set_multicast_loop(on)
}
/// Joins a multicast IP address (becomes a member of it)
pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
self.0.join_multicast(multi)
}
/// Leaves a multicast IP address (drops membership from it)
pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
self.0.leave_multicast(multi)
}
/// Sets the multicast TTL
pub fn set_multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
self.0.multicast_time_to_live(ttl)
}
/// Sets this socket's TTL
pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
self.0.time_to_live(ttl)
}
}
impl AsInner<net_imp::UdpSocket> for UdpSocket {
fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
use io::ErrorKind;
use net::*;
use net::test::{next_test_ip4, next_test_ip6};
use sync::mpsc::channel;
use thread::Thread;
fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
f(next_test_ip4(), next_test_ip4());
f(next_test_ip6(), next_test_ip6());
}
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
}
}
// FIXME #11530 this fails on android because tests are run as root
#[cfg_attr(any(windows, target_os = "android"), ignore)]
#[test]
fn bind_error() {
let addr = SocketAddr::new(IpAddr::new_v4(0, 0, 0, 0), 1);
match UdpSocket::bind(&addr) {
Ok(..) => panic!(),
Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied),
}
}
#[test]
fn socket_smoke_test_ip4() {
each_ip(&mut |server_ip, client_ip| {
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = Thread::spawn(move|| {
let client = t!(UdpSocket::bind(&client_ip));
rx1.recv().unwrap();
t!(client.send_to(&[99], &server_ip));
tx2.send(()).unwrap();
});
let server = t!(UdpSocket::bind(&server_ip));
tx1.send(()).unwrap();
let mut buf = [0];
let (nread, src) = t!(server.recv_from(&mut buf));
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
rx2.recv().unwrap();
})
}
#[test]
fn socket_name_ip4() {
each_ip(&mut |addr, _| {
let server = t!(UdpSocket::bind(&addr));
assert_eq!(addr, t!(server.socket_addr()));
})
}
#[test]
fn udp_clone_smoke() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let _t = Thread::spawn(move|| {
let mut buf = [0, 0];
assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1)));
assert_eq!(buf[0], 1);
t!(sock2.send_to(&[2], &addr1));
});
let sock3 = t!(sock1.try_clone());
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let _t = Thread::spawn(move|| {
rx1.recv().unwrap();
t!(sock3.send_to(&[1], &addr2));
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
let mut buf = [0, 0];
assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2)));
rx2.recv().unwrap();
})
}
#[test]
fn udp_clone_two_read() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let (tx1, rx) = channel();
let tx2 = tx1.clone();
let _t = Thread::spawn(move|| {
t!(sock2.send_to(&[1], &addr1));
rx.recv().unwrap();
t!(sock2.send_to(&[2], &addr1));
rx.recv().unwrap();
});
let sock3 = t!(sock1.try_clone());
let (done, rx) = channel();
let _t = Thread::spawn(move|| {
let mut buf = [0, 0];
t!(sock3.recv_from(&mut buf));
tx2.send(()).unwrap();
done.send(()).unwrap();
});
let mut buf = [0, 0];
t!(sock1.recv_from(&mut buf));
tx1.send(()).unwrap();
rx.recv().unwrap();
})
}
#[test]
fn udp_clone_two_write() {
each_ip(&mut |addr1, addr2| {
let sock1 = t!(UdpSocket::bind(&addr1));
let sock2 = t!(UdpSocket::bind(&addr2));
let (tx, rx) = channel();
let (serv_tx, serv_rx) = channel();
let _t = Thread::spawn(move|| {
let mut buf = [0, 1];
rx.recv().unwrap();
t!(sock2.recv_from(&mut buf));
serv_tx.send(()).unwrap();
});
let sock3 = t!(sock1.try_clone());
let (done, rx) = channel();
let tx2 = tx.clone();
let _t = Thread::spawn(move|| {
match sock3.send_to(&[1], &addr2) {
Ok(..) => { let _ = tx2.send(()); }
Err(..) => {}
}
done.send(()).unwrap();
});
match sock1.send_to(&[2], &addr2) {
Ok(..) => { let _ = tx.send(()); }
Err(..) => {}
}
drop(tx);
rx.recv().unwrap();
serv_rx.recv().unwrap();
})
}
}
......@@ -24,6 +24,7 @@
pub mod helper_thread;
pub mod mutex;
pub mod net;
pub mod net2;
pub mod rwlock;
pub mod stack;
pub mod thread;
......
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
use prelude::v1::*;
use ffi::CString;
use io::{self, Error, ErrorKind};
use libc::{self, c_int, c_char, c_void, socklen_t};
use mem;
use net::{IpAddr, SocketAddr, Shutdown};
use num::Int;
use sys::c;
use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
use sys_common::{AsInner, FromInner, IntoInner};
////////////////////////////////////////////////////////////////////////////////
// sockaddr and misc bindings
////////////////////////////////////////////////////////////////////////////////
fn hton<I: Int>(i: I) -> I { i.to_be() }
fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
payload: T) -> io::Result<()> {
unsafe {
let payload = &payload as *const T as *const c_void;
try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload,
mem::size_of::<T>() as socklen_t)));
Ok(())
}
}
#[allow(dead_code)]
fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
val: c_int) -> io::Result<T> {
unsafe {
let mut slot: T = mem::zeroed();
let mut len = mem::size_of::<T>() as socklen_t;
let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
&mut slot as *mut _ as *mut _,
&mut len)));
assert_eq!(ret as usize, mem::size_of::<T>());
Ok(slot)
}
}
fn sockname<F>(f: F) -> io::Result<SocketAddr>
where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int
{
unsafe {
let mut storage: libc::sockaddr_storage = mem::zeroed();
let mut len = mem::size_of_val(&storage) as socklen_t;
try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len)));
sockaddr_to_addr(&storage, len as usize)
}
}
fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
len: usize) -> io::Result<SocketAddr> {
match storage.ss_family as libc::c_int {
libc::AF_INET => {
assert!(len as usize >= mem::size_of::<libc::sockaddr_in>());
Ok(FromInner::from_inner(unsafe {
*(storage as *const _ as *const libc::sockaddr_in)
}))
}
libc::AF_INET6 => {
assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>());
Ok(FromInner::from_inner(unsafe {
*(storage as *const _ as *const libc::sockaddr_in6)
}))
}
_ => {
Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None))
}
}
}
////////////////////////////////////////////////////////////////////////////////
// get_host_addresses
////////////////////////////////////////////////////////////////////////////////
extern "system" {
fn getaddrinfo(node: *const c_char, service: *const c_char,
hints: *const libc::addrinfo,
res: *mut *mut libc::addrinfo) -> c_int;
fn freeaddrinfo(res: *mut libc::addrinfo);
}
pub struct LookupHost {
original: *mut libc::addrinfo,
cur: *mut libc::addrinfo,
}
impl Iterator for LookupHost {
type Item = io::Result<SocketAddr>;
fn next(&mut self) -> Option<io::Result<SocketAddr>> {
unsafe {
if self.cur.is_null() { return None }
let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr),
(*self.cur).ai_addrlen as usize);
self.cur = (*self.cur).ai_next as *mut libc::addrinfo;
Some(ret)
}
}
}
impl Drop for LookupHost {
fn drop(&mut self) {
unsafe { freeaddrinfo(self.original) }
}
}
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
init();
let c_host = CString::from_slice(host.as_bytes());
let mut res = 0 as *mut _;
unsafe {
try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _,
&mut res)));
Ok(LookupHost { original: res, cur: res })
}
}
////////////////////////////////////////////////////////////////////////////////
// TCP streams
////////////////////////////////////////////////////////////////////////////////
pub struct TcpStream {
inner: Socket,
}
impl TcpStream {
pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
init();
let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
let (addrp, len) = addr.into_inner();
try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) }));
Ok(TcpStream { inner: sock })
}
pub fn socket(&self) -> &Socket { &self.inner }
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY,
nodelay as c_int)
}
pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE,
seconds.is_some() as c_int);
match seconds {
Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
None => ret,
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
seconds as c_int)
}
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
seconds as c_int)
}
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly")))]
fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
Ok(())
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = try!(cvt(unsafe {
libc::send(*self.inner.as_inner(),
buf.as_ptr() as *const c_void,
buf.len() as wrlen_t,
0)
}));
Ok(ret as usize)
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe {
libc::getpeername(*self.inner.as_inner(), buf, len)
})
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe {
libc::getsockname(*self.inner.as_inner(), buf, len)
})
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
use libc::consts::os::bsd44::SHUT_RDWR;
let how = match how {
Shutdown::Write => libc::SHUT_WR,
Shutdown::Read => libc::SHUT_RD,
Shutdown::Both => SHUT_RDWR,
};
try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) }));
Ok(())
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
self.inner.duplicate().map(|s| TcpStream { inner: s })
}
}
////////////////////////////////////////////////////////////////////////////////
// TCP listeners
////////////////////////////////////////////////////////////////////////////////
pub struct TcpListener {
inner: Socket,
}
impl TcpListener {
pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
init();
let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
// On platforms with Berkeley-derived sockets, this allows
// to quickly rebind a socket, without needing to wait for
// the OS to clean up the previous one.
if !cfg!(windows) {
try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR,
1 as c_int));
}
// Bind our new socket
let (addrp, len) = addr.into_inner();
try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
// Start listening
try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) }));
Ok(TcpListener { inner: sock })
}
pub fn socket(&self) -> &Socket { &self.inner }
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe {
libc::getsockname(*self.inner.as_inner(), buf, len)
})
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
let mut len = mem::size_of_val(&storage) as socklen_t;
let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _,
&mut len));
let addr = try!(sockaddr_to_addr(&storage, len as usize));
Ok((TcpStream { inner: sock, }, addr))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
self.inner.duplicate().map(|s| TcpListener { inner: s })
}
}
////////////////////////////////////////////////////////////////////////////////
// UDP
////////////////////////////////////////////////////////////////////////////////
pub struct UdpSocket {
inner: Socket,
}
impl UdpSocket {
pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
init();
let sock = try!(Socket::new(addr, libc::SOCK_DGRAM));
let (addrp, len) = addr.into_inner();
try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
Ok(UdpSocket { inner: sock })
}
pub fn socket(&self) -> &Socket { &self.inner }
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe {
libc::getsockname(*self.inner.as_inner(), buf, len)
})
}
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
let mut addrlen = mem::size_of_val(&storage) as socklen_t;
let n = try!(cvt(unsafe {
libc::recvfrom(*self.inner.as_inner(),
buf.as_mut_ptr() as *mut c_void,
buf.len() as wrlen_t, 0,
&mut storage as *mut _ as *mut _, &mut addrlen)
}));
Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize))))
}
pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
let (dstp, dstlen) = dst.into_inner();
let ret = try!(cvt(unsafe {
libc::sendto(*self.inner.as_inner(),
buf.as_ptr() as *const c_void, buf.len() as wrlen_t,
0, dstp, dstlen)
}));
Ok(ret as usize)
}
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST,
on as c_int)
}
pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_IP,
libc::IP_MULTICAST_LOOP, on as c_int)
}
pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
match *multi {
IpAddr::V4(..) => {
self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
}
IpAddr::V6(..) => {
self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
}
}
}
pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
match *multi {
IpAddr::V4(..) => {
self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
}
IpAddr::V6(..) => {
self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
}
}
}
fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
match *addr {
IpAddr::V4(ref addr) => {
let mreq = libc::ip_mreq {
imr_multiaddr: *addr.as_inner(),
// interface == INADDR_ANY
imr_interface: libc::in_addr { s_addr: 0x0 },
};
setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
}
IpAddr::V6(ref addr) => {
let mreq = libc::ip6_mreq {
ipv6mr_multiaddr: *addr.as_inner(),
ipv6mr_interface: 0,
};
setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)
}
}
}
pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
ttl as c_int)
}
pub fn time_to_live(&self, ttl: i32) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int)
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
self.inner.duplicate().map(|s| UdpSocket { inner: s })
}
}
......@@ -157,6 +157,7 @@ pub fn getpwuid_r(uid: libc::uid_t,
pub fn utimes(filename: *const libc::c_char,
times: *const libc::timeval) -> libc::c_int;
pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
......
......@@ -32,8 +32,8 @@
#![unstable(feature = "std_misc")]
use ffi::{OsStr, OsString};
use fs::{Permissions, OpenOptions};
use fs;
use fs::{self, Permissions, OpenOptions};
use net;
use libc;
use mem;
use sys::os_str::Buf;
......@@ -111,6 +111,16 @@ fn as_raw_fd(&self) -> Fd {
}
}
impl AsRawFd for net::TcpStream {
fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
}
impl AsRawFd for net::TcpListener {
fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
}
impl AsRawFd for net::UdpSocket {
fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
}
// Unix-specific extensions to `OsString`.
pub trait OsStringExt {
/// Create an `OsString` from a byte vector.
......
......@@ -15,8 +15,7 @@
use libc::{self, c_int, size_t, c_void};
use mem;
use sys::cvt;
pub type fd_t = c_int;
use sys_common::AsInner;
pub struct FileDesc {
fd: c_int,
......@@ -55,6 +54,10 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
}
}
impl AsInner<c_int> for FileDesc {
fn as_inner(&self) -> &c_int { &self.fd }
}
impl Drop for FileDesc {
fn drop(&mut self) {
// closing stdio file handles makes no sense, so never do it. Also, note
......
......@@ -18,12 +18,11 @@
use prelude::v1::*;
use ffi;
use io::ErrorKind;
use io::{self, ErrorKind};
use libc;
use num::{Int, SignedInt};
use num;
use old_io::{self, IoResult, IoError};
use io;
use str;
use sys_common::mkerr_libc;
......@@ -47,6 +46,7 @@
pub mod fs2; // support for std::fs
pub mod helper_signal;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod pipe;
......
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
use prelude::v1::*;
use ffi;
use io;
use libc::{self, c_int, size_t};
use str;
use sys::c;
use net::{SocketAddr, IpAddr};
use sys::fd::FileDesc;
use sys_common::AsInner;
pub use sys::{cvt, cvt_r};
pub type wrlen_t = size_t;
pub struct Socket(FileDesc);
pub fn init() {}
pub fn cvt_gai(err: c_int) -> io::Result<()> {
if err == 0 { return Ok(()) }
let detail = unsafe {
str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap()
.to_string()
};
Err(io::Error::new(io::ErrorKind::Other,
"failed to lookup address information", Some(detail)))
}
impl Socket {
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
let fam = match addr.ip() {
IpAddr::V4(..) => libc::AF_INET,
IpAddr::V6(..) => libc::AF_INET6,
};
unsafe {
let fd = try!(cvt(libc::socket(fam, ty, 0)));
Ok(Socket(FileDesc::new(fd)))
}
}
pub fn accept(&self, storage: *mut libc::sockaddr,
len: *mut libc::socklen_t) -> io::Result<Socket> {
let fd = try!(cvt_r(|| unsafe {
libc::accept(self.0.raw(), storage, len)
}));
Ok(Socket(FileDesc::new(fd)))
}
pub fn duplicate(&self) -> io::Result<Socket> {
cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| {
Socket(FileDesc::new(fd))
})
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
impl AsInner<c_int> for Socket {
fn as_inner(&self) -> &c_int { self.0.as_inner() }
}
......@@ -21,6 +21,7 @@
use ffi::{OsStr, OsString};
use fs::{self, OpenOptions};
use libc;
use net;
use sys::os_str::Buf;
use sys_common::{AsInner, FromInner, AsInnerMut};
......@@ -103,6 +104,16 @@ fn as_raw_socket(&self) -> Socket {
}
}
impl AsRawSocket for net::TcpStream {
fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
}
impl AsRawSocket for net::TcpListener {
fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
}
impl AsRawSocket for net::UdpSocket {
fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
}
// Windows-specific extensions to `OsString`.
pub trait OsStringExt {
/// Create an `OsString` from a potentially ill-formed UTF-16 slice of 16-bit code units.
......
......@@ -43,6 +43,7 @@
pub mod handle;
pub mod helper_signal;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod pipe;
......
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
use prelude::v1::*;
use io;
use libc::consts::os::extra::INVALID_SOCKET;
use libc::{self, c_int, c_void};
use mem;
use net::{SocketAddr, IpAddr};
use num::{SignedInt, Int};
use rt;
use sync::{Once, ONCE_INIT};
use sys::c;
use sys_common::AsInner;
pub type wrlen_t = i32;
pub struct Socket(libc::SOCKET);
pub fn init() {
static START: Once = ONCE_INIT;
START.call_once(|| unsafe {
let mut data: c::WSADATA = mem::zeroed();
let ret = c::WSAStartup(0x202, // version 2.2
&mut data);
assert_eq!(ret, 0);
rt::at_exit(|| { c::WSACleanup(); })
});
}
fn last_error() -> io::Error {
io::Error::from_os_error(unsafe { c::WSAGetLastError() })
}
pub fn cvt<T: SignedInt>(t: T) -> io::Result<T> {
let one: T = Int::one();
if t == -one {
Err(last_error())
} else {
Ok(t)
}
}
pub fn cvt_gai(err: c_int) -> io::Result<()> {
if err == 0 { return Ok(()) }
cvt(err).map(|_| ())
}
pub fn cvt_r<T: SignedInt, F>(mut f: F) -> io::Result<T> where F: FnMut() -> T {
cvt(f())
}
impl Socket {
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
let fam = match addr.ip {
IpAddr::V4(..) => libc::AF_INET,
IpAddr::V6(..) => libc::AF_INET6,
};
match unsafe { libc::socket(fam, ty, 0) } {
INVALID_SOCKET => Err(last_error()),
n => Ok(Socket(n)),
}
}
pub fn accept(&self, storage: *mut libc::sockaddr,
len: *mut libc::socklen_t) -> io::Result<Socket> {
match unsafe { libc::accept(self.0, storage, len) } {
INVALID_SOCKET => Err(last_error()),
n => Ok(Socket(n)),
}
}
pub fn duplicate(&self) -> io::Result<Socket> {
unsafe {
let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
try!(cvt(c::WSADuplicateSocketW(self.0,
c::GetCurrentProcessId(),
&mut info)));
match c::WSASocketW(info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info, 0, 0) {
INVALID_SOCKET => Err(last_error()),
n => Ok(Socket(n)),
}
}
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
unsafe {
match libc::recv(self.0, buf.as_mut_ptr() as *mut c_void,
buf.len() as i32, 0) {
-1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
-1 => Err(last_error()),
n => Ok(n as usize)
}
}
}
}
impl Drop for Socket {
fn drop(&mut self) {
unsafe { let _ = libc::closesocket(self.0); }
}
}
impl AsInner<libc::SOCKET> for Socket {
fn as_inner(&self) -> &libc::SOCKET { &self.0 }
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册