Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 395709c

Browse files
committedFeb 11, 2015
std: Add a net module for TCP/UDP
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 rust-lang#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.
1 parent a954663 commit 395709c

File tree

18 files changed

+3214
-6
lines changed

18 files changed

+3214
-6
lines changed
 

‎src/libstd/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ pub mod ffi;
250250
pub mod old_io;
251251
pub mod io;
252252
pub mod fs;
253+
pub mod net;
253254
pub mod os;
254255
pub mod env;
255256
pub mod path;

‎src/libstd/net/addr.rs‎

Lines changed: 592 additions & 0 deletions
Large diffs are not rendered by default.

‎src/libstd/net/ip.rs‎

Lines changed: 449 additions & 0 deletions
Large diffs are not rendered by default.

‎src/libstd/net/mod.rs‎

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Networking primitives for TCP/UDP communication
12+
//!
13+
//! > **NOTE**: This module is very much a work in progress and is under active
14+
//! > development. At this time it is still recommended to use the `old_io`
15+
//! > module while the details of this module shake out.
16+
17+
#![unstable(feature = "net")]
18+
19+
use prelude::v1::*;
20+
21+
use io::{self, Error, ErrorKind};
22+
use num::Int;
23+
use sys_common::net2 as net_imp;
24+
25+
pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
26+
pub use self::addr::{SocketAddr, ToSocketAddrs};
27+
pub use self::tcp::{TcpStream, TcpListener};
28+
pub use self::udp::UdpSocket;
29+
30+
mod ip;
31+
mod addr;
32+
mod tcp;
33+
mod udp;
34+
mod parser;
35+
#[cfg(test)] mod test;
36+
37+
/// Possible values which can be passed to the `shutdown` method of `TcpStream`
38+
/// and `UdpSocket`.
39+
#[derive(Copy, Clone, PartialEq)]
40+
pub enum Shutdown {
41+
/// Indicates that the reading portion of this stream/socket should be shut
42+
/// down. All currently blocked and future reads will return `Ok(0)`.
43+
Read,
44+
/// Indicates that the writing portion of this stream/socket should be shut
45+
/// down. All currently blocked and future writes will return an error.
46+
Write,
47+
/// Shut down both the reading and writing portions of this stream.
48+
///
49+
/// See `Shutdown::Read` and `Shutdown::Write` for more information.
50+
Both
51+
}
52+
53+
fn hton<I: Int>(i: I) -> I { i.to_be() }
54+
fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
55+
56+
fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<T>
57+
where F: FnMut(&SocketAddr) -> io::Result<T>
58+
{
59+
let mut last_err = None;
60+
for addr in try!(addr.to_socket_addrs()) {
61+
match f(&addr) {
62+
Ok(l) => return Ok(l),
63+
Err(e) => last_err = Some(e),
64+
}
65+
}
66+
Err(last_err.unwrap_or_else(|| {
67+
Error::new(ErrorKind::InvalidInput,
68+
"could not resolve to any addresses", None)
69+
}))
70+
}
71+
72+
/// An iterator over `SocketAddr` values returned from a host lookup operation.
73+
pub struct LookupHost(net_imp::LookupHost);
74+
75+
impl Iterator for LookupHost {
76+
type Item = io::Result<SocketAddr>;
77+
fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
78+
}
79+
80+
/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
81+
///
82+
/// This method may perform a DNS query to resolve `host` and may also inspect
83+
/// system configuration to resolve the specified hostname.
84+
///
85+
/// # Example
86+
///
87+
/// ```no_run
88+
/// use std::net;
89+
///
90+
/// # fn foo() -> std::io::Result<()> {
91+
/// for host in try!(net::lookup_host("rust-lang.org")) {
92+
/// println!("found address: {}", try!(host));
93+
/// }
94+
/// # Ok(())
95+
/// # }
96+
/// ```
97+
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
98+
net_imp::lookup_host(host).map(LookupHost)
99+
}

‎src/libstd/net/parser.rs‎

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! A private parser implementation of IPv4, IPv6, and socket addresses.
12+
//!
13+
//! This module is "publicly exported" through the `FromStr` implementations
14+
//! below.
15+
16+
use prelude::v1::*;
17+
18+
use str::FromStr;
19+
use net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
20+
21+
struct Parser<'a> {
22+
// parsing as ASCII, so can use byte array
23+
s: &'a [u8],
24+
pos: usize,
25+
}
26+
27+
impl<'a> Parser<'a> {
28+
fn new(s: &'a str) -> Parser<'a> {
29+
Parser {
30+
s: s.as_bytes(),
31+
pos: 0,
32+
}
33+
}
34+
35+
fn is_eof(&self) -> bool {
36+
self.pos == self.s.len()
37+
}
38+
39+
// Commit only if parser returns Some
40+
fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
41+
F: FnOnce(&mut Parser) -> Option<T>,
42+
{
43+
let pos = self.pos;
44+
let r = cb(self);
45+
if r.is_none() {
46+
self.pos = pos;
47+
}
48+
r
49+
}
50+
51+
// Commit only if parser read till EOF
52+
fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
53+
F: FnOnce(&mut Parser) -> Option<T>,
54+
{
55+
self.read_atomically(move |p| {
56+
match cb(p) {
57+
Some(x) => if p.is_eof() {Some(x)} else {None},
58+
None => None,
59+
}
60+
})
61+
}
62+
63+
// Return result of first successful parser
64+
fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>])
65+
-> Option<T> {
66+
for pf in parsers.iter_mut() {
67+
match self.read_atomically(|p: &mut Parser| pf(p)) {
68+
Some(r) => return Some(r),
69+
None => {}
70+
}
71+
}
72+
None
73+
}
74+
75+
// Apply 3 parsers sequentially
76+
fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
77+
pa: PA,
78+
pb: PB,
79+
pc: PC)
80+
-> Option<(A, B, C)> where
81+
PA: FnOnce(&mut Parser) -> Option<A>,
82+
PB: FnOnce(&mut Parser) -> Option<B>,
83+
PC: FnOnce(&mut Parser) -> Option<C>,
84+
{
85+
self.read_atomically(move |p| {
86+
let a = pa(p);
87+
let b = if a.is_some() { pb(p) } else { None };
88+
let c = if b.is_some() { pc(p) } else { None };
89+
match (a, b, c) {
90+
(Some(a), Some(b), Some(c)) => Some((a, b, c)),
91+
_ => None
92+
}
93+
})
94+
}
95+
96+
// Read next char
97+
fn read_char(&mut self) -> Option<char> {
98+
if self.is_eof() {
99+
None
100+
} else {
101+
let r = self.s[self.pos] as char;
102+
self.pos += 1;
103+
Some(r)
104+
}
105+
}
106+
107+
// Return char and advance iff next char is equal to requested
108+
fn read_given_char(&mut self, c: char) -> Option<char> {
109+
self.read_atomically(|p| {
110+
match p.read_char() {
111+
Some(next) if next == c => Some(next),
112+
_ => None,
113+
}
114+
})
115+
}
116+
117+
// Read digit
118+
fn read_digit(&mut self, radix: u8) -> Option<u8> {
119+
fn parse_digit(c: char, radix: u8) -> Option<u8> {
120+
let c = c as u8;
121+
// assuming radix is either 10 or 16
122+
if c >= b'0' && c <= b'9' {
123+
Some(c - b'0')
124+
} else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
125+
Some(c - b'a' + 10)
126+
} else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
127+
Some(c - b'A' + 10)
128+
} else {
129+
None
130+
}
131+
}
132+
133+
self.read_atomically(|p| {
134+
p.read_char().and_then(|c| parse_digit(c, radix))
135+
})
136+
}
137+
138+
fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
139+
let mut r = 0u32;
140+
let mut digit_count = 0;
141+
loop {
142+
match self.read_digit(radix) {
143+
Some(d) => {
144+
r = r * (radix as u32) + (d as u32);
145+
digit_count += 1;
146+
if digit_count > max_digits || r >= upto {
147+
return None
148+
}
149+
}
150+
None => {
151+
if digit_count == 0 {
152+
return None
153+
} else {
154+
return Some(r)
155+
}
156+
}
157+
};
158+
}
159+
}
160+
161+
// Read number, failing if max_digits of number value exceeded
162+
fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
163+
self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
164+
}
165+
166+
fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
167+
let mut bs = [0u8; 4];
168+
let mut i = 0;
169+
while i < 4 {
170+
if i != 0 && self.read_given_char('.').is_none() {
171+
return None;
172+
}
173+
174+
let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
175+
match octet {
176+
Some(d) => bs[i] = d,
177+
None => return None,
178+
};
179+
i += 1;
180+
}
181+
Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
182+
}
183+
184+
// Read IPv4 address
185+
fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
186+
self.read_atomically(|p| p.read_ipv4_addr_impl())
187+
}
188+
189+
fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
190+
fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
191+
assert!(head.len() + tail.len() <= 8);
192+
let mut gs = [0u16; 8];
193+
gs.clone_from_slice(head);
194+
gs[(8 - tail.len()) .. 8].clone_from_slice(tail);
195+
Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
196+
}
197+
198+
fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
199+
-> (usize, bool) {
200+
let mut i = 0;
201+
while i < limit {
202+
if i < limit - 1 {
203+
let ipv4 = p.read_atomically(|p| {
204+
if i == 0 || p.read_given_char(':').is_some() {
205+
p.read_ipv4_addr()
206+
} else {
207+
None
208+
}
209+
});
210+
if let Some(v4_addr) = ipv4 {
211+
let octets = v4_addr.octets();
212+
groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
213+
groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
214+
return (i + 2, true);
215+
}
216+
}
217+
218+
let group = p.read_atomically(|p| {
219+
if i == 0 || p.read_given_char(':').is_some() {
220+
p.read_number(16, 4, 0x10000).map(|n| n as u16)
221+
} else {
222+
None
223+
}
224+
});
225+
match group {
226+
Some(g) => groups[i] = g,
227+
None => return (i, false)
228+
}
229+
i += 1;
230+
}
231+
(i, false)
232+
}
233+
234+
let mut head = [0u16; 8];
235+
let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
236+
237+
if head_size == 8 {
238+
return Some(Ipv6Addr::new(
239+
head[0], head[1], head[2], head[3],
240+
head[4], head[5], head[6], head[7]))
241+
}
242+
243+
// IPv4 part is not allowed before `::`
244+
if head_ipv4 {
245+
return None
246+
}
247+
248+
// read `::` if previous code parsed less than 8 groups
249+
if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
250+
return None;
251+
}
252+
253+
let mut tail = [0u16; 8];
254+
let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
255+
Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
256+
}
257+
258+
fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
259+
self.read_atomically(|p| p.read_ipv6_addr_impl())
260+
}
261+
262+
fn read_ip_addr(&mut self) -> Option<IpAddr> {
263+
let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4));
264+
let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6));
265+
self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
266+
}
267+
268+
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
269+
let ip_addr = |p: &mut Parser| {
270+
let ipv4_p = |p: &mut Parser| p.read_ip_addr();
271+
let ipv6_p = |p: &mut Parser| {
272+
let open_br = |p: &mut Parser| p.read_given_char('[');
273+
let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
274+
let clos_br = |p: &mut Parser| p.read_given_char(']');
275+
p.read_seq_3::<char, Ipv6Addr, char, _, _, _>(open_br, ip_addr, clos_br)
276+
.map(|t| match t { (_, ip, _) => IpAddr::V6(ip) })
277+
};
278+
p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)])
279+
};
280+
let colon = |p: &mut Parser| p.read_given_char(':');
281+
let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
282+
283+
// host, colon, port
284+
self.read_seq_3::<IpAddr, char, u16, _, _, _>(ip_addr, colon, port)
285+
.map(|t| match t { (ip, _, port) => SocketAddr::new(ip, port) })
286+
}
287+
}
288+
289+
impl FromStr for IpAddr {
290+
type Err = ParseError;
291+
fn from_str(s: &str) -> Result<IpAddr, ParseError> {
292+
match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
293+
Some(s) => Ok(s),
294+
None => Err(ParseError),
295+
}
296+
}
297+
}
298+
299+
impl FromStr for Ipv4Addr {
300+
type Err = ParseError;
301+
fn from_str(s: &str) -> Result<Ipv4Addr, ParseError> {
302+
match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
303+
Some(s) => Ok(s),
304+
None => Err(ParseError)
305+
}
306+
}
307+
}
308+
309+
impl FromStr for Ipv6Addr {
310+
type Err = ParseError;
311+
fn from_str(s: &str) -> Result<Ipv6Addr, ParseError> {
312+
match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
313+
Some(s) => Ok(s),
314+
None => Err(ParseError)
315+
}
316+
}
317+
}
318+
319+
impl FromStr for SocketAddr {
320+
type Err = ParseError;
321+
fn from_str(s: &str) -> Result<SocketAddr, ParseError> {
322+
match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
323+
Some(s) => Ok(s),
324+
None => Err(ParseError),
325+
}
326+
}
327+
}
328+
329+
#[derive(Debug, Clone, PartialEq, Copy)]
330+
pub struct ParseError;

‎src/libstd/net/tcp.rs‎

Lines changed: 792 additions & 0 deletions
Large diffs are not rendered by default.

‎src/libstd/net/test.rs‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use prelude::v1::*;
12+
13+
use env;
14+
use net::{SocketAddr, IpAddr};
15+
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
16+
17+
pub fn next_test_ip4() -> SocketAddr {
18+
static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
19+
SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1),
20+
PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
21+
}
22+
23+
pub fn next_test_ip6() -> SocketAddr {
24+
static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
25+
SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0, 1),
26+
PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
27+
}
28+
29+
// The bots run multiple builds at the same time, and these builds
30+
// all want to use ports. This function figures out which workspace
31+
// it is running in and assigns a port range based on it.
32+
fn base_port() -> u16 {
33+
let cwd = env::current_dir().unwrap();
34+
let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg",
35+
"all-opt", "snap3", "dist"];
36+
dirs.iter().enumerate().find(|&(i, dir)| {
37+
cwd.as_str().unwrap().contains(dir)
38+
}).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
39+
}

‎src/libstd/net/udp.rs‎

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use prelude::v1::*;
12+
13+
use io::{self, Error, ErrorKind};
14+
use net::{ToSocketAddrs, SocketAddr, IpAddr};
15+
use sys_common::net2 as net_imp;
16+
use sys_common::AsInner;
17+
18+
/// A User Datagram Protocol socket.
19+
///
20+
/// This is an implementation of a bound UDP socket. This supports both IPv4 and
21+
/// IPv6 addresses, and there is no corresponding notion of a server because UDP
22+
/// is a datagram protocol.
23+
///
24+
/// # Example
25+
///
26+
/// ```no_run
27+
/// use std::net::UdpSocket;
28+
///
29+
/// # fn foo() -> std::io::Result<()> {
30+
/// let mut socket = try!(UdpSocket::bind("127.0.0.1:34254"));
31+
///
32+
/// let mut buf = [0; 10];
33+
/// let (amt, src) = try!(socket.recv_from(&mut buf));
34+
///
35+
/// // Send a reply to the socket we received data from
36+
/// let buf = &mut buf[..amt];
37+
/// buf.reverse();
38+
/// try!(socket.send_to(buf, &src));
39+
///
40+
/// drop(socket); // close the socket
41+
/// # Ok(())
42+
/// # }
43+
/// ```
44+
pub struct UdpSocket(net_imp::UdpSocket);
45+
46+
impl UdpSocket {
47+
/// Creates a UDP socket from the given address.
48+
///
49+
/// Address type can be any implementor of `ToSocketAddr` trait. See its
50+
/// documentation for concrete examples.
51+
pub fn bind<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<UdpSocket> {
52+
super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
53+
}
54+
55+
/// Receives data from the socket. On success, returns the number of bytes
56+
/// read and the address from whence the data came.
57+
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
58+
self.0.recv_from(buf)
59+
}
60+
61+
/// Sends data on the socket to the given address. Returns nothing on
62+
/// success.
63+
///
64+
/// Address type can be any implementor of `ToSocketAddrs` trait. See its
65+
/// documentation for concrete examples.
66+
pub fn send_to<A: ToSocketAddrs + ?Sized>(&self, buf: &[u8], addr: &A)
67+
-> io::Result<usize> {
68+
match try!(addr.to_socket_addrs()).next() {
69+
Some(addr) => self.0.send_to(buf, &addr),
70+
None => Err(Error::new(ErrorKind::InvalidInput,
71+
"no addresses to send data to", None)),
72+
}
73+
}
74+
75+
/// Returns the socket address that this socket was created from.
76+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
77+
self.0.socket_addr()
78+
}
79+
80+
/// Create a new independently owned handle to the underlying socket.
81+
///
82+
/// The returned `UdpSocket` is a reference to the same socket that this
83+
/// object references. Both handles will read and write the same port, and
84+
/// options set on one socket will be propagated to the other.
85+
pub fn try_clone(&self) -> io::Result<UdpSocket> {
86+
self.0.duplicate().map(UdpSocket)
87+
}
88+
89+
/// Sets the broadcast flag on or off
90+
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
91+
self.0.set_broadcast(on)
92+
}
93+
94+
/// Set the multicast loop flag to the specified value
95+
///
96+
/// This lets multicast packets loop back to local sockets (if enabled)
97+
pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
98+
self.0.set_multicast_loop(on)
99+
}
100+
101+
/// Joins a multicast IP address (becomes a member of it)
102+
pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
103+
self.0.join_multicast(multi)
104+
}
105+
106+
/// Leaves a multicast IP address (drops membership from it)
107+
pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
108+
self.0.leave_multicast(multi)
109+
}
110+
111+
/// Sets the multicast TTL
112+
pub fn set_multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
113+
self.0.multicast_time_to_live(ttl)
114+
}
115+
116+
/// Sets this socket's TTL
117+
pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
118+
self.0.time_to_live(ttl)
119+
}
120+
}
121+
122+
impl AsInner<net_imp::UdpSocket> for UdpSocket {
123+
fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
124+
}
125+
126+
#[cfg(test)]
127+
mod tests {
128+
use prelude::v1::*;
129+
130+
use io::ErrorKind;
131+
use net::*;
132+
use net::test::{next_test_ip4, next_test_ip6};
133+
use sync::mpsc::channel;
134+
use thread::Thread;
135+
136+
fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
137+
f(next_test_ip4(), next_test_ip4());
138+
f(next_test_ip6(), next_test_ip6());
139+
}
140+
141+
macro_rules! t {
142+
($e:expr) => {
143+
match $e {
144+
Ok(t) => t,
145+
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
146+
}
147+
}
148+
}
149+
150+
// FIXME #11530 this fails on android because tests are run as root
151+
#[cfg_attr(any(windows, target_os = "android"), ignore)]
152+
#[test]
153+
fn bind_error() {
154+
let addr = SocketAddr::new(IpAddr::new_v4(0, 0, 0, 0), 1);
155+
match UdpSocket::bind(&addr) {
156+
Ok(..) => panic!(),
157+
Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied),
158+
}
159+
}
160+
161+
#[test]
162+
fn socket_smoke_test_ip4() {
163+
each_ip(&mut |server_ip, client_ip| {
164+
let (tx1, rx1) = channel();
165+
let (tx2, rx2) = channel();
166+
167+
let _t = Thread::spawn(move|| {
168+
let client = t!(UdpSocket::bind(&client_ip));
169+
rx1.recv().unwrap();
170+
t!(client.send_to(&[99], &server_ip));
171+
tx2.send(()).unwrap();
172+
});
173+
174+
let server = t!(UdpSocket::bind(&server_ip));
175+
tx1.send(()).unwrap();
176+
let mut buf = [0];
177+
let (nread, src) = t!(server.recv_from(&mut buf));
178+
assert_eq!(nread, 1);
179+
assert_eq!(buf[0], 99);
180+
assert_eq!(src, client_ip);
181+
rx2.recv().unwrap();
182+
})
183+
}
184+
185+
#[test]
186+
fn socket_name_ip4() {
187+
each_ip(&mut |addr, _| {
188+
let server = t!(UdpSocket::bind(&addr));
189+
assert_eq!(addr, t!(server.socket_addr()));
190+
})
191+
}
192+
193+
#[test]
194+
fn udp_clone_smoke() {
195+
each_ip(&mut |addr1, addr2| {
196+
let sock1 = t!(UdpSocket::bind(&addr1));
197+
let sock2 = t!(UdpSocket::bind(&addr2));
198+
199+
let _t = Thread::spawn(move|| {
200+
let mut buf = [0, 0];
201+
assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1)));
202+
assert_eq!(buf[0], 1);
203+
t!(sock2.send_to(&[2], &addr1));
204+
});
205+
206+
let sock3 = t!(sock1.try_clone());
207+
208+
let (tx1, rx1) = channel();
209+
let (tx2, rx2) = channel();
210+
let _t = Thread::spawn(move|| {
211+
rx1.recv().unwrap();
212+
t!(sock3.send_to(&[1], &addr2));
213+
tx2.send(()).unwrap();
214+
});
215+
tx1.send(()).unwrap();
216+
let mut buf = [0, 0];
217+
assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2)));
218+
rx2.recv().unwrap();
219+
})
220+
}
221+
222+
#[test]
223+
fn udp_clone_two_read() {
224+
each_ip(&mut |addr1, addr2| {
225+
let sock1 = t!(UdpSocket::bind(&addr1));
226+
let sock2 = t!(UdpSocket::bind(&addr2));
227+
let (tx1, rx) = channel();
228+
let tx2 = tx1.clone();
229+
230+
let _t = Thread::spawn(move|| {
231+
t!(sock2.send_to(&[1], &addr1));
232+
rx.recv().unwrap();
233+
t!(sock2.send_to(&[2], &addr1));
234+
rx.recv().unwrap();
235+
});
236+
237+
let sock3 = t!(sock1.try_clone());
238+
239+
let (done, rx) = channel();
240+
let _t = Thread::spawn(move|| {
241+
let mut buf = [0, 0];
242+
t!(sock3.recv_from(&mut buf));
243+
tx2.send(()).unwrap();
244+
done.send(()).unwrap();
245+
});
246+
let mut buf = [0, 0];
247+
t!(sock1.recv_from(&mut buf));
248+
tx1.send(()).unwrap();
249+
250+
rx.recv().unwrap();
251+
})
252+
}
253+
254+
#[test]
255+
fn udp_clone_two_write() {
256+
each_ip(&mut |addr1, addr2| {
257+
let sock1 = t!(UdpSocket::bind(&addr1));
258+
let sock2 = t!(UdpSocket::bind(&addr2));
259+
260+
let (tx, rx) = channel();
261+
let (serv_tx, serv_rx) = channel();
262+
263+
let _t = Thread::spawn(move|| {
264+
let mut buf = [0, 1];
265+
rx.recv().unwrap();
266+
t!(sock2.recv_from(&mut buf));
267+
serv_tx.send(()).unwrap();
268+
});
269+
270+
let sock3 = t!(sock1.try_clone());
271+
272+
let (done, rx) = channel();
273+
let tx2 = tx.clone();
274+
let _t = Thread::spawn(move|| {
275+
match sock3.send_to(&[1], &addr2) {
276+
Ok(..) => { let _ = tx2.send(()); }
277+
Err(..) => {}
278+
}
279+
done.send(()).unwrap();
280+
});
281+
match sock1.send_to(&[2], &addr2) {
282+
Ok(..) => { let _ = tx.send(()); }
283+
Err(..) => {}
284+
}
285+
drop(tx);
286+
287+
rx.recv().unwrap();
288+
serv_rx.recv().unwrap();
289+
})
290+
}
291+
}

‎src/libstd/sys/common/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub mod condvar;
2424
pub mod helper_thread;
2525
pub mod mutex;
2626
pub mod net;
27+
pub mod net2;
2728
pub mod rwlock;
2829
pub mod stack;
2930
pub mod thread;

‎src/libstd/sys/common/net2.rs‎

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use prelude::v1::*;
12+
13+
use ffi::CString;
14+
use io::{self, Error, ErrorKind};
15+
use libc::{self, c_int, c_char, c_void, socklen_t};
16+
use mem;
17+
use net::{IpAddr, SocketAddr, Shutdown};
18+
use num::Int;
19+
use sys::c;
20+
use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
21+
use sys_common::{AsInner, FromInner, IntoInner};
22+
23+
////////////////////////////////////////////////////////////////////////////////
24+
// sockaddr and misc bindings
25+
////////////////////////////////////////////////////////////////////////////////
26+
27+
fn hton<I: Int>(i: I) -> I { i.to_be() }
28+
fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
29+
30+
fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
31+
payload: T) -> io::Result<()> {
32+
unsafe {
33+
let payload = &payload as *const T as *const c_void;
34+
try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload,
35+
mem::size_of::<T>() as socklen_t)));
36+
Ok(())
37+
}
38+
}
39+
40+
#[allow(dead_code)]
41+
fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
42+
val: c_int) -> io::Result<T> {
43+
unsafe {
44+
let mut slot: T = mem::zeroed();
45+
let mut len = mem::size_of::<T>() as socklen_t;
46+
let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
47+
&mut slot as *mut _ as *mut _,
48+
&mut len)));
49+
assert_eq!(ret as usize, mem::size_of::<T>());
50+
Ok(slot)
51+
}
52+
}
53+
54+
fn sockname<F>(f: F) -> io::Result<SocketAddr>
55+
where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int
56+
{
57+
unsafe {
58+
let mut storage: libc::sockaddr_storage = mem::zeroed();
59+
let mut len = mem::size_of_val(&storage) as socklen_t;
60+
try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len)));
61+
sockaddr_to_addr(&storage, len as usize)
62+
}
63+
}
64+
65+
fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
66+
len: usize) -> io::Result<SocketAddr> {
67+
match storage.ss_family as libc::c_int {
68+
libc::AF_INET => {
69+
assert!(len as usize >= mem::size_of::<libc::sockaddr_in>());
70+
Ok(FromInner::from_inner(unsafe {
71+
*(storage as *const _ as *const libc::sockaddr_in)
72+
}))
73+
}
74+
libc::AF_INET6 => {
75+
assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>());
76+
Ok(FromInner::from_inner(unsafe {
77+
*(storage as *const _ as *const libc::sockaddr_in6)
78+
}))
79+
}
80+
_ => {
81+
Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None))
82+
}
83+
}
84+
}
85+
86+
////////////////////////////////////////////////////////////////////////////////
87+
// get_host_addresses
88+
////////////////////////////////////////////////////////////////////////////////
89+
90+
extern "system" {
91+
fn getaddrinfo(node: *const c_char, service: *const c_char,
92+
hints: *const libc::addrinfo,
93+
res: *mut *mut libc::addrinfo) -> c_int;
94+
fn freeaddrinfo(res: *mut libc::addrinfo);
95+
}
96+
97+
pub struct LookupHost {
98+
original: *mut libc::addrinfo,
99+
cur: *mut libc::addrinfo,
100+
}
101+
102+
impl Iterator for LookupHost {
103+
type Item = io::Result<SocketAddr>;
104+
fn next(&mut self) -> Option<io::Result<SocketAddr>> {
105+
unsafe {
106+
if self.cur.is_null() { return None }
107+
let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr),
108+
(*self.cur).ai_addrlen as usize);
109+
self.cur = (*self.cur).ai_next as *mut libc::addrinfo;
110+
Some(ret)
111+
}
112+
}
113+
}
114+
115+
impl Drop for LookupHost {
116+
fn drop(&mut self) {
117+
unsafe { freeaddrinfo(self.original) }
118+
}
119+
}
120+
121+
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
122+
init();
123+
124+
let c_host = CString::from_slice(host.as_bytes());
125+
let mut res = 0 as *mut _;
126+
unsafe {
127+
try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _,
128+
&mut res)));
129+
Ok(LookupHost { original: res, cur: res })
130+
}
131+
}
132+
133+
////////////////////////////////////////////////////////////////////////////////
134+
// TCP streams
135+
////////////////////////////////////////////////////////////////////////////////
136+
137+
pub struct TcpStream {
138+
inner: Socket,
139+
}
140+
141+
impl TcpStream {
142+
pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
143+
init();
144+
145+
let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
146+
147+
let (addrp, len) = addr.into_inner();
148+
try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) }));
149+
Ok(TcpStream { inner: sock })
150+
}
151+
152+
pub fn socket(&self) -> &Socket { &self.inner }
153+
154+
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
155+
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY,
156+
nodelay as c_int)
157+
}
158+
159+
pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
160+
let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE,
161+
seconds.is_some() as c_int);
162+
match seconds {
163+
Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
164+
None => ret,
165+
}
166+
}
167+
168+
#[cfg(any(target_os = "macos", target_os = "ios"))]
169+
fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
170+
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
171+
seconds as c_int)
172+
}
173+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
174+
fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
175+
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
176+
seconds as c_int)
177+
}
178+
#[cfg(not(any(target_os = "macos",
179+
target_os = "ios",
180+
target_os = "freebsd",
181+
target_os = "dragonfly")))]
182+
fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
183+
Ok(())
184+
}
185+
186+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
187+
self.inner.read(buf)
188+
}
189+
190+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
191+
let ret = try!(cvt(unsafe {
192+
libc::send(*self.inner.as_inner(),
193+
buf.as_ptr() as *const c_void,
194+
buf.len() as wrlen_t,
195+
0)
196+
}));
197+
Ok(ret as usize)
198+
}
199+
200+
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
201+
sockname(|buf, len| unsafe {
202+
libc::getpeername(*self.inner.as_inner(), buf, len)
203+
})
204+
}
205+
206+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
207+
sockname(|buf, len| unsafe {
208+
libc::getsockname(*self.inner.as_inner(), buf, len)
209+
})
210+
}
211+
212+
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
213+
use libc::consts::os::bsd44::SHUT_RDWR;
214+
215+
let how = match how {
216+
Shutdown::Write => libc::SHUT_WR,
217+
Shutdown::Read => libc::SHUT_RD,
218+
Shutdown::Both => SHUT_RDWR,
219+
};
220+
try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) }));
221+
Ok(())
222+
}
223+
224+
pub fn duplicate(&self) -> io::Result<TcpStream> {
225+
self.inner.duplicate().map(|s| TcpStream { inner: s })
226+
}
227+
}
228+
229+
////////////////////////////////////////////////////////////////////////////////
230+
// TCP listeners
231+
////////////////////////////////////////////////////////////////////////////////
232+
233+
pub struct TcpListener {
234+
inner: Socket,
235+
}
236+
237+
impl TcpListener {
238+
pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
239+
init();
240+
241+
let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
242+
243+
// On platforms with Berkeley-derived sockets, this allows
244+
// to quickly rebind a socket, without needing to wait for
245+
// the OS to clean up the previous one.
246+
if !cfg!(windows) {
247+
try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR,
248+
1 as c_int));
249+
}
250+
251+
// Bind our new socket
252+
let (addrp, len) = addr.into_inner();
253+
try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
254+
255+
// Start listening
256+
try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) }));
257+
Ok(TcpListener { inner: sock })
258+
}
259+
260+
pub fn socket(&self) -> &Socket { &self.inner }
261+
262+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
263+
sockname(|buf, len| unsafe {
264+
libc::getsockname(*self.inner.as_inner(), buf, len)
265+
})
266+
}
267+
268+
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
269+
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
270+
let mut len = mem::size_of_val(&storage) as socklen_t;
271+
let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _,
272+
&mut len));
273+
let addr = try!(sockaddr_to_addr(&storage, len as usize));
274+
Ok((TcpStream { inner: sock, }, addr))
275+
}
276+
277+
pub fn duplicate(&self) -> io::Result<TcpListener> {
278+
self.inner.duplicate().map(|s| TcpListener { inner: s })
279+
}
280+
}
281+
282+
////////////////////////////////////////////////////////////////////////////////
283+
// UDP
284+
////////////////////////////////////////////////////////////////////////////////
285+
286+
pub struct UdpSocket {
287+
inner: Socket,
288+
}
289+
290+
impl UdpSocket {
291+
pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
292+
init();
293+
294+
let sock = try!(Socket::new(addr, libc::SOCK_DGRAM));
295+
let (addrp, len) = addr.into_inner();
296+
try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
297+
Ok(UdpSocket { inner: sock })
298+
}
299+
300+
pub fn socket(&self) -> &Socket { &self.inner }
301+
302+
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
303+
sockname(|buf, len| unsafe {
304+
libc::getsockname(*self.inner.as_inner(), buf, len)
305+
})
306+
}
307+
308+
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
309+
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
310+
let mut addrlen = mem::size_of_val(&storage) as socklen_t;
311+
312+
let n = try!(cvt(unsafe {
313+
libc::recvfrom(*self.inner.as_inner(),
314+
buf.as_mut_ptr() as *mut c_void,
315+
buf.len() as wrlen_t, 0,
316+
&mut storage as *mut _ as *mut _, &mut addrlen)
317+
}));
318+
Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize))))
319+
}
320+
321+
pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
322+
let (dstp, dstlen) = dst.into_inner();
323+
let ret = try!(cvt(unsafe {
324+
libc::sendto(*self.inner.as_inner(),
325+
buf.as_ptr() as *const c_void, buf.len() as wrlen_t,
326+
0, dstp, dstlen)
327+
}));
328+
Ok(ret as usize)
329+
}
330+
331+
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
332+
setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST,
333+
on as c_int)
334+
}
335+
336+
pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
337+
setsockopt(&self.inner, libc::IPPROTO_IP,
338+
libc::IP_MULTICAST_LOOP, on as c_int)
339+
}
340+
341+
pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
342+
match *multi {
343+
IpAddr::V4(..) => {
344+
self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
345+
}
346+
IpAddr::V6(..) => {
347+
self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
348+
}
349+
}
350+
}
351+
pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
352+
match *multi {
353+
IpAddr::V4(..) => {
354+
self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
355+
}
356+
IpAddr::V6(..) => {
357+
self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
358+
}
359+
}
360+
}
361+
fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
362+
match *addr {
363+
IpAddr::V4(ref addr) => {
364+
let mreq = libc::ip_mreq {
365+
imr_multiaddr: *addr.as_inner(),
366+
// interface == INADDR_ANY
367+
imr_interface: libc::in_addr { s_addr: 0x0 },
368+
};
369+
setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
370+
}
371+
IpAddr::V6(ref addr) => {
372+
let mreq = libc::ip6_mreq {
373+
ipv6mr_multiaddr: *addr.as_inner(),
374+
ipv6mr_interface: 0,
375+
};
376+
setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)
377+
}
378+
}
379+
}
380+
381+
pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
382+
setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
383+
ttl as c_int)
384+
}
385+
386+
pub fn time_to_live(&self, ttl: i32) -> io::Result<()> {
387+
setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int)
388+
}
389+
390+
pub fn duplicate(&self) -> io::Result<UdpSocket> {
391+
self.inner.duplicate().map(|s| UdpSocket { inner: s })
392+
}
393+
}

‎src/libstd/sys/unix/c.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ extern {
157157

158158
pub fn utimes(filename: *const libc::c_char,
159159
times: *const libc::timeval) -> libc::c_int;
160+
pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
160161
}
161162

162163
#[cfg(any(target_os = "macos", target_os = "ios"))]

‎src/libstd/sys/unix/ext.rs‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
#![unstable(feature = "std_misc")]
3333

3434
use ffi::{OsStr, OsString};
35-
use fs::{Permissions, OpenOptions};
36-
use fs;
35+
use fs::{self, Permissions, OpenOptions};
36+
use net;
3737
use libc;
3838
use mem;
3939
use sys::os_str::Buf;
@@ -111,6 +111,16 @@ impl AsRawFd for old_io::net::udp::UdpSocket {
111111
}
112112
}
113113

114+
impl AsRawFd for net::TcpStream {
115+
fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
116+
}
117+
impl AsRawFd for net::TcpListener {
118+
fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
119+
}
120+
impl AsRawFd for net::UdpSocket {
121+
fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
122+
}
123+
114124
// Unix-specific extensions to `OsString`.
115125
pub trait OsStringExt {
116126
/// Create an `OsString` from a byte vector.

‎src/libstd/sys/unix/fd.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ use io;
1515
use libc::{self, c_int, size_t, c_void};
1616
use mem;
1717
use sys::cvt;
18-
19-
pub type fd_t = c_int;
18+
use sys_common::AsInner;
2019

2120
pub struct FileDesc {
2221
fd: c_int,
@@ -55,6 +54,10 @@ impl FileDesc {
5554
}
5655
}
5756

57+
impl AsInner<c_int> for FileDesc {
58+
fn as_inner(&self) -> &c_int { &self.fd }
59+
}
60+
5861
impl Drop for FileDesc {
5962
fn drop(&mut self) {
6063
// closing stdio file handles makes no sense, so never do it. Also, note

‎src/libstd/sys/unix/mod.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@
1818
use prelude::v1::*;
1919

2020
use ffi;
21-
use io::ErrorKind;
21+
use io::{self, ErrorKind};
2222
use libc;
2323
use num::{Int, SignedInt};
2424
use num;
2525
use old_io::{self, IoResult, IoError};
26-
use io;
2726
use str;
2827
use sys_common::mkerr_libc;
2928

@@ -47,6 +46,7 @@ pub mod fs; // support for std::old_io
4746
pub mod fs2; // support for std::fs
4847
pub mod helper_signal;
4948
pub mod mutex;
49+
pub mod net;
5050
pub mod os;
5151
pub mod os_str;
5252
pub mod pipe;

‎src/libstd/sys/unix/net.rs‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use prelude::v1::*;
12+
13+
use ffi;
14+
use io;
15+
use libc::{self, c_int, size_t};
16+
use str;
17+
use sys::c;
18+
use net::{SocketAddr, IpAddr};
19+
use sys::fd::FileDesc;
20+
use sys_common::AsInner;
21+
22+
pub use sys::{cvt, cvt_r};
23+
24+
pub type wrlen_t = size_t;
25+
26+
pub struct Socket(FileDesc);
27+
28+
pub fn init() {}
29+
30+
pub fn cvt_gai(err: c_int) -> io::Result<()> {
31+
if err == 0 { return Ok(()) }
32+
33+
let detail = unsafe {
34+
str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap()
35+
.to_string()
36+
};
37+
Err(io::Error::new(io::ErrorKind::Other,
38+
"failed to lookup address information", Some(detail)))
39+
}
40+
41+
impl Socket {
42+
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
43+
let fam = match addr.ip() {
44+
IpAddr::V4(..) => libc::AF_INET,
45+
IpAddr::V6(..) => libc::AF_INET6,
46+
};
47+
unsafe {
48+
let fd = try!(cvt(libc::socket(fam, ty, 0)));
49+
Ok(Socket(FileDesc::new(fd)))
50+
}
51+
}
52+
53+
pub fn accept(&self, storage: *mut libc::sockaddr,
54+
len: *mut libc::socklen_t) -> io::Result<Socket> {
55+
let fd = try!(cvt_r(|| unsafe {
56+
libc::accept(self.0.raw(), storage, len)
57+
}));
58+
Ok(Socket(FileDesc::new(fd)))
59+
}
60+
61+
pub fn duplicate(&self) -> io::Result<Socket> {
62+
cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| {
63+
Socket(FileDesc::new(fd))
64+
})
65+
}
66+
67+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
68+
self.0.read(buf)
69+
}
70+
}
71+
72+
impl AsInner<c_int> for Socket {
73+
fn as_inner(&self) -> &c_int { self.0.as_inner() }
74+
}

‎src/libstd/sys/windows/ext.rs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub use sys_common::wtf8::{Wtf8Buf, EncodeWide};
2121
use ffi::{OsStr, OsString};
2222
use fs::{self, OpenOptions};
2323
use libc;
24+
use net;
2425
use sys::os_str::Buf;
2526
use sys_common::{AsInner, FromInner, AsInnerMut};
2627

@@ -103,6 +104,16 @@ impl AsRawSocket for old_io::net::udp::UdpSocket {
103104
}
104105
}
105106

107+
impl AsRawSocket for net::TcpStream {
108+
fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
109+
}
110+
impl AsRawSocket for net::TcpListener {
111+
fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
112+
}
113+
impl AsRawSocket for net::UdpSocket {
114+
fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
115+
}
116+
106117
// Windows-specific extensions to `OsString`.
107118
pub trait OsStringExt {
108119
/// Create an `OsString` from a potentially ill-formed UTF-16 slice of 16-bit code units.

‎src/libstd/sys/windows/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub mod fs2;
4343
pub mod handle;
4444
pub mod helper_signal;
4545
pub mod mutex;
46+
pub mod net;
4647
pub mod os;
4748
pub mod os_str;
4849
pub mod pipe;

‎src/libstd/sys/windows/net.rs‎

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use prelude::v1::*;
12+
13+
use io;
14+
use libc::consts::os::extra::INVALID_SOCKET;
15+
use libc::{self, c_int, c_void};
16+
use mem;
17+
use net::{SocketAddr, IpAddr};
18+
use num::{SignedInt, Int};
19+
use rt;
20+
use sync::{Once, ONCE_INIT};
21+
use sys::c;
22+
use sys_common::AsInner;
23+
24+
pub type wrlen_t = i32;
25+
26+
pub struct Socket(libc::SOCKET);
27+
28+
pub fn init() {
29+
static START: Once = ONCE_INIT;
30+
31+
START.call_once(|| unsafe {
32+
let mut data: c::WSADATA = mem::zeroed();
33+
let ret = c::WSAStartup(0x202, // version 2.2
34+
&mut data);
35+
assert_eq!(ret, 0);
36+
37+
rt::at_exit(|| { c::WSACleanup(); })
38+
});
39+
}
40+
41+
fn last_error() -> io::Error {
42+
io::Error::from_os_error(unsafe { c::WSAGetLastError() })
43+
}
44+
45+
pub fn cvt<T: SignedInt>(t: T) -> io::Result<T> {
46+
let one: T = Int::one();
47+
if t == -one {
48+
Err(last_error())
49+
} else {
50+
Ok(t)
51+
}
52+
}
53+
54+
pub fn cvt_gai(err: c_int) -> io::Result<()> {
55+
if err == 0 { return Ok(()) }
56+
cvt(err).map(|_| ())
57+
}
58+
59+
pub fn cvt_r<T: SignedInt, F>(mut f: F) -> io::Result<T> where F: FnMut() -> T {
60+
cvt(f())
61+
}
62+
63+
impl Socket {
64+
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
65+
let fam = match addr.ip {
66+
IpAddr::V4(..) => libc::AF_INET,
67+
IpAddr::V6(..) => libc::AF_INET6,
68+
};
69+
match unsafe { libc::socket(fam, ty, 0) } {
70+
INVALID_SOCKET => Err(last_error()),
71+
n => Ok(Socket(n)),
72+
}
73+
}
74+
75+
pub fn accept(&self, storage: *mut libc::sockaddr,
76+
len: *mut libc::socklen_t) -> io::Result<Socket> {
77+
match unsafe { libc::accept(self.0, storage, len) } {
78+
INVALID_SOCKET => Err(last_error()),
79+
n => Ok(Socket(n)),
80+
}
81+
}
82+
83+
pub fn duplicate(&self) -> io::Result<Socket> {
84+
unsafe {
85+
let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
86+
try!(cvt(c::WSADuplicateSocketW(self.0,
87+
c::GetCurrentProcessId(),
88+
&mut info)));
89+
match c::WSASocketW(info.iAddressFamily,
90+
info.iSocketType,
91+
info.iProtocol,
92+
&mut info, 0, 0) {
93+
INVALID_SOCKET => Err(last_error()),
94+
n => Ok(Socket(n)),
95+
}
96+
}
97+
}
98+
99+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
100+
// On unix when a socket is shut down all further reads return 0, so we
101+
// do the same on windows to map a shut down socket to returning EOF.
102+
unsafe {
103+
match libc::recv(self.0, buf.as_mut_ptr() as *mut c_void,
104+
buf.len() as i32, 0) {
105+
-1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
106+
-1 => Err(last_error()),
107+
n => Ok(n as usize)
108+
}
109+
}
110+
}
111+
}
112+
113+
impl Drop for Socket {
114+
fn drop(&mut self) {
115+
unsafe { let _ = libc::closesocket(self.0); }
116+
}
117+
}
118+
119+
impl AsInner<libc::SOCKET> for Socket {
120+
fn as_inner(&self) -> &libc::SOCKET { &self.0 }
121+
}

0 commit comments

Comments
 (0)
This repository has been archived.