From 8d1fa487e54892e82e134ee526873e0ad4b81e25 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 19:56:29 +0000 Subject: [PATCH 01/54] Add low level support for polling arbitary file descriptors with libuv. --- src/librustuv/uvll.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index eefccf05a542c..745c33b013cab 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -104,6 +104,9 @@ pub struct uv_buf_t { len: uv_buf_len_t, } +#[cfg(unix)] +pub type uv_os_socket = c_int; + // see libuv/include/uv-win.h #[cfg(windows)] pub struct uv_buf_t { @@ -111,6 +114,9 @@ pub struct uv_buf_t { base: *u8, } +#[cfg(windows)] +pub type uv_os_socket = libc::SOCKET; + #[repr(C)] pub enum uv_run_mode { RUN_DEFAULT = 0, @@ -118,6 +124,12 @@ pub enum uv_run_mode { RUN_NOWAIT, } +#[repr(C)] +pub enum uv_poll_event { + UV_READABLE = 1, + UV_WRITABLE = 2, +} + pub struct uv_process_options_t { exit_cb: uv_exit_cb, file: *libc::c_char, @@ -144,6 +156,7 @@ pub type uv_loop_t = c_void; pub type uv_idle_t = c_void; pub type uv_tcp_t = c_void; pub type uv_udp_t = c_void; +pub type uv_poll_t = c_void; pub type uv_connect_t = c_void; pub type uv_connection_t = c_void; pub type uv_write_t = c_void; @@ -227,6 +240,9 @@ pub type uv_udp_recv_cb = extern "C" fn(handle: *uv_udp_t, addr: *sockaddr, flags: c_uint); pub type uv_close_cb = extern "C" fn(handle: *uv_handle_t); +pub type uv_poll_cb = extern "C" fn(handle: *uv_poll_t, + status: c_int, + events: c_int); pub type uv_walk_cb = extern "C" fn(handle: *uv_handle_t, arg: *c_void); pub type uv_async_cb = extern "C" fn(handle: *uv_async_t, @@ -697,6 +713,11 @@ extern { pub fn uv_fs_lstat(handle: *uv_loop_t, req: *uv_fs_t, file: *c_char, cb: uv_fs_cb) -> c_int; + // poll bindings + pub fn uv_poll_init_socket(l: *uv_loop_t, h: *uv_poll_t, s: uv_os_socket) -> c_int; + pub fn uv_poll_start(h: *uv_poll_t, events: c_int, cb: uv_poll_cb) -> c_int; + pub fn uv_poll_stop(h: *uv_poll_t) -> c_int; + // getaddrinfo pub fn uv_getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t, getaddrinfo_cb: uv_getaddrinfo_cb, From 99eb9fd4e09b4691e37ee67f92d9c6b4241091b9 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 19:58:46 +0000 Subject: [PATCH 02/54] Add support for passing options to libc::fcntl(). fcntl() is a vararg function allowing many options to be passed. This commit adds support for a single argument, as well as adding some options which may be passed to it. --- src/libstd/libc.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 1cbaa5f06a67f..5a042b67c3de5 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2123,6 +2123,12 @@ pub mod consts { pub mod posix01 { use libc::types::os::arch::c95::c_int; + pub static F_DUPFD : c_int = 0; + pub static F_GETFD : c_int = 1; + pub static F_SETFD : c_int = 2; + pub static F_GETFL : c_int = 3; + pub static F_SETFL : c_int = 4; + pub static SIGTRAP : c_int = 5; pub static GLOB_ERR : c_int = 1 << 0; @@ -3449,7 +3455,7 @@ pub mod funcs { pub fn open(path: *c_char, oflag: c_int, mode: c_int) -> c_int; pub fn creat(path: *c_char, mode: mode_t) -> c_int; - pub fn fcntl(fd: c_int, cmd: c_int) -> c_int; + pub fn fcntl(fd: c_int, cmd: c_int, opt: c_int) -> c_int; } } From a7c72a5eb1976ae69547a48b3f0f3fc17bfb22e6 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 20:08:18 +0000 Subject: [PATCH 03/54] Add some constants to libc required for raw socket support. --- src/libstd/libc.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 5a042b67c3de5..c7ce81f7a5069 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2205,12 +2205,14 @@ pub mod consts { pub static AF_INET6: c_int = 10; pub static SOCK_STREAM: c_int = 1; pub static SOCK_DGRAM: c_int = 2; + pub static SOCK_RAW: c_int = 3; pub static IPPROTO_TCP: c_int = 6; pub static IPPROTO_IP: c_int = 0; pub static IPPROTO_IPV6: c_int = 41; pub static IP_MULTICAST_TTL: c_int = 33; pub static IP_MULTICAST_LOOP: c_int = 34; pub static IP_TTL: c_int = 2; + pub static IP_HDRINCL: c_int = 2; pub static IP_ADD_MEMBERSHIP: c_int = 35; pub static IP_DROP_MEMBERSHIP: c_int = 36; pub static IPV6_ADD_MEMBERSHIP: c_int = 20; @@ -2229,6 +2231,7 @@ pub mod consts { pub static O_RSYNC : c_int = 1052672; pub static O_DSYNC : c_int = 4096; + pub static O_NONBLOCK : c_int = 2048; pub static O_SYNC : c_int = 1052672; pub static PROT_GROWSDOWN : c_int = 0x010000000; @@ -3042,6 +3045,7 @@ pub mod consts { pub static O_DSYNC : c_int = 4194304; pub static O_SYNC : c_int = 128; + pub static O_NONBLOCK : c_int = 4; pub static F_FULLFSYNC : c_int = 51; pub static MAP_COPY : c_int = 0x0002; From 8cfb7e507505b50754a632b5f1187f6d93079bbb Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 20:13:26 +0000 Subject: [PATCH 04/54] Add raw socket support using libuv. Adds a new IoFactory method for creating a raw socket. Native/blocking implementation is stubbed out. Adds a RawSocketWatcher which creates a non-blocking raw socket using berkeley sockets. It registers the socket with libuv to handle reading and writing. When the socket is ready the sendto/recvfrom calls are used to handle sending. Note that Windows does not support raw sockets. --- src/libnative/io/mod.rs | 4 + src/librustuv/net.rs | 221 ++++++++++++++++++++++++++++++++++++++++ src/librustuv/uvio.rs | 10 +- src/libstd/rt/rtio.rs | 12 ++- 4 files changed, 245 insertions(+), 2 deletions(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index f1bec440547e1..0e4cad9b5b3a1 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -190,6 +190,10 @@ impl rtio::IoFactory for IoFactory { _hint: Option) -> IoResult<~[ai::Info]> { Err(unimpl()) } + fn raw_socket_new(&mut self, _domain: rtio::CommDomain, _protocol: rtio::Protocol, + _includeIpHeader: bool) -> IoResult<~rtio::RtioRawSocket> { + Err(unimpl()) + } // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index ee78585fcfd71..0c8c2b7d6da71 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -633,6 +633,227 @@ impl Drop for UdpWatcher { } } +//////////////////////////////////////////////////////////////////////////////// +/// Raw socket implementation +//////////////////////////////////////////////////////////////////////////////// + +pub struct RawSocketWatcher { + handle: *uvll::uv_poll_t, + socket: uvll::uv_os_socket, + home: HomeHandle, +} + +impl RawSocketWatcher { + pub fn new(io: &mut UvIoFactory, domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) + -> Result + { + let socket = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; + if socket == -1 { + return Err(uv_error_to_io_error(UvError(errno() as i32))); + } + if includeIpHeader { + let one: c_int = 1; + let proto = if domain == libc::AF_INET { libc::IPPROTO_IP } else { libc::IPPROTO_IPV6 }; + let res = unsafe { libc::setsockopt(socket, proto, libc::IP_HDRINCL, (&one as *c_int) as *c_void, intrinsics::size_of::() as u32) }; + if res == -1 { + return Err(uv_error_to_io_error(UvError(errno() as i32))); + } + } + // Make socket non-blocking + let flags = unsafe { libc::fcntl(socket, libc::F_GETFL, 0) }; + if (flags == -1) { + return Err(uv_error_to_io_error(UvError(errno() as i32))); + } + if unsafe { libc::fcntl(socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { + return Err(uv_error_to_io_error(UvError(errno() as i32))); + } + let raw = RawSocketWatcher { + handle: unsafe { uvll::malloc_handle(uvll::UV_POLL) }, + home: io.make_handle(), + socket: socket, + }; + + assert_eq!(unsafe { + uvll::uv_poll_init_socket(io.uv_loop(), raw.handle, socket) + }, 0); + return Ok(raw); + } +} + +impl UvHandle for RawSocketWatcher { + fn uv_handle(&self) -> *uvll::uv_poll_t { self.handle } +} + +impl Drop for RawSocketWatcher { + fn drop(&mut self) { + let _m = self.fire_homing_missile(); + self.close(); + } +} + +impl HomingIO for RawSocketWatcher { + fn home<'r>(&'r mut self) -> &'r mut HomeHandle { &mut self.home } +} + +impl rtio::RtioRawSocket for RawSocketWatcher { + fn recvfrom(&mut self, buf: &mut [u8]) + -> Result<(uint, SocketAddr), IoError> + { + let max: c_int = Bounded::max_value(); + assert!(buf.len() <= (max as uint)); + struct Ctx { + task: Option, + buf: Option, + result: Option<(ssize_t, Option)>, + socket: Option, + } + let _m = self.fire_homing_missile(); + let a = match unsafe { + uvll::uv_poll_start(self.handle, uvll::UV_READABLE as c_int, recv_cb) + } { + 0 => { + let mut cx = Ctx { + task: None, + buf: Some(slice_to_uv_buf(buf)), + result: None, + socket: Some(self.socket), + }; + wait_until_woken_after(&mut cx.task, || { + unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } + }); + match cx.result.take_unwrap() { + (n, _) if n < 0 => + Err(uv_error_to_io_error(UvError(n as c_int))), + (n, addr) => Ok((n as uint, addr.unwrap())) + } + } + n => Err(uv_error_to_io_error(UvError(n))) + }; + return a; + + extern fn recv_cb(handle: *uvll::uv_poll_t, status: c_int, events: c_int) { + assert!((events & (uvll::UV_READABLE as c_int)) != 0); + let cx: &mut Ctx = unsafe { + cast::transmute(uvll::get_data_for_uv_handle(handle)) + }; + + if status < 0 { + cx.result = Some((status as ssize_t, None)); + return; + } + + unsafe { + assert_eq!(uvll::uv_poll_stop(handle), 0) + } + + let mut caddr = unsafe { intrinsics::init::() }; + let mut caddrlen = unsafe { intrinsics::size_of::() } as libc::socklen_t; + let len = match (cx.socket, cx.buf) { + (Some(sock), Some(buf)) => unsafe { + libc::recvfrom(sock, + buf.base as *mut c_void, + buf.len, + 0, + (&mut caddr as *mut libc::sockaddr_storage) as *mut libc::sockaddr, + &mut caddrlen) + }, + _ => -1 + }; + if len == -1 { + cx.result = Some((errno() as ssize_t, None)); + return; + } + let addr = Some(sockaddr_to_socket_addr((&caddr as *libc::sockaddr_storage) as *uvll::sockaddr)); + cx.result = Some((len as ssize_t, addr)); + + wakeup(&mut cx.task); + } + } + + fn sendto(&mut self, buf: &[u8], dst: IpAddr) + -> Result + { + struct Ctx { + task: Option, + buf: Option, + result: Option, + socket: Option, + addr: IpAddr, + } + let _m = self.fire_homing_missile(); + + let a = match unsafe { + uvll::uv_poll_start(self.handle, uvll::UV_WRITABLE as c_int, send_cb) + } { + 0 => { + let mut cx = Ctx { + task: None, + buf: Some(slice_to_uv_buf(buf)), + result: None, + socket: Some(self.socket), + addr: dst + }; + wait_until_woken_after(&mut cx.task, || { + unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } + }); + match cx.result.take_unwrap() { + n if n < 0 => + Err(uv_error_to_io_error(UvError(n as c_int))), + n => Ok(n) + } + } + n => Err(uv_error_to_io_error(UvError(n))) + }; + return a; + + extern fn send_cb(handle: *uvll::uv_poll_t, status: c_int, events: c_int) { + assert!((events & (uvll::UV_WRITABLE as c_int)) != 0); + let cx: &mut Ctx = unsafe { + cast::transmute(uvll::get_data_for_uv_handle(handle)) + }; + if status < 0 { + cx.result = Some(status as ssize_t); + return; + } + + unsafe { + assert_eq!(uvll::uv_poll_stop(handle), 0) + } + + let len = match (cx.socket, cx.buf) { + (Some(sock), Some(buf)) => socket_addr_as_sockaddr(SocketAddr{ ip: cx.addr, port: 0 }, |addr| { + unsafe { + if match cx.addr { Ipv4Addr(..) => true, Ipv6Addr(..) => false } { + libc::sendto(sock, + buf.base as *c_void, + buf.len, + 0, + addr as *libc::sockaddr, + intrinsics::size_of::() as libc::socklen_t) + } else { + libc::sendto(sock, + buf.base as *c_void, + buf.len, + 0, + addr as *libc::sockaddr, + intrinsics::size_of::() as libc::socklen_t) + } + } + }), + _ => -1 + }; + + cx.result = if len < 0 { + Some(errno() as ssize_t) + } else { + Some(len) + }; + + wakeup(&mut cx.task); + } + } +} + #[cfg(test)] mod test { use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioTcpAcceptor, diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index dbf129d0b699c..da015b672ea6b 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -37,7 +37,7 @@ use file::{FsRequest, FileWatcher}; use queue::QueuePool; use homing::HomeHandle; use idle::IdleWatcher; -use net::{TcpWatcher, TcpListener, UdpWatcher}; +use net::{RawSocketWatcher, TcpWatcher, TcpListener, UdpWatcher}; use pipe::{PipeWatcher, PipeListener}; use process::Process; use signal::SignalWatcher; @@ -176,6 +176,14 @@ impl IoFactory for UvIoFactory { r.map_err(uv_error_to_io_error) } + fn raw_socket_new(&mut self, domain: rtio::CommDomain, protocol: rtio::Protocol, + includeIpHeader: bool) -> Result<~rtio::RtioRawSocket, IoError> { + match RawSocketWatcher::new(self, domain, protocol, includeIpHeader) { + Ok(r) => Ok(~r as ~rtio::RtioRawSocket), + Err(e) => Err(e), + } + } + fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior) -> ~rtio::RtioFileStream { ~FileWatcher::new(self, fd, close) as ~rtio::RtioFileStream diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 6b3d50a76ac8f..6246ae4ecb171 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -11,7 +11,7 @@ use c_str::CString; use cast; use comm::{SharedChan, Port}; -use libc::c_int; +use libc::{c_int, ssize_t}; use libc; use ops::Drop; use option::{Option, Some, None}; @@ -151,6 +151,9 @@ impl<'a> LocalIo<'a> { } } +pub type CommDomain = c_int; +pub type Protocol = c_int; + pub trait IoFactory { // networking fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; @@ -161,6 +164,8 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; + fn raw_socket_new(&mut self, domain: CommDomain, protocol: Protocol, + includeIpHeader: bool) -> Result<~RtioRawSocket, IoError>; // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; @@ -237,6 +242,11 @@ pub trait RtioUdpSocket : RtioSocket { fn ignore_broadcasts(&mut self) -> Result<(), IoError>; } +pub trait RtioRawSocket { + fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError>; + fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result; +} + pub trait RtioTimer { fn sleep(&mut self, msecs: u64); fn oneshot(&mut self, msecs: u64) -> Port<()>; From 0545404df4da958e997b67ef0d5b779acdcf588e Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 20:27:24 +0000 Subject: [PATCH 05/54] Add libstd support for raw sockets. This is a small weapper around the functionality provided by IoFactory and very similar to std::io::net::udp. --- src/libstd/io/net/mod.rs | 3 +++ src/libstd/io/net/raw.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/libstd/io/net/raw.rs diff --git a/src/libstd/io/net/mod.rs b/src/libstd/io/net/mod.rs index cf109167089d4..6d851560122a2 100644 --- a/src/libstd/io/net/mod.rs +++ b/src/libstd/io/net/mod.rs @@ -14,5 +14,8 @@ pub mod addrinfo; pub mod tcp; pub mod udp; pub mod ip; +// Windows does not support Raw sockets +#[cfg(unix)] +pub mod raw; #[cfg(unix)] pub mod unix; diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs new file mode 100644 index 0000000000000..acc3117186ba4 --- /dev/null +++ b/src/libstd/io/net/raw.rs @@ -0,0 +1,47 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use option::{Option, Some, None}; +use result::{Ok, Err}; +use io::net::ip::{IpAddr, SocketAddr}; +use io::{io_error, EndOfFile}; +use rt::rtio::{IoFactory, LocalIo, RtioRawSocket, Protocol, CommDomain}; + +pub struct RawSocket { + priv obj: ~RtioRawSocket +} + +impl RawSocket { + pub fn new(domain: CommDomain, protocol: Protocol, includeIpHeader: bool) -> Option { + LocalIo::maybe_raise(|io| { + io.raw_socket_new(domain, protocol, includeIpHeader).map(|s| RawSocket { obj: s }) + }) + } + + pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> { + match self.obj.recvfrom(buf) { + Ok((nread, src)) => Some((nread, src)), + Err(ioerr) => { + // EOF is indicated by returning None + if ioerr.kind != EndOfFile { + io_error::cond.raise(ioerr); + } + None + } + } + } + + pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) { + match self.obj.sendto(buf, dst) { + Ok(_) => (), + Err(ioerr) => io_error::cond.raise(ioerr), + } + } +} From 167d52bfec5dd61a3b55c622ee3189b62fa29753 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 20:47:21 +0000 Subject: [PATCH 06/54] Add missing constants for FreeBSD and OS X. --- src/libstd/libc.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index c7ce81f7a5069..957dd00075b5a 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2648,12 +2648,14 @@ pub mod consts { pub static AF_INET6: c_int = 28; pub static SOCK_STREAM: c_int = 1; pub static SOCK_DGRAM: c_int = 2; + pub static SOCK_RAW: c_int = 3; pub static IPPROTO_TCP: c_int = 6; pub static IPPROTO_IP: c_int = 0; pub static IPPROTO_IPV6: c_int = 41; pub static IP_MULTICAST_TTL: c_int = 10; pub static IP_MULTICAST_LOOP: c_int = 11; pub static IP_TTL: c_int = 4; + pub static IP_HDRINCL: c_int = 2; pub static IP_ADD_MEMBERSHIP: c_int = 12; pub static IP_DROP_MEMBERSHIP: c_int = 13; pub static IPV6_ADD_MEMBERSHIP: c_int = 12; @@ -2669,6 +2671,7 @@ pub mod consts { use libc::types::os::arch::c95::c_int; pub static O_SYNC : c_int = 128; + pub static O_NONBLOCK : c_int = 4; pub static CTL_KERN: c_int = 1; pub static KERN_PROC: c_int = 14; pub static KERN_PROC_PATHNAME: c_int = 12; @@ -3023,12 +3026,14 @@ pub mod consts { pub static AF_INET6: c_int = 30; pub static SOCK_STREAM: c_int = 1; pub static SOCK_DGRAM: c_int = 2; + pub static SOCK_RAW: c_int = 3; pub static IPPROTO_TCP: c_int = 6; pub static IPPROTO_IP: c_int = 0; pub static IPPROTO_IPV6: c_int = 41; pub static IP_MULTICAST_TTL: c_int = 10; pub static IP_MULTICAST_LOOP: c_int = 11; pub static IP_TTL: c_int = 4; + pub static IP_HDRINCL: c_int = 2; pub static IP_ADD_MEMBERSHIP: c_int = 12; pub static IP_DROP_MEMBERSHIP: c_int = 13; pub static IPV6_ADD_MEMBERSHIP: c_int = 12; From a20ab413df1a0a467d3b3bede551f49db907e176 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 21:14:26 +0000 Subject: [PATCH 07/54] Rust now supports varargs. --- src/libstd/libc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 957dd00075b5a..386b065c2b639 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -3464,7 +3464,7 @@ pub mod funcs { pub fn open(path: *c_char, oflag: c_int, mode: c_int) -> c_int; pub fn creat(path: *c_char, mode: mode_t) -> c_int; - pub fn fcntl(fd: c_int, cmd: c_int, opt: c_int) -> c_int; + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; } } From ec2046137978aad68e6bf9f382a0a06bff40c308 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 8 Jan 2014 21:39:00 +0000 Subject: [PATCH 08/54] Slight stylistic fix. --- src/librustuv/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 0c8c2b7d6da71..b36d05cb25b10 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -661,7 +661,7 @@ impl RawSocketWatcher { } // Make socket non-blocking let flags = unsafe { libc::fcntl(socket, libc::F_GETFL, 0) }; - if (flags == -1) { + if flags == -1 { return Err(uv_error_to_io_error(UvError(errno() as i32))); } if unsafe { libc::fcntl(socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { From 2e37656400601e7ae00606b69783a51404597875 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Thu, 9 Jan 2014 12:31:12 +0000 Subject: [PATCH 09/54] Add uncommitted use statements. --- src/librustuv/net.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index b36d05cb25b10..c9ee5c8268751 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -13,10 +13,13 @@ use std::io::IoError; use std::io::net::ip::{Ipv4Addr, Ipv6Addr, SocketAddr, IpAddr}; use std::libc::{size_t, ssize_t, c_int, c_void, c_uint, c_char}; use std::libc; +use std::num::Bounded; +use std::os::errno; use std::ptr; use std::rt::rtio; use std::rt::task::BlockedTask; use std::str; +use std::unstable::intrinsics; use std::unstable::finally::Finally; use std::vec; From 8f733b2b246c4e3e78c1b16f4b207e07e10bf10e Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Thu, 9 Jan 2014 12:31:59 +0000 Subject: [PATCH 10/54] Add native backend support for raw sockets. --- src/libnative/io/mod.rs | 9 +++-- src/libnative/io/net.rs | 88 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 0e4cad9b5b3a1..7c7408bbad585 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -29,7 +29,8 @@ use std::os; use std::rt::rtio; use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket, RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess, - RtioSignal, RtioTTY, CloseBehavior, RtioTimer}; + RtioSignal, RtioTTY, CloseBehavior, RtioTimer, + RtioRawSocket}; use std::io; use std::io::IoError; use std::io::net::ip::SocketAddr; @@ -190,9 +191,9 @@ impl rtio::IoFactory for IoFactory { _hint: Option) -> IoResult<~[ai::Info]> { Err(unimpl()) } - fn raw_socket_new(&mut self, _domain: rtio::CommDomain, _protocol: rtio::Protocol, - _includeIpHeader: bool) -> IoResult<~rtio::RtioRawSocket> { - Err(unimpl()) + fn raw_socket_new(&mut self, domain: rtio::CommDomain, protocol: rtio::Protocol, + includeIpHeader: bool) -> IoResult<~rtio::RtioRawSocket> { + net::RawSocket::new(domain, protocol, includeIpHeader).map(|r| ~r as ~RtioRawSocket) } // filesystem operations diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index adcd21f0ac4c5..b558ca0ab024c 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -584,3 +584,91 @@ impl rtio::RtioUdpSocket for UdpSocket { impl Drop for UdpSocket { fn drop(&mut self) { unsafe { close(self.fd) } } } + +//////////////////////////////////////////////////////////////////////////////// +/// Raw socket +//////////////////////////////////////////////////////////////////////////////// + +pub struct RawSocket { + priv fd: sock_t, +} + +impl RawSocket { + pub fn new(domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) + -> IoResult + { + let socket = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; + if socket == -1 { + return Err(super::last_error()); + } + if includeIpHeader { + let one: libc::c_int = 1; + let proto = if domain == libc::AF_INET { libc::IPPROTO_IP } else { libc::IPPROTO_IPV6 }; + let res = unsafe { libc::setsockopt(socket, proto, libc::IP_HDRINCL, (&one as *libc::c_int) as *libc::c_void, intrinsics::size_of::() as u32) }; + if res == -1 { + return Err(super::last_error()); + } + } + return Ok(RawSocket { fd: socket }); + } +} + +impl rtio::RtioRawSocket for RawSocket { + fn recvfrom(&mut self, buf: &mut [u8]) + -> IoResult<(uint, ip::SocketAddr)> + { + let max: libc::c_int = Bounded::max_value(); + assert!(buf.len() <= (max as uint)); + + let mut caddr = unsafe { intrinsics::init::() }; + let mut caddrlen = unsafe { intrinsics::size_of::() } as libc::socklen_t; + let len = unsafe { libc::recvfrom(self.fd, + buf.as_ptr() as *mut libc::c_void, + buf.len() as u64, + 0, + (&mut caddr as *mut libc::sockaddr_storage) as *mut libc::sockaddr, + &mut caddrlen) }; + if len == -1 { + return Err(super::last_error()); + } + + return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { + Ok((len as uint, addr)) + }); + } + + fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) + -> IoResult + { + let (sockaddr, _) = addr_to_sockaddr(ip::SocketAddr { ip: dst, port: 0 }); + let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; + let len = unsafe { + if match dst { ip::Ipv4Addr(..) => true, ip::Ipv6Addr(..) => false } { + libc::sendto(self.fd, + buf.as_ptr() as *libc::c_void, + buf.len() as u64, + 0, + addr, + intrinsics::size_of::() as libc::socklen_t) + } else { + libc::sendto(self.fd, + buf.as_ptr() as *libc::c_void, + buf.len() as u64, + 0, + addr, + intrinsics::size_of::() as libc::socklen_t) + } + }; + + return if len < 0 { + Err(super::last_error()) + } else { + Ok(len) + }; + } +} + +impl Drop for RawSocket { + fn drop(&mut self) { unsafe { close(self.fd) } } +} + From 8afa3916415d023204cbb57f1adad2c17e484f2b Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Thu, 9 Jan 2014 15:41:21 +0000 Subject: [PATCH 11/54] Another stylistic fix. --- src/libnative/io/net.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index b558ca0ab024c..af2713970c917 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -643,21 +643,15 @@ impl rtio::RtioRawSocket for RawSocket { let (sockaddr, _) = addr_to_sockaddr(ip::SocketAddr { ip: dst, port: 0 }); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { - if match dst { ip::Ipv4Addr(..) => true, ip::Ipv6Addr(..) => false } { - libc::sendto(self.fd, - buf.as_ptr() as *libc::c_void, - buf.len() as u64, - 0, - addr, - intrinsics::size_of::() as libc::socklen_t) - } else { - libc::sendto(self.fd, - buf.as_ptr() as *libc::c_void, - buf.len() as u64, - 0, - addr, - intrinsics::size_of::() as libc::socklen_t) - } + libc::sendto(self.fd, + buf.as_ptr() as *libc::c_void, + buf.len() as u64, + 0, + addr, + match dst { + ip::Ipv4Addr(..) => intrinsics::size_of::(), + ip::Ipv6Addr(..) => intrinsics::size_of::() + } as libc::socklen_t) }; return if len < 0 { From 20de502baaaef59fa00bb894afb4fbba15234289 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 31 Jan 2014 00:24:35 +0000 Subject: [PATCH 12/54] Build fixes for latest Rust. --- src/libnative/io/net.rs | 3 --- src/librustuv/net.rs | 30 +++++++++++++----------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 70442ead69e87..91ed4d8d16fd4 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -628,9 +628,6 @@ impl rtio::RtioRawSocket for RawSocket { fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, ip::SocketAddr)> { - let max: libc::c_int = Bounded::max_value(); - assert!(buf.len() <= (max as uint)); - let mut caddr = unsafe { intrinsics::init::() }; let mut caddrlen = unsafe { intrinsics::size_of::() } as libc::socklen_t; let len = unsafe { libc::recvfrom(self.fd, diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 58b9487427ec9..ccaabcf855f68 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -11,7 +11,7 @@ use std::cast; use std::io::IoError; use std::io::net::ip; -use std::libc::{size_t, ssize_t, c_int, c_void, c_uint, c_char}; +use std::libc::{size_t, ssize_t, c_int, c_void, c_uint}; use std::libc; use std::mem; use std::num::Bounded; @@ -19,10 +19,7 @@ use std::os::errno; use std::ptr; use std::rt::rtio; use std::rt::task::BlockedTask; -use std::str; use std::unstable::intrinsics; -use std::unstable::finally::Finally; -use std::vec; use homing::{HomingIO, HomeHandle}; use stream::StreamWatcher; @@ -31,7 +28,6 @@ use super::{Loop, Request, UvError, Buf, status_to_io_result, wait_until_woken_after, wakeup}; use uvio::UvIoFactory; use uvll; -use uvll::sockaddr; //////////////////////////////////////////////////////////////////////////////// /// Generic functions related to dealing with sockaddr things @@ -716,14 +712,14 @@ impl HomingIO for RawSocketWatcher { impl rtio::RtioRawSocket for RawSocketWatcher { fn recvfrom(&mut self, buf: &mut [u8]) - -> Result<(uint, SocketAddr), IoError> + -> Result<(uint, ip::SocketAddr), IoError> { let max: c_int = Bounded::max_value(); assert!(buf.len() <= (max as uint)); struct Ctx { task: Option, buf: Option, - result: Option<(ssize_t, Option)>, + result: Option<(ssize_t, Option)>, socket: Option, } let _m = self.fire_homing_missile(); @@ -782,14 +778,14 @@ impl rtio::RtioRawSocket for RawSocketWatcher { cx.result = Some((errno() as ssize_t, None)); return; } - let addr = Some(sockaddr_to_socket_addr((&caddr as *libc::sockaddr_storage) as *uvll::sockaddr)); + let addr = Some(sockaddr_to_addr(&caddr, caddrlen as uint)); cx.result = Some((len as ssize_t, addr)); wakeup(&mut cx.task); } } - fn sendto(&mut self, buf: &[u8], dst: IpAddr) + fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) -> Result { struct Ctx { @@ -797,7 +793,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: Option, result: Option, socket: Option, - addr: IpAddr, + addr: ip::IpAddr, } let _m = self.fire_homing_missile(); @@ -840,25 +836,25 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } let len = match (cx.socket, cx.buf) { - (Some(sock), Some(buf)) => socket_addr_as_sockaddr(SocketAddr{ ip: cx.addr, port: 0 }, |addr| { + (Some(sock), Some(buf)) => { let (addr, len) = addr_to_sockaddr(ip::SocketAddr{ ip: cx.addr, port: 0 }); unsafe { - if match cx.addr { Ipv4Addr(..) => true, Ipv6Addr(..) => false } { + if match cx.addr { ip::Ipv4Addr(..) => true, ip::Ipv6Addr(..) => false } { libc::sendto(sock, buf.base as *c_void, buf.len, 0, - addr as *libc::sockaddr, - intrinsics::size_of::() as libc::socklen_t) + (&addr as *libc::sockaddr_storage) as *libc::sockaddr, + len as libc::socklen_t) } else { libc::sendto(sock, buf.base as *c_void, buf.len, 0, - addr as *libc::sockaddr, - intrinsics::size_of::() as libc::socklen_t) + (&addr as *libc::sockaddr_storage) as *libc::sockaddr, + len as libc::socklen_t) } } - }), + }, _ => -1 }; From 64b6ba4ad48ba48922068af896fc7d95340b25b8 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 31 Jan 2014 16:25:48 +0000 Subject: [PATCH 13/54] Some refactoring of native raw socket code. --- src/libnative/io/mod.rs | 19 +++++++------ src/libnative/io/net.rs | 59 ++++++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index f7de990e23bf8..6b64f1aac73ec 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -30,6 +30,7 @@ use std::io::process::ProcessConfig; use std::io::signal::Signum; use std::libc::c_int; use std::libc; +use std::num::from_i32; use std::os; use std::rt::rtio; use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket, @@ -154,22 +155,24 @@ fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { #[cfg(windows)] #[inline] -fn retry(f: || -> libc::c_int) -> libc::c_int { +fn retry(f: || -> T) -> T { loop { - match f() { - -1 if os::errno() as int == libc::WSAEINTR as int => {} - n => return n, + let minus1: T = from_i32(-1).unwrap(); + let ret = f(); + if ret != minus1 || os::errno() as int != libc::WSAEINTR as int { + return ret } } } #[cfg(unix)] #[inline] -fn retry(f: || -> libc::c_int) -> libc::c_int { +fn retry(f: || -> T) -> T { loop { - match f() { - -1 if os::errno() as int == libc::EINTR as int => {} - n => return n, + let minus1: T = from_i32(-1).unwrap(); + let ret = f(); + if ret != minus1 || os::errno() as int != libc::EINTR as int { + return ret } } } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 91ed4d8d16fd4..466ca22567980 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -608,19 +608,28 @@ impl RawSocket { pub fn new(domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) -> IoResult { - let socket = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; - if socket == -1 { + let socket = RawSocket { + fd: unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) } + }; + if socket.fd == -1 { return Err(super::last_error()); } - if includeIpHeader { + if includeIpHeader && domain == libc::AF_INET { let one: libc::c_int = 1; - let proto = if domain == libc::AF_INET { libc::IPPROTO_IP } else { libc::IPPROTO_IPV6 }; - let res = unsafe { libc::setsockopt(socket, proto, libc::IP_HDRINCL, (&one as *libc::c_int) as *libc::c_void, intrinsics::size_of::() as u32) }; + // Only windows supports IPV6_HDRINCL + let (proto, hdrincl) = (libc::IPPROTO_IP, libc::IP_HDRINCL); + let res = unsafe { + libc::setsockopt(socket.fd, + proto, + hdrincl, + (&one as *libc::c_int) as *libc::c_void, + intrinsics::size_of::() as u32) + }; if res == -1 { return Err(super::last_error()); } } - return Ok(RawSocket { fd: socket }); + return Ok(socket); } } @@ -628,14 +637,19 @@ impl rtio::RtioRawSocket for RawSocket { fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, ip::SocketAddr)> { - let mut caddr = unsafe { intrinsics::init::() }; - let mut caddrlen = unsafe { intrinsics::size_of::() } as libc::socklen_t; - let len = unsafe { libc::recvfrom(self.fd, - buf.as_ptr() as *mut libc::c_void, - buf.len() as u64, - 0, - (&mut caddr as *mut libc::sockaddr_storage) as *mut libc::sockaddr, - &mut caddrlen) }; + let mut caddr: libc::sockaddr_storage = unsafe { intrinsics::init() }; + let mut caddrlen = unsafe { + intrinsics::size_of::() + } as libc::socklen_t; + let len = unsafe { + let addr = &mut caddr as *mut libc::sockaddr_storage; + retry( || libc::recvfrom(self.fd, + buf.as_ptr() as *mut libc::c_void, + buf.len() as u64, + 0, + addr as *mut libc::sockaddr, + &mut caddrlen)) + }; if len == -1 { return Err(super::last_error()); } @@ -648,18 +662,15 @@ impl rtio::RtioRawSocket for RawSocket { fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) -> IoResult { - let (sockaddr, _) = addr_to_sockaddr(ip::SocketAddr { ip: dst, port: 0 }); + let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst, port: 0 }); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { - libc::sendto(self.fd, - buf.as_ptr() as *libc::c_void, - buf.len() as u64, - 0, - addr, - match dst { - ip::Ipv4Addr(..) => intrinsics::size_of::(), - ip::Ipv6Addr(..) => intrinsics::size_of::() - } as libc::socklen_t) + retry( || libc::sendto(self.fd, + buf.as_ptr() as *libc::c_void, + buf.len() as u64, + 0, + addr, + slen as libc::socklen_t)) }; return if len < 0 { From 80ed5e69e52224e86c2a2ca3a5656a722f1481f9 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 1 Feb 2014 01:14:19 +0000 Subject: [PATCH 14/54] API and bug fixes for raw socket support. --- src/libnative/io/net.rs | 13 +-- src/librustuv/net.rs | 196 ++++++++++++++++++++++++++------------- src/librustuv/uvio.rs | 6 +- src/librustuv/uvll.rs | 6 +- src/libstd/io/net/raw.rs | 13 ++- src/libstd/rt/rtio.rs | 2 +- 6 files changed, 152 insertions(+), 84 deletions(-) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 466ca22567980..c9c5bb00c6e47 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -608,12 +608,13 @@ impl RawSocket { pub fn new(domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) -> IoResult { - let socket = RawSocket { - fd: unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) } - }; - if socket.fd == -1 { + let sock = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; + if sock == -1 { return Err(super::last_error()); } + + let socket = RawSocket { fd: sock }; + if includeIpHeader && domain == libc::AF_INET { let one: libc::c_int = 1; // Only windows supports IPV6_HDRINCL @@ -635,7 +636,7 @@ impl RawSocket { impl rtio::RtioRawSocket for RawSocket { fn recvfrom(&mut self, buf: &mut [u8]) - -> IoResult<(uint, ip::SocketAddr)> + -> IoResult<(uint, ip::IpAddr)> { let mut caddr: libc::sockaddr_storage = unsafe { intrinsics::init() }; let mut caddrlen = unsafe { @@ -655,7 +656,7 @@ impl rtio::RtioRawSocket for RawSocket { } return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { - Ok((len as uint, addr)) + Ok((len as uint, addr.ip)) }); } diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index ccaabcf855f68..b6d6f316381b1 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -9,12 +9,13 @@ // except according to those terms. use std::cast; +use std::io; use std::io::IoError; use std::io::net::ip; use std::libc::{size_t, ssize_t, c_int, c_void, c_uint}; use std::libc; use std::mem; -use std::num::Bounded; +use std::os; use std::os::errno; use std::ptr; use std::rt::rtio; @@ -654,42 +655,114 @@ impl Drop for UdpWatcher { pub struct RawSocketWatcher { handle: *uvll::uv_poll_t, - socket: uvll::uv_os_socket, + socket: uvll::uv_os_socket_t, home: HomeHandle, } +// TODO This is copied from libnative::io +// ---------------------------------------------------------------------------- +fn translate_error(errno: i32, detail: bool) -> IoError { + #[cfg(windows)] + fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { + match errno { + libc::EOF => (io::EndOfFile, "end of file"), + libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"), + libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"), + libc::WSAEACCES => (io::PermissionDenied, "permission denied"), + libc::WSAEWOULDBLOCK => + (io::ResourceUnavailable, "resource temporarily unavailable"), + libc::WSAENOTCONN => (io::NotConnected, "not connected"), + libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"), + libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), + libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"), + + x => { + debug!("ignoring {}: {}", x, os::last_os_error()); + (io::OtherIoError, "unknown error") + } + } + } + + #[cfg(not(windows))] + fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { + // FIXME: this should probably be a bit more descriptive... + match errno { + libc::EOF => (io::EndOfFile, "end of file"), + libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"), + libc::ECONNRESET => (io::ConnectionReset, "connection reset"), + libc::EPERM | libc::EACCES => + (io::PermissionDenied, "permission denied"), + libc::EPIPE => (io::BrokenPipe, "broken pipe"), + libc::ENOTCONN => (io::NotConnected, "not connected"), + libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"), + libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), + libc::EADDRINUSE => (io::ConnectionRefused, "address in use"), + + // These two constants can have the same value on some systems, but + // different values on others, so we can't use a match clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + (io::ResourceUnavailable, "resource temporarily unavailable"), + + x => { + debug!("ignoring {}: {}", x, os::last_os_error()); + (io::OtherIoError, "unknown error") + } + } + } + + let (kind, desc) = get_err(errno); + IoError { + kind: kind, + desc: desc, + detail: if detail {Some(os::last_os_error())} else {None}, + } +} + +fn last_error() -> IoError { translate_error(os::errno() as i32, true) } +// ---------------------------------------------------------------------------- + impl RawSocketWatcher { pub fn new(io: &mut UvIoFactory, domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) -> Result { let socket = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; if socket == -1 { - return Err(uv_error_to_io_error(UvError(errno() as i32))); + return Err(last_error()); } - if includeIpHeader { - let one: c_int = 1; - let proto = if domain == libc::AF_INET { libc::IPPROTO_IP } else { libc::IPPROTO_IPV6 }; - let res = unsafe { libc::setsockopt(socket, proto, libc::IP_HDRINCL, (&one as *c_int) as *c_void, intrinsics::size_of::() as u32) }; + + let raw = RawSocketWatcher { + handle: unsafe { uvll::malloc_handle(uvll::UV_POLL) }, + home: io.make_handle(), + socket: socket + }; + + if includeIpHeader && domain == libc::AF_INET { + let one: libc::c_int = 1; + // Only windows supports IPV6_HDRINCL + let (proto, hdrincl) = (libc::IPPROTO_IP, libc::IP_HDRINCL); + let res = unsafe { + libc::setsockopt(raw.socket, + proto, + hdrincl, + (&one as *libc::c_int) as *libc::c_void, + intrinsics::size_of::() as u32) + }; if res == -1 { - return Err(uv_error_to_io_error(UvError(errno() as i32))); + return Err(last_error()); } } - // Make socket non-blocking - let flags = unsafe { libc::fcntl(socket, libc::F_GETFL, 0) }; + + // Make socket non-blocking - required for libuv + let flags = unsafe { libc::fcntl(raw.socket, libc::F_GETFL, 0) }; if flags == -1 { - return Err(uv_error_to_io_error(UvError(errno() as i32))); + return Err(last_error()); } - if unsafe { libc::fcntl(socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { - return Err(uv_error_to_io_error(UvError(errno() as i32))); + if unsafe { libc::fcntl(raw.socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { + return Err(last_error()); } - let raw = RawSocketWatcher { - handle: unsafe { uvll::malloc_handle(uvll::UV_POLL) }, - home: io.make_handle(), - socket: socket, - }; assert_eq!(unsafe { - uvll::uv_poll_init_socket(io.uv_loop(), raw.handle, socket) + uvll::uv_poll_init_socket(io.uv_loop(), raw.handle, raw.socket) }, 0); return Ok(raw); } @@ -712,15 +785,13 @@ impl HomingIO for RawSocketWatcher { impl rtio::RtioRawSocket for RawSocketWatcher { fn recvfrom(&mut self, buf: &mut [u8]) - -> Result<(uint, ip::SocketAddr), IoError> + -> Result<(uint, ip::IpAddr), IoError> { - let max: c_int = Bounded::max_value(); - assert!(buf.len() <= (max as uint)); - struct Ctx { + struct Ctx<'b> { task: Option, - buf: Option, - result: Option<(ssize_t, Option)>, - socket: Option, + buf: &'b [u8], + result: Option<(ssize_t, Option)>, + socket: Option, } let _m = self.fire_homing_missile(); let a = match unsafe { @@ -729,7 +800,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { 0 => { let mut cx = Ctx { task: None, - buf: Some(slice_to_uv_buf(buf)), + buf: buf, result: None, socket: Some(self.socket), }; @@ -738,7 +809,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { (n, _) if n < 0 => - Err(uv_error_to_io_error(UvError(n as c_int))), + Err(last_error()), (n, addr) => Ok((n as uint, addr.unwrap())) } } @@ -763,22 +834,24 @@ impl rtio::RtioRawSocket for RawSocketWatcher { let mut caddr = unsafe { intrinsics::init::() }; let mut caddrlen = unsafe { intrinsics::size_of::() } as libc::socklen_t; - let len = match (cx.socket, cx.buf) { - (Some(sock), Some(buf)) => unsafe { - libc::recvfrom(sock, - buf.base as *mut c_void, - buf.len, - 0, - (&mut caddr as *mut libc::sockaddr_storage) as *mut libc::sockaddr, - &mut caddrlen) - }, - _ => -1 + let len = match cx.socket { + Some(sock) => unsafe { + let addr = &mut caddr as *mut libc::sockaddr_storage; + libc::recvfrom(sock, + cx.buf.as_ptr() as *mut c_void, + cx.buf.len() as u64, + 0, + addr as *mut libc::sockaddr, + &mut caddrlen) + }, + _ => -1 }; if len == -1 { cx.result = Some((errno() as ssize_t, None)); + wakeup(&mut cx.task); return; } - let addr = Some(sockaddr_to_addr(&caddr, caddrlen as uint)); + let addr = Some(sockaddr_to_addr(&caddr, caddrlen as uint).ip); cx.result = Some((len as ssize_t, addr)); wakeup(&mut cx.task); @@ -788,11 +861,11 @@ impl rtio::RtioRawSocket for RawSocketWatcher { fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) -> Result { - struct Ctx { + struct Ctx<'b> { task: Option, - buf: Option, + buf: &'b [u8], result: Option, - socket: Option, + socket: Option, addr: ip::IpAddr, } let _m = self.fire_homing_missile(); @@ -803,7 +876,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { 0 => { let mut cx = Ctx { task: None, - buf: Some(slice_to_uv_buf(buf)), + buf: buf, result: None, socket: Some(self.socket), addr: dst @@ -813,7 +886,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { n if n < 0 => - Err(uv_error_to_io_error(UvError(n as c_int))), + Err(last_error()), n => Ok(n) } } @@ -828,6 +901,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }; if status < 0 { cx.result = Some(status as ssize_t); + wakeup(&mut cx.task); return; } @@ -835,27 +909,19 @@ impl rtio::RtioRawSocket for RawSocketWatcher { assert_eq!(uvll::uv_poll_stop(handle), 0) } - let len = match (cx.socket, cx.buf) { - (Some(sock), Some(buf)) => { let (addr, len) = addr_to_sockaddr(ip::SocketAddr{ ip: cx.addr, port: 0 }); - unsafe { - if match cx.addr { ip::Ipv4Addr(..) => true, ip::Ipv6Addr(..) => false } { - libc::sendto(sock, - buf.base as *c_void, - buf.len, - 0, - (&addr as *libc::sockaddr_storage) as *libc::sockaddr, - len as libc::socklen_t) - } else { - libc::sendto(sock, - buf.base as *c_void, - buf.len, - 0, - (&addr as *libc::sockaddr_storage) as *libc::sockaddr, - len as libc::socklen_t) - } - } - }, - _ => -1 + let len = match cx.socket { + Some(sock) => { + let (addr, len) = addr_to_sockaddr(ip::SocketAddr{ ip: cx.addr, port: 0 }); + unsafe { + libc::sendto(sock, + cx.buf.as_ptr() as *c_void, + cx.buf.len() as u64, + 0, + (&addr as *libc::sockaddr_storage) as *libc::sockaddr, + len as libc::socklen_t) + } + }, + _ => -1 }; cx.result = if len < 0 { diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 9a7df58ca613f..221b62d6ef383 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -178,10 +178,8 @@ impl IoFactory for UvIoFactory { fn raw_socket_new(&mut self, domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) -> Result<~rtio::RtioRawSocket, IoError> { - match RawSocketWatcher::new(self, domain, protocol, includeIpHeader) { - Ok(r) => Ok(~r as ~rtio::RtioRawSocket), - Err(e) => Err(e), - } + RawSocketWatcher::new(self, domain, protocol, includeIpHeader) + .map(|rsw| ~rsw as ~rtio::RtioRawSocket) } fn fs_from_raw_fd(&mut self, fd: c_int, diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 17bb671548f6c..d977efc8cfd94 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -105,7 +105,7 @@ pub struct uv_buf_t { } #[cfg(unix)] -pub type uv_os_socket = c_int; +pub type uv_os_socket_t = c_int; // see libuv/include/uv-win.h #[cfg(windows)] @@ -115,7 +115,7 @@ pub struct uv_buf_t { } #[cfg(windows)] -pub type uv_os_socket = libc::SOCKET; +pub type uv_os_socket_t = libc::SOCKET; #[repr(C)] pub enum uv_run_mode { @@ -651,7 +651,7 @@ extern { cb: uv_fs_cb) -> c_int; // poll bindings - pub fn uv_poll_init_socket(l: *uv_loop_t, h: *uv_poll_t, s: uv_os_socket) -> c_int; + pub fn uv_poll_init_socket(l: *uv_loop_t, h: *uv_poll_t, s: uv_os_socket_t) -> c_int; pub fn uv_poll_start(h: *uv_poll_t, events: c_int, cb: uv_poll_cb) -> c_int; pub fn uv_poll_stop(h: *uv_poll_t) -> c_int; diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index acc3117186ba4..1b381820d8f97 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -10,7 +10,7 @@ use option::{Option, Some, None}; use result::{Ok, Err}; -use io::net::ip::{IpAddr, SocketAddr}; +use io::net::ip::{IpAddr}; use io::{io_error, EndOfFile}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket, Protocol, CommDomain}; @@ -25,7 +25,7 @@ impl RawSocket { }) } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> { + pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, IpAddr)> { match self.obj.recvfrom(buf) { Ok((nread, src)) => Some((nread, src)), Err(ioerr) => { @@ -38,10 +38,13 @@ impl RawSocket { } } - pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) { + pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Option { match self.obj.sendto(buf, dst) { - Ok(_) => (), - Err(ioerr) => io_error::cond.raise(ioerr), + Ok(len) => Some(len as uint), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + }, } } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 085a6ffd939b9..da838b3bb085e 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -243,7 +243,7 @@ pub trait RtioUdpSocket : RtioSocket { } pub trait RtioRawSocket { - fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError>; + fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>; fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result; } From d9a24dd026cdf85428c32a9354218150634f707f Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Tue, 4 Feb 2014 21:47:31 +0000 Subject: [PATCH 15/54] Stop leaking c_int and ssize_t in the API. --- src/libnative/io/mod.rs | 2 +- src/libnative/io/net.rs | 6 +++--- src/librustuv/net.rs | 12 ++++++------ src/librustuv/uvio.rs | 2 +- src/libstd/io/net/raw.rs | 4 ++-- src/libstd/rt/rtio.rs | 9 +++------ 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 6b64f1aac73ec..e7768757421bb 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -211,7 +211,7 @@ impl rtio::IoFactory for IoFactory { hint: Option) -> IoResult<~[ai::Info]> { addrinfo::GetAddrInfoRequest::run(host, servname, hint) } - fn raw_socket_new(&mut self, domain: rtio::CommDomain, protocol: rtio::Protocol, + fn raw_socket_new(&mut self, domain: i32, protocol: i32, includeIpHeader: bool) -> IoResult<~rtio::RtioRawSocket> { net::RawSocket::new(domain, protocol, includeIpHeader).map(|r| ~r as ~RtioRawSocket) } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index c9c5bb00c6e47..28044d93d7807 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -605,7 +605,7 @@ pub struct RawSocket { } impl RawSocket { - pub fn new(domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) + pub fn new(domain: i32, protocol: i32, includeIpHeader: bool) -> IoResult { let sock = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; @@ -661,7 +661,7 @@ impl rtio::RtioRawSocket for RawSocket { } fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) - -> IoResult + -> IoResult { let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst, port: 0 }); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; @@ -677,7 +677,7 @@ impl rtio::RtioRawSocket for RawSocket { return if len < 0 { Err(super::last_error()) } else { - Ok(len) + Ok(len as int) }; } } diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index b6d6f316381b1..ae2a2b8683006 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -722,7 +722,7 @@ fn last_error() -> IoError { translate_error(os::errno() as i32, true) } // ---------------------------------------------------------------------------- impl RawSocketWatcher { - pub fn new(io: &mut UvIoFactory, domain: rtio::CommDomain, protocol: rtio::Protocol, includeIpHeader: bool) + pub fn new(io: &mut UvIoFactory, domain: i32, protocol: i32, includeIpHeader: bool) -> Result { let socket = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; @@ -859,12 +859,12 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) - -> Result + -> Result { struct Ctx<'b> { task: Option, buf: &'b [u8], - result: Option, + result: Option, socket: Option, addr: ip::IpAddr, } @@ -900,7 +900,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { cast::transmute(uvll::get_data_for_uv_handle(handle)) }; if status < 0 { - cx.result = Some(status as ssize_t); + cx.result = Some(status as int); wakeup(&mut cx.task); return; } @@ -925,9 +925,9 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }; cx.result = if len < 0 { - Some(errno() as ssize_t) + Some(errno() as int) } else { - Some(len) + Some(len as int) }; wakeup(&mut cx.task); diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 221b62d6ef383..950fb19cbcd13 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -176,7 +176,7 @@ impl IoFactory for UvIoFactory { r.map_err(uv_error_to_io_error) } - fn raw_socket_new(&mut self, domain: rtio::CommDomain, protocol: rtio::Protocol, + fn raw_socket_new(&mut self, domain: i32, protocol: i32, includeIpHeader: bool) -> Result<~rtio::RtioRawSocket, IoError> { RawSocketWatcher::new(self, domain, protocol, includeIpHeader) .map(|rsw| ~rsw as ~rtio::RtioRawSocket) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 1b381820d8f97..615b221daafb3 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -12,14 +12,14 @@ use option::{Option, Some, None}; use result::{Ok, Err}; use io::net::ip::{IpAddr}; use io::{io_error, EndOfFile}; -use rt::rtio::{IoFactory, LocalIo, RtioRawSocket, Protocol, CommDomain}; +use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; pub struct RawSocket { priv obj: ~RtioRawSocket } impl RawSocket { - pub fn new(domain: CommDomain, protocol: Protocol, includeIpHeader: bool) -> Option { + pub fn new(domain: i32, protocol: i32, includeIpHeader: bool) -> Option { LocalIo::maybe_raise(|io| { io.raw_socket_new(domain, protocol, includeIpHeader).map(|s| RawSocket { obj: s }) }) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index da838b3bb085e..fef6f09bc758a 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -11,7 +11,7 @@ use c_str::CString; use cast; use comm::{SharedChan, Port}; -use libc::{c_int, ssize_t}; +use libc::{c_int}; use libc; use ops::Drop; use option::{Option, Some, None}; @@ -151,9 +151,6 @@ impl<'a> LocalIo<'a> { } } -pub type CommDomain = c_int; -pub type Protocol = c_int; - pub trait IoFactory { // networking fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; @@ -164,7 +161,7 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; - fn raw_socket_new(&mut self, domain: CommDomain, protocol: Protocol, + fn raw_socket_new(&mut self, domain: i32, protocol: i32, includeIpHeader: bool) -> Result<~RtioRawSocket, IoError>; // filesystem operations @@ -244,7 +241,7 @@ pub trait RtioUdpSocket : RtioSocket { pub trait RtioRawSocket { fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>; - fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result; + fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result; } pub trait RtioTimer { From a618b470536215328a0289799c23b1ba63f50e3a Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 5 Feb 2014 00:46:52 +0000 Subject: [PATCH 16/54] Fixes for lints. --- src/librustuv/net.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index ae2a2b8683006..059d8acb6ad8c 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -659,7 +659,7 @@ pub struct RawSocketWatcher { home: HomeHandle, } -// TODO This is copied from libnative::io +// FIXME This is copied from libnative::io // ---------------------------------------------------------------------------- fn translate_error(errno: i32, detail: bool) -> IoError { #[cfg(windows)] @@ -833,7 +833,9 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } let mut caddr = unsafe { intrinsics::init::() }; - let mut caddrlen = unsafe { intrinsics::size_of::() } as libc::socklen_t; + let mut caddrlen = unsafe { + intrinsics::size_of::() + } as libc::socklen_t; let len = match cx.socket { Some(sock) => unsafe { let addr = &mut caddr as *mut libc::sockaddr_storage; @@ -911,7 +913,9 @@ impl rtio::RtioRawSocket for RawSocketWatcher { let len = match cx.socket { Some(sock) => { - let (addr, len) = addr_to_sockaddr(ip::SocketAddr{ ip: cx.addr, port: 0 }); + let (addr, len) = addr_to_sockaddr( + ip::SocketAddr{ ip: cx.addr, port: 0 } + ); unsafe { libc::sendto(sock, cx.buf.as_ptr() as *c_void, From 65aa0be595b5b4e9151ee91c1ea144e8ec27aa66 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Mon, 10 Feb 2014 14:31:54 +0000 Subject: [PATCH 17/54] Fix return types for RawSocket methods. --- src/libstd/io/net/raw.rs | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 615b221daafb3..4a9b10be4ac0b 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::{Option, Some, None}; -use result::{Ok, Err}; use io::net::ip::{IpAddr}; -use io::{io_error, EndOfFile}; +use io::{IoResult}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; pub struct RawSocket { @@ -19,32 +17,17 @@ pub struct RawSocket { } impl RawSocket { - pub fn new(domain: i32, protocol: i32, includeIpHeader: bool) -> Option { + pub fn new(domain: i32, protocol: i32, includeIpHeader: bool) -> IoResult { LocalIo::maybe_raise(|io| { io.raw_socket_new(domain, protocol, includeIpHeader).map(|s| RawSocket { obj: s }) }) } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, IpAddr)> { - match self.obj.recvfrom(buf) { - Ok((nread, src)) => Some((nread, src)), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - None - } - } + pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, IpAddr)> { + self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Option { - match self.obj.sendto(buf, dst) { - Ok(len) => Some(len as uint), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - }, - } + pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> IoResult { + self.obj.sendto(buf, dst) } } From 70abec4bdcd4294db71ced98051efad639a6b4c5 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Mon, 10 Feb 2014 15:52:56 +0000 Subject: [PATCH 18/54] Add missing import. --- src/libnative/io/net.rs | 1 + src/librustuv/net.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 9c8f9c169e2e0..331571a6c4782 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -15,6 +15,7 @@ use std::libc; use std::mem; use std::rt::rtio; use std::sync::arc::UnsafeArc; +use std::unstable::intrinsics; use super::{IoResult, retry}; use super::file::keep_going; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 673d710e28beb..d2c8da1c60027 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -20,6 +20,7 @@ use std::os::errno; use std::ptr; use std::rt::rtio; use std::rt::task::BlockedTask; +use std::unstable::intrinsics; use access::Access; use homing::{HomingIO, HomeHandle}; From 4c25273e78087686539b00f8e38250da934bd764 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Mon, 10 Feb 2014 16:02:23 +0000 Subject: [PATCH 19/54] Add tests for raw sockets. --- src/test/run-make/raw-sockets/Makefile | 13 ++++ src/test/run-make/raw-sockets/clib.rs | 89 ++++++++++++++++++++++++++ src/test/run-make/raw-sockets/test.rs | 62 ++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 src/test/run-make/raw-sockets/Makefile create mode 100644 src/test/run-make/raw-sockets/clib.rs create mode 100644 src/test/run-make/raw-sockets/test.rs diff --git a/src/test/run-make/raw-sockets/Makefile b/src/test/run-make/raw-sockets/Makefile new file mode 100644 index 0000000000000..cf65e7538cc7d --- /dev/null +++ b/src/test/run-make/raw-sockets/Makefile @@ -0,0 +1,13 @@ +-include ../tools.mk + +ifneq ($(shell uname),Darwin) + EXTRAFLAGS := -lm -lrt -ldl -lpthread +endif + +all: + $(RUSTC) clib.rs + ln -s $(call STATICLIB,clib-*) $(call STATICLIB,clib) + $(RUSTC) test.rs --test -o $(call RUN,test) -C link-args="$(call STATICLIB,clib) $(EXTRAFLAGS)" + $(call RUN,test) + rm $(call STATICLIB,clib*) + rm $(call RUN,test*) diff --git a/src/test/run-make/raw-sockets/clib.rs b/src/test/run-make/raw-sockets/clib.rs new file mode 100644 index 0000000000000..e3be26323ba16 --- /dev/null +++ b/src/test/run-make/raw-sockets/clib.rs @@ -0,0 +1,89 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! Dummy functions for raw sockets + + Ordinarily raw sockets require root access to the machine. By + re-implementing the library functions used and replacing them + with dummy functions we are able to test the functionality without + root access. +*/ +#[crate_type="staticlib"]; + +extern mod rustuv; + +use std::libc::{c_int, c_void, size_t, ssize_t}; +use std::libc::{sockaddr, sockaddr_storage, socklen_t}; + + +static mut data: *c_void = 0 as *c_void; +static mut datalen: ssize_t = 0; + +static mut fromaddr: sockaddr_storage = sockaddr_storage { ss_family: 0, __ss_align: 0, __ss_pad2: [0, ..112] }; +static mut fromaddrlen: socklen_t = 0; + +// Only one socket, always succeeds +#[no_mangle] +pub extern "C" fn socket(_domain: c_int, _ty: c_int, _protocol: c_int) -> c_int { + 1 +} + +#[no_mangle] +pub extern "C" fn close(_fd: c_int) -> c_int { + 1 +} +#[no_mangle] +pub extern "C" fn setsockopt(_socket: c_int, _level: c_int, _name: c_int, + _value: *c_void, _option_len: socklen_t) -> c_int { + 1 +} + +// FIXME This doesn't match the C definition, so may stop working if +// the usage in the raw socket backend code changes +#[no_mangle] +pub extern "C" fn fcntl(_fd: c_int, _cmd: c_int, _opt: c_int) -> c_int { + 1 +} + +// Receive data from previous sendto() +#[no_mangle] +pub extern "C" fn recvfrom(_socket: c_int, buf: *mut c_void, len: size_t, + _flags: c_int, addr: *mut sockaddr, + addrlen: *mut socklen_t) -> ssize_t { + unsafe { + // This could/should be replaced with memcpy + for i in range(0, datalen) { + if i >= len as ssize_t { + break; + } + *(((buf as size_t) + i as size_t) as *mut char) = *(((data as size_t) + i as size_t) as *char); + } + let stoAddr = addr as *mut sockaddr_storage; + *stoAddr = fromaddr; + *addrlen = fromaddrlen; + + datalen + } +} + +// Send data +#[no_mangle] +pub extern "C" fn sendto(_socket: c_int, buf: *c_void, len: size_t, + _flags: c_int, addr: *sockaddr, + addrlen: socklen_t) -> ssize_t { + unsafe { + datalen = len as ssize_t; + data = buf; + fromaddr = *(addr as *sockaddr_storage); + fromaddrlen = addrlen; + + datalen + } +} diff --git a/src/test/run-make/raw-sockets/test.rs b/src/test/run-make/raw-sockets/test.rs new file mode 100644 index 0000000000000..3b452e1bd82ef --- /dev/null +++ b/src/test/run-make/raw-sockets/test.rs @@ -0,0 +1,62 @@ +extern mod native; + +use std::io::net::raw::{RawSocket}; +use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::libc::{AF_INET, AF_INET6}; + + +// RFC 3692 test protocol number +static testProtocol: i32 = 253; + +fn test(ip: IpAddr) { + let message = "message"; + let prot = match ip { + Ipv4Addr(..) => AF_INET, + Ipv6Addr(..) => AF_INET6 + }; + spawn( proc() { + let mut buf: ~[u8] = ~[0, .. 128]; + let sock = RawSocket::new(prot, testProtocol, false); + match sock { + Ok(mut s) => match s.recvfrom(buf) { + Ok((len, addr)) => { + assert_eq!(buf.slice(0, message.len()), message.as_bytes()); + assert_eq!(len, message.len()); + assert_eq!(addr, ip); + }, + Err(_) => fail!() + }, + Err(_) => fail!() + }; + }); + + let sock = RawSocket::new(prot, testProtocol, false); + let _res = sock.map(|mut sock| { + match sock.sendto(message.as_bytes(), ip) { + Ok(res) => assert_eq!(res as uint, message.len()), + Err(_) => fail!() + } + }); +} + +fn ipv4_test() { + test(Ipv4Addr(127, 0, 0, 1)); +} + +fn ipv6_test() { + test(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); +} + +#[test] +fn native_ipv4_test() { + let (p, c) = Chan::new(); + native::task::spawn(proc() { c.send(ipv4_test()) }); + p.recv(); +} + +#[test] +fn native_ipv6_test() { + let (p, c) = Chan::new(); + native::task::spawn(proc() { c.send(ipv6_test()) }); + p.recv(); +} From 75b9a2b525e3bd030cddd45f20db5420e44805ef Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sun, 16 Feb 2014 22:46:23 +0000 Subject: [PATCH 20/54] Fix merge fallout. --- src/librustuv/net.rs | 4 ++-- src/libstd/rt/rtio.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 6e198689d5e1c..a6673f847f432 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -857,7 +857,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { result: None, socket: Some(self.socket), }; - wait_until_woken_after(&mut cx.task, || { + wait_until_woken_after(&mut cx.task, &self.uv_loop(), || { unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } }); match cx.result.take_unwrap() { @@ -936,7 +936,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { socket: Some(self.socket), addr: dst }; - wait_until_woken_after(&mut cx.task, || { + wait_until_woken_after(&mut cx.task, &self.uv_loop(), || { unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } }); match cx.result.take_unwrap() { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index c32a9ed501376..5968eaf74f367 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -151,6 +151,8 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; + fn raw_socket_new(&mut self, domain: i32, protocol: i32, + includeIpHeader: bool) -> Result<~RtioRawSocket, IoError>; // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; From 726aa82e5d1f6fb5cdc365ef5b64b805d0d2325b Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Mon, 17 Feb 2014 23:18:56 +0000 Subject: [PATCH 21/54] Beginnings of a new RawSocket interface with tests. Currently it compiles on linux x86-64, but very little works. --- src/libnative/io/mod.rs | 6 +- src/libnative/io/net.rs | 39 +- src/librustuv/net.rs | 42 +- src/librustuv/uvio.rs | 6 +- src/libstd/io/net/raw.rs | 874 ++++++++++++++++++++++++- src/libstd/io/test.rs | 2 + src/libstd/lib.rs | 1 + src/libstd/libc.rs | 3 + src/libstd/rt/rtio.rs | 8 +- src/test/run-make/raw-sockets/Makefile | 13 - src/test/run-make/raw-sockets/clib.rs | 89 --- src/test/run-make/raw-sockets/test.rs | 62 -- 12 files changed, 947 insertions(+), 198 deletions(-) delete mode 100644 src/test/run-make/raw-sockets/Makefile delete mode 100644 src/test/run-make/raw-sockets/clib.rs delete mode 100644 src/test/run-make/raw-sockets/test.rs diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index a4385a9f05ec2..25be2c5957973 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -25,6 +25,7 @@ use std::c_str::CString; use std::io; use std::io::IoError; use std::io::net::ip::SocketAddr; +use std::io::net::raw::Protocol; use std::io::process::ProcessConfig; use std::io::signal::Signum; use std::libc::c_int; @@ -210,9 +211,8 @@ impl rtio::IoFactory for IoFactory { hint: Option) -> IoResult<~[ai::Info]> { addrinfo::GetAddrInfoRequest::run(host, servname, hint) } - fn raw_socket_new(&mut self, domain: i32, protocol: i32, - includeIpHeader: bool) -> IoResult<~rtio::RtioRawSocket> { - net::RawSocket::new(domain, protocol, includeIpHeader).map(|r| ~r as ~RtioRawSocket) + fn raw_socket_new(&mut self, protocol: Protocol) -> IoResult<~rtio::RtioRawSocket> { + net::RawSocket::new(protocol).map(|r| ~r as ~RtioRawSocket) } // filesystem operations diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 12f1b3759414e..dc581cc1778f1 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -10,6 +10,7 @@ use std::cast; use std::io::net::ip; +use std::io::net::raw; use std::io; use std::libc; use std::mem; @@ -642,18 +643,37 @@ pub struct RawSocket { priv fd: sock_t, } +fn protocol_to_libc(protocol: raw::Protocol) + -> (libc::c_int, libc::c_int, libc::c_int, Option) { + let ETH_P_ALL: u16 = htons(0x0003); + match protocol { + raw::DataLinkProtocol(raw::EthernetProtocol(iface)) + => (libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL as libc::c_int, Some(iface)), + raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) + => (libc::AF_PACKET, libc::SOCK_DGRAM, ETH_P_ALL as libc::c_int, Some(iface)), + raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), + raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW, None), + raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int, None), + raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int, None) + } +} + impl RawSocket { - pub fn new(domain: i32, protocol: i32, includeIpHeader: bool) - -> IoResult + pub fn new(protocol: raw::Protocol) -> IoResult { - let sock = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; + let (domain, typ, proto, _) = protocol_to_libc(protocol); + let sock = unsafe { libc::socket(domain, typ, proto) }; if sock == -1 { return Err(super::last_error()); } let socket = RawSocket { fd: sock }; - if includeIpHeader && domain == libc::AF_INET { + /*if includeIpHeader && domain == libc::AF_INET { let one: libc::c_int = 1; // Only windows supports IPV6_HDRINCL let (proto, hdrincl) = (libc::IPPROTO_IP, libc::IP_HDRINCL); @@ -667,14 +687,14 @@ impl RawSocket { if res == -1 { return Err(super::last_error()); } - } + }*/ return Ok(socket); } } impl rtio::RtioRawSocket for RawSocket { fn recvfrom(&mut self, buf: &mut [u8]) - -> IoResult<(uint, ip::IpAddr)> + -> IoResult<(uint, Option)> { let mut caddr: libc::sockaddr_storage = unsafe { intrinsics::init() }; let mut caddrlen = unsafe { @@ -694,14 +714,15 @@ impl rtio::RtioRawSocket for RawSocket { } return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { - Ok((len as uint, addr.ip)) + Ok((len as uint, Some(raw::IpAddress(addr.ip)))) }); } - fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) + fn sendto(&mut self, buf: &[u8], dst: Option) -> IoResult { - let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst, port: 0 }); + let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; + let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { retry( || libc::sendto(self.fd, diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index a6673f847f432..8c40d834b70f8 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -12,6 +12,7 @@ use std::cast; use std::io; use std::io::IoError; use std::io::net::ip; +use std::io::net::raw; use std::libc::{size_t, ssize_t, c_int, c_void, c_uint}; use std::libc; use std::mem; @@ -774,11 +775,31 @@ fn translate_error(errno: i32, detail: bool) -> IoError { fn last_error() -> IoError { translate_error(os::errno() as i32, true) } // ---------------------------------------------------------------------------- +fn protocol_to_libc(protocol: raw::Protocol) + -> (c_int, c_int, c_int, Option) { + let ETH_P_ALL: u16 = htons(0x0003); + match protocol { + raw::DataLinkProtocol(raw::EthernetProtocol(iface)) + => (libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL as c_int, Some(iface)), + raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) + => (libc::AF_PACKET, libc::SOCK_DGRAM, ETH_P_ALL as c_int, Some(iface)), + raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), + raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW, None), + raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + => (libc::AF_INET, libc::SOCK_RAW, proto as c_int, None), + raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + => (libc::AF_INET6, libc::SOCK_RAW, proto as c_int, None) + } +} + impl RawSocketWatcher { - pub fn new(io: &mut UvIoFactory, domain: i32, protocol: i32, includeIpHeader: bool) + pub fn new(io: &mut UvIoFactory, protocol: raw::Protocol) -> Result { - let socket = unsafe { libc::socket(domain, libc::SOCK_RAW, protocol) }; + let (domain, typ, proto, _) = protocol_to_libc(protocol); + let socket = unsafe { libc::socket(domain, typ, proto) }; if socket == -1 { return Err(last_error()); } @@ -789,7 +810,7 @@ impl RawSocketWatcher { socket: socket }; - if includeIpHeader && domain == libc::AF_INET { + /*if includeIpHeader && domain == libc::AF_INET { let one: libc::c_int = 1; // Only windows supports IPV6_HDRINCL let (proto, hdrincl) = (libc::IPPROTO_IP, libc::IP_HDRINCL); @@ -803,7 +824,7 @@ impl RawSocketWatcher { if res == -1 { return Err(last_error()); } - } + }*/ // Make socket non-blocking - required for libuv let flags = unsafe { libc::fcntl(raw.socket, libc::F_GETFL, 0) }; @@ -838,12 +859,12 @@ impl HomingIO for RawSocketWatcher { impl rtio::RtioRawSocket for RawSocketWatcher { fn recvfrom(&mut self, buf: &mut [u8]) - -> Result<(uint, ip::IpAddr), IoError> + -> Result<(uint, Option), IoError> { struct Ctx<'b> { task: Option, buf: &'b [u8], - result: Option<(ssize_t, Option)>, + result: Option<(ssize_t, Option)>, socket: Option, } let _m = self.fire_homing_missile(); @@ -863,7 +884,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { match cx.result.take_unwrap() { (n, _) if n < 0 => Err(last_error()), - (n, addr) => Ok((n as uint, addr.unwrap())) + (n, addr) => Ok((n as uint, Some(addr.unwrap()))) } } n => Err(uv_error_to_io_error(UvError(n))) @@ -906,14 +927,14 @@ impl rtio::RtioRawSocket for RawSocketWatcher { wakeup(&mut cx.task); return; } - let addr = Some(sockaddr_to_addr(&caddr, caddrlen as uint).ip); + let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); cx.result = Some((len as ssize_t, addr)); wakeup(&mut cx.task); } } - fn sendto(&mut self, buf: &[u8], dst: ip::IpAddr) + fn sendto(&mut self, buf: &[u8], dst: Option) -> Result { struct Ctx<'b> { @@ -925,6 +946,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } let _m = self.fire_homing_missile(); + let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; let a = match unsafe { uvll::uv_poll_start(self.handle, uvll::UV_WRITABLE as c_int, send_cb) } { @@ -934,7 +956,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: buf, result: None, socket: Some(self.socket), - addr: dst + addr: dst_ip.unwrap() }; wait_until_woken_after(&mut cx.task, &self.uv_loop(), || { unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index f91c958e112a4..c3f7f75bc93f8 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -12,6 +12,7 @@ use std::c_str::CString; use std::cast; use std::io::IoError; use std::io::net::ip::SocketAddr; +use std::io::net::raw::{Protocol}; use std::io::process::ProcessConfig; use std::io::signal::Signum; use std::io::{FileMode, FileAccess, Open, Append, Truncate, Read, Write, @@ -179,9 +180,8 @@ impl IoFactory for UvIoFactory { r.map_err(uv_error_to_io_error) } - fn raw_socket_new(&mut self, domain: i32, protocol: i32, - includeIpHeader: bool) -> Result<~rtio::RtioRawSocket, IoError> { - RawSocketWatcher::new(self, domain, protocol, includeIpHeader) + fn raw_socket_new(&mut self, protocol: Protocol) -> Result<~rtio::RtioRawSocket, IoError> { + RawSocketWatcher::new(self, protocol) .map(|rsw| ~rsw as ~rtio::RtioRawSocket) } diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 4a9b10be4ac0b..669aa3727ba3e 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -8,26 +8,890 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io::net::ip::{IpAddr}; +//use clone::Clone; +use cast; +use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; +use iter::Iterator; +use num; +use option::{Option, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; +use vec::ImmutableVector; pub struct RawSocket { priv obj: ~RtioRawSocket } impl RawSocket { - pub fn new(domain: i32, protocol: i32, includeIpHeader: bool) -> IoResult { + pub fn new(protocol: Protocol) -> IoResult { LocalIo::maybe_raise(|io| { - io.raw_socket_new(domain, protocol, includeIpHeader).map(|s| RawSocket { obj: s }) + io.raw_socket_new(protocol).map(|s| RawSocket { obj: s }) }) } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, IpAddr)> { + pub fn get_interfaces() -> ~[NetworkInterface] { + ~[] // FIXME + } + + pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, Option)> { self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> IoResult { + pub fn sendto(&mut self, buf: &[u8], dst: Option) -> IoResult { self.obj.sendto(buf, dst) } } + +pub struct NetworkInterface; + + +impl NetworkInterface { + pub fn mac_address(&self) -> MacAddr { + MacAddr(0, 0, 0, 0, 0, 0) // FIXME + } + + pub fn is_loopback(&self) -> bool { + false // FIXME + } +} + +pub struct EthernetHeader<'p> { + priv packet: &'p mut [u8], + priv offset: uint +} + +impl<'p> EthernetHeader<'p> { + pub fn act(packet: &mut [u8], offset: uint, act: |&mut EthernetHeader| -> T) -> T { + let mut header = EthernetHeader { packet: packet, offset: offset }; + act(&mut header) + } + + pub fn set_source(&mut self, _mac: MacAddr) { + // FIXME + } + + pub fn get_source(&self) -> MacAddr { + // FIXME + MacAddr(0, 0, 0, 0, 0, 0) + } + + pub fn set_destination(&mut self, _mac: MacAddr) { + // FIXME + } + + pub fn get_destination(&self) -> MacAddr { + // FIXME + MacAddr(0, 0, 0, 0, 0, 0) + } + + pub fn set_ethertype(&mut self, _ethertype: u16) { + // FIXME + } + + pub fn get_ethertype(&self) -> u16 { + // FIXME + 0 + } +} + +pub struct Ipv4Header<'p> { + priv packet: &'p mut [u8], + priv offset: uint +} + +impl<'p> Ipv4Header<'p> { + pub fn act(packet: &mut [u8], offset: uint, act: |&mut Ipv4Header| -> T) -> T { + let mut header = Ipv4Header { packet: packet, offset: offset }; + act(&mut header) + } + + pub fn set_version(&mut self, version: uint) { + let ver = ((version & 0xF) << 4) as u8; + self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; + } + + pub fn get_version(&self) -> uint { + (self.packet[self.offset] >> 4) as uint + } + + pub fn set_header_length(&mut self, ihl: uint) { + let len = (ihl & 0xF) as u8; + self.packet[self.offset] = (self.packet[self.offset] & 0xF0) | len; + } + + pub fn get_header_length(&self) -> uint { + (self.packet[self.offset] << 4) as uint + } + + pub fn set_dscp(&mut self, dscp: uint) { + let cp = (dscp & 0xFC) as u8; + self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 3) | cp; + } + + pub fn get_dscp(&self) -> uint { + (self.packet[self.offset + 1] & 0xFC) as uint + } + + pub fn set_ecn(&mut self, ecn: uint) { + let cn = (ecn & 3) as u8; + self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xFC) | cn; + } + + pub fn get_ecn(&self) -> uint { + (self.packet[self.offset + 1] & 3) as uint + } + + pub fn set_total_length(&mut self, len: uint) { + let tlen = (len & 0xFFFF) as u16; + self.packet[self.offset + 2] = (tlen >> 8) as u8; + self.packet[self.offset + 3] = (tlen << 8) as u8; + } + + pub fn get_total_length(&self) -> uint { + let b1 = self.packet[self.offset + 2] as u16 << 8; + let b2 = self.packet[self.offset + 3] as u16; + (b1 | b2) as uint + } + + pub fn set_identification(&mut self, identification: uint) { + let ident = (identification & 0xFFFF) as u16; + self.packet[self.offset + 4] = (ident >> 8) as u8; + self.packet[self.offset + 5] = (ident & 0x00FF) as u8; + } + + pub fn get_identification(&self) -> uint { + let b1 = self.packet[self.offset + 4] as u16 << 8; + let b2 = self.packet[self.offset + 5] as u16; + (b1 | b2) as uint + } + + pub fn set_flags(&mut self, flags: uint) { + let fs = ((flags & 7) << 5) as u8; + self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0x1F) | fs; + } + + pub fn get_flags(&self) -> uint { + (self.packet[self.offset + 6] >> 5) as uint + } + + pub fn set_fragment_offset(&mut self, offset: uint) { + let fo = (offset & 0x1FFF) as u16; + self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0xE0) | (fo & 0xFF00) as u8; + self.packet[self.offset + 7] = (fo & 0xFF) as u8; + } + + pub fn get_fragment_offset(&self) -> uint { + let b1 = (self.packet[self.offset + 6] & 0x1F) as u16 << 8; + let b2 = self.packet[self.offset + 7] as u16; + (b1 | b2) as uint + } + + pub fn set_ttl(&mut self, ttl: uint) { + self.packet[self.offset + 8] = (ttl & 0xFF) as u8; + } + + pub fn get_ttl(&self) -> uint { + self.packet[self.offset + 8] as uint + } + + pub fn set_next_level_protocol(&mut self, protocol: IpNextHeaderProtocol) { + self.packet[self.offset + 9] = protocol as u8; + } + + pub fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { + num::FromPrimitive::from_u8(self.packet[self.offset + 9]).unwrap() + } + + pub fn set_checksum(&mut self, checksum: uint) { + let cs1 = ((checksum & 0xFF00) >> 8) as u8; + let cs2 = (checksum & 0x00FF) as u8; + self.packet[self.offset + 10] = cs1; + self.packet[self.offset + 11] = cs2; + } + + pub fn get_checksum(&self) -> uint { + let cs1 = self.packet[self.offset + 10] as u16 << 8; + let cs2 = self.packet[self.offset + 11] as u16; + (cs1 | cs2) as uint + } + + pub fn set_source(&mut self, ip: IpAddr) { + match ip { + Ipv4Addr(a, b, c, d) => { + self.packet[self.offset + 12] = a; + self.packet[self.offset + 13] = b; + self.packet[self.offset + 14] = c; + self.packet[self.offset + 15] = d; + }, + _ => () + } + } + + pub fn get_source(&self) -> IpAddr { + Ipv4Addr(self.packet[self.offset + 12], + self.packet[self.offset + 13], + self.packet[self.offset + 14], + self.packet[self.offset + 15]) + } + + pub fn set_destination(&mut self, ip: IpAddr) { + match ip { + Ipv4Addr(a, b, c, d) => { + self.packet[self.offset + 16] = a; + self.packet[self.offset + 17] = b; + self.packet[self.offset + 18] = c; + self.packet[self.offset + 19] = d; + }, + _ => () + } + } + + pub fn get_destination(&self) -> IpAddr { + Ipv4Addr(self.packet[self.offset + 16], + self.packet[self.offset + 17], + self.packet[self.offset + 18], + self.packet[self.offset + 19]) + } + + pub fn set_options(&mut self, options: &[u8]) { + let mut i = 0; + for opt in options.iter() { + self.packet[self.offset + 20 + i] = *opt; + i = i + 1; + } + } + + /*pub fn get_options(&self) -> ~[u8] { + let numOpts = self.get_total_length() - 5; + ~self.packet.slice(self.offset + 20, self.offset + 20 + numOpts).clone() + /*let mut opts: ~[u8] = ~[]; + for opt in self.packet.slice(self.offset + 20, self.offset + 20 + numOpts).iter() { + opts.push(*opt); + } + opts*/ + }*/ + + pub fn checksum(&mut self) { + let len = self.get_header_length(); + let packet: &[u16] = unsafe { + cast::transmute(self.packet.slice(self.offset, self.offset + len * 4)) + }; + let mut sum = 0u32; + let mut i = 0; + loop { + if i == len * 2 { + break; + } + sum = sum + packet[i] as u32; + i = i + 1; + } + self.set_checksum(!((sum >> 16) + (sum & 0xFF)) as uint); + } +} + +pub struct Ipv6Header<'p> { + priv packet: &'p mut [u8], + priv offset: uint +} + +// FIXME Support extension headers +impl<'p> Ipv6Header<'p> { + pub fn act(packet: &mut [u8], offset: uint, act: |&mut Ipv6Header| -> T) -> T { + let mut header = Ipv6Header { packet: packet, offset: offset }; + act(&mut header) + } + + pub fn set_version(&mut self, _version: uint) { + // FIXME + } + + pub fn get_version(&self) -> uint { + // FIXME + 0 + } + + pub fn set_traffic_class(&mut self, _tc: uint) { + // FIXME + } + + pub fn get_traffic_class(&self) -> uint { + // FIXME + 0 + } + + pub fn set_flow_label(&mut self, _label: uint) { + // FIXME + } + + pub fn get_flow_label(&self) -> uint { + // FIXME + 0 + } + + pub fn set_payload_length(&mut self, _len: uint) { + // FIXME + } + + pub fn get_payload_length(&self) -> uint { + // FIXME + 0 + } + + pub fn set_next_header(&mut self, _protocol: IpNextHeaderProtocol) { + // FIXME + } + + pub fn get_next_header(&self) -> IpNextHeaderProtocol { + // FIXME + IpNextHeaderProtocol::Tcp + } + + pub fn set_hop_limit(&mut self, _limit: uint) { + // FIXME + } + + pub fn get_hop_limit(&self) -> uint { + // FIXME + 0 + } + + pub fn set_source(&mut self, _ip: IpAddr) { + // FIXME + } + + pub fn get_source(&self) -> IpAddr { + // FIXME + Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0) + } + + pub fn set_destination(&mut self, _ip: IpAddr) { + // FIXME + } + + pub fn get_destination(&self) -> IpAddr { + // FIXME + Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0) + } +} + +pub struct UdpHeader<'p> { + priv packet: &'p mut [u8], + priv offset: uint +} + +impl<'p> UdpHeader<'p> { + pub fn act(packet: &mut [u8], offset: uint, act: |&mut UdpHeader| -> T) -> T { + let mut header = UdpHeader { packet: packet, offset: offset }; + act(&mut header) + } + + pub fn set_source(&mut self, port: uint) { + let p = (port & 0xFFFF) as u16; + self.packet[self.offset + 0] = (p >> 8) as u8; + self.packet[self.offset + 1] = (p & 0xFF) as u8; + } + + pub fn get_source(&self) -> uint { + let s1 = self.packet[self.offset + 0] as u16 << 8; + let s2 = self.packet[self.offset + 1] as u16; + (s1 | s2) as uint + } + + pub fn set_destination(&mut self, port: uint) { + let p = (port & 0xFFFF) as u16; + self.packet[self.offset + 2] = (p >> 8) as u8; + self.packet[self.offset + 3] = (p & 0xFF) as u8; + } + + pub fn get_destination(&self) -> uint { + let d1 = self.packet[self.offset + 2] as u16 << 8; + let d2 = self.packet[self.offset + 3] as u16; + (d1 | d2) as uint + } + + pub fn set_length(&mut self, len: uint) { + let l = (len & 0xFFFF) as u16; + self.packet[self.offset + 4] = (l >> 8) as u8; + self.packet[self.offset + 5] = (l & 0xFF) as u8; + } + + pub fn get_length(&self) -> uint { + let l1 = self.packet[self.offset + 4] as u16 << 8; + let l2 = self.packet[self.offset + 5] as u16; + (l1 | l2) as uint + } + + pub fn set_checksum(&mut self, checksum: uint) { + let c = (checksum & 0xFFFF) as u16; + self.packet[self.offset + 6] = (c >> 8) as u8; + self.packet[self.offset + 7] = (c & 0xFF) as u8; + } + + pub fn get_checksum(&self) -> uint { + let c1 = self.packet[self.offset + 6] as u16 << 8; + let c2 = self.packet[self.offset + 7] as u16; + (c1 | c2) as uint + } + + pub fn checksum(&mut self) { + // FIXME + } +} + +#[deriving(Eq)] +pub enum NetworkAddress { + IpAddress(IpAddr), + MacAddress(MacAddr) +} + +#[deriving(Eq)] +pub enum MacAddr { + MacAddr(u8, u8, u8, u8, u8, u8) +} + +pub enum Protocol { + DataLinkProtocol(DataLinkProto), + NetworkProtocol(NetworkProto), + TransportProtocol(TransportProto) +} + +pub enum DataLinkProto { + EthernetProtocol(NetworkInterface), + CookedEthernetProtocol(NetworkInterface) +} + +pub enum NetworkProto { + Ipv4NetworkProtocol, + Ipv6NetworkProtocol +} + +pub enum TransportProto { + Ipv4TransportProtocol(IpNextHeaderProtocol), + Ipv6TransportProtocol(IpNextHeaderProtocol) +} + +// EtherTypes defined at: +// http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml +// These values should be used in the Ethernet EtherType field +// +// A handful of these have been selected since most are archaic and unused. +pub static Ipv4EtherType: u16 = 0x0800; +pub static ArpEtherType: u16 = 0x0806; +pub static WakeOnLanEtherType: u16 = 0x0842; +pub static RarpEtherType: u16 = 0x8035; +pub static Ipv6EtherType: u16 = 0x86DD; + +// Protocol numbers as defined at: +// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml +// Above protocol numbers last updated: 2014-01-16 +// These values should be used in either the IPv4 Next Level Protocol field +// or the IPv6 Next Header field. +pub mod IpNextHeaderProtocol { + //use num::FromPrimitive; + #[deriving(FromPrimitive)] + pub enum IpNextHeaderProtocol { + Hopopt = 0, // IPv6 Hop-by-Hop Option [RFC2460] + Icmp = 1, // Internet Control Message [RFC792] + Igmp = 2, // Internet Group Management [RFC1112] + Ggp = 3, // Gateway-to-Gateway [RFC823] + Ipv4 = 4, // IPv4 encapsulation [RFC2003] + St = 5, // Stream [RFC1190][RFC1819] + Tcp = 6, // Transmission Control [RFC793] + Cbt = 7, // CBT + Egp = 8, // Exterior Gateway Protocol [RFC888] + Igp = 9, // any private interior gateway (used by Cisco for their IGRP) + BbnRccMon = 10, // BBN RCC Monitoring + NvpII = 11, // Network Voice Protocol [RFC741] + Pup = 12, // PUP + Argus = 13, // ARGUS + Emcon = 14, // EMCON + Xnet = 15, // Cross Net Debugger + Chaos = 16, // Chaos + Udp = 17, // User Datagram [RFC768] + Mux = 18, // Multiplexing + DcnMeas = 19, // DCN Measurement Subsystems + Hmp = 20, // Host Monitoring [RFC869] + Prm = 21, // Packet Radio Measurement + XnsIdp = 22, // XEROX NS IDP + Trunk1 = 23, // Trunk-1 + Trunk2 = 24, // Trunk-2 + Leaf1 = 25, // Leaf-1 + Leaf2 = 26, // Leaf-2 + Rdp = 27, // Reliable Data Protocol [RFC908] + Irtp = 28, // Internet Reliable Transaction [RFC938] + IsoTp4 = 29, // ISO Transport Protocol Class 4 [RFC905] + Netblt = 30, // Bulk Data Transfer Protocol [RFC969] + MfeNsp = 31, // MFE Network Services Protocol + MeritInp = 32, // MERIT Internodal Protocol + Dccp = 33, // Datagram Congestion Control Protocol [RFC4340] + ThreePc = 34, // Third Party Connect Protocol + Idpr = 35, // Inter-Domain Policy Routing Protocol + Xtp = 36, // XTP + Ddp = 37, // Datagram Delivery Protocol + IdprCmtp = 38, // IDPR Control Message Transport Proto + TpPlusPlus = 39, // TP++ Transport Protocol + Il = 40, // IL Transport Protocol + Ipv6 = 41, // IPv6 encapsulation [RFC2473] + Sdrp = 42, // Source Demand Routing Protocol + Ipv6Route = 43, // Routing Header for IPv6 + Ipv6Frag = 44, // Fragment Header for IPv6 + Idrp = 45, // Inter-Domain Routing Protocol + Rsvp = 46, // Reservation Protocol [RFC2205][RFC3209] + Gre = 47, // Generic Routing Encapsulation [RFC1701] + Dsr = 48, // Dynamic Source Routing Protocol [RFC4728] + Bna = 49, // BNA + Esp = 50, // Encap Security Payload [RFC4303] + Ah = 51, // Authentication Header [RFC4302] + INlsp = 52, // Integrated Net Layer Security TUBA + Swipe = 53, // IP with Encryption + Narp = 54, // NBMA Address Resolution Protocol [RFC1735] + Mobile = 55, // IP Mobility + Tlsp = 56, // Transport Layer Security Protocol using Kryptonet key management + Skip = 57, // SKIP + Ipv6Icmp = 58, // ICMP for IPv6 [RFC2460] + Ipv6NoNxt = 59, // No Next Header for IPv6 [RFC2460] + Ipv6Opts = 60, // Destination Options for IPv6 [RFC2460] + HostInternal = 61, // any host internal protocol + Cftp = 62, // CFTP + LocalNetwork = 63, // any local network + SatExpak = 64, // SATNET and Backroom EXPAK + Kryptolan = 65, // Kryptolan + Rvd = 66, // MIT Remote Virtual Disk Protocol + Ippc = 67, // Internet Pluribus Packet Core + DistributedFs = 68, // any distributed file system + SatMon = 69, // SATNET Monitoring + Visa = 70, // VISA Protocol + Ipcv = 71, // Internet Packet Core Utility + Cpnx = 72, // Computer Protocol Network Executive + Cphb = 73, // Computer Protocol Heart Beat + Wsn = 74, // Wang Span Network + Pvp = 75, // Packet Video Protocol + BrSatMon = 76, // Backroom SATNET Monitoring + SunNd = 77, // SUN ND PROTOCOL-Temporary + WbMon = 78, // WIDEBAND Monitoring + WbExpak = 79, // WIDEBAND EXPAK + IsoIp = 80, // ISO Internet Protocol + Vmtp = 81, // VMTP + SecureVmtp = 82, // SECURE-VMTP + Vines = 83, // VINES + TtpOrIptm = 84, // Transaction Transport Protocol/Internet Protocol Traffic Manager + NsfnetIgp = 85, // NSFNET-IGP + Dgp = 86, // Dissimilar Gateway Protocol + Tcf = 87, // TCF + Eigrp = 88, // EIGRP + OspfigP = 89, // OSPFIGP [RFC1583][RFC2328][RFC5340] + SpriteRpc = 90, // Sprite RPC Protocol + Larp = 91, // Locus Address Resolution Protocol + Mtp = 92, // Multicast Transport Protocol + Ax25 = 93, // AX.25 Frames + IpIp = 94, // IP-within-IP Encapsulation Protocol + Micp = 95, // Mobile Internetworking Control Pro. + SccSp = 96, // Semaphore Communications Sec. Pro. + Etherip = 97, // Ethernet-within-IP Encapsulation [RFC3378] + Encap = 98, // Encapsulation Header [RFC1241] + PrivEncryption = 99, // any private encryption scheme + Gmtp = 100, // GMTP + Ifmp = 101, // Ipsilon Flow Management Protocol + Pnni = 102, // PNNI over IP + Pim = 103, // Protocol Independent Multicast [RFC4601] + Aris = 104, // ARIS + Scps = 105, // SCPS + Qnx = 106, // QNX + AN = 107, // Active Networks + IpComp = 108, // IP Payload Compression Protocol [RFC2393] + Snp = 109, // Sitara Networks Protocol + CompaqPeer = 110, // Compaq Peer Protocol + IpxInIp = 111, // IPX in IP + Vrrp = 112, // Virtual Router Redundancy Protocol [RFC5798] + Pgm = 113, // PGM Reliable Transport Protocol + ZeroHop = 114, // any 0-hop protocol + L2tp = 115, // Layer Two Tunneling Protocol [RFC3931] + Ddx = 116, // D-II Data Exchange (DDX) + Iatp = 117, // Interactive Agent Transfer Protocol + Stp = 118, // Schedule Transfer Protocol + Srp = 119, // SpectraLink Radio Protocol + Uti = 120, // UTI + Smp = 121, // Simple Message Protocol + Sm = 122, // Simple Multicast Protocol + Ptp = 123, // Performance Transparency Protocol + IsisOverIpv4 = 124, // + Fire = 125, // + Crtp = 126, // Combat Radio Transport Protocol + Crudp = 127, // Combat Radio User Datagram + Sscopmce = 128, // + Iplt = 129, // + Sps = 130, // Secure Packet Shield + Pipe = 131, // Private IP Encapsulation within IP + Sctp = 132, // Stream Control Transmission Protocol + Fc = 133, // Fibre Channel [RFC6172] + RsvpE2eIgnore = 134, // [RFC3175] + MobilityHeader = 135, // [RFC6275] + UdpLite = 136, // [RFC3828] + MplsInIp = 137, // [RFC4023] + Manet = 138, // MANET Protocols [RFC5498] + Hip = 139, // Host Identity Protocol [RFC5201] + Shim6 = 140, // Shim6 Protocol [RFC5533] + Wesp = 141, // Wrapped Encapsulating Security Payload [RFC5840] + Rohc = 142, // Robust Header Compression [RFC5858] + Test1 = 253, // Use for experimentation and testing [RFC3692] + Test2 = 254, // Use for experimentation and testing [RFC3692] + Reserved = 255, // + } +} + +pub type IpNextHeaderProtocol = self::IpNextHeaderProtocol::IpNextHeaderProtocol; + +#[cfg(test)] +pub mod test { + use result::{Ok, Err}; + use iter::Iterator; + use container::Container; + use option::{Some}; + use str::StrSlice; + use super::*; + use task::spawn; + use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; + use vec::ImmutableVector; + + pub static ETHERNET_HEADER_LEN: uint = 14; + pub static IPV4_HEADER_LEN: uint = 20; + pub static IPV6_HEADER_LEN: uint = 40; + pub static UDP_HEADER_LEN: uint = 8; + pub static TEST_DATA_LEN: uint = 4; + + pub fn layer4_test(ip: IpAddr, headerLen: uint) { + let message = "message"; + let proto = match ip { + Ipv4Addr(..) => TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocol::Test1)), + Ipv6Addr(..) => TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocol::Test1)) + }; + spawn( proc() { + let mut buf: ~[u8] = ~[0, ..128]; + match RawSocket::new(proto) { + Ok(mut sock) => match sock.recvfrom(buf) { + Ok((len, Some(IpAddress(addr)))) => { + assert_eq!(buf.slice(headerLen, message.len()), message.as_bytes()); + assert_eq!(len, message.len()); + assert_eq!(addr, ip); + }, + _ => fail!() + }, + Err(_) => fail!() + } + }); + + match RawSocket::new(proto) { + Ok(mut sock) => match sock.sendto(message.as_bytes(), Some(IpAddress(ip))) { + Ok(res) => assert_eq!(res as uint, message.len()), + Err(_) => fail!() + }, + Err(_) => fail!() + } + } + + iotest!(fn layer4_ipv4() { + layer4_test(Ipv4Addr(127, 0, 0, 1), IPV4_HEADER_LEN); + } #[cfg(hasroot)]) + + iotest!(fn layer4_ipv6() { + layer4_test(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), IPV6_HEADER_LEN); + } #[cfg(hasroot)]) + + pub fn build_ipv4_header(packet: &mut [u8], offset: uint) { + Ipv4Header::act(packet, offset, |ipHeader| { + ipHeader.set_version(4); + ipHeader.set_header_length(5); + ipHeader.set_total_length(IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN); + ipHeader.set_ttl(4); + ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); + ipHeader.set_source(Ipv4Addr(127, 0, 0, 1)); + ipHeader.set_destination(Ipv4Addr(127, 0, 0, 1)); + ipHeader.checksum(); + }); + } + + pub fn build_ipv6_header(packet: &mut [u8], offset: uint) { + Ipv6Header::act(packet, offset, |ipHeader| { + ipHeader.set_version(6); + ipHeader.set_payload_length(UDP_HEADER_LEN + TEST_DATA_LEN); + ipHeader.set_next_header(IpNextHeaderProtocol::Udp); + ipHeader.set_hop_limit(4); + ipHeader.set_source(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); + ipHeader.set_destination(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); + }); + } + + pub fn build_udp_header(packet: &mut [u8], offset: uint) { + UdpHeader::act(packet, offset, |udpHeader| { + udpHeader.set_source(1234); // Arbitary port number + udpHeader.set_destination(1234); + udpHeader.set_length(UDP_HEADER_LEN + TEST_DATA_LEN); + udpHeader.checksum(); + }); + } + + pub fn build_udp4_packet(packet: &mut [u8], start: uint) { + build_ipv4_header(packet, start); + build_udp_header(packet, IPV4_HEADER_LEN); + + let dataStart = IPV4_HEADER_LEN + UDP_HEADER_LEN; + packet[dataStart + 0] = 't' as u8; + packet[dataStart + 1] = 'e' as u8; + packet[dataStart + 2] = 's' as u8; + packet[dataStart + 3] = 't' as u8; + } + + pub fn build_udp6_packet(packet: &mut [u8], start: uint) { + build_ipv6_header(packet, start); + build_udp_header(packet, IPV6_HEADER_LEN); + + let dataStart = IPV6_HEADER_LEN + UDP_HEADER_LEN; + packet[dataStart + 0] = 't' as u8; + packet[dataStart + 1] = 'e' as u8; + packet[dataStart + 2] = 's' as u8; + packet[dataStart + 3] = 't' as u8; + } + + pub fn get_test_interface() -> NetworkInterface { + *RawSocket::get_interfaces() + .iter() + .filter(|&x| x.is_loopback()) + .next() + .unwrap() + } + + iotest!(fn layer3_ipv4_test() { + let sendAddr = Ipv4Addr(127, 0, 0, 1); + let mut packet = [0u8, ..IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN]; + build_udp4_packet(packet.as_mut_slice(), 0); + + spawn( proc() { + let mut buf: ~[u8] = ~[0, ..128]; + match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { + Ok(mut sock) => match sock.recvfrom(buf) { + Ok((len, Some(IpAddress(addr)))) => { + assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); + assert_eq!(len, packet.len()); + assert_eq!(addr, sendAddr); + }, + _ => fail!() + }, + Err(_) => fail!() + } + }); + + match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { + Ok(mut sock) => match sock.sendto(packet, Some(IpAddress(sendAddr))) { + Ok(res) => assert_eq!(res as uint, packet.len()), + Err(_) => fail!() + }, + Err(_) => fail!() + } + + } #[cfg(hasroot)]) + + iotest!(fn layer3_ipv6_test() { + let sendAddr = Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1); + let mut packet = [0u8, ..IPV6_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN]; + build_udp6_packet(packet.as_mut_slice(), 0); + + spawn( proc() { + let mut buf: ~[u8] = ~[0, ..128]; + match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { + Ok(mut sock) => match sock.recvfrom(buf) { + Ok((len, Some(IpAddress(addr)))) => { + assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); + assert_eq!(len, packet.len()); + assert_eq!(addr, sendAddr); + }, + _ => fail!() + }, + Err(_) => fail!() + } + }); + + match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { + Ok(mut sock) => match sock.sendto(packet, Some(IpAddress(sendAddr))) { + Ok(res) => assert_eq!(res as uint, packet.len()), + Err(_) => fail!() + }, + Err(_) => fail!() + } + + } #[cfg(hasroot)]) + + iotest!(fn layer2_cooked_test() { + let interface = get_test_interface(); + + let mut packet = [0u8, ..32]; + + build_udp4_packet(packet.as_mut_slice(), 0); + + spawn( proc() { + let mut buf: ~[u8] = ~[0, ..128]; + match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(interface))) { + Ok(mut sock) => match sock.recvfrom(buf) { + Ok((len, Some(MacAddress(addr)))) => { + assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); + assert_eq!(len, packet.len()); + assert_eq!(addr, interface.mac_address()); + }, + _ => fail!() + }, + Err(_) => fail!() + } + }); + + match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(interface))) { + Ok(mut sock) => match sock.sendto(packet, Some(MacAddress(interface.mac_address()))) { + Ok(res) => assert_eq!(res as uint, packet.len()), + Err(_) => fail!() + }, + Err(_) => fail!() + } + } #[cfg(hasroot)]) + + iotest!(fn layer2_test() { + let interface = get_test_interface(); + + let mut packet = [0u8, ..46]; + + //let mut ethernetHeader = EthernetHeader::new(0); + //ethernetHeader.set_source(interface.mac_address()); + //ethernetHeader.set_destination(interface.mac_address()); + //ethernetHeader.set_ethertype(Ipv4EtherType); + + EthernetHeader::act(packet.as_mut_slice(), 0, |ethernetHeader| { + ethernetHeader.set_source(interface.mac_address()); + ethernetHeader.set_destination(interface.mac_address()); + ethernetHeader.set_ethertype(Ipv4EtherType); + }); + + build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN); + + spawn( proc() { + let mut buf: ~[u8] = ~[0, ..128]; + match RawSocket::new(DataLinkProtocol(EthernetProtocol(interface))) { + Ok(mut sock) => match sock.recvfrom(buf) { + Ok((len, Some(MacAddress(addr)))) => { + assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); + assert_eq!(len, packet.len()); + assert_eq!(addr, interface.mac_address()); + }, + _ => fail!() + }, + Err(_) => fail!() + } + }); + + match RawSocket::new(DataLinkProtocol(EthernetProtocol(interface))) { + Ok(mut sock) => match sock.sendto(packet, None) { + Ok(res) => assert_eq!(res as uint, packet.len()), + Err(_) => fail!() + }, + Err(_) => fail!() + } + + } #[cfg(hasroot)]) + +} diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs index 04ecb479060c4..55e1a7c40078e 100644 --- a/src/libstd/io/test.rs +++ b/src/libstd/io/test.rs @@ -32,6 +32,8 @@ macro_rules! iotest ( use io::net::tcp::*; use io::net::ip::*; use io::net::udp::*; + use io::net::raw::*; + use io::net::raw::test::*; #[cfg(unix)] use io::net::unix::*; use io::timer::*; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4452482b7e8ce..d638d6a020568 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -217,6 +217,7 @@ mod std { pub use kinds; pub use local_data; pub use logging; + pub use num; pub use option; pub use os; pub use rt; diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 62301f55fa52c..f84b207a32e72 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2342,6 +2342,9 @@ pub mod consts { pub mod extra { use libc::types::os::arch::c95::c_int; + pub static AF_PACKET : c_int = 17; + pub static IPPROTO_RAW : c_int = 255; + pub static O_RSYNC : c_int = 1052672; pub static O_DSYNC : c_int = 4096; pub static O_NONBLOCK : c_int = 2048; diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 5968eaf74f367..e54f3351ea4ef 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -24,6 +24,7 @@ use ai = io::net::addrinfo; use io; use io::{IoError, IoResult}; use io::net::ip::{IpAddr, SocketAddr}; +use io::net::raw::{NetworkAddress, Protocol}; use io::process::{ProcessConfig, ProcessExit}; use io::signal::Signum; use io::{FileMode, FileAccess, FileStat, FilePermission}; @@ -151,8 +152,7 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; - fn raw_socket_new(&mut self, domain: i32, protocol: i32, - includeIpHeader: bool) -> Result<~RtioRawSocket, IoError>; + fn raw_socket_new(&mut self, protocol: Protocol) -> Result<~RtioRawSocket, IoError>; // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; @@ -233,8 +233,8 @@ pub trait RtioUdpSocket : RtioSocket { } pub trait RtioRawSocket { - fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>; - fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result; + fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, Option), IoError>; + fn sendto(&mut self, buf: &[u8], dst: Option) -> Result; } pub trait RtioTimer { diff --git a/src/test/run-make/raw-sockets/Makefile b/src/test/run-make/raw-sockets/Makefile deleted file mode 100644 index cf65e7538cc7d..0000000000000 --- a/src/test/run-make/raw-sockets/Makefile +++ /dev/null @@ -1,13 +0,0 @@ --include ../tools.mk - -ifneq ($(shell uname),Darwin) - EXTRAFLAGS := -lm -lrt -ldl -lpthread -endif - -all: - $(RUSTC) clib.rs - ln -s $(call STATICLIB,clib-*) $(call STATICLIB,clib) - $(RUSTC) test.rs --test -o $(call RUN,test) -C link-args="$(call STATICLIB,clib) $(EXTRAFLAGS)" - $(call RUN,test) - rm $(call STATICLIB,clib*) - rm $(call RUN,test*) diff --git a/src/test/run-make/raw-sockets/clib.rs b/src/test/run-make/raw-sockets/clib.rs deleted file mode 100644 index e3be26323ba16..0000000000000 --- a/src/test/run-make/raw-sockets/clib.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Dummy functions for raw sockets - - Ordinarily raw sockets require root access to the machine. By - re-implementing the library functions used and replacing them - with dummy functions we are able to test the functionality without - root access. -*/ -#[crate_type="staticlib"]; - -extern mod rustuv; - -use std::libc::{c_int, c_void, size_t, ssize_t}; -use std::libc::{sockaddr, sockaddr_storage, socklen_t}; - - -static mut data: *c_void = 0 as *c_void; -static mut datalen: ssize_t = 0; - -static mut fromaddr: sockaddr_storage = sockaddr_storage { ss_family: 0, __ss_align: 0, __ss_pad2: [0, ..112] }; -static mut fromaddrlen: socklen_t = 0; - -// Only one socket, always succeeds -#[no_mangle] -pub extern "C" fn socket(_domain: c_int, _ty: c_int, _protocol: c_int) -> c_int { - 1 -} - -#[no_mangle] -pub extern "C" fn close(_fd: c_int) -> c_int { - 1 -} -#[no_mangle] -pub extern "C" fn setsockopt(_socket: c_int, _level: c_int, _name: c_int, - _value: *c_void, _option_len: socklen_t) -> c_int { - 1 -} - -// FIXME This doesn't match the C definition, so may stop working if -// the usage in the raw socket backend code changes -#[no_mangle] -pub extern "C" fn fcntl(_fd: c_int, _cmd: c_int, _opt: c_int) -> c_int { - 1 -} - -// Receive data from previous sendto() -#[no_mangle] -pub extern "C" fn recvfrom(_socket: c_int, buf: *mut c_void, len: size_t, - _flags: c_int, addr: *mut sockaddr, - addrlen: *mut socklen_t) -> ssize_t { - unsafe { - // This could/should be replaced with memcpy - for i in range(0, datalen) { - if i >= len as ssize_t { - break; - } - *(((buf as size_t) + i as size_t) as *mut char) = *(((data as size_t) + i as size_t) as *char); - } - let stoAddr = addr as *mut sockaddr_storage; - *stoAddr = fromaddr; - *addrlen = fromaddrlen; - - datalen - } -} - -// Send data -#[no_mangle] -pub extern "C" fn sendto(_socket: c_int, buf: *c_void, len: size_t, - _flags: c_int, addr: *sockaddr, - addrlen: socklen_t) -> ssize_t { - unsafe { - datalen = len as ssize_t; - data = buf; - fromaddr = *(addr as *sockaddr_storage); - fromaddrlen = addrlen; - - datalen - } -} diff --git a/src/test/run-make/raw-sockets/test.rs b/src/test/run-make/raw-sockets/test.rs deleted file mode 100644 index 3b452e1bd82ef..0000000000000 --- a/src/test/run-make/raw-sockets/test.rs +++ /dev/null @@ -1,62 +0,0 @@ -extern mod native; - -use std::io::net::raw::{RawSocket}; -use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; -use std::libc::{AF_INET, AF_INET6}; - - -// RFC 3692 test protocol number -static testProtocol: i32 = 253; - -fn test(ip: IpAddr) { - let message = "message"; - let prot = match ip { - Ipv4Addr(..) => AF_INET, - Ipv6Addr(..) => AF_INET6 - }; - spawn( proc() { - let mut buf: ~[u8] = ~[0, .. 128]; - let sock = RawSocket::new(prot, testProtocol, false); - match sock { - Ok(mut s) => match s.recvfrom(buf) { - Ok((len, addr)) => { - assert_eq!(buf.slice(0, message.len()), message.as_bytes()); - assert_eq!(len, message.len()); - assert_eq!(addr, ip); - }, - Err(_) => fail!() - }, - Err(_) => fail!() - }; - }); - - let sock = RawSocket::new(prot, testProtocol, false); - let _res = sock.map(|mut sock| { - match sock.sendto(message.as_bytes(), ip) { - Ok(res) => assert_eq!(res as uint, message.len()), - Err(_) => fail!() - } - }); -} - -fn ipv4_test() { - test(Ipv4Addr(127, 0, 0, 1)); -} - -fn ipv6_test() { - test(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); -} - -#[test] -fn native_ipv4_test() { - let (p, c) = Chan::new(); - native::task::spawn(proc() { c.send(ipv4_test()) }); - p.recv(); -} - -#[test] -fn native_ipv6_test() { - let (p, c) = Chan::new(); - native::task::spawn(proc() { c.send(ipv6_test()) }); - p.recv(); -} From bd9d046b3d1c98a65386143f99f101a35b9108c2 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Tue, 18 Feb 2014 18:53:08 +0000 Subject: [PATCH 22/54] Clean up packet building interfaces. Disable UDP/TCP tests which require no-root. --- src/libstd/io/net/raw.rs | 253 +++++++++++++++++++-------------------- src/libstd/io/net/tcp.rs | 2 +- src/libstd/io/net/udp.rs | 2 +- 3 files changed, 124 insertions(+), 133 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 669aa3727ba3e..373215ca2d125 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -61,9 +61,8 @@ pub struct EthernetHeader<'p> { } impl<'p> EthernetHeader<'p> { - pub fn act(packet: &mut [u8], offset: uint, act: |&mut EthernetHeader| -> T) -> T { - let mut header = EthernetHeader { packet: packet, offset: offset }; - act(&mut header) + pub fn new(packet: &'p mut [u8], offset: uint) -> EthernetHeader<'p> { + EthernetHeader { packet: packet, offset: offset } } pub fn set_source(&mut self, _mac: MacAddr) { @@ -100,98 +99,95 @@ pub struct Ipv4Header<'p> { } impl<'p> Ipv4Header<'p> { - pub fn act(packet: &mut [u8], offset: uint, act: |&mut Ipv4Header| -> T) -> T { - let mut header = Ipv4Header { packet: packet, offset: offset }; - act(&mut header) + pub fn new(packet: &'p mut [u8], offset: uint) -> Ipv4Header<'p> { + Ipv4Header { packet: packet, offset: offset } } - pub fn set_version(&mut self, version: uint) { - let ver = ((version & 0xF) << 4) as u8; + pub fn set_version(&mut self, version: u8) { + let ver = version << 4; self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; } - pub fn get_version(&self) -> uint { - (self.packet[self.offset] >> 4) as uint + pub fn get_version(&self) -> u8 { + self.packet[self.offset] >> 4 } - pub fn set_header_length(&mut self, ihl: uint) { - let len = (ihl & 0xF) as u8; + pub fn set_header_length(&mut self, ihl: u8) { + let len = ihl & 0xF; self.packet[self.offset] = (self.packet[self.offset] & 0xF0) | len; } - pub fn get_header_length(&self) -> uint { - (self.packet[self.offset] << 4) as uint + pub fn get_header_length(&self) -> u8 { + self.packet[self.offset] << 4 } - pub fn set_dscp(&mut self, dscp: uint) { - let cp = (dscp & 0xFC) as u8; + pub fn set_dscp(&mut self, dscp: u8) { + let cp = dscp & 0xFC; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 3) | cp; } - pub fn get_dscp(&self) -> uint { - (self.packet[self.offset + 1] & 0xFC) as uint + pub fn get_dscp(&self) -> u8 { + self.packet[self.offset + 1] & 0xFC } - pub fn set_ecn(&mut self, ecn: uint) { - let cn = (ecn & 3) as u8; + pub fn set_ecn(&mut self, ecn: u8) { + let cn = ecn & 3; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xFC) | cn; } - pub fn get_ecn(&self) -> uint { - (self.packet[self.offset + 1] & 3) as uint + pub fn get_ecn(&self) -> u8 { + self.packet[self.offset + 1] & 3 } - pub fn set_total_length(&mut self, len: uint) { - let tlen = (len & 0xFFFF) as u16; - self.packet[self.offset + 2] = (tlen >> 8) as u8; - self.packet[self.offset + 3] = (tlen << 8) as u8; + pub fn set_total_length(&mut self, len: u16) { + self.packet[self.offset + 2] = (len >> 8) as u8; + self.packet[self.offset + 3] = (len << 8) as u8; } - pub fn get_total_length(&self) -> uint { + pub fn get_total_length(&self) -> u16 { let b1 = self.packet[self.offset + 2] as u16 << 8; let b2 = self.packet[self.offset + 3] as u16; - (b1 | b2) as uint + b1 | b2 } - pub fn set_identification(&mut self, identification: uint) { - let ident = (identification & 0xFFFF) as u16; - self.packet[self.offset + 4] = (ident >> 8) as u8; - self.packet[self.offset + 5] = (ident & 0x00FF) as u8; + pub fn set_identification(&mut self, identification: u16) { + self.packet[self.offset + 4] = (identification >> 8) as u8; + self.packet[self.offset + 5] = (identification & 0x00FF) as u8; } - pub fn get_identification(&self) -> uint { + pub fn get_identification(&self) -> u16 { let b1 = self.packet[self.offset + 4] as u16 << 8; let b2 = self.packet[self.offset + 5] as u16; - (b1 | b2) as uint + b1 | b2 } - pub fn set_flags(&mut self, flags: uint) { - let fs = ((flags & 7) << 5) as u8; + pub fn set_flags(&mut self, flags: u8) { + let fs = (flags & 7) << 5; self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0x1F) | fs; } - pub fn get_flags(&self) -> uint { - (self.packet[self.offset + 6] >> 5) as uint + pub fn get_flags(&self) -> u8 { + self.packet[self.offset + 6] >> 5 } - pub fn set_fragment_offset(&mut self, offset: uint) { - let fo = (offset & 0x1FFF) as u16; + pub fn set_fragment_offset(&mut self, offset: u16) { + let fo = offset & 0x1FFF; self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0xE0) | (fo & 0xFF00) as u8; self.packet[self.offset + 7] = (fo & 0xFF) as u8; } - pub fn get_fragment_offset(&self) -> uint { + pub fn get_fragment_offset(&self) -> u16 { let b1 = (self.packet[self.offset + 6] & 0x1F) as u16 << 8; let b2 = self.packet[self.offset + 7] as u16; - (b1 | b2) as uint + b1 | b2 } - pub fn set_ttl(&mut self, ttl: uint) { - self.packet[self.offset + 8] = (ttl & 0xFF) as u8; + pub fn set_ttl(&mut self, ttl: u8) { + self.packet[self.offset + 8] = ttl; } - pub fn get_ttl(&self) -> uint { - self.packet[self.offset + 8] as uint + pub fn get_ttl(&self) -> u8 { + self.packet[self.offset + 8] } pub fn set_next_level_protocol(&mut self, protocol: IpNextHeaderProtocol) { @@ -202,17 +198,17 @@ impl<'p> Ipv4Header<'p> { num::FromPrimitive::from_u8(self.packet[self.offset + 9]).unwrap() } - pub fn set_checksum(&mut self, checksum: uint) { + pub fn set_checksum(&mut self, checksum: u16) { let cs1 = ((checksum & 0xFF00) >> 8) as u8; let cs2 = (checksum & 0x00FF) as u8; self.packet[self.offset + 10] = cs1; self.packet[self.offset + 11] = cs2; } - pub fn get_checksum(&self) -> uint { + pub fn get_checksum(&self) -> u16 { let cs1 = self.packet[self.offset + 10] as u16 << 8; let cs2 = self.packet[self.offset + 11] as u16; - (cs1 | cs2) as uint + cs1 | cs2 } pub fn set_source(&mut self, ip: IpAddr) { @@ -272,7 +268,7 @@ impl<'p> Ipv4Header<'p> { }*/ pub fn checksum(&mut self) { - let len = self.get_header_length(); + let len = self.get_header_length() as uint; let packet: &[u16] = unsafe { cast::transmute(self.packet.slice(self.offset, self.offset + len * 4)) }; @@ -285,7 +281,7 @@ impl<'p> Ipv4Header<'p> { sum = sum + packet[i] as u32; i = i + 1; } - self.set_checksum(!((sum >> 16) + (sum & 0xFF)) as uint); + self.set_checksum(!((sum >> 16) + (sum & 0xFF)) as u16); } } @@ -296,12 +292,11 @@ pub struct Ipv6Header<'p> { // FIXME Support extension headers impl<'p> Ipv6Header<'p> { - pub fn act(packet: &mut [u8], offset: uint, act: |&mut Ipv6Header| -> T) -> T { - let mut header = Ipv6Header { packet: packet, offset: offset }; - act(&mut header) + pub fn new(packet: &'p mut [u8], offset: uint) -> Ipv6Header<'p> { + Ipv6Header { packet: packet, offset: offset } } - pub fn set_version(&mut self, _version: uint) { + pub fn set_version(&mut self, _version: u8) { // FIXME } @@ -310,29 +305,29 @@ impl<'p> Ipv6Header<'p> { 0 } - pub fn set_traffic_class(&mut self, _tc: uint) { + pub fn set_traffic_class(&mut self, _tc: u8) { // FIXME } - pub fn get_traffic_class(&self) -> uint { + pub fn get_traffic_class(&self) -> u8 { // FIXME 0 } - pub fn set_flow_label(&mut self, _label: uint) { + pub fn set_flow_label(&mut self, _label: u32) { // FIXME } - pub fn get_flow_label(&self) -> uint { + pub fn get_flow_label(&self) -> u32 { // FIXME 0 } - pub fn set_payload_length(&mut self, _len: uint) { + pub fn set_payload_length(&mut self, _len: u16) { // FIXME } - pub fn get_payload_length(&self) -> uint { + pub fn get_payload_length(&self) -> u16 { // FIXME 0 } @@ -346,11 +341,11 @@ impl<'p> Ipv6Header<'p> { IpNextHeaderProtocol::Tcp } - pub fn set_hop_limit(&mut self, _limit: uint) { + pub fn set_hop_limit(&mut self, _limit: u8) { // FIXME } - pub fn get_hop_limit(&self) -> uint { + pub fn get_hop_limit(&self) -> u8 { // FIXME 0 } @@ -380,57 +375,52 @@ pub struct UdpHeader<'p> { } impl<'p> UdpHeader<'p> { - pub fn act(packet: &mut [u8], offset: uint, act: |&mut UdpHeader| -> T) -> T { - let mut header = UdpHeader { packet: packet, offset: offset }; - act(&mut header) + pub fn new(packet: &'p mut [u8], offset: uint) -> UdpHeader<'p> { + UdpHeader { packet: packet, offset: offset } } - pub fn set_source(&mut self, port: uint) { - let p = (port & 0xFFFF) as u16; - self.packet[self.offset + 0] = (p >> 8) as u8; - self.packet[self.offset + 1] = (p & 0xFF) as u8; + pub fn set_source(&mut self, port: u16) { + self.packet[self.offset + 0] = (port >> 8) as u8; + self.packet[self.offset + 1] = (port & 0xFF) as u8; } - pub fn get_source(&self) -> uint { + pub fn get_source(&self) -> u16 { let s1 = self.packet[self.offset + 0] as u16 << 8; let s2 = self.packet[self.offset + 1] as u16; - (s1 | s2) as uint + s1 | s2 } - pub fn set_destination(&mut self, port: uint) { - let p = (port & 0xFFFF) as u16; - self.packet[self.offset + 2] = (p >> 8) as u8; - self.packet[self.offset + 3] = (p & 0xFF) as u8; + pub fn set_destination(&mut self, port: u16) { + self.packet[self.offset + 2] = (port >> 8) as u8; + self.packet[self.offset + 3] = (port & 0xFF) as u8; } - pub fn get_destination(&self) -> uint { + pub fn get_destination(&self) -> u16 { let d1 = self.packet[self.offset + 2] as u16 << 8; let d2 = self.packet[self.offset + 3] as u16; - (d1 | d2) as uint + d1 | d2 } - pub fn set_length(&mut self, len: uint) { - let l = (len & 0xFFFF) as u16; - self.packet[self.offset + 4] = (l >> 8) as u8; - self.packet[self.offset + 5] = (l & 0xFF) as u8; + pub fn set_length(&mut self, len: u16) { + self.packet[self.offset + 4] = (len >> 8) as u8; + self.packet[self.offset + 5] = (len & 0xFF) as u8; } - pub fn get_length(&self) -> uint { + pub fn get_length(&self) -> u16 { let l1 = self.packet[self.offset + 4] as u16 << 8; let l2 = self.packet[self.offset + 5] as u16; - (l1 | l2) as uint + l1 | l2 } - pub fn set_checksum(&mut self, checksum: uint) { - let c = (checksum & 0xFFFF) as u16; - self.packet[self.offset + 6] = (c >> 8) as u8; - self.packet[self.offset + 7] = (c & 0xFF) as u8; + pub fn set_checksum(&mut self, checksum: u16) { + self.packet[self.offset + 6] = (checksum >> 8) as u8; + self.packet[self.offset + 7] = (checksum & 0xFF) as u8; } - pub fn get_checksum(&self) -> uint { + pub fn get_checksum(&self) -> u16 { let c1 = self.packet[self.offset + 6] as u16 << 8; let c2 = self.packet[self.offset + 7] as u16; - (c1 | c2) as uint + c1 | c2 } pub fn checksum(&mut self) { @@ -653,11 +643,11 @@ pub mod test { use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use vec::ImmutableVector; - pub static ETHERNET_HEADER_LEN: uint = 14; - pub static IPV4_HEADER_LEN: uint = 20; - pub static IPV6_HEADER_LEN: uint = 40; - pub static UDP_HEADER_LEN: uint = 8; - pub static TEST_DATA_LEN: uint = 4; + pub static ETHERNET_HEADER_LEN: u16 = 14; + pub static IPV4_HEADER_LEN: u16 = 20; + pub static IPV6_HEADER_LEN: u16 = 40; + pub static UDP_HEADER_LEN: u16 = 8; + pub static TEST_DATA_LEN: u16 = 4; pub fn layer4_test(ip: IpAddr, headerLen: uint) { let message = "message"; @@ -690,49 +680,49 @@ pub mod test { } iotest!(fn layer4_ipv4() { - layer4_test(Ipv4Addr(127, 0, 0, 1), IPV4_HEADER_LEN); + layer4_test(Ipv4Addr(127, 0, 0, 1), IPV4_HEADER_LEN as uint); } #[cfg(hasroot)]) iotest!(fn layer4_ipv6() { - layer4_test(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), IPV6_HEADER_LEN); + layer4_test(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), IPV6_HEADER_LEN as uint); } #[cfg(hasroot)]) pub fn build_ipv4_header(packet: &mut [u8], offset: uint) { - Ipv4Header::act(packet, offset, |ipHeader| { - ipHeader.set_version(4); - ipHeader.set_header_length(5); - ipHeader.set_total_length(IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN); - ipHeader.set_ttl(4); - ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); - ipHeader.set_source(Ipv4Addr(127, 0, 0, 1)); - ipHeader.set_destination(Ipv4Addr(127, 0, 0, 1)); - ipHeader.checksum(); - }); + let mut ipHeader = Ipv4Header::new(packet, offset); + + ipHeader.set_version(4); + ipHeader.set_header_length(5); + ipHeader.set_total_length(IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN); + ipHeader.set_ttl(4); + ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); + ipHeader.set_source(Ipv4Addr(127, 0, 0, 1)); + ipHeader.set_destination(Ipv4Addr(127, 0, 0, 1)); + ipHeader.checksum(); } pub fn build_ipv6_header(packet: &mut [u8], offset: uint) { - Ipv6Header::act(packet, offset, |ipHeader| { - ipHeader.set_version(6); - ipHeader.set_payload_length(UDP_HEADER_LEN + TEST_DATA_LEN); - ipHeader.set_next_header(IpNextHeaderProtocol::Udp); - ipHeader.set_hop_limit(4); - ipHeader.set_source(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); - ipHeader.set_destination(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); - }); + let mut ipHeader = Ipv6Header::new(packet, offset); + + ipHeader.set_version(6); + ipHeader.set_payload_length(UDP_HEADER_LEN + TEST_DATA_LEN); + ipHeader.set_next_header(IpNextHeaderProtocol::Udp); + ipHeader.set_hop_limit(4); + ipHeader.set_source(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); + ipHeader.set_destination(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); } pub fn build_udp_header(packet: &mut [u8], offset: uint) { - UdpHeader::act(packet, offset, |udpHeader| { - udpHeader.set_source(1234); // Arbitary port number - udpHeader.set_destination(1234); - udpHeader.set_length(UDP_HEADER_LEN + TEST_DATA_LEN); - udpHeader.checksum(); - }); + let mut udpHeader = UdpHeader::new(packet, offset); + + udpHeader.set_source(1234); // Arbitary port number + udpHeader.set_destination(1234); + udpHeader.set_length(UDP_HEADER_LEN + TEST_DATA_LEN); + udpHeader.checksum(); } pub fn build_udp4_packet(packet: &mut [u8], start: uint) { build_ipv4_header(packet, start); - build_udp_header(packet, IPV4_HEADER_LEN); + build_udp_header(packet, IPV4_HEADER_LEN as uint); let dataStart = IPV4_HEADER_LEN + UDP_HEADER_LEN; packet[dataStart + 0] = 't' as u8; @@ -743,7 +733,7 @@ pub mod test { pub fn build_udp6_packet(packet: &mut [u8], start: uint) { build_ipv6_header(packet, start); - build_udp_header(packet, IPV6_HEADER_LEN); + build_udp_header(packet, IPV6_HEADER_LEN as uint); let dataStart = IPV6_HEADER_LEN + UDP_HEADER_LEN; packet[dataStart + 0] = 't' as u8; @@ -856,18 +846,19 @@ pub mod test { let mut packet = [0u8, ..46]; - //let mut ethernetHeader = EthernetHeader::new(0); - //ethernetHeader.set_source(interface.mac_address()); - //ethernetHeader.set_destination(interface.mac_address()); - //ethernetHeader.set_ethertype(Ipv4EtherType); - - EthernetHeader::act(packet.as_mut_slice(), 0, |ethernetHeader| { + { + let mut ethernetHeader = EthernetHeader::new(packet.as_mut_slice(), 0); ethernetHeader.set_source(interface.mac_address()); ethernetHeader.set_destination(interface.mac_address()); ethernetHeader.set_ethertype(Ipv4EtherType); - }); + } + //EthernetHeader::act(packet.as_mut_slice(), 0, |ethernetHeader| { + // ethernetHeader.set_source(interface.mac_address()); + // ethernetHeader.set_destination(interface.mac_address()); + // ethernetHeader.set_ethertype(Ipv4EtherType); + //}); - build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN); + build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 53129f3df9b6f..464ae69ba391d 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -183,7 +183,7 @@ mod test { Ok(..) => fail!(), Err(e) => assert_eq!(e.kind, PermissionDenied), } - } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))]) + } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))] #[ignore(cfg(hasroot))]) iotest!(fn connect_error() { let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index f779d80976f6b..15e90a2217ace 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -100,7 +100,7 @@ mod test { Ok(..) => fail!(), Err(e) => assert_eq!(e.kind, PermissionDenied), } - } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))]) + } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))] #[ignore(cfg(hasroot))]) iotest!(fn socket_smoke_test_ip4() { let server_ip = next_test_ip4(); From fdaf0ba2d8735f523bfa3ca105c611b2ca04f57e Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Tue, 18 Feb 2014 20:52:17 +0000 Subject: [PATCH 23/54] Add test case for Ipv4Header. --- src/libstd/io/net/raw.rs | 101 +++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 373215ca2d125..5aa7583a7635a 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -9,14 +9,14 @@ // except according to those terms. //use clone::Clone; -use cast; +//use cast; use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; use iter::Iterator; use num; use option::{Option, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; -use vec::ImmutableVector; +use vec::{MutableVector, ImmutableVector}; pub struct RawSocket { priv obj: ~RtioRawSocket @@ -118,7 +118,7 @@ impl<'p> Ipv4Header<'p> { } pub fn get_header_length(&self) -> u8 { - self.packet[self.offset] << 4 + self.packet[self.offset] & 0xF } pub fn set_dscp(&mut self, dscp: u8) { @@ -141,7 +141,7 @@ impl<'p> Ipv4Header<'p> { pub fn set_total_length(&mut self, len: u16) { self.packet[self.offset + 2] = (len >> 8) as u8; - self.packet[self.offset + 3] = (len << 8) as u8; + self.packet[self.offset + 3] = (len & 0xFF) as u8; } pub fn get_total_length(&self) -> u16 { @@ -249,42 +249,68 @@ impl<'p> Ipv4Header<'p> { self.packet[self.offset + 19]) } - pub fn set_options(&mut self, options: &[u8]) { - let mut i = 0; - for opt in options.iter() { - self.packet[self.offset + 20 + i] = *opt; - i = i + 1; - } - } - - /*pub fn get_options(&self) -> ~[u8] { - let numOpts = self.get_total_length() - 5; - ~self.packet.slice(self.offset + 20, self.offset + 20 + numOpts).clone() - /*let mut opts: ~[u8] = ~[]; - for opt in self.packet.slice(self.offset + 20, self.offset + 20 + numOpts).iter() { - opts.push(*opt); - } - opts*/ - }*/ - pub fn checksum(&mut self) { - let len = self.get_header_length() as uint; - let packet: &[u16] = unsafe { - cast::transmute(self.packet.slice(self.offset, self.offset + len * 4)) - }; + let len = self.offset + self.get_header_length() as uint * 4; let mut sum = 0u32; - let mut i = 0; - loop { - if i == len * 2 { - break; - } - sum = sum + packet[i] as u32; - i = i + 1; + let mut i = self.offset; + while i < len { + let word = self.packet[i] as u32 << 8 | self.packet[i + 1] as u32; + sum = sum + word; + i = i + 2; + } + while sum >> 16 != 0 { + sum = (sum >> 16) + (sum & 0xFFFF); } - self.set_checksum(!((sum >> 16) + (sum & 0xFF)) as u16); + self.set_checksum(!sum as u16); } } +#[test] +fn ipv4_header_test() { + let mut packet = [0u8, ..20]; + { + let mut ipHeader = Ipv4Header::new(packet.as_mut_slice(), 0); + ipHeader.set_version(4); + assert_eq!(ipHeader.get_version(), 4); + + ipHeader.set_header_length(5); + assert_eq!(ipHeader.get_header_length(), 5); + + ipHeader.set_total_length(115); + assert_eq!(ipHeader.get_total_length(), 115); + + ipHeader.set_flags(2); + assert_eq!(ipHeader.get_flags(), 2); + + ipHeader.set_ttl(64); + assert_eq!(ipHeader.get_ttl(), 64); + + ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); + assert_eq!(ipHeader.get_next_level_protocol(), IpNextHeaderProtocol::Udp); + + ipHeader.set_source(Ipv4Addr(192, 168, 0, 1)); + assert_eq!(ipHeader.get_source(), Ipv4Addr(192, 168, 0, 1)); + + ipHeader.set_destination(Ipv4Addr(192, 168, 0, 199)); + assert_eq!(ipHeader.get_destination(), Ipv4Addr(192, 168, 0, 199)); + + ipHeader.checksum(); + assert_eq!(ipHeader.get_checksum(), 0xb861); + } + + let refPacket = [0x45, /* ver/ihl */ + 0x00, /* dscp/ecn */ + 0x00, 0x73, /* total len */ + 0x00, 0x00, /* identification */ + 0x40, 0x00, /* flags/frag offset */ + 0x40, /* ttl */ + 0x11, /* proto */ + 0xb8, 0x61, /* checksum */ + 0xc0, 0xa8, 0x00, 0x01, /* source ip */ + 0xc0, 0xa8, 0x00, 0xc7 /* dest ip */]; + assert_eq!(packet, refPacket); +} + pub struct Ipv6Header<'p> { priv packet: &'p mut [u8], priv offset: uint @@ -478,7 +504,7 @@ pub static Ipv6EtherType: u16 = 0x86DD; // or the IPv6 Next Header field. pub mod IpNextHeaderProtocol { //use num::FromPrimitive; - #[deriving(FromPrimitive)] + #[deriving(Eq,FromPrimitive)] pub enum IpNextHeaderProtocol { Hopopt = 0, // IPv6 Hop-by-Hop Option [RFC2460] Icmp = 1, // Internet Control Message [RFC792] @@ -852,11 +878,6 @@ pub mod test { ethernetHeader.set_destination(interface.mac_address()); ethernetHeader.set_ethertype(Ipv4EtherType); } - //EthernetHeader::act(packet.as_mut_slice(), 0, |ethernetHeader| { - // ethernetHeader.set_source(interface.mac_address()); - // ethernetHeader.set_destination(interface.mac_address()); - // ethernetHeader.set_ethertype(Ipv4EtherType); - //}); build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); From 9712b53b73b14cd77606c0d09d8069f0890fb726 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Tue, 18 Feb 2014 22:21:54 +0000 Subject: [PATCH 24/54] More comprehensive testing for Ipv4Header. --- src/libstd/io/net/raw.rs | 79 +++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 5aa7583a7635a..bcd877e54dbf7 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -123,11 +123,11 @@ impl<'p> Ipv4Header<'p> { pub fn set_dscp(&mut self, dscp: u8) { let cp = dscp & 0xFC; - self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 3) | cp; + self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 3) | (cp << 2); } pub fn get_dscp(&self) -> u8 { - self.packet[self.offset + 1] & 0xFC + (self.packet[self.offset + 1] & 0xFC) >> 2 } pub fn set_ecn(&mut self, ecn: u8) { @@ -172,7 +172,8 @@ impl<'p> Ipv4Header<'p> { pub fn set_fragment_offset(&mut self, offset: u16) { let fo = offset & 0x1FFF; - self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0xE0) | (fo & 0xFF00) as u8; + self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0xE0) | + ((fo & 0xFF00) >> 8) as u8; self.packet[self.offset + 7] = (fo & 0xFF) as u8; } @@ -276,12 +277,24 @@ fn ipv4_header_test() { ipHeader.set_header_length(5); assert_eq!(ipHeader.get_header_length(), 5); + ipHeader.set_dscp(4); + assert_eq!(ipHeader.get_dscp(), 4); + + ipHeader.set_ecn(1); + assert_eq!(ipHeader.get_ecn(), 1); + ipHeader.set_total_length(115); assert_eq!(ipHeader.get_total_length(), 115); + ipHeader.set_identification(257); + assert_eq!(ipHeader.get_identification(), 257); + ipHeader.set_flags(2); assert_eq!(ipHeader.get_flags(), 2); + ipHeader.set_fragment_offset(257); + assert_eq!(ipHeader.get_fragment_offset(), 257); + ipHeader.set_ttl(64); assert_eq!(ipHeader.get_ttl(), 64); @@ -295,20 +308,20 @@ fn ipv4_header_test() { assert_eq!(ipHeader.get_destination(), Ipv4Addr(192, 168, 0, 199)); ipHeader.checksum(); - assert_eq!(ipHeader.get_checksum(), 0xb861); + assert_eq!(ipHeader.get_checksum(), 0xb64e); } let refPacket = [0x45, /* ver/ihl */ - 0x00, /* dscp/ecn */ + 0x11, /* dscp/ecn */ 0x00, 0x73, /* total len */ - 0x00, 0x00, /* identification */ - 0x40, 0x00, /* flags/frag offset */ + 0x01, 0x01, /* identification */ + 0x41, 0x01, /* flags/frag offset */ 0x40, /* ttl */ 0x11, /* proto */ - 0xb8, 0x61, /* checksum */ + 0xb6, 0x4e, /* checksum */ 0xc0, 0xa8, 0x00, 0x01, /* source ip */ 0xc0, 0xa8, 0x00, 0xc7 /* dest ip */]; - assert_eq!(packet, refPacket); + assert_eq!(refPacket, packet); } pub struct Ipv6Header<'p> { @@ -316,7 +329,6 @@ pub struct Ipv6Header<'p> { priv offset: uint } -// FIXME Support extension headers impl<'p> Ipv6Header<'p> { pub fn new(packet: &'p mut [u8], offset: uint) -> Ipv6Header<'p> { Ipv6Header { packet: packet, offset: offset } @@ -395,6 +407,53 @@ impl<'p> Ipv6Header<'p> { } } +#[test] +fn ipv6_header_test() { + /*let mut packet = [0u8, ..40]; + { + let mut ipHeader = Ipv6Header::new(packet.as_mut_slice(), 0); + ipHeader.set_version(6); + assert_eq!(ipHeader.get_version(), 6); + + ipHeader.set_header_length(5); + assert_eq!(ipHeader.get_header_length(), 5); + + ipHeader.set_total_length(115); + assert_eq!(ipHeader.get_total_length(), 115); + + ipHeader.set_flags(2); + assert_eq!(ipHeader.get_flags(), 2); + + ipHeader.set_ttl(64); + assert_eq!(ipHeader.get_ttl(), 64); + + ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); + assert_eq!(ipHeader.get_next_level_protocol(), IpNextHeaderProtocol::Udp); + + ipHeader.set_source(Ipv4Addr(192, 168, 0, 1)); + assert_eq!(ipHeader.get_source(), Ipv4Addr(192, 168, 0, 1)); + + ipHeader.set_destination(Ipv4Addr(192, 168, 0, 199)); + assert_eq!(ipHeader.get_destination(), Ipv4Addr(192, 168, 0, 199)); + + ipHeader.checksum(); + assert_eq!(ipHeader.get_checksum(), 0xb861); + } + + let refPacket = [0x45, /* ver/ihl */ + 0x00, /* dscp/ecn */ + 0x00, 0x73, /* total len */ + 0x00, 0x00, /* identification */ + 0x40, 0x00, /* flags/frag offset */ + 0x40, /* ttl */ + 0x11, /* proto */ + 0xb8, 0x61, /* checksum */ + 0xc0, 0xa8, 0x00, 0x01, /* source ip */ + 0xc0, 0xa8, 0x00, 0xc7 /* dest ip */]; + assert_eq!(packet, refPacket);*/ +} + + pub struct UdpHeader<'p> { priv packet: &'p mut [u8], priv offset: uint From 96094fd81a9109edd750cfba30bee127f0990072 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 19 Feb 2014 00:17:49 +0000 Subject: [PATCH 25/54] Implement Ipv6Header and test. --- src/libstd/io/net/raw.rs | 209 ++++++++++++++++++++++++++------------- 1 file changed, 142 insertions(+), 67 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index bcd877e54dbf7..a5e333d60271f 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -334,123 +334,198 @@ impl<'p> Ipv6Header<'p> { Ipv6Header { packet: packet, offset: offset } } - pub fn set_version(&mut self, _version: u8) { - // FIXME + pub fn set_version(&mut self, version: u8) { + let ver = version << 4; + self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; } - pub fn get_version(&self) -> uint { - // FIXME - 0 + pub fn get_version(&self) -> u8 { + self.packet[self.offset] >> 4 } - pub fn set_traffic_class(&mut self, _tc: u8) { - // FIXME + pub fn set_traffic_class(&mut self, tc: u8) { + self.packet[self.offset + 0] = (self.packet[self.offset] & 0xF0) | (tc >> 4); + self.packet[self.offset + 1] = ((tc & 0x0F) << 4) | + ((self.packet[self.offset + 1] & 0xF0) >> 4); } pub fn get_traffic_class(&self) -> u8 { - // FIXME - 0 + let tc1 = (self.packet[self.offset + 0] & 0x0F) << 4; + let tc2 = self.packet[self.offset + 1] >> 4; + tc1 | tc2 } - pub fn set_flow_label(&mut self, _label: u32) { - // FIXME + pub fn set_flow_label(&mut self, label: u32) { + let lbl = ((label & 0xF0000) >> 16) as u8; + self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xF0) | lbl; + self.packet[self.offset + 2] = ((label & 0xFF00) >> 8) as u8; + self.packet[self.offset + 3] = (label & 0x00FF) as u8; } pub fn get_flow_label(&self) -> u32 { - // FIXME - 0 + let fl1 = (self.packet[self.offset + 1] as u32 & 0xF) << 16; + let fl2 = (self.packet[self.offset + 2] as u32 << 8); + let fl3 = self.packet[self.offset + 3] as u32; + fl1 | fl2 | fl3 } - pub fn set_payload_length(&mut self, _len: u16) { - // FIXME + pub fn set_payload_length(&mut self, len: u16) { + self.packet[self.offset + 4] = (len >> 8) as u8; + self.packet[self.offset + 5] = (len & 0xFF) as u8; } pub fn get_payload_length(&self) -> u16 { - // FIXME - 0 + let len1 = self.packet[self.offset + 4] as u16 << 8; + let len2 = self.packet[self.offset + 5] as u16; + len1 | len2 } - pub fn set_next_header(&mut self, _protocol: IpNextHeaderProtocol) { - // FIXME + pub fn set_next_header(&mut self, protocol: IpNextHeaderProtocol) { + self.packet[self.offset + 6] = protocol as u8; } pub fn get_next_header(&self) -> IpNextHeaderProtocol { - // FIXME - IpNextHeaderProtocol::Tcp + num::FromPrimitive::from_u8(self.packet[self.offset + 6]).unwrap() } - pub fn set_hop_limit(&mut self, _limit: u8) { - // FIXME + pub fn set_hop_limit(&mut self, limit: u8) { + self.packet[self.offset + 7] = limit; } pub fn get_hop_limit(&self) -> u8 { - // FIXME - 0 + self.packet[self.offset + 7] } - pub fn set_source(&mut self, _ip: IpAddr) { - // FIXME + pub fn set_source(&mut self, ip: IpAddr) { + match ip { + Ipv6Addr(a, b, c, d, e, f, g, h) => { + self.packet[self.offset + 8] = (a >> 8) as u8; + self.packet[self.offset + 9] = (a & 0xFF) as u8; + self.packet[self.offset + 10] = (b >> 8) as u8; + self.packet[self.offset + 11] = (b & 0xFF) as u8;; + self.packet[self.offset + 12] = (c >> 8) as u8; + self.packet[self.offset + 13] = (c & 0xFF) as u8;; + self.packet[self.offset + 14] = (d >> 8) as u8; + self.packet[self.offset + 15] = (d & 0xFF) as u8;; + self.packet[self.offset + 16] = (e >> 8) as u8; + self.packet[self.offset + 17] = (e & 0xFF) as u8;; + self.packet[self.offset + 18] = (f >> 8) as u8; + self.packet[self.offset + 19] = (f & 0xFF) as u8;; + self.packet[self.offset + 20] = (g >> 8) as u8; + self.packet[self.offset + 21] = (g & 0xFF) as u8;; + self.packet[self.offset + 22] = (h >> 8) as u8; + self.packet[self.offset + 23] = (h & 0xFF) as u8; + }, + _ => () + } } pub fn get_source(&self) -> IpAddr { - // FIXME - Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0) + let a = (self.packet[self.offset + 8] as u16 << 8) | self.packet[self.offset + 9] as u16; + let b = (self.packet[self.offset + 10] as u16 << 8) | self.packet[self.offset + 11] as u16; + let c = (self.packet[self.offset + 12] as u16 << 8) | self.packet[self.offset + 13] as u16; + let d = (self.packet[self.offset + 14] as u16 << 8) | self.packet[self.offset + 15] as u16; + let e = (self.packet[self.offset + 16] as u16 << 8) | self.packet[self.offset + 17] as u16; + let f = (self.packet[self.offset + 18] as u16 << 8) | self.packet[self.offset + 19] as u16; + let g = (self.packet[self.offset + 20] as u16 << 8) | self.packet[self.offset + 21] as u16; + let h = (self.packet[self.offset + 22] as u16 << 8) | self.packet[self.offset + 23] as u16; + + Ipv6Addr(a, b, c, d, e, f, g, h) } - pub fn set_destination(&mut self, _ip: IpAddr) { - // FIXME + pub fn set_destination(&mut self, ip: IpAddr) { + match ip { + Ipv6Addr(a, b, c, d, e, f, g, h) => { + self.packet[self.offset + 24] = (a >> 8) as u8; + self.packet[self.offset + 25] = (a & 0xFF) as u8; + self.packet[self.offset + 26] = (b >> 8) as u8; + self.packet[self.offset + 27] = (b & 0xFF) as u8;; + self.packet[self.offset + 28] = (c >> 8) as u8; + self.packet[self.offset + 29] = (c & 0xFF) as u8;; + self.packet[self.offset + 30] = (d >> 8) as u8; + self.packet[self.offset + 31] = (d & 0xFF) as u8;; + self.packet[self.offset + 32] = (e >> 8) as u8; + self.packet[self.offset + 33] = (e & 0xFF) as u8;; + self.packet[self.offset + 34] = (f >> 8) as u8; + self.packet[self.offset + 35] = (f & 0xFF) as u8;; + self.packet[self.offset + 36] = (g >> 8) as u8; + self.packet[self.offset + 37] = (g & 0xFF) as u8;; + self.packet[self.offset + 38] = (h >> 8) as u8; + self.packet[self.offset + 39] = (h & 0xFF) as u8; + }, + _ => () + } } pub fn get_destination(&self) -> IpAddr { - // FIXME - Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0) + let a = (self.packet[self.offset + 24] as u16 << 8) | self.packet[self.offset + 25] as u16; + let b = (self.packet[self.offset + 26] as u16 << 8) | self.packet[self.offset + 27] as u16; + let c = (self.packet[self.offset + 28] as u16 << 8) | self.packet[self.offset + 29] as u16; + let d = (self.packet[self.offset + 30] as u16 << 8) | self.packet[self.offset + 31] as u16; + let e = (self.packet[self.offset + 32] as u16 << 8) | self.packet[self.offset + 33] as u16; + let f = (self.packet[self.offset + 34] as u16 << 8) | self.packet[self.offset + 35] as u16; + let g = (self.packet[self.offset + 36] as u16 << 8) | self.packet[self.offset + 37] as u16; + let h = (self.packet[self.offset + 38] as u16 << 8) | self.packet[self.offset + 39] as u16; + + Ipv6Addr(a, b, c, d, e, f, g, h) } } #[test] fn ipv6_header_test() { - /*let mut packet = [0u8, ..40]; + let mut packet = [0u8, ..40]; { let mut ipHeader = Ipv6Header::new(packet.as_mut_slice(), 0); ipHeader.set_version(6); assert_eq!(ipHeader.get_version(), 6); - ipHeader.set_header_length(5); - assert_eq!(ipHeader.get_header_length(), 5); - - ipHeader.set_total_length(115); - assert_eq!(ipHeader.get_total_length(), 115); - - ipHeader.set_flags(2); - assert_eq!(ipHeader.get_flags(), 2); - - ipHeader.set_ttl(64); - assert_eq!(ipHeader.get_ttl(), 64); - - ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); - assert_eq!(ipHeader.get_next_level_protocol(), IpNextHeaderProtocol::Udp); + ipHeader.set_traffic_class(17); + assert_eq!(ipHeader.get_traffic_class(), 17); - ipHeader.set_source(Ipv4Addr(192, 168, 0, 1)); - assert_eq!(ipHeader.get_source(), Ipv4Addr(192, 168, 0, 1)); + ipHeader.set_flow_label(0x10101); + assert_eq!(ipHeader.get_flow_label(), 0x10101); - ipHeader.set_destination(Ipv4Addr(192, 168, 0, 199)); - assert_eq!(ipHeader.get_destination(), Ipv4Addr(192, 168, 0, 199)); - - ipHeader.checksum(); - assert_eq!(ipHeader.get_checksum(), 0xb861); - } + ipHeader.set_payload_length(0x0101); + assert_eq!(ipHeader.get_payload_length(), 0x0101); - let refPacket = [0x45, /* ver/ihl */ - 0x00, /* dscp/ecn */ - 0x00, 0x73, /* total len */ - 0x00, 0x00, /* identification */ - 0x40, 0x00, /* flags/frag offset */ - 0x40, /* ttl */ - 0x11, /* proto */ - 0xb8, 0x61, /* checksum */ - 0xc0, 0xa8, 0x00, 0x01, /* source ip */ - 0xc0, 0xa8, 0x00, 0xc7 /* dest ip */]; - assert_eq!(packet, refPacket);*/ + ipHeader.set_next_header(IpNextHeaderProtocol::Udp); + assert_eq!(ipHeader.get_next_header(), IpNextHeaderProtocol::Udp); + + ipHeader.set_hop_limit(1); + assert_eq!(ipHeader.get_hop_limit(), 1) + + let source = Ipv6Addr(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001); + ipHeader.set_source(source); + assert_eq!(ipHeader.get_source(), source); + + let dest = Ipv6Addr(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001); + ipHeader.set_destination(dest); + assert_eq!(ipHeader.get_destination(), dest); + } + + let refPacket = [0x61, /* ver/traffic class */ + 0x11, /* traffic class/flow label */ + 0x01, 0x01, /* flow label */ + 0x01, 0x01, /* payload length */ + 0x11, /* next header */ + 0x01, /* hop limit */ + 0x01, 0x10, /* source ip */ + 0x10, 0x01, + 0x01, 0x10, + 0x10, 0x01, + 0x01, 0x10, + 0x10, 0x01, + 0x01, 0x10, + 0x10, 0x01, + 0x01, 0x10, /* dest ip */ + 0x10, 0x01, + 0x01, 0x10, + 0x10, 0x01, + 0x01, 0x10, + 0x10, 0x01, + 0x01, 0x10, + 0x10, 0x01]; + assert_eq!(refPacket, packet); } From bda6811ebe4b0a4d257b09d7bb6c092f68673d8e Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 19 Feb 2014 00:41:08 +0000 Subject: [PATCH 26/54] Refactor IpNextHeaderProtocol to be u8 rather than an enum. --- src/libstd/io/net/raw.rs | 311 +++++++++++++++++++-------------------- 1 file changed, 153 insertions(+), 158 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index a5e333d60271f..2bffbee519c16 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//use clone::Clone; -//use cast; use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; use iter::Iterator; -use num; use option::{Option, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; use vec::{MutableVector, ImmutableVector}; @@ -192,11 +189,11 @@ impl<'p> Ipv4Header<'p> { } pub fn set_next_level_protocol(&mut self, protocol: IpNextHeaderProtocol) { - self.packet[self.offset + 9] = protocol as u8; + self.packet[self.offset + 9] = protocol; } pub fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { - num::FromPrimitive::from_u8(self.packet[self.offset + 9]).unwrap() + self.packet[self.offset + 9] } pub fn set_checksum(&mut self, checksum: u16) { @@ -381,11 +378,11 @@ impl<'p> Ipv6Header<'p> { } pub fn set_next_header(&mut self, protocol: IpNextHeaderProtocol) { - self.packet[self.offset + 6] = protocol as u8; + self.packet[self.offset + 6] = protocol; } pub fn get_next_header(&self) -> IpNextHeaderProtocol { - num::FromPrimitive::from_u8(self.packet[self.offset + 6]).unwrap() + self.packet[self.offset + 6] } pub fn set_hop_limit(&mut self, limit: u8) { @@ -637,159 +634,157 @@ pub static Ipv6EtherType: u16 = 0x86DD; // These values should be used in either the IPv4 Next Level Protocol field // or the IPv6 Next Header field. pub mod IpNextHeaderProtocol { - //use num::FromPrimitive; - #[deriving(Eq,FromPrimitive)] - pub enum IpNextHeaderProtocol { - Hopopt = 0, // IPv6 Hop-by-Hop Option [RFC2460] - Icmp = 1, // Internet Control Message [RFC792] - Igmp = 2, // Internet Group Management [RFC1112] - Ggp = 3, // Gateway-to-Gateway [RFC823] - Ipv4 = 4, // IPv4 encapsulation [RFC2003] - St = 5, // Stream [RFC1190][RFC1819] - Tcp = 6, // Transmission Control [RFC793] - Cbt = 7, // CBT - Egp = 8, // Exterior Gateway Protocol [RFC888] - Igp = 9, // any private interior gateway (used by Cisco for their IGRP) - BbnRccMon = 10, // BBN RCC Monitoring - NvpII = 11, // Network Voice Protocol [RFC741] - Pup = 12, // PUP - Argus = 13, // ARGUS - Emcon = 14, // EMCON - Xnet = 15, // Cross Net Debugger - Chaos = 16, // Chaos - Udp = 17, // User Datagram [RFC768] - Mux = 18, // Multiplexing - DcnMeas = 19, // DCN Measurement Subsystems - Hmp = 20, // Host Monitoring [RFC869] - Prm = 21, // Packet Radio Measurement - XnsIdp = 22, // XEROX NS IDP - Trunk1 = 23, // Trunk-1 - Trunk2 = 24, // Trunk-2 - Leaf1 = 25, // Leaf-1 - Leaf2 = 26, // Leaf-2 - Rdp = 27, // Reliable Data Protocol [RFC908] - Irtp = 28, // Internet Reliable Transaction [RFC938] - IsoTp4 = 29, // ISO Transport Protocol Class 4 [RFC905] - Netblt = 30, // Bulk Data Transfer Protocol [RFC969] - MfeNsp = 31, // MFE Network Services Protocol - MeritInp = 32, // MERIT Internodal Protocol - Dccp = 33, // Datagram Congestion Control Protocol [RFC4340] - ThreePc = 34, // Third Party Connect Protocol - Idpr = 35, // Inter-Domain Policy Routing Protocol - Xtp = 36, // XTP - Ddp = 37, // Datagram Delivery Protocol - IdprCmtp = 38, // IDPR Control Message Transport Proto - TpPlusPlus = 39, // TP++ Transport Protocol - Il = 40, // IL Transport Protocol - Ipv6 = 41, // IPv6 encapsulation [RFC2473] - Sdrp = 42, // Source Demand Routing Protocol - Ipv6Route = 43, // Routing Header for IPv6 - Ipv6Frag = 44, // Fragment Header for IPv6 - Idrp = 45, // Inter-Domain Routing Protocol - Rsvp = 46, // Reservation Protocol [RFC2205][RFC3209] - Gre = 47, // Generic Routing Encapsulation [RFC1701] - Dsr = 48, // Dynamic Source Routing Protocol [RFC4728] - Bna = 49, // BNA - Esp = 50, // Encap Security Payload [RFC4303] - Ah = 51, // Authentication Header [RFC4302] - INlsp = 52, // Integrated Net Layer Security TUBA - Swipe = 53, // IP with Encryption - Narp = 54, // NBMA Address Resolution Protocol [RFC1735] - Mobile = 55, // IP Mobility - Tlsp = 56, // Transport Layer Security Protocol using Kryptonet key management - Skip = 57, // SKIP - Ipv6Icmp = 58, // ICMP for IPv6 [RFC2460] - Ipv6NoNxt = 59, // No Next Header for IPv6 [RFC2460] - Ipv6Opts = 60, // Destination Options for IPv6 [RFC2460] - HostInternal = 61, // any host internal protocol - Cftp = 62, // CFTP - LocalNetwork = 63, // any local network - SatExpak = 64, // SATNET and Backroom EXPAK - Kryptolan = 65, // Kryptolan - Rvd = 66, // MIT Remote Virtual Disk Protocol - Ippc = 67, // Internet Pluribus Packet Core - DistributedFs = 68, // any distributed file system - SatMon = 69, // SATNET Monitoring - Visa = 70, // VISA Protocol - Ipcv = 71, // Internet Packet Core Utility - Cpnx = 72, // Computer Protocol Network Executive - Cphb = 73, // Computer Protocol Heart Beat - Wsn = 74, // Wang Span Network - Pvp = 75, // Packet Video Protocol - BrSatMon = 76, // Backroom SATNET Monitoring - SunNd = 77, // SUN ND PROTOCOL-Temporary - WbMon = 78, // WIDEBAND Monitoring - WbExpak = 79, // WIDEBAND EXPAK - IsoIp = 80, // ISO Internet Protocol - Vmtp = 81, // VMTP - SecureVmtp = 82, // SECURE-VMTP - Vines = 83, // VINES - TtpOrIptm = 84, // Transaction Transport Protocol/Internet Protocol Traffic Manager - NsfnetIgp = 85, // NSFNET-IGP - Dgp = 86, // Dissimilar Gateway Protocol - Tcf = 87, // TCF - Eigrp = 88, // EIGRP - OspfigP = 89, // OSPFIGP [RFC1583][RFC2328][RFC5340] - SpriteRpc = 90, // Sprite RPC Protocol - Larp = 91, // Locus Address Resolution Protocol - Mtp = 92, // Multicast Transport Protocol - Ax25 = 93, // AX.25 Frames - IpIp = 94, // IP-within-IP Encapsulation Protocol - Micp = 95, // Mobile Internetworking Control Pro. - SccSp = 96, // Semaphore Communications Sec. Pro. - Etherip = 97, // Ethernet-within-IP Encapsulation [RFC3378] - Encap = 98, // Encapsulation Header [RFC1241] - PrivEncryption = 99, // any private encryption scheme - Gmtp = 100, // GMTP - Ifmp = 101, // Ipsilon Flow Management Protocol - Pnni = 102, // PNNI over IP - Pim = 103, // Protocol Independent Multicast [RFC4601] - Aris = 104, // ARIS - Scps = 105, // SCPS - Qnx = 106, // QNX - AN = 107, // Active Networks - IpComp = 108, // IP Payload Compression Protocol [RFC2393] - Snp = 109, // Sitara Networks Protocol - CompaqPeer = 110, // Compaq Peer Protocol - IpxInIp = 111, // IPX in IP - Vrrp = 112, // Virtual Router Redundancy Protocol [RFC5798] - Pgm = 113, // PGM Reliable Transport Protocol - ZeroHop = 114, // any 0-hop protocol - L2tp = 115, // Layer Two Tunneling Protocol [RFC3931] - Ddx = 116, // D-II Data Exchange (DDX) - Iatp = 117, // Interactive Agent Transfer Protocol - Stp = 118, // Schedule Transfer Protocol - Srp = 119, // SpectraLink Radio Protocol - Uti = 120, // UTI - Smp = 121, // Simple Message Protocol - Sm = 122, // Simple Multicast Protocol - Ptp = 123, // Performance Transparency Protocol - IsisOverIpv4 = 124, // - Fire = 125, // - Crtp = 126, // Combat Radio Transport Protocol - Crudp = 127, // Combat Radio User Datagram - Sscopmce = 128, // - Iplt = 129, // - Sps = 130, // Secure Packet Shield - Pipe = 131, // Private IP Encapsulation within IP - Sctp = 132, // Stream Control Transmission Protocol - Fc = 133, // Fibre Channel [RFC6172] - RsvpE2eIgnore = 134, // [RFC3175] - MobilityHeader = 135, // [RFC6275] - UdpLite = 136, // [RFC3828] - MplsInIp = 137, // [RFC4023] - Manet = 138, // MANET Protocols [RFC5498] - Hip = 139, // Host Identity Protocol [RFC5201] - Shim6 = 140, // Shim6 Protocol [RFC5533] - Wesp = 141, // Wrapped Encapsulating Security Payload [RFC5840] - Rohc = 142, // Robust Header Compression [RFC5858] - Test1 = 253, // Use for experimentation and testing [RFC3692] - Test2 = 254, // Use for experimentation and testing [RFC3692] - Reserved = 255, // - } + pub static Hopopt: u8 = 0; // IPv6 Hop-by-Hop Option [RFC2460] + pub static Icmp: u8 = 1; // Internet Control Message [RFC792] + pub static Igmp: u8 = 2; // Internet Group Management [RFC1112] + pub static Ggp: u8 = 3; // Gateway-to-Gateway [RFC823] + pub static Ipv4: u8 = 4; // IPv4 encapsulation [RFC2003] + pub static St: u8 = 5; // Stream [RFC1190][RFC1819] + pub static Tcp: u8 = 6; // Transmission Control [RFC793] + pub static Cbt: u8 = 7; // CBT + pub static Egp: u8 = 8; // Exterior Gateway Protocol [RFC888] + pub static Igp: u8 = 9; // any private interior gateway (used by Cisco for + // their IGRP) + pub static BbnRccMon: u8 = 10; // BBN RCC Monitoring + pub static NvpII: u8 = 11; // Network Voice Protocol [RFC741] + pub static Pup: u8 = 12; // PUP + pub static Argus: u8 = 13; // ARGUS + pub static Emcon: u8 = 14; // EMCON + pub static Xnet: u8 = 15; // Cross Net Debugger + pub static Chaos: u8 = 16; // Chaos + pub static Udp: u8 = 17; // User Datagram [RFC768] + pub static Mux: u8 = 18; // Multiplexing + pub static DcnMeas: u8 = 19; // DCN Measurement Subsystems + pub static Hmp: u8 = 20; // Host Monitoring [RFC869] + pub static Prm: u8 = 21; // Packet Radio Measurement + pub static XnsIdp: u8 = 22; // XEROX NS IDP + pub static Trunk1: u8 = 23; // Trunk-1 + pub static Trunk2: u8 = 24; // Trunk-2 + pub static Leaf1: u8 = 25; // Leaf-1 + pub static Leaf2: u8 = 26; // Leaf-2 + pub static Rdp: u8 = 27; // Reliable Data Protocol [RFC908] + pub static Irtp: u8 = 28; // Internet Reliable Transaction [RFC938] + pub static IsoTp4: u8 = 29; // ISO Transport Protocol Class 4 [RFC905] + pub static Netblt: u8 = 30; // Bulk Data Transfer Protocol [RFC969] + pub static MfeNsp: u8 = 31; // MFE Network Services Protocol + pub static MeritInp: u8 = 32; // MERIT Internodal Protocol + pub static Dccp: u8 = 33; // Datagram Congestion Control Protocol [RFC4340] + pub static ThreePc: u8 = 34; // Third Party Connect Protocol + pub static Idpr: u8 = 35; // Inter-Domain Policy Routing Protocol + pub static Xtp: u8 = 36; // XTP + pub static Ddp: u8 = 37; // Datagram Delivery Protocol + pub static IdprCmtp: u8 = 38; // IDPR Control Message Transport Proto + pub static TpPlusPlus: u8 = 39; // TP++ Transport Protocol + pub static Il: u8 = 40; // IL Transport Protocol + pub static Ipv6: u8 = 41; // IPv6 encapsulation [RFC2473] + pub static Sdrp: u8 = 42; // Source Demand Routing Protocol + pub static Ipv6Route: u8 = 43; // Routing Header for IPv6 + pub static Ipv6Frag: u8 = 44; // Fragment Header for IPv6 + pub static Idrp: u8 = 45; // Inter-Domain Routing Protocol + pub static Rsvp: u8 = 46; // Reservation Protocol [RFC2205][RFC3209] + pub static Gre: u8 = 47; // Generic Routing Encapsulation [RFC1701] + pub static Dsr: u8 = 48; // Dynamic Source Routing Protocol [RFC4728] + pub static Bna: u8 = 49; // BNA + pub static Esp: u8 = 50; // Encap Security Payload [RFC4303] + pub static Ah: u8 = 51; // Authentication Header [RFC4302] + pub static INlsp: u8 = 52; // Integrated Net Layer Security TUBA + pub static Swipe: u8 = 53; // IP with Encryption + pub static Narp: u8 = 54; // NBMA Address Resolution Protocol [RFC1735] + pub static Mobile: u8 = 55; // IP Mobility + pub static Tlsp: u8 = 56; // Transport Layer Security Protocol using Kryptonet key + // management + pub static Skip: u8 = 57; // SKIP + pub static Ipv6Icmp: u8 = 58; // ICMP for IPv6 [RFC2460] + pub static Ipv6NoNxt: u8 = 59; // No Next Header for IPv6 [RFC2460] + pub static Ipv6Opts: u8 = 60; // Destination Options for IPv6 [RFC2460] + pub static HostInternal: u8 = 61; // any host internal protocol + pub static Cftp: u8 = 62; // CFTP + pub static LocalNetwork: u8 = 63; // any local network + pub static SatExpak: u8 = 64; // SATNET and Backroom EXPAK + pub static Kryptolan: u8 = 65; // Kryptolan + pub static Rvd: u8 = 66; // MIT Remote Virtual Disk Protocol + pub static Ippc: u8 = 67; // Internet Pluribus Packet Core + pub static DistributedFs: u8 = 68; // any distributed file system + pub static SatMon: u8 = 69; // SATNET Monitoring + pub static Visa: u8 = 70; // VISA Protocol + pub static Ipcv: u8 = 71; // Internet Packet Core Utility + pub static Cpnx: u8 = 72; // Computer Protocol Network Executive + pub static Cphb: u8 = 73; // Computer Protocol Heart Beat + pub static Wsn: u8 = 74; // Wang Span Network + pub static Pvp: u8 = 75; // Packet Video Protocol + pub static BrSatMon: u8 = 76; // Backroom SATNET Monitoring + pub static SunNd: u8 = 77; // SUN ND PROTOCOL-Temporary + pub static WbMon: u8 = 78; // WIDEBAND Monitoring + pub static WbExpak: u8 = 79; // WIDEBAND EXPAK + pub static IsoIp: u8 = 80; // ISO Internet Protocol + pub static Vmtp: u8 = 81; // VMTP + pub static SecureVmtp: u8 = 82; // SECURE-VMTP + pub static Vines: u8 = 83; // VINES + pub static TtpOrIptm: u8 = 84; // Transaction Transport Protocol/IP Traffic Manager + pub static NsfnetIgp: u8 = 85; // NSFNET-IGP + pub static Dgp: u8 = 86; // Dissimilar Gateway Protocol + pub static Tcf: u8 = 87; // TCF + pub static Eigrp: u8 = 88; // EIGRP + pub static OspfigP: u8 = 89; // OSPFIGP [RFC1583][RFC2328][RFC5340] + pub static SpriteRpc: u8 = 90; // Sprite RPC Protocol + pub static Larp: u8 = 91; // Locus Address Resolution Protocol + pub static Mtp: u8 = 92; // Multicast Transport Protocol + pub static Ax25: u8 = 93; // AX.25 Frames + pub static IpIp: u8 = 94; // IP-within-IP Encapsulation Protocol + pub static Micp: u8 = 95; // Mobile Internetworking Control Pro. + pub static SccSp: u8 = 96; // Semaphore Communications Sec. Pro. + pub static Etherip: u8 = 97; // Ethernet-within-IP Encapsulation [RFC3378] + pub static Encap: u8 = 98; // Encapsulation Header [RFC1241] + pub static PrivEncryption: u8 = 99; // any private encryption scheme + pub static Gmtp: u8 = 100; // GMTP + pub static Ifmp: u8 = 101; // Ipsilon Flow Management Protocol + pub static Pnni: u8 = 102; // PNNI over IP + pub static Pim: u8 = 103; // Protocol Independent Multicast [RFC4601] + pub static Aris: u8 = 104; // ARIS + pub static Scps: u8 = 105; // SCPS + pub static Qnx: u8 = 106; // QNX + pub static AN: u8 = 107; // Active Networks + pub static IpComp: u8 = 108; // IP Payload Compression Protocol [RFC2393] + pub static Snp: u8 = 109; // Sitara Networks Protocol + pub static CompaqPeer: u8 = 110; // Compaq Peer Protocol + pub static IpxInIp: u8 = 111; // IPX in IP + pub static Vrrp: u8 = 112; // Virtual Router Redundancy Protocol [RFC5798] + pub static Pgm: u8 = 113; // PGM Reliable Transport Protocol + pub static ZeroHop: u8 = 114; // any 0-hop protocol + pub static L2tp: u8 = 115; // Layer Two Tunneling Protocol [RFC3931] + pub static Ddx: u8 = 116; // D-II Data Exchange (DDX) + pub static Iatp: u8 = 117; // Interactive Agent Transfer Protocol + pub static Stp: u8 = 118; // Schedule Transfer Protocol + pub static Srp: u8 = 119; // SpectraLink Radio Protocol + pub static Uti: u8 = 120; // UTI + pub static Smp: u8 = 121; // Simple Message Protocol + pub static Sm: u8 = 122; // Simple Multicast Protocol + pub static Ptp: u8 = 123; // Performance Transparency Protocol + pub static IsisOverIpv4: u8 = 124; // + pub static Fire: u8 = 125; // + pub static Crtp: u8 = 126; // Combat Radio Transport Protocol + pub static Crudp: u8 = 127; // Combat Radio User Datagram + pub static Sscopmce: u8 = 128; // + pub static Iplt: u8 = 129; // + pub static Sps: u8 = 130; // Secure Packet Shield + pub static Pipe: u8 = 131; // Private IP Encapsulation within IP + pub static Sctp: u8 = 132; // Stream Control Transmission Protocol + pub static Fc: u8 = 133; // Fibre Channel [RFC6172] + pub static RsvpE2eIgnore: u8 = 134; // [RFC3175] + pub static MobilityHeader: u8 = 135; // [RFC6275] + pub static UdpLite: u8 = 136; // [RFC3828] + pub static MplsInIp: u8 = 137; // [RFC4023] + pub static Manet: u8 = 138; // MANET Protocols [RFC5498] + pub static Hip: u8 = 139; // Host Identity Protocol [RFC5201] + pub static Shim6: u8 = 140; // Shim6 Protocol [RFC5533] + pub static Wesp: u8 = 141; // Wrapped Encapsulating Security Payload [RFC5840] + pub static Rohc: u8 = 142; // Robust Header Compression [RFC5858] + pub static Test1: u8 = 253; // Use for experimentation and testing [RFC3692] + pub static Test2: u8 = 254; // Use for experimentation and testing [RFC3692] + pub static Reserved: u8 = 255; // } -pub type IpNextHeaderProtocol = self::IpNextHeaderProtocol::IpNextHeaderProtocol; +pub type IpNextHeaderProtocol = u8; #[cfg(test)] pub mod test { From c6b531b7ecd588db7b564c51f058dc149b4ebfdd Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 26 Feb 2014 03:09:52 +0000 Subject: [PATCH 27/54] getifaddrs() stuff for raw sockets. WIP. --- src/libnative/io/mod.rs | 2 +- src/libnative/io/net.rs | 45 +++---- src/librustuv/net.rs | 49 +++---- src/librustuv/uvio.rs | 2 +- src/libstd/io/net/raw.rs | 270 ++++++++++++++++++++++++++++++++++----- src/libstd/libc.rs | 40 +++++- src/libstd/rt/rtio.rs | 2 +- 7 files changed, 309 insertions(+), 101 deletions(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 25be2c5957973..6165bedaa3de7 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -211,7 +211,7 @@ impl rtio::IoFactory for IoFactory { hint: Option) -> IoResult<~[ai::Info]> { addrinfo::GetAddrInfoRequest::run(host, servname, hint) } - fn raw_socket_new(&mut self, protocol: Protocol) -> IoResult<~rtio::RtioRawSocket> { + fn raw_socket_new(&mut self, protocol: &Protocol) -> IoResult<~rtio::RtioRawSocket> { net::RawSocket::new(protocol).map(|r| ~r as ~RtioRawSocket) } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index dc581cc1778f1..4652b0a03e28c 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -643,27 +643,27 @@ pub struct RawSocket { priv fd: sock_t, } -fn protocol_to_libc(protocol: raw::Protocol) - -> (libc::c_int, libc::c_int, libc::c_int, Option) { +fn protocol_to_libc<'ni>(protocol: &raw::Protocol<'ni>) + -> (libc::c_int, libc::c_int, libc::c_int, Option<&'ni raw::NetworkInterface>) { let ETH_P_ALL: u16 = htons(0x0003); match protocol { - raw::DataLinkProtocol(raw::EthernetProtocol(iface)) + &raw::DataLinkProtocol(raw::EthernetProtocol(iface)) => (libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL as libc::c_int, Some(iface)), - raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) + &raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) => (libc::AF_PACKET, libc::SOCK_DGRAM, ETH_P_ALL as libc::c_int, Some(iface)), - raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + &raw::NetworkProtocol(raw::Ipv4NetworkProtocol) => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + &raw::NetworkProtocol(raw::Ipv6NetworkProtocol) => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + &raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int, None), - raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + &raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int, None) } } impl RawSocket { - pub fn new(protocol: raw::Protocol) -> IoResult + pub fn new(protocol: &raw::Protocol) -> IoResult { let (domain, typ, proto, _) = protocol_to_libc(protocol); let sock = unsafe { libc::socket(domain, typ, proto) }; @@ -673,21 +673,6 @@ impl RawSocket { let socket = RawSocket { fd: sock }; - /*if includeIpHeader && domain == libc::AF_INET { - let one: libc::c_int = 1; - // Only windows supports IPV6_HDRINCL - let (proto, hdrincl) = (libc::IPPROTO_IP, libc::IP_HDRINCL); - let res = unsafe { - libc::setsockopt(socket.fd, - proto, - hdrincl, - (&one as *libc::c_int) as *libc::c_void, - intrinsics::size_of::() as u32) - }; - if res == -1 { - return Err(super::last_error()); - } - }*/ return Ok(socket); } } @@ -713,16 +698,18 @@ impl rtio::RtioRawSocket for RawSocket { return Err(super::last_error()); } - return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { - Ok((len as uint, Some(raw::IpAddress(addr.ip)))) - }); + return Ok((len as uint, sockaddr_to_network_addr(&caddr))); + //return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { + // Ok((len as uint, Some(raw::IpAddress(addr.ip)))) + //}); } fn sendto(&mut self, buf: &[u8], dst: Option) -> IoResult { - let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; - let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); + //let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; + //let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); + let (sockaddr, slen) = network_addr_to_sockaddr(dst.unwrap()); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { retry( || libc::sendto(self.fd, diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 8c40d834b70f8..632e809960be4 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -775,27 +775,27 @@ fn translate_error(errno: i32, detail: bool) -> IoError { fn last_error() -> IoError { translate_error(os::errno() as i32, true) } // ---------------------------------------------------------------------------- -fn protocol_to_libc(protocol: raw::Protocol) - -> (c_int, c_int, c_int, Option) { +fn protocol_to_libc<'ni>(protocol: &raw::Protocol<'ni>) + -> (c_int, c_int, c_int, Option<&'ni raw::NetworkInterface>) { let ETH_P_ALL: u16 = htons(0x0003); match protocol { - raw::DataLinkProtocol(raw::EthernetProtocol(iface)) + &raw::DataLinkProtocol(raw::EthernetProtocol(iface)) => (libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL as c_int, Some(iface)), - raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) + &raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) => (libc::AF_PACKET, libc::SOCK_DGRAM, ETH_P_ALL as c_int, Some(iface)), - raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + &raw::NetworkProtocol(raw::Ipv4NetworkProtocol) => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + &raw::NetworkProtocol(raw::Ipv6NetworkProtocol) => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + &raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) => (libc::AF_INET, libc::SOCK_RAW, proto as c_int, None), - raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + &raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) => (libc::AF_INET6, libc::SOCK_RAW, proto as c_int, None) } } impl RawSocketWatcher { - pub fn new(io: &mut UvIoFactory, protocol: raw::Protocol) + pub fn new(io: &mut UvIoFactory, protocol: &raw::Protocol) -> Result { let (domain, typ, proto, _) = protocol_to_libc(protocol); @@ -810,22 +810,6 @@ impl RawSocketWatcher { socket: socket }; - /*if includeIpHeader && domain == libc::AF_INET { - let one: libc::c_int = 1; - // Only windows supports IPV6_HDRINCL - let (proto, hdrincl) = (libc::IPPROTO_IP, libc::IP_HDRINCL); - let res = unsafe { - libc::setsockopt(raw.socket, - proto, - hdrincl, - (&one as *libc::c_int) as *libc::c_void, - intrinsics::size_of::() as u32) - }; - if res == -1 { - return Err(last_error()); - } - }*/ - // Make socket non-blocking - required for libuv let flags = unsafe { libc::fcntl(raw.socket, libc::F_GETFL, 0) }; if flags == -1 { @@ -927,7 +911,8 @@ impl rtio::RtioRawSocket for RawSocketWatcher { wakeup(&mut cx.task); return; } - let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); + //let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); + let addr = raw::sockaddr_to_network_addr(&caddr); cx.result = Some((len as ssize_t, addr)); wakeup(&mut cx.task); @@ -942,11 +927,10 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: &'b [u8], result: Option, socket: Option, - addr: ip::IpAddr, + addr: ip::NetworkAddress, } let _m = self.fire_homing_missile(); - let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; let a = match unsafe { uvll::uv_poll_start(self.handle, uvll::UV_WRITABLE as c_int, send_cb) } { @@ -956,7 +940,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: buf, result: None, socket: Some(self.socket), - addr: dst_ip.unwrap() + addr: dst.unwrap() }; wait_until_woken_after(&mut cx.task, &self.uv_loop(), || { unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } @@ -988,9 +972,10 @@ impl rtio::RtioRawSocket for RawSocketWatcher { let len = match cx.socket { Some(sock) => { - let (addr, len) = addr_to_sockaddr( - ip::SocketAddr{ ip: cx.addr, port: 0 } - ); + //let (addr, len) = addr_to_sockaddr( + // ip::SocketAddr{ ip: cx.addr, port: 0 } + // ); + let (addr, len) = raw::network_addr_to_sockaddr(cx.addr); unsafe { libc::sendto(sock, cx.buf.as_ptr() as *c_void, diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index c3f7f75bc93f8..175aef25093df 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -180,7 +180,7 @@ impl IoFactory for UvIoFactory { r.map_err(uv_error_to_io_error) } - fn raw_socket_new(&mut self, protocol: Protocol) -> Result<~rtio::RtioRawSocket, IoError> { + fn raw_socket_new(&mut self, protocol: &Protocol) -> Result<~rtio::RtioRawSocket, IoError> { RawSocketWatcher::new(self, protocol) .map(|rsw| ~rsw as ~rtio::RtioRawSocket) } diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 2bffbee519c16..241e46fd86184 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -8,28 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; +use cast; +use hashmap::HashMap; +use std::io::net::ip; +use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; use iter::Iterator; -use option::{Option, Some}; +use libc; +use mem; +use option::{Option, None, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; -use vec::{MutableVector, ImmutableVector}; +use clone::Clone; +use vec::ImmutableVector; + +#[test] +use vec::MutableVector; pub struct RawSocket { priv obj: ~RtioRawSocket } impl RawSocket { - pub fn new(protocol: Protocol) -> IoResult { + pub fn new(protocol: &Protocol) -> IoResult { LocalIo::maybe_raise(|io| { io.raw_socket_new(protocol).map(|s| RawSocket { obj: s }) }) } - pub fn get_interfaces() -> ~[NetworkInterface] { - ~[] // FIXME - } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, Option)> { self.obj.recvfrom(buf) } @@ -39,16 +44,200 @@ impl RawSocket { } } -pub struct NetworkInterface; +// from librustuv/net.rs +pub fn htons(u: u16) -> u16 { + mem::to_be16(u as i16) as u16 +} +pub fn ntohs(u: u16) -> u16 { + mem::from_be16(u as i16) as u16 +} +pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, + len: uint) -> ip::SocketAddr { + match storage.ss_family as libc::c_int { + libc::AF_INET => { + assert!(len as uint >= mem::size_of::()); + let storage: &libc::sockaddr_in = unsafe { + cast::transmute(storage) + }; + let addr = storage.sin_addr.s_addr as u32; + let a = (addr >> 0) as u8; + let b = (addr >> 8) as u8; + let c = (addr >> 16) as u8; + let d = (addr >> 24) as u8; + ip::SocketAddr { + ip: ip::Ipv4Addr(a, b, c, d), + port: ntohs(storage.sin_port), + } + } + libc::AF_INET6 => { + assert!(len as uint >= mem::size_of::()); + let storage: &libc::sockaddr_in6 = unsafe { + cast::transmute(storage) + }; + let a = ntohs(storage.sin6_addr.s6_addr[0]); + let b = ntohs(storage.sin6_addr.s6_addr[1]); + let c = ntohs(storage.sin6_addr.s6_addr[2]); + let d = ntohs(storage.sin6_addr.s6_addr[3]); + let e = ntohs(storage.sin6_addr.s6_addr[4]); + let f = ntohs(storage.sin6_addr.s6_addr[5]); + let g = ntohs(storage.sin6_addr.s6_addr[6]); + let h = ntohs(storage.sin6_addr.s6_addr[7]); + ip::SocketAddr { + ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), + port: ntohs(storage.sin6_port), + } + } + n => { + fail!("unknown family {}", n); + } + } +} + +fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { + unsafe { + let mut storage: libc::sockaddr_storage = mem::init(); + let len = match addr.ip { + ip::Ipv4Addr(a, b, c, d) => { + let storage: &mut libc::sockaddr_in = + cast::transmute(&mut storage); + (*storage).sin_family = libc::AF_INET as libc::sa_family_t; + (*storage).sin_port = htons(addr.port); + (*storage).sin_addr = libc::in_addr { + s_addr: (d as u32 << 24) | + (c as u32 << 16) | + (b as u32 << 8) | + (a as u32 << 0) + }; + mem::size_of::() + } + ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { + let storage: &mut libc::sockaddr_in6 = + cast::transmute(&mut storage); + storage.sin6_family = libc::AF_INET6 as libc::sa_family_t; + storage.sin6_port = htons(addr.port); + storage.sin6_addr = libc::in6_addr { + s6_addr: [ + htons(a), + htons(b), + htons(c), + htons(d), + htons(e), + htons(f), + htons(g), + htons(h), + ] + }; + mem::size_of::() + } + }; + return (storage, len); + } +} + +// /copy/paste + +pub fn sockaddr_to_network_addr(sa: *libc::sockaddr) -> Option { + unsafe { + if (*sa).sa_family as libc::c_int == libc::AF_PACKET { + let sll: *libc::sockaddr_ll = cast::transmute(sa); + Some(MacAddress(MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1], + (*sll).sll_addr[2], (*sll).sll_addr[3], + (*sll).sll_addr[4], (*sll).sll_addr[5]))) + } else { + Some(IpAddress(sockaddr_to_addr(cast::transmute(sa), mem::size_of::()).ip)) + } + } +} + +pub fn network_addr_to_sockaddr(na: NetworkAddress) -> (libc::sockaddr_storage, uint) { + unsafe { + match na { + IpAddress(ip) => addr_to_sockaddr(ip::SocketAddr { ip: ip, port : 0}), + MacAddress(MacAddr(a, b, c, d, e, f)) => { + let mut storage: libc::sockaddr_storage = mem::init(); + let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); + sll.sll_family = libc::AF_PACKET as libc::sa_family_t; + sll.sll_addr = [a, b, c, d, e, f, 0, 0]; + (storage, mem::size_of::()) + } + } + } +} + +fn sockaddr_to_network_addrs(sa: *libc::sockaddr) + -> (Option, Option, Option) { + match sockaddr_to_network_addr(sa) { + Some(IpAddress(ip@Ipv4Addr(..))) => (None, Some(ip), None), + Some(IpAddress(ip@Ipv6Addr(..))) => (None, None, Some(ip)), + Some(MacAddress(mac@MacAddr(..))) => (Some(mac), None, None), + None => (None, None, None) + } +} + +pub fn get_network_interfaces<'ni>() -> ~HashMap<~str, ~NetworkInterface> { + use ptr; + use str::raw; + let mut map = HashMap::<~str, ~NetworkInterface>::new(); + unsafe { + let mut addrs: *libc::ifaddrs = mem::init(); + if libc::getifaddrs(&mut addrs) != 0 { + return ~map; + } + let mut addr = addrs; + while addr != ptr::null() { + let name = raw::from_c_str((*addr).ifa_name); + let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); + let mut ni = NetworkInterface { + name: name.clone(), + mac: mac, + ipv4: ipv4, + ipv6: ipv6, + flags: (*addr).ifa_flags + }; + println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); + map.insert_or_update_with(ni.name.clone(), ~ni.clone(), |_, v| merge(v, ~ni.clone())); + + addr = (*addr).ifa_next; + } + libc::freeifaddrs(addrs); + + return ~map; + } + + fn merge(old: &mut ~NetworkInterface, new: &NetworkInterface) { + old.mac = match new.mac { + None => old.mac, + _ => new.mac + }; + old.ipv4 = match new.ipv4 { + None => old.ipv4, + _ => new.ipv4 + }; + old.ipv6 = match new.ipv6 { + None => old.ipv6, + _ => new.ipv6 + }; + old.flags = old.flags | new.flags; + } +} + +#[deriving(Clone)] +pub struct NetworkInterface { + priv name: ~str, + priv mac: Option, + priv ipv4: Option, + priv ipv6: Option, + priv flags: u32, +} impl NetworkInterface { pub fn mac_address(&self) -> MacAddr { - MacAddr(0, 0, 0, 0, 0, 0) // FIXME + self.mac.unwrap() } pub fn is_loopback(&self) -> bool { - false // FIXME + self.flags & (libc::IFF_LOOPBACK as u32) != 0 } } @@ -591,20 +780,20 @@ pub enum NetworkAddress { MacAddress(MacAddr) } -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum MacAddr { MacAddr(u8, u8, u8, u8, u8, u8) } -pub enum Protocol { - DataLinkProtocol(DataLinkProto), +pub enum Protocol<'ni> { + DataLinkProtocol(DataLinkProto<'ni>), NetworkProtocol(NetworkProto), TransportProtocol(TransportProto) } -pub enum DataLinkProto { - EthernetProtocol(NetworkInterface), - CookedEthernetProtocol(NetworkInterface) +pub enum DataLinkProto<'ni> { + EthernetProtocol(&'ni NetworkInterface), + CookedEthernetProtocol(&'ni NetworkInterface) } pub enum NetworkProto { @@ -806,13 +995,10 @@ pub mod test { pub fn layer4_test(ip: IpAddr, headerLen: uint) { let message = "message"; - let proto = match ip { - Ipv4Addr(..) => TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocol::Test1)), - Ipv6Addr(..) => TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocol::Test1)) - }; + spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(proto) { + match RawSocket::new(&get_proto(ip)) { Ok(mut sock) => match sock.recvfrom(buf) { Ok((len, Some(IpAddress(addr)))) => { assert_eq!(buf.slice(headerLen, message.len()), message.as_bytes()); @@ -825,13 +1011,20 @@ pub mod test { } }); - match RawSocket::new(proto) { + match RawSocket::new(&get_proto(ip)) { Ok(mut sock) => match sock.sendto(message.as_bytes(), Some(IpAddress(ip))) { Ok(res) => assert_eq!(res as uint, message.len()), Err(_) => fail!() }, Err(_) => fail!() } + + fn get_proto(ip: IpAddr) -> Protocol { + match ip { + Ipv4Addr(..) => TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocol::Test1)), + Ipv6Addr(..) => TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocol::Test1)) + } + } } iotest!(fn layer4_ipv4() { @@ -898,11 +1091,15 @@ pub mod test { } pub fn get_test_interface() -> NetworkInterface { - *RawSocket::get_interfaces() - .iter() + use clone::Clone; + + (**get_network_interfaces() + .values() + //.iter() .filter(|&x| x.is_loopback()) .next() - .unwrap() + .unwrap()) + .clone() } iotest!(fn layer3_ipv4_test() { @@ -912,7 +1109,7 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { + match RawSocket::new(&NetworkProtocol(Ipv4NetworkProtocol)) { Ok(mut sock) => match sock.recvfrom(buf) { Ok((len, Some(IpAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); @@ -925,7 +1122,7 @@ pub mod test { } }); - match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { + match RawSocket::new(&NetworkProtocol(Ipv4NetworkProtocol)) { Ok(mut sock) => match sock.sendto(packet, Some(IpAddress(sendAddr))) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() @@ -942,7 +1139,7 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { + match RawSocket::new(&NetworkProtocol(Ipv6NetworkProtocol)) { Ok(mut sock) => match sock.recvfrom(buf) { Ok((len, Some(IpAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); @@ -955,7 +1152,7 @@ pub mod test { } }); - match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { + match RawSocket::new(&NetworkProtocol(Ipv6NetworkProtocol)) { Ok(mut sock) => match sock.sendto(packet, Some(IpAddress(sendAddr))) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() @@ -967,6 +1164,8 @@ pub mod test { iotest!(fn layer2_cooked_test() { let interface = get_test_interface(); + let interface2 = interface.clone(); + let macAddr = interface.mac_address(); let mut packet = [0u8, ..32]; @@ -974,7 +1173,7 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(interface))) { + match RawSocket::new(&DataLinkProtocol(CookedEthernetProtocol(&interface))) { Ok(mut sock) => match sock.recvfrom(buf) { Ok((len, Some(MacAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); @@ -987,8 +1186,8 @@ pub mod test { } }); - match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(interface))) { - Ok(mut sock) => match sock.sendto(packet, Some(MacAddress(interface.mac_address()))) { + match RawSocket::new(&DataLinkProtocol(CookedEthernetProtocol(&interface2))) { + Ok(mut sock) => match sock.sendto(packet, Some(MacAddress(macAddr))) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() }, @@ -998,6 +1197,7 @@ pub mod test { iotest!(fn layer2_test() { let interface = get_test_interface(); + let interface2 = interface.clone(); let mut packet = [0u8, ..46]; @@ -1012,7 +1212,7 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(DataLinkProtocol(EthernetProtocol(interface))) { + match RawSocket::new(&DataLinkProtocol(EthernetProtocol(&interface))) { Ok(mut sock) => match sock.recvfrom(buf) { Ok((len, Some(MacAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); @@ -1025,7 +1225,7 @@ pub mod test { } }); - match RawSocket::new(DataLinkProtocol(EthernetProtocol(interface))) { + match RawSocket::new(&DataLinkProtocol(EthernetProtocol(&interface2))) { Ok(mut sock) => match sock.sendto(packet, None) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index f84b207a32e72..ce5376fab7c9c 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -267,6 +267,7 @@ pub mod types { pub enum timezone {} } pub mod bsd44 { + use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -319,6 +320,16 @@ pub mod types { ai_canonname: *c_char, ai_next: *addrinfo } + + pub struct ifaddrs { + ifa_next: *ifaddrs, + ifa_name: *c_char, + ifa_flags: c_uint, + ifa_addr: *sockaddr, + ifa_netmask: *sockaddr, + ifa_ifu: *sockaddr, // FIXME This should be a union + ifa_data: *c_void + } } } @@ -505,7 +516,18 @@ pub mod types { } pub mod posix08 {} pub mod bsd44 {} - pub mod extra {} + pub mod extra { + use libc::types::os::arch::c95::{c_ushort, c_int, c_uchar}; + pub struct sockaddr_ll { + sll_family: c_ushort, + sll_protocol: c_ushort, + sll_ifindex: c_int, + sll_hatype: c_ushort, + sll_pkttype: c_uchar, + sll_halen: c_uchar, + sll_addr: [c_uchar, ..8] + } + } } #[cfg(target_arch = "x86_64")] @@ -590,6 +612,16 @@ pub mod types { pub mod bsd44 { } pub mod extra { + use libc::types::os::arch::c95::{c_ushort, c_int, c_uchar}; + pub struct sockaddr_ll { + sll_family: c_ushort, + sll_protocol: c_ushort, + sll_ifindex: c_int, + sll_hatype: c_ushort, + sll_pkttype: c_uchar, + sll_halen: c_uchar, + sll_addr: [c_uchar, ..8] + } } } } @@ -2313,6 +2345,8 @@ pub mod consts { pub static MADV_UNMERGEABLE : c_int = 13; pub static MADV_HWPOISON : c_int = 100; + pub static IFF_LOOPBACK: c_int = 0x8; + pub static AF_INET: c_int = 2; pub static AF_INET6: c_int = 10; pub static SOCK_STREAM: c_int = 1; @@ -3856,7 +3890,7 @@ pub mod funcs { #[cfg(not(windows))] pub mod bsd43 { use libc::types::common::c95::{c_void}; - use libc::types::os::common::bsd44::{socklen_t, sockaddr}; + use libc::types::os::common::bsd44::{socklen_t, sockaddr, ifaddrs}; use libc::types::os::arch::c95::{c_int, size_t}; use libc::types::os::arch::posix88::ssize_t; @@ -3885,6 +3919,8 @@ pub mod funcs { pub fn sendto(socket: c_int, buf: *c_void, len: size_t, flags: c_int, addr: *sockaddr, addrlen: socklen_t) -> ssize_t; + pub fn getifaddrs(ifap: *mut *ifaddrs) -> c_int; + pub fn freeifaddrs(ifa: *ifaddrs); } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index e54f3351ea4ef..d17deac09d1c8 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -152,7 +152,7 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; - fn raw_socket_new(&mut self, protocol: Protocol) -> Result<~RtioRawSocket, IoError>; + fn raw_socket_new(&mut self, protocol: &Protocol) -> Result<~RtioRawSocket, IoError>; // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; From a372303ccccbca52253434e67f052f457206f7ab Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Thu, 6 Mar 2014 01:22:34 +0000 Subject: [PATCH 28/54] Get raw sockets compiling with latest rust again. --- src/libnative/io/net.rs | 14 +++++----- src/librustuv/net.rs | 14 +++++----- src/libstd/io/net/raw.rs | 58 +++++++++++++++++++++++++--------------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index f5f16f4f60d4c..5edfef90d7c0f 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -16,7 +16,7 @@ use std::libc; use std::mem; use std::rt::rtio; use std::sync::arc::UnsafeArc; -use std::unstable::intrinsics; +use std::intrinsics; use super::{IoResult, retry, keep_going}; @@ -642,12 +642,12 @@ pub struct RawSocket { fn protocol_to_libc<'ni>(protocol: &raw::Protocol<'ni>) -> (libc::c_int, libc::c_int, libc::c_int, Option<&'ni raw::NetworkInterface>) { - let ETH_P_ALL: u16 = htons(0x0003); + let eth_p_all: u16 = htons(0x0003); match protocol { &raw::DataLinkProtocol(raw::EthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL as libc::c_int, Some(iface)), + => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int, Some(iface)), &raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_DGRAM, ETH_P_ALL as libc::c_int, Some(iface)), + => (libc::AF_PACKET, libc::SOCK_DGRAM, eth_p_all as libc::c_int, Some(iface)), &raw::NetworkProtocol(raw::Ipv4NetworkProtocol) => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), &raw::NetworkProtocol(raw::Ipv6NetworkProtocol) @@ -695,7 +695,9 @@ impl rtio::RtioRawSocket for RawSocket { return Err(super::last_error()); } - return Ok((len as uint, sockaddr_to_network_addr(&caddr))); + return Ok((len as uint, raw::sockaddr_to_network_addr( + (&caddr as *libc::sockaddr_storage) as *libc::sockaddr) + )); //return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { // Ok((len as uint, Some(raw::IpAddress(addr.ip)))) //}); @@ -706,7 +708,7 @@ impl rtio::RtioRawSocket for RawSocket { { //let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; //let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); - let (sockaddr, slen) = network_addr_to_sockaddr(dst.unwrap()); + let (sockaddr, slen) = raw::network_addr_to_sockaddr(dst.unwrap()); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { retry( || libc::sendto(self.fd, diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 632e809960be4..4a0ee2d913f58 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -21,7 +21,7 @@ use std::os::errno; use std::ptr; use std::rt::rtio; use std::rt::task::BlockedTask; -use std::unstable::intrinsics; +use std::intrinsics; use access::Access; use homing::{HomingIO, HomeHandle}; @@ -777,12 +777,12 @@ fn last_error() -> IoError { translate_error(os::errno() as i32, true) } fn protocol_to_libc<'ni>(protocol: &raw::Protocol<'ni>) -> (c_int, c_int, c_int, Option<&'ni raw::NetworkInterface>) { - let ETH_P_ALL: u16 = htons(0x0003); + let eth_p_all: u16 = htons(0x0003); match protocol { &raw::DataLinkProtocol(raw::EthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL as c_int, Some(iface)), + => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as c_int, Some(iface)), &raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_DGRAM, ETH_P_ALL as c_int, Some(iface)), + => (libc::AF_PACKET, libc::SOCK_DGRAM, eth_p_all as c_int, Some(iface)), &raw::NetworkProtocol(raw::Ipv4NetworkProtocol) => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), &raw::NetworkProtocol(raw::Ipv6NetworkProtocol) @@ -912,7 +912,9 @@ impl rtio::RtioRawSocket for RawSocketWatcher { return; } //let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); - let addr = raw::sockaddr_to_network_addr(&caddr); + let addr = raw::sockaddr_to_network_addr( + (&caddr as *libc::sockaddr_storage) as *libc::sockaddr + ); cx.result = Some((len as ssize_t, addr)); wakeup(&mut cx.task); @@ -927,7 +929,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: &'b [u8], result: Option, socket: Option, - addr: ip::NetworkAddress, + addr: raw::NetworkAddress, } let _m = self.fire_homing_missile(); diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 241e46fd86184..7903757a88d0b 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -8,8 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME +#[allow(missing_doc)]; +#[allow(unused_imports)]; + use cast; -use hashmap::HashMap; use std::io::net::ip; use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; @@ -19,10 +22,10 @@ use mem; use option::{Option, None, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; use clone::Clone; -use vec::ImmutableVector; +use vec::{OwnedVector, ImmutableVector}; #[test] -use vec::MutableVector; +use vec::{Vector, MutableVector}; pub struct RawSocket { priv obj: ~RtioRawSocket @@ -174,14 +177,15 @@ fn sockaddr_to_network_addrs(sa: *libc::sockaddr) } } -pub fn get_network_interfaces<'ni>() -> ~HashMap<~str, ~NetworkInterface> { +pub fn get_network_interfaces() -> ~[NetworkInterface] { use ptr; use str::raw; - let mut map = HashMap::<~str, ~NetworkInterface>::new(); + + let mut ifaces: ~[NetworkInterface] = ~[]; unsafe { let mut addrs: *libc::ifaddrs = mem::init(); if libc::getifaddrs(&mut addrs) != 0 { - return ~map; + return ifaces; } let mut addr = addrs; while addr != ptr::null() { @@ -195,16 +199,25 @@ pub fn get_network_interfaces<'ni>() -> ~HashMap<~str, ~NetworkInterface> { flags: (*addr).ifa_flags }; println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); - map.insert_or_update_with(ni.name.clone(), ~ni.clone(), |_, v| merge(v, ~ni.clone())); + let mut found: bool = false; + for iface in ifaces.mut_iter() { + if name == iface.name { + merge(iface, &ni); + found = true; + } + } + if !found { + ifaces.push(ni); + } addr = (*addr).ifa_next; } libc::freeifaddrs(addrs); - return ~map; + return ifaces; } - fn merge(old: &mut ~NetworkInterface, new: &NetworkInterface) { + fn merge(old: &mut NetworkInterface, new: &NetworkInterface) { old.mac = match new.mac { None => old.mac, _ => new.mac @@ -219,6 +232,7 @@ pub fn get_network_interfaces<'ni>() -> ~HashMap<~str, ~NetworkInterface> { }; old.flags = old.flags | new.flags; } + } #[deriving(Clone)] @@ -507,7 +521,7 @@ fn ipv4_header_test() { 0xb6, 0x4e, /* checksum */ 0xc0, 0xa8, 0x00, 0x01, /* source ip */ 0xc0, 0xa8, 0x00, 0xc7 /* dest ip */]; - assert_eq!(refPacket, packet); + assert_eq!(refPacket.as_slice(), packet.as_slice()); } pub struct Ipv6Header<'p> { @@ -550,7 +564,7 @@ impl<'p> Ipv6Header<'p> { pub fn get_flow_label(&self) -> u32 { let fl1 = (self.packet[self.offset + 1] as u32 & 0xF) << 16; - let fl2 = (self.packet[self.offset + 2] as u32 << 8); + let fl2 = self.packet[self.offset + 2] as u32 << 8; let fl3 = self.packet[self.offset + 3] as u32; fl1 | fl2 | fl3 } @@ -711,7 +725,7 @@ fn ipv6_header_test() { 0x10, 0x01, 0x01, 0x10, 0x10, 0x01]; - assert_eq!(refPacket, packet); + assert_eq!(refPacket.as_slice(), packet.as_slice()); } @@ -774,13 +788,13 @@ impl<'p> UdpHeader<'p> { } } -#[deriving(Eq)] +#[deriving(Eq, Show)] pub enum NetworkAddress { IpAddress(IpAddr), MacAddress(MacAddr) } -#[deriving(Eq, Clone)] +#[deriving(Eq, Clone, Show)] pub enum MacAddr { MacAddr(u8, u8, u8, u8, u8, u8) } @@ -1093,13 +1107,15 @@ pub mod test { pub fn get_test_interface() -> NetworkInterface { use clone::Clone; - (**get_network_interfaces() - .values() - //.iter() - .filter(|&x| x.is_loopback()) - .next() - .unwrap()) - .clone() + get_network_interfaces()[0] + + //(**get_network_interfaces() + // .values() + // //.iter() + // .filter(|&x| x.is_loopback()) + // .next() + // .unwrap()) + // .clone() } iotest!(fn layer3_ipv4_test() { From a12898e1917c2fb2ec70bb7f41fd760c60ce575a Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 7 Mar 2014 14:05:48 +0000 Subject: [PATCH 29/54] Make network interface bits compile. --- src/libstd/io/net/raw.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 7903757a88d0b..54b1af24d62fb 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -177,11 +177,11 @@ fn sockaddr_to_network_addrs(sa: *libc::sockaddr) } } -pub fn get_network_interfaces() -> ~[NetworkInterface] { +pub fn get_network_interfaces() -> ~[~NetworkInterface] { use ptr; use str::raw; - let mut ifaces: ~[NetworkInterface] = ~[]; + let mut ifaces: ~[~NetworkInterface] = ~[]; unsafe { let mut addrs: *libc::ifaddrs = mem::init(); if libc::getifaddrs(&mut addrs) != 0 { @@ -191,7 +191,7 @@ pub fn get_network_interfaces() -> ~[NetworkInterface] { while addr != ptr::null() { let name = raw::from_c_str((*addr).ifa_name); let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); - let mut ni = NetworkInterface { + let mut ni = ~NetworkInterface { name: name.clone(), mac: mac, ipv4: ipv4, @@ -217,7 +217,7 @@ pub fn get_network_interfaces() -> ~[NetworkInterface] { return ifaces; } - fn merge(old: &mut NetworkInterface, new: &NetworkInterface) { + fn merge(old: &mut ~NetworkInterface, new: &~NetworkInterface) { old.mac = match new.mac { None => old.mac, _ => new.mac @@ -1107,7 +1107,12 @@ pub mod test { pub fn get_test_interface() -> NetworkInterface { use clone::Clone; - get_network_interfaces()[0] + (**get_network_interfaces() + .iter() + .filter(|x| x.is_loopback()) + .next() + .unwrap()) + .clone() //(**get_network_interfaces() // .values() From c1f28277cf1a30ee7b5d5cc2a61a53ce5d84764b Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 8 Mar 2014 13:50:16 +0000 Subject: [PATCH 30/54] Fix some issues from the pull request. --- src/librustuv/net.rs | 66 +++++++++++++++++++++------------------- src/libstd/io/net/mod.rs | 2 -- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 4a0ee2d913f58..26d9a052bb18e 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -799,13 +799,14 @@ impl RawSocketWatcher { -> Result { let (domain, typ, proto, _) = protocol_to_libc(protocol); + let handle = unsafe { uvll::malloc_handle(uvll::UV_POLL) }; let socket = unsafe { libc::socket(domain, typ, proto) }; if socket == -1 { return Err(last_error()); } let raw = RawSocketWatcher { - handle: unsafe { uvll::malloc_handle(uvll::UV_POLL) }, + handle: handle, home: io.make_handle(), socket: socket }; @@ -867,7 +868,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { (n, _) if n < 0 => - Err(last_error()), + Err(translate_error(n, true)), (n, addr) => Ok((n as uint, Some(addr.unwrap()))) } } @@ -883,6 +884,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { if status < 0 { cx.result = Some((status as ssize_t, None)); + wakeup(&mut cx.task); return; } @@ -895,19 +897,19 @@ impl rtio::RtioRawSocket for RawSocketWatcher { intrinsics::size_of::() } as libc::socklen_t; let len = match cx.socket { - Some(sock) => unsafe { - let addr = &mut caddr as *mut libc::sockaddr_storage; - libc::recvfrom(sock, - cx.buf.as_ptr() as *mut c_void, - cx.buf.len() as u64, - 0, - addr as *mut libc::sockaddr, - &mut caddrlen) - }, - _ => -1 - }; + Some(sock) => unsafe { + let addr = &mut caddr as *mut libc::sockaddr_storage; + libc::recvfrom(sock, + cx.buf.as_ptr() as *mut c_void, + cx.buf.len() as u64, + 0, + addr as *mut libc::sockaddr, + &mut caddrlen) + }, + _ => -1 + }; if len == -1 { - cx.result = Some((errno() as ssize_t, None)); + cx.result = Some((-errno() as ssize_t, None)); wakeup(&mut cx.task); return; } @@ -949,7 +951,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { n if n < 0 => - Err(last_error()), + Err(translate_error(n, true)), n => Ok(n) } } @@ -973,25 +975,25 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } let len = match cx.socket { - Some(sock) => { - //let (addr, len) = addr_to_sockaddr( - // ip::SocketAddr{ ip: cx.addr, port: 0 } - // ); - let (addr, len) = raw::network_addr_to_sockaddr(cx.addr); - unsafe { - libc::sendto(sock, - cx.buf.as_ptr() as *c_void, - cx.buf.len() as u64, - 0, - (&addr as *libc::sockaddr_storage) as *libc::sockaddr, - len as libc::socklen_t) - } - }, - _ => -1 - }; + Some(sock) => { + //let (addr, len) = addr_to_sockaddr( + // ip::SocketAddr{ ip: cx.addr, port: 0 } + // ); + let (addr, len) = raw::network_addr_to_sockaddr(cx.addr); + unsafe { + libc::sendto(sock, + cx.buf.as_ptr() as *c_void, + cx.buf.len() as u64, + 0, + (&addr as *libc::sockaddr_storage) as *libc::sockaddr, + len as libc::socklen_t) + } + }, + _ => -1 + }; cx.result = if len < 0 { - Some(errno() as int) + Some(-errno() as int) } else { Some(len as int) }; diff --git a/src/libstd/io/net/mod.rs b/src/libstd/io/net/mod.rs index 1610f839a8941..f71adb80bccfc 100644 --- a/src/libstd/io/net/mod.rs +++ b/src/libstd/io/net/mod.rs @@ -16,8 +16,6 @@ pub mod addrinfo; pub mod tcp; pub mod udp; pub mod ip; -// Windows does not support Raw sockets -#[cfg(unix)] pub mod raw; // FIXME(#12093) - this should not be called unix pub mod unix; From c49903a9cce8ac9aac53b8368b51608021bcad33 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 8 Mar 2014 16:07:38 +0000 Subject: [PATCH 31/54] Support immutable packet types. --- src/libstd/io/net/raw.rs | 507 ++++++++++++++++++++++++--------------- 1 file changed, 320 insertions(+), 187 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 54b1af24d62fb..57499c8628ff2 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -23,6 +23,7 @@ use option::{Option, None, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; use clone::Clone; use vec::{OwnedVector, ImmutableVector}; +use vec_ng::Vec; #[test] use vec::{Vector, MutableVector}; @@ -177,11 +178,11 @@ fn sockaddr_to_network_addrs(sa: *libc::sockaddr) } } -pub fn get_network_interfaces() -> ~[~NetworkInterface] { +pub fn get_network_interfaces() -> Vec<~NetworkInterface> { use ptr; use str::raw; - let mut ifaces: ~[~NetworkInterface] = ~[]; + let mut ifaces: Vec<~NetworkInterface> = Vec::new(); unsafe { let mut addrs: *libc::ifaddrs = mem::init(); if libc::getifaddrs(&mut addrs) != 0 { @@ -191,14 +192,14 @@ pub fn get_network_interfaces() -> ~[~NetworkInterface] { while addr != ptr::null() { let name = raw::from_c_str((*addr).ifa_name); let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); - let mut ni = ~NetworkInterface { + let ni = ~NetworkInterface { name: name.clone(), mac: mac, ipv4: ipv4, ipv6: ipv6, flags: (*addr).ifa_flags }; - println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); + //println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); let mut found: bool = false; for iface in ifaces.mut_iter() { if name == iface.name { @@ -255,121 +256,207 @@ impl NetworkInterface { } } +trait Packet { + fn packet<'p>(&'p self) -> &'p [u8]; + fn offset(&self) -> uint; +} + pub struct EthernetHeader<'p> { + priv packet: &'p [u8], + priv offset: uint +} + +pub struct MutableEthernetHeader<'p> { priv packet: &'p mut [u8], priv offset: uint } -impl<'p> EthernetHeader<'p> { - pub fn new(packet: &'p mut [u8], offset: uint) -> EthernetHeader<'p> { - EthernetHeader { packet: packet, offset: offset } - } +impl<'p> Packet for EthernetHeader<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} - pub fn set_source(&mut self, _mac: MacAddr) { +impl<'p> Packet for MutableEthernetHeader<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet.as_slice() } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +trait EthernetPacket : Packet { + fn get_source(&self) -> MacAddr { // FIXME + MacAddr(0, 0, 0, 0, 0, 0) } - pub fn get_source(&self) -> MacAddr { + fn get_destination(&self) -> MacAddr { // FIXME MacAddr(0, 0, 0, 0, 0, 0) } - pub fn set_destination(&mut self, _mac: MacAddr) { + fn get_ethertype(&self) -> u16 { // FIXME + 0 + } +} + +impl<'p> EthernetPacket for EthernetHeader<'p> {} +impl<'p> EthernetPacket for MutableEthernetHeader<'p> {} + +impl<'p> EthernetHeader<'p> { + pub fn new(packet: &'p [u8], offset: uint) -> EthernetHeader<'p> { + EthernetHeader { packet: packet, offset: offset } + } +} + +impl<'p> MutableEthernetHeader<'p> { + pub fn new(packet: &'p mut [u8], offset: uint) -> MutableEthernetHeader<'p> { + MutableEthernetHeader { packet: packet, offset: offset } } - pub fn get_destination(&self) -> MacAddr { + pub fn set_source(&mut self, _mac: MacAddr) { // FIXME - MacAddr(0, 0, 0, 0, 0, 0) } - pub fn set_ethertype(&mut self, _ethertype: u16) { + pub fn set_destination(&mut self, _mac: MacAddr) { // FIXME } - pub fn get_ethertype(&self) -> u16 { + pub fn set_ethertype(&mut self, _ethertype: u16) { // FIXME - 0 } } pub struct Ipv4Header<'p> { + priv packet: &'p [u8], + priv offset: uint +} + +pub struct MutableIpv4Header<'p> { priv packet: &'p mut [u8], priv offset: uint } +impl<'p> Packet for Ipv4Header<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +impl<'p> Packet for MutableIpv4Header<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet.as_slice() } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +trait Ipv4Packet : Packet { + fn get_version(&self) -> u8 { + self.packet()[self.offset()] >> 4 + } + fn get_header_length(&self) -> u8 { + self.packet()[self.offset()] & 0xF + } + fn get_dscp(&self) -> u8 { + (self.packet()[self.offset() + 1] & 0xFC) >> 2 + } + fn get_ecn(&self) -> u8 { + self.packet()[self.offset() + 1] & 3 + } + fn get_total_length(&self) -> u16 { + let b1 = self.packet()[self.offset() + 2] as u16 << 8; + let b2 = self.packet()[self.offset() + 3] as u16; + b1 | b2 + } + fn get_identification(&self) -> u16 { + let b1 = self.packet()[self.offset() + 4] as u16 << 8; + let b2 = self.packet()[self.offset() + 5] as u16; + b1 | b2 + } + fn get_flags(&self) -> u8 { + self.packet()[self.offset() + 6] >> 5 + } + fn get_fragment_offset(&self) -> u16 { + let b1 = (self.packet()[self.offset() + 6] & 0x1F) as u16 << 8; + let b2 = self.packet()[self.offset() + 7] as u16; + b1 | b2 + } + fn get_ttl(&self) -> u8 { + self.packet()[self.offset() + 8] + } + fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { + self.packet()[self.offset() + 9] + } + fn get_checksum(&self) -> u16 { + let cs1 = self.packet()[self.offset() + 10] as u16 << 8; + let cs2 = self.packet()[self.offset() + 11] as u16; + cs1 | cs2 + } + fn get_source(&self) -> IpAddr { + Ipv4Addr(self.packet()[self.offset() + 12], + self.packet()[self.offset() + 13], + self.packet()[self.offset() + 14], + self.packet()[self.offset() + 15]) + } + fn get_destination(&self) -> IpAddr { + Ipv4Addr(self.packet()[self.offset() + 16], + self.packet()[self.offset() + 17], + self.packet()[self.offset() + 18], + self.packet()[self.offset() + 19]) + } +} + +impl<'p> Ipv4Packet for Ipv4Header<'p> {} +impl<'p> Ipv4Packet for MutableIpv4Header<'p> {} + impl<'p> Ipv4Header<'p> { - pub fn new(packet: &'p mut [u8], offset: uint) -> Ipv4Header<'p> { + pub fn new(packet: &'p [u8], offset: uint) -> Ipv4Header<'p> { Ipv4Header { packet: packet, offset: offset } } +} +impl<'p> MutableIpv4Header<'p> { + pub fn new(packet: &'p mut [u8], offset: uint) -> MutableIpv4Header<'p> { + MutableIpv4Header { packet: packet, offset: offset } + } pub fn set_version(&mut self, version: u8) { let ver = version << 4; self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; } - pub fn get_version(&self) -> u8 { - self.packet[self.offset] >> 4 - } - pub fn set_header_length(&mut self, ihl: u8) { let len = ihl & 0xF; self.packet[self.offset] = (self.packet[self.offset] & 0xF0) | len; } - pub fn get_header_length(&self) -> u8 { - self.packet[self.offset] & 0xF - } - pub fn set_dscp(&mut self, dscp: u8) { let cp = dscp & 0xFC; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 3) | (cp << 2); } - pub fn get_dscp(&self) -> u8 { - (self.packet[self.offset + 1] & 0xFC) >> 2 - } - pub fn set_ecn(&mut self, ecn: u8) { let cn = ecn & 3; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xFC) | cn; } - pub fn get_ecn(&self) -> u8 { - self.packet[self.offset + 1] & 3 - } - pub fn set_total_length(&mut self, len: u16) { self.packet[self.offset + 2] = (len >> 8) as u8; self.packet[self.offset + 3] = (len & 0xFF) as u8; } - pub fn get_total_length(&self) -> u16 { - let b1 = self.packet[self.offset + 2] as u16 << 8; - let b2 = self.packet[self.offset + 3] as u16; - b1 | b2 - } - pub fn set_identification(&mut self, identification: u16) { self.packet[self.offset + 4] = (identification >> 8) as u8; self.packet[self.offset + 5] = (identification & 0x00FF) as u8; } - pub fn get_identification(&self) -> u16 { - let b1 = self.packet[self.offset + 4] as u16 << 8; - let b2 = self.packet[self.offset + 5] as u16; - b1 | b2 - } - pub fn set_flags(&mut self, flags: u8) { let fs = (flags & 7) << 5; self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0x1F) | fs; } - pub fn get_flags(&self) -> u8 { - self.packet[self.offset + 6] >> 5 - } - pub fn set_fragment_offset(&mut self, offset: u16) { let fo = offset & 0x1FFF; self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0xE0) | @@ -377,28 +464,14 @@ impl<'p> Ipv4Header<'p> { self.packet[self.offset + 7] = (fo & 0xFF) as u8; } - pub fn get_fragment_offset(&self) -> u16 { - let b1 = (self.packet[self.offset + 6] & 0x1F) as u16 << 8; - let b2 = self.packet[self.offset + 7] as u16; - b1 | b2 - } - pub fn set_ttl(&mut self, ttl: u8) { self.packet[self.offset + 8] = ttl; } - pub fn get_ttl(&self) -> u8 { - self.packet[self.offset + 8] - } - pub fn set_next_level_protocol(&mut self, protocol: IpNextHeaderProtocol) { self.packet[self.offset + 9] = protocol; } - pub fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { - self.packet[self.offset + 9] - } - pub fn set_checksum(&mut self, checksum: u16) { let cs1 = ((checksum & 0xFF00) >> 8) as u8; let cs2 = (checksum & 0x00FF) as u8; @@ -406,12 +479,6 @@ impl<'p> Ipv4Header<'p> { self.packet[self.offset + 11] = cs2; } - pub fn get_checksum(&self) -> u16 { - let cs1 = self.packet[self.offset + 10] as u16 << 8; - let cs2 = self.packet[self.offset + 11] as u16; - cs1 | cs2 - } - pub fn set_source(&mut self, ip: IpAddr) { match ip { Ipv4Addr(a, b, c, d) => { @@ -424,13 +491,6 @@ impl<'p> Ipv4Header<'p> { } } - pub fn get_source(&self) -> IpAddr { - Ipv4Addr(self.packet[self.offset + 12], - self.packet[self.offset + 13], - self.packet[self.offset + 14], - self.packet[self.offset + 15]) - } - pub fn set_destination(&mut self, ip: IpAddr) { match ip { Ipv4Addr(a, b, c, d) => { @@ -443,13 +503,6 @@ impl<'p> Ipv4Header<'p> { } } - pub fn get_destination(&self) -> IpAddr { - Ipv4Addr(self.packet[self.offset + 16], - self.packet[self.offset + 17], - self.packet[self.offset + 18], - self.packet[self.offset + 19]) - } - pub fn checksum(&mut self) { let len = self.offset + self.get_header_length() as uint * 4; let mut sum = 0u32; @@ -470,7 +523,7 @@ impl<'p> Ipv4Header<'p> { fn ipv4_header_test() { let mut packet = [0u8, ..20]; { - let mut ipHeader = Ipv4Header::new(packet.as_mut_slice(), 0); + let mut ipHeader = MutableIpv4Header::new(packet.as_mut_slice(), 0); ipHeader.set_version(4); assert_eq!(ipHeader.get_version(), 4); @@ -525,36 +578,112 @@ fn ipv4_header_test() { } pub struct Ipv6Header<'p> { + priv packet: &'p [u8], + priv offset: uint +} + +pub struct MutableIpv6Header<'p> { priv packet: &'p mut [u8], priv offset: uint } +impl<'p> Packet for Ipv6Header<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +impl<'p> Packet for MutableIpv6Header<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet.as_slice() } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +trait Ipv6Packet : Packet { + fn get_version(&self) -> u8 { + self.packet()[self.offset()] >> 4 + } + fn get_traffic_class(&self) -> u8 { + let tc1 = (self.packet()[self.offset() + 0] & 0x0F) << 4; + let tc2 = self.packet()[self.offset() + 1] >> 4; + tc1 | tc2 + } + fn get_flow_label(&self) -> u32 { + let fl1 = (self.packet()[self.offset() + 1] as u32 & 0xF) << 16; + let fl2 = self.packet()[self.offset() + 2] as u32 << 8; + let fl3 = self.packet()[self.offset() + 3] as u32; + fl1 | fl2 | fl3 + } + fn get_payload_length(&self) -> u16 { + let len1 = self.packet()[self.offset() + 4] as u16 << 8; + let len2 = self.packet()[self.offset() + 5] as u16; + len1 | len2 + } + fn get_next_header(&self) -> IpNextHeaderProtocol { + self.packet()[self.offset() + 6] + } + fn get_hop_limit(&self) -> u8 { + self.packet()[self.offset() + 7] + } + fn get_source(&self) -> IpAddr { + let packet = self.packet(); + let offset = self.offset(); + + let a = (packet[offset + 8] as u16 << 8) | packet[offset + 9] as u16; + let b = (packet[offset + 10] as u16 << 8) | packet[offset + 11] as u16; + let c = (packet[offset + 12] as u16 << 8) | packet[offset + 13] as u16; + let d = (packet[offset + 14] as u16 << 8) | packet[offset + 15] as u16; + let e = (packet[offset + 16] as u16 << 8) | packet[offset + 17] as u16; + let f = (packet[offset + 18] as u16 << 8) | packet[offset + 19] as u16; + let g = (packet[offset + 20] as u16 << 8) | packet[offset + 21] as u16; + let h = (packet[offset + 22] as u16 << 8) | packet[offset + 23] as u16; + + Ipv6Addr(a, b, c, d, e, f, g, h) + } + fn get_destination(&self) -> IpAddr { + let packet = self.packet(); + let offset = self.offset(); + + let a = (packet[offset + 24] as u16 << 8) | packet[offset + 25] as u16; + let b = (packet[offset + 26] as u16 << 8) | packet[offset + 27] as u16; + let c = (packet[offset + 28] as u16 << 8) | packet[offset + 29] as u16; + let d = (packet[offset + 30] as u16 << 8) | packet[offset + 31] as u16; + let e = (packet[offset + 32] as u16 << 8) | packet[offset + 33] as u16; + let f = (packet[offset + 34] as u16 << 8) | packet[offset + 35] as u16; + let g = (packet[offset + 36] as u16 << 8) | packet[offset + 37] as u16; + let h = (packet[offset + 38] as u16 << 8) | packet[offset + 39] as u16; + + Ipv6Addr(a, b, c, d, e, f, g, h) + } +} + +impl<'p> Ipv6Packet for Ipv6Header<'p> {} +impl<'p> Ipv6Packet for MutableIpv6Header<'p> {} + impl<'p> Ipv6Header<'p> { - pub fn new(packet: &'p mut [u8], offset: uint) -> Ipv6Header<'p> { + pub fn new(packet: &'p [u8], offset: uint) -> Ipv6Header<'p> { Ipv6Header { packet: packet, offset: offset } } +} + +impl<'p> MutableIpv6Header<'p> { + pub fn new(packet: &'p mut [u8], offset: uint) -> MutableIpv6Header<'p> { + MutableIpv6Header { packet: packet, offset: offset } + } pub fn set_version(&mut self, version: u8) { let ver = version << 4; self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; } - pub fn get_version(&self) -> u8 { - self.packet[self.offset] >> 4 - } - pub fn set_traffic_class(&mut self, tc: u8) { self.packet[self.offset + 0] = (self.packet[self.offset] & 0xF0) | (tc >> 4); self.packet[self.offset + 1] = ((tc & 0x0F) << 4) | ((self.packet[self.offset + 1] & 0xF0) >> 4); } - pub fn get_traffic_class(&self) -> u8 { - let tc1 = (self.packet[self.offset + 0] & 0x0F) << 4; - let tc2 = self.packet[self.offset + 1] >> 4; - tc1 | tc2 - } - pub fn set_flow_label(&mut self, label: u32) { let lbl = ((label & 0xF0000) >> 16) as u8; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xF0) | lbl; @@ -562,40 +691,19 @@ impl<'p> Ipv6Header<'p> { self.packet[self.offset + 3] = (label & 0x00FF) as u8; } - pub fn get_flow_label(&self) -> u32 { - let fl1 = (self.packet[self.offset + 1] as u32 & 0xF) << 16; - let fl2 = self.packet[self.offset + 2] as u32 << 8; - let fl3 = self.packet[self.offset + 3] as u32; - fl1 | fl2 | fl3 - } - pub fn set_payload_length(&mut self, len: u16) { self.packet[self.offset + 4] = (len >> 8) as u8; self.packet[self.offset + 5] = (len & 0xFF) as u8; } - pub fn get_payload_length(&self) -> u16 { - let len1 = self.packet[self.offset + 4] as u16 << 8; - let len2 = self.packet[self.offset + 5] as u16; - len1 | len2 - } - pub fn set_next_header(&mut self, protocol: IpNextHeaderProtocol) { self.packet[self.offset + 6] = protocol; } - pub fn get_next_header(&self) -> IpNextHeaderProtocol { - self.packet[self.offset + 6] - } - pub fn set_hop_limit(&mut self, limit: u8) { self.packet[self.offset + 7] = limit; } - pub fn get_hop_limit(&self) -> u8 { - self.packet[self.offset + 7] - } - pub fn set_source(&mut self, ip: IpAddr) { match ip { Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -620,19 +728,6 @@ impl<'p> Ipv6Header<'p> { } } - pub fn get_source(&self) -> IpAddr { - let a = (self.packet[self.offset + 8] as u16 << 8) | self.packet[self.offset + 9] as u16; - let b = (self.packet[self.offset + 10] as u16 << 8) | self.packet[self.offset + 11] as u16; - let c = (self.packet[self.offset + 12] as u16 << 8) | self.packet[self.offset + 13] as u16; - let d = (self.packet[self.offset + 14] as u16 << 8) | self.packet[self.offset + 15] as u16; - let e = (self.packet[self.offset + 16] as u16 << 8) | self.packet[self.offset + 17] as u16; - let f = (self.packet[self.offset + 18] as u16 << 8) | self.packet[self.offset + 19] as u16; - let g = (self.packet[self.offset + 20] as u16 << 8) | self.packet[self.offset + 21] as u16; - let h = (self.packet[self.offset + 22] as u16 << 8) | self.packet[self.offset + 23] as u16; - - Ipv6Addr(a, b, c, d, e, f, g, h) - } - pub fn set_destination(&mut self, ip: IpAddr) { match ip { Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -656,26 +751,13 @@ impl<'p> Ipv6Header<'p> { _ => () } } - - pub fn get_destination(&self) -> IpAddr { - let a = (self.packet[self.offset + 24] as u16 << 8) | self.packet[self.offset + 25] as u16; - let b = (self.packet[self.offset + 26] as u16 << 8) | self.packet[self.offset + 27] as u16; - let c = (self.packet[self.offset + 28] as u16 << 8) | self.packet[self.offset + 29] as u16; - let d = (self.packet[self.offset + 30] as u16 << 8) | self.packet[self.offset + 31] as u16; - let e = (self.packet[self.offset + 32] as u16 << 8) | self.packet[self.offset + 33] as u16; - let f = (self.packet[self.offset + 34] as u16 << 8) | self.packet[self.offset + 35] as u16; - let g = (self.packet[self.offset + 36] as u16 << 8) | self.packet[self.offset + 37] as u16; - let h = (self.packet[self.offset + 38] as u16 << 8) | self.packet[self.offset + 39] as u16; - - Ipv6Addr(a, b, c, d, e, f, g, h) - } } #[test] fn ipv6_header_test() { let mut packet = [0u8, ..40]; { - let mut ipHeader = Ipv6Header::new(packet.as_mut_slice(), 0); + let mut ipHeader = MutableIpv6Header::new(packet.as_mut_slice(), 0); ipHeader.set_version(6); assert_eq!(ipHeader.get_version(), 6); @@ -728,61 +810,86 @@ fn ipv6_header_test() { assert_eq!(refPacket.as_slice(), packet.as_slice()); } - pub struct UdpHeader<'p> { + priv packet: &'p [u8], + priv offset: uint +} +pub struct MutableUdpHeader<'p> { priv packet: &'p mut [u8], priv offset: uint } +impl<'p> Packet for UdpHeader<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +impl<'p> Packet for MutableUdpHeader<'p> { + #[inline(always)] + fn packet<'p>(&'p self) -> &'p [u8] { self.packet.as_slice() } + #[inline(always)] + fn offset(&self) -> uint { self.offset } +} + +trait UdpPacket : Packet { + fn get_source(&self) -> u16 { + let s1 = self.packet()[self.offset() + 0] as u16 << 8; + let s2 = self.packet()[self.offset() + 1] as u16; + s1 | s2 + } + fn get_destination(&self) -> u16 { + let d1 = self.packet()[self.offset() + 2] as u16 << 8; + let d2 = self.packet()[self.offset() + 3] as u16; + d1 | d2 + } + fn get_length(&self) -> u16 { + let l1 = self.packet()[self.offset() + 4] as u16 << 8; + let l2 = self.packet()[self.offset() + 5] as u16; + l1 | l2 + } + fn get_checksum(&self) -> u16 { + let c1 = self.packet()[self.offset() + 6] as u16 << 8; + let c2 = self.packet()[self.offset() + 7] as u16; + c1 | c2 + } +} + +impl<'p> UdpPacket for UdpHeader<'p> {} +impl<'p> UdpPacket for MutableUdpHeader<'p> {} + impl<'p> UdpHeader<'p> { - pub fn new(packet: &'p mut [u8], offset: uint) -> UdpHeader<'p> { + pub fn new(packet: &'p [u8], offset: uint) -> UdpHeader<'p> { UdpHeader { packet: packet, offset: offset } } +} + +impl<'p> MutableUdpHeader<'p> { + pub fn new(packet: &'p mut [u8], offset: uint) -> MutableUdpHeader<'p> { + MutableUdpHeader { packet: packet, offset: offset } + } pub fn set_source(&mut self, port: u16) { self.packet[self.offset + 0] = (port >> 8) as u8; self.packet[self.offset + 1] = (port & 0xFF) as u8; } - pub fn get_source(&self) -> u16 { - let s1 = self.packet[self.offset + 0] as u16 << 8; - let s2 = self.packet[self.offset + 1] as u16; - s1 | s2 - } - pub fn set_destination(&mut self, port: u16) { self.packet[self.offset + 2] = (port >> 8) as u8; self.packet[self.offset + 3] = (port & 0xFF) as u8; } - pub fn get_destination(&self) -> u16 { - let d1 = self.packet[self.offset + 2] as u16 << 8; - let d2 = self.packet[self.offset + 3] as u16; - d1 | d2 - } - pub fn set_length(&mut self, len: u16) { self.packet[self.offset + 4] = (len >> 8) as u8; self.packet[self.offset + 5] = (len & 0xFF) as u8; } - pub fn get_length(&self) -> u16 { - let l1 = self.packet[self.offset + 4] as u16 << 8; - let l2 = self.packet[self.offset + 5] as u16; - l1 | l2 - } - pub fn set_checksum(&mut self, checksum: u16) { self.packet[self.offset + 6] = (checksum >> 8) as u8; self.packet[self.offset + 7] = (checksum & 0xFF) as u8; } - pub fn get_checksum(&self) -> u16 { - let c1 = self.packet[self.offset + 6] as u16 << 8; - let c2 = self.packet[self.offset + 7] as u16; - c1 | c2 - } - pub fn checksum(&mut self) { // FIXME } @@ -997,6 +1104,7 @@ pub mod test { use option::{Some}; use str::StrSlice; use super::*; + use super::{Ipv4Packet,UdpPacket}; use task::spawn; use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use vec::ImmutableVector; @@ -1050,7 +1158,7 @@ pub mod test { } #[cfg(hasroot)]) pub fn build_ipv4_header(packet: &mut [u8], offset: uint) { - let mut ipHeader = Ipv4Header::new(packet, offset); + let mut ipHeader = MutableIpv4Header::new(packet, offset); ipHeader.set_version(4); ipHeader.set_header_length(5); @@ -1063,7 +1171,7 @@ pub mod test { } pub fn build_ipv6_header(packet: &mut [u8], offset: uint) { - let mut ipHeader = Ipv6Header::new(packet, offset); + let mut ipHeader = MutableIpv6Header::new(packet, offset); ipHeader.set_version(6); ipHeader.set_payload_length(UDP_HEADER_LEN + TEST_DATA_LEN); @@ -1074,7 +1182,7 @@ pub mod test { } pub fn build_udp_header(packet: &mut [u8], offset: uint) { - let mut udpHeader = UdpHeader::new(packet, offset); + let mut udpHeader = MutableUdpHeader::new(packet, offset); udpHeader.set_source(1234); // Arbitary port number udpHeader.set_destination(1234); @@ -1113,14 +1221,30 @@ pub mod test { .next() .unwrap()) .clone() + } - //(**get_network_interfaces() - // .values() - // //.iter() - // .filter(|&x| x.is_loopback()) - // .next() - // .unwrap()) - // .clone() + pub fn same_ports(packet1: &[u8], packet2: &[u8]) -> bool { + { + let ip1 = Ipv4Header::new(packet1, 0); + let ip2 = Ipv4Header::new(packet2, 0); + + // Check we have an IPv4/UDP packet + if ip1.get_version() != 4 || ip2.get_version() != 4 || + ip1.get_next_level_protocol() != IpNextHeaderProtocol::Udp || + ip2.get_next_level_protocol() != IpNextHeaderProtocol::Udp { + return false; + } + } + + let udp1 = UdpHeader::new(packet1, IPV4_HEADER_LEN as uint); + let udp2 = UdpHeader::new(packet2, IPV4_HEADER_LEN as uint); + + if udp1.get_source() == udp2.get_source() && + udp1.get_destination() == udp2.get_destination() { + return true; + } + + return false; } iotest!(fn layer3_ipv4_test() { @@ -1195,13 +1319,22 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; match RawSocket::new(&DataLinkProtocol(CookedEthernetProtocol(&interface))) { - Ok(mut sock) => match sock.recvfrom(buf) { - Ok((len, Some(MacAddress(addr)))) => { - assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); - assert_eq!(len, packet.len()); - assert_eq!(addr, interface.mac_address()); - }, - _ => fail!() + Ok(mut sock) => { + loop { + match sock.recvfrom(buf) { + Ok((len, Some(MacAddress(addr)))) => { + println!("packet: {:?}", packet.as_slice()); + println!("buf: {:?}", buf.slice(0, packet.len())); + if len == packet.len() && same_ports(packet.as_slice(), buf) { + assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); + //assert_eq!(len, packet.len()); + assert_eq!(addr, interface.mac_address()); + break; + } + }, + _ => fail!() + } + } }, Err(_) => fail!() } @@ -1223,7 +1356,7 @@ pub mod test { let mut packet = [0u8, ..46]; { - let mut ethernetHeader = EthernetHeader::new(packet.as_mut_slice(), 0); + let mut ethernetHeader = MutableEthernetHeader::new(packet.as_mut_slice(), 0); ethernetHeader.set_source(interface.mac_address()); ethernetHeader.set_destination(interface.mac_address()); ethernetHeader.set_ethertype(Ipv4EtherType); From 045f11e648230468d1bd99a847c0b7bf0bbb9297 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sun, 9 Mar 2014 22:53:37 +0000 Subject: [PATCH 32/54] Working cooked layer 2 support for Linux x86_64. --- src/libnative/io/mod.rs | 2 +- src/libnative/io/net.rs | 38 ++++----- src/librustuv/net.rs | 48 +++++------ src/librustuv/uvio.rs | 2 +- src/libstd/io/net/raw.rs | 177 +++++++++++++++++++++++++++------------ src/libstd/io/test.rs | 2 +- src/libstd/libc.rs | 11 +++ src/libstd/rt/rtio.rs | 6 +- 8 files changed, 182 insertions(+), 104 deletions(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index dccf1d909bf4c..046c13ba5c2ac 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -256,7 +256,7 @@ impl rtio::IoFactory for IoFactory { hint: Option) -> IoResult<~[ai::Info]> { addrinfo::GetAddrInfoRequest::run(host, servname, hint) } - fn raw_socket_new(&mut self, protocol: &Protocol) -> IoResult<~rtio::RtioRawSocket> { + fn raw_socket_new(&mut self, protocol: Protocol) -> IoResult<~rtio::RtioRawSocket> { net::RawSocket::new(protocol).map(|r| ~r as ~RtioRawSocket) } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 5edfef90d7c0f..e36adc3f77ee2 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -640,29 +640,29 @@ pub struct RawSocket { priv fd: sock_t, } -fn protocol_to_libc<'ni>(protocol: &raw::Protocol<'ni>) - -> (libc::c_int, libc::c_int, libc::c_int, Option<&'ni raw::NetworkInterface>) { +fn protocol_to_libc(protocol: raw::Protocol) + -> (libc::c_int, libc::c_int, libc::c_int) { let eth_p_all: u16 = htons(0x0003); match protocol { - &raw::DataLinkProtocol(raw::EthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int, Some(iface)), - &raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_DGRAM, eth_p_all as libc::c_int, Some(iface)), - &raw::NetworkProtocol(raw::Ipv4NetworkProtocol) - => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - &raw::NetworkProtocol(raw::Ipv6NetworkProtocol) - => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - &raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) - => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int, None), - &raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) - => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int, None) + raw::DataLinkProtocol(raw::EthernetProtocol) + => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), + raw::DataLinkProtocol(raw::CookedEthernetProtocol(proto)) + => (libc::AF_PACKET, libc::SOCK_DGRAM, proto as libc::c_int), + raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int), + raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int) } } impl RawSocket { - pub fn new(protocol: &raw::Protocol) -> IoResult + pub fn new(protocol: raw::Protocol) -> IoResult { - let (domain, typ, proto, _) = protocol_to_libc(protocol); + let (domain, typ, proto) = protocol_to_libc(protocol); let sock = unsafe { libc::socket(domain, typ, proto) }; if sock == -1 { return Err(super::last_error()); @@ -676,7 +676,7 @@ impl RawSocket { impl rtio::RtioRawSocket for RawSocket { fn recvfrom(&mut self, buf: &mut [u8]) - -> IoResult<(uint, Option)> + -> IoResult<(uint, Option<~raw::NetworkAddress>)> { let mut caddr: libc::sockaddr_storage = unsafe { intrinsics::init() }; let mut caddrlen = unsafe { @@ -696,14 +696,14 @@ impl rtio::RtioRawSocket for RawSocket { } return Ok((len as uint, raw::sockaddr_to_network_addr( - (&caddr as *libc::sockaddr_storage) as *libc::sockaddr) + (&caddr as *libc::sockaddr_storage) as *libc::sockaddr, true) )); //return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { // Ok((len as uint, Some(raw::IpAddress(addr.ip)))) //}); } - fn sendto(&mut self, buf: &[u8], dst: Option) + fn sendto(&mut self, buf: &[u8], dst: Option<~raw::NetworkAddress>) -> IoResult { //let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 26d9a052bb18e..f79dede5088ec 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -775,30 +775,30 @@ fn translate_error(errno: i32, detail: bool) -> IoError { fn last_error() -> IoError { translate_error(os::errno() as i32, true) } // ---------------------------------------------------------------------------- -fn protocol_to_libc<'ni>(protocol: &raw::Protocol<'ni>) - -> (c_int, c_int, c_int, Option<&'ni raw::NetworkInterface>) { +fn protocol_to_libc(protocol: raw::Protocol) + -> (libc::c_int, libc::c_int, libc::c_int) { let eth_p_all: u16 = htons(0x0003); match protocol { - &raw::DataLinkProtocol(raw::EthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as c_int, Some(iface)), - &raw::DataLinkProtocol(raw::CookedEthernetProtocol(iface)) - => (libc::AF_PACKET, libc::SOCK_DGRAM, eth_p_all as c_int, Some(iface)), - &raw::NetworkProtocol(raw::Ipv4NetworkProtocol) - => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - &raw::NetworkProtocol(raw::Ipv6NetworkProtocol) - => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW, None), - &raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) - => (libc::AF_INET, libc::SOCK_RAW, proto as c_int, None), - &raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) - => (libc::AF_INET6, libc::SOCK_RAW, proto as c_int, None) + raw::DataLinkProtocol(raw::EthernetProtocol) + => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), + raw::DataLinkProtocol(raw::CookedEthernetProtocol(proto)) + => (libc::AF_PACKET, libc::SOCK_DGRAM, proto as libc::c_int), + raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int), + raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int) } } impl RawSocketWatcher { - pub fn new(io: &mut UvIoFactory, protocol: &raw::Protocol) + pub fn new(io: &mut UvIoFactory, protocol: raw::Protocol) -> Result { - let (domain, typ, proto, _) = protocol_to_libc(protocol); + let (domain, typ, proto) = protocol_to_libc(protocol); let handle = unsafe { uvll::malloc_handle(uvll::UV_POLL) }; let socket = unsafe { libc::socket(domain, typ, proto) }; if socket == -1 { @@ -844,12 +844,12 @@ impl HomingIO for RawSocketWatcher { impl rtio::RtioRawSocket for RawSocketWatcher { fn recvfrom(&mut self, buf: &mut [u8]) - -> Result<(uint, Option), IoError> + -> Result<(uint, Option<~raw::NetworkAddress>), IoError> { struct Ctx<'b> { task: Option, buf: &'b [u8], - result: Option<(ssize_t, Option)>, + result: Option<(ssize_t, Option<~raw::NetworkAddress>)>, socket: Option, } let _m = self.fire_homing_missile(); @@ -868,7 +868,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { (n, _) if n < 0 => - Err(translate_error(n, true)), + Err(translate_error(n as i32, true)), (n, addr) => Ok((n as uint, Some(addr.unwrap()))) } } @@ -915,7 +915,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } //let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); let addr = raw::sockaddr_to_network_addr( - (&caddr as *libc::sockaddr_storage) as *libc::sockaddr + (&caddr as *libc::sockaddr_storage) as *libc::sockaddr, true ); cx.result = Some((len as ssize_t, addr)); @@ -923,7 +923,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } } - fn sendto(&mut self, buf: &[u8], dst: Option) + fn sendto(&mut self, buf: &[u8], dst: Option<~raw::NetworkAddress>) -> Result { struct Ctx<'b> { @@ -931,7 +931,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: &'b [u8], result: Option, socket: Option, - addr: raw::NetworkAddress, + addr: ~raw::NetworkAddress, } let _m = self.fire_homing_missile(); @@ -951,7 +951,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { n if n < 0 => - Err(translate_error(n, true)), + Err(translate_error(n as i32, true)), n => Ok(n) } } @@ -979,7 +979,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { //let (addr, len) = addr_to_sockaddr( // ip::SocketAddr{ ip: cx.addr, port: 0 } // ); - let (addr, len) = raw::network_addr_to_sockaddr(cx.addr); + let (addr, len) = raw::network_addr_to_sockaddr(cx.addr.clone()); unsafe { libc::sendto(sock, cx.buf.as_ptr() as *c_void, diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index a62ba465e6918..388ae21e4d243 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -180,7 +180,7 @@ impl IoFactory for UvIoFactory { r.map_err(uv_error_to_io_error) } - fn raw_socket_new(&mut self, protocol: &Protocol) -> Result<~rtio::RtioRawSocket, IoError> { + fn raw_socket_new(&mut self, protocol: Protocol) -> Result<~rtio::RtioRawSocket, IoError> { RawSocketWatcher::new(self, protocol) .map(|rsw| ~rsw as ~rtio::RtioRawSocket) } diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 57499c8628ff2..6b91e5db33ac3 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -13,6 +13,7 @@ #[allow(unused_imports)]; use cast; +use c_str::ToCStr; use std::io::net::ip; use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; @@ -22,7 +23,7 @@ use mem; use option::{Option, None, Some}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; use clone::Clone; -use vec::{OwnedVector, ImmutableVector}; +use vec::{Vector, OwnedVector, ImmutableVector}; use vec_ng::Vec; #[test] @@ -33,17 +34,17 @@ pub struct RawSocket { } impl RawSocket { - pub fn new(protocol: &Protocol) -> IoResult { + pub fn new(protocol: Protocol) -> IoResult { LocalIo::maybe_raise(|io| { io.raw_socket_new(protocol).map(|s| RawSocket { obj: s }) }) } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, Option)> { + pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, Option<~NetworkAddress>)> { self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: Option) -> IoResult { + pub fn sendto(&mut self, buf: &[u8], dst: Option<~NetworkAddress>) -> IoResult { self.obj.sendto(buf, dst) } } @@ -140,40 +141,87 @@ fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { // /copy/paste -pub fn sockaddr_to_network_addr(sa: *libc::sockaddr) -> Option { +pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~NetworkAddress> { unsafe { if (*sa).sa_family as libc::c_int == libc::AF_PACKET { let sll: *libc::sockaddr_ll = cast::transmute(sa); - Some(MacAddress(MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1], - (*sll).sll_addr[2], (*sll).sll_addr[3], - (*sll).sll_addr[4], (*sll).sll_addr[5]))) + let ni = if useLocal { + let nis = get_network_interfaces(); + if nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).len() == 1 { + (*nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).next().unwrap()).clone() + } else { + sll_to_ni(*sll) + } + } else { + sll_to_ni(*sll) + }; + + //let ni = get_network_interfaces() + // .iter() + // .next() + // .unwrap(); + return Some(~NetworkAddress(ni)); + //None + // FIXME Find right interface and return that + //Some(MacAddress(MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1], + // (*sll).sll_addr[2], (*sll).sll_addr[3], + // (*sll).slluint_addr[4], (*sll).sll_addr[5]))) } else { - Some(IpAddress(sockaddr_to_addr(cast::transmute(sa), mem::size_of::()).ip)) + return Some(~IpAddress(sockaddr_to_addr(cast::transmute(sa), mem::size_of::()).ip)); + } + } + + fn sll_to_ni(sll: libc::sockaddr_ll) -> ~NetworkInterface { + let mac = MacAddr(sll.sll_addr[0], sll.sll_addr[1], + sll.sll_addr[2], sll.sll_addr[3], + sll.sll_addr[4], sll.sll_addr[5]); + ~NetworkInterface { + name: ~"", + index: 0, + mac: Some(mac), + ipv4: None, + ipv6: None, + flags: 0 } } } -pub fn network_addr_to_sockaddr(na: NetworkAddress) -> (libc::sockaddr_storage, uint) { +pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, uint) { unsafe { match na { - IpAddress(ip) => addr_to_sockaddr(ip::SocketAddr { ip: ip, port : 0}), - MacAddress(MacAddr(a, b, c, d, e, f)) => { + ~IpAddress(ip) => addr_to_sockaddr(ip::SocketAddr { ip: ip, port : 0}), + //_ => (mem::init(), 0) + ~NetworkAddress(ni) => { let mut storage: libc::sockaddr_storage = mem::init(); let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); sll.sll_family = libc::AF_PACKET as libc::sa_family_t; - sll.sll_addr = [a, b, c, d, e, f, 0, 0]; + match ni.mac { + Some(MacAddr(a, b, c, d, e, f)) => sll.sll_addr = [a, b, c, d, e, f, 0, 0], + _ => () + } + sll.sll_halen = 6; + sll.sll_ifindex = ni.index as i32; + //sll.sll_addr = [a, b, c, d, e, f, 0, 0]; (storage, mem::size_of::()) } + //MacAddress(MacAddr(a, b, c, d, e, f)) => { + // let mut storage: libc::sockaddr_storage = mem::init(); + // let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); + // sll.sll_family = libc::AF_PACKET as libc::sa_family_t; + // sll.sll_addr = [a, b, c, d, e, f, 0, 0]; + // (storage, mem::size_of::()) + //} } } } fn sockaddr_to_network_addrs(sa: *libc::sockaddr) -> (Option, Option, Option) { - match sockaddr_to_network_addr(sa) { - Some(IpAddress(ip@Ipv4Addr(..))) => (None, Some(ip), None), - Some(IpAddress(ip@Ipv6Addr(..))) => (None, None, Some(ip)), - Some(MacAddress(mac@MacAddr(..))) => (Some(mac), None, None), + //(None, None, None) + match sockaddr_to_network_addr(sa, false) { + Some(~IpAddress(ip@Ipv4Addr(..))) => (None, Some(ip), None), + Some(~IpAddress(ip@Ipv6Addr(..))) => (None, None, Some(ip)), + Some(~NetworkAddress(ni)) => (ni.mac, None, None), None => (None, None, None) } } @@ -194,6 +242,7 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); let ni = ~NetworkInterface { name: name.clone(), + index: 0, mac: mac, ipv4: ipv4, ipv6: ipv6, @@ -215,6 +264,9 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { } libc::freeifaddrs(addrs); + for iface in ifaces.mut_iter() { + iface.index = libc::if_nametoindex(iface.name.to_c_str().unwrap()); + } return ifaces; } @@ -236,9 +288,10 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { } -#[deriving(Clone)] +#[deriving(Clone, Eq, Show)] pub struct NetworkInterface { priv name: ~str, + priv index: u32, priv mac: Option, priv ipv4: Option, priv ipv6: Option, @@ -895,10 +948,10 @@ impl<'p> MutableUdpHeader<'p> { } } -#[deriving(Eq, Show)] +#[deriving(Clone, Eq, Show)] pub enum NetworkAddress { IpAddress(IpAddr), - MacAddress(MacAddr) + NetworkAddress(~NetworkInterface) } #[deriving(Eq, Clone, Show)] @@ -906,15 +959,15 @@ pub enum MacAddr { MacAddr(u8, u8, u8, u8, u8, u8) } -pub enum Protocol<'ni> { - DataLinkProtocol(DataLinkProto<'ni>), +pub enum Protocol { + DataLinkProtocol(DataLinkProto), NetworkProtocol(NetworkProto), TransportProtocol(TransportProto) } -pub enum DataLinkProto<'ni> { - EthernetProtocol(&'ni NetworkInterface), - CookedEthernetProtocol(&'ni NetworkInterface) +pub enum DataLinkProto { + EthernetProtocol, + CookedEthernetProtocol(EtherType) } pub enum NetworkProto { @@ -932,11 +985,15 @@ pub enum TransportProto { // These values should be used in the Ethernet EtherType field // // A handful of these have been selected since most are archaic and unused. -pub static Ipv4EtherType: u16 = 0x0800; -pub static ArpEtherType: u16 = 0x0806; -pub static WakeOnLanEtherType: u16 = 0x0842; -pub static RarpEtherType: u16 = 0x8035; -pub static Ipv6EtherType: u16 = 0x86DD; +pub mod EtherType { + pub static Ipv4: u16 = 0x0800; + pub static Arp: u16 = 0x0806; + pub static WakeOnLan: u16 = 0x0842; + pub static Rarp: u16 = 0x8035; + pub static Ipv6: u16 = 0x86DD; +} + +pub type EtherType = u16; // Protocol numbers as defined at: // http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml @@ -1120,9 +1177,9 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(&get_proto(ip)) { + match RawSocket::new(get_proto(ip)) { Ok(mut sock) => match sock.recvfrom(buf) { - Ok((len, Some(IpAddress(addr)))) => { + Ok((len, Some(~IpAddress(addr)))) => { assert_eq!(buf.slice(headerLen, message.len()), message.as_bytes()); assert_eq!(len, message.len()); assert_eq!(addr, ip); @@ -1133,8 +1190,8 @@ pub mod test { } }); - match RawSocket::new(&get_proto(ip)) { - Ok(mut sock) => match sock.sendto(message.as_bytes(), Some(IpAddress(ip))) { + match RawSocket::new(get_proto(ip)) { + Ok(mut sock) => match sock.sendto(message.as_bytes(), Some(~IpAddress(ip))) { Ok(res) => assert_eq!(res as uint, message.len()), Err(_) => fail!() }, @@ -1254,9 +1311,9 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(&NetworkProtocol(Ipv4NetworkProtocol)) { + match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { Ok(mut sock) => match sock.recvfrom(buf) { - Ok((len, Some(IpAddress(addr)))) => { + Ok((len, Some(~IpAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert_eq!(len, packet.len()); assert_eq!(addr, sendAddr); @@ -1267,8 +1324,8 @@ pub mod test { } }); - match RawSocket::new(&NetworkProtocol(Ipv4NetworkProtocol)) { - Ok(mut sock) => match sock.sendto(packet, Some(IpAddress(sendAddr))) { + match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { + Ok(mut sock) => match sock.sendto(packet, Some(~IpAddress(sendAddr))) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() }, @@ -1284,9 +1341,9 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(&NetworkProtocol(Ipv6NetworkProtocol)) { + match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { Ok(mut sock) => match sock.recvfrom(buf) { - Ok((len, Some(IpAddress(addr)))) => { + Ok((len, Some(~IpAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert_eq!(len, packet.len()); assert_eq!(addr, sendAddr); @@ -1297,8 +1354,8 @@ pub mod test { } }); - match RawSocket::new(&NetworkProtocol(Ipv6NetworkProtocol)) { - Ok(mut sock) => match sock.sendto(packet, Some(IpAddress(sendAddr))) { + match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { + Ok(mut sock) => match sock.sendto(packet, Some(~IpAddress(sendAddr))) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() }, @@ -1316,19 +1373,22 @@ pub mod test { build_udp4_packet(packet.as_mut_slice(), 0); + let (port, chan) = Chan::new(); + let (port2, chan2) = Chan::new(); + spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(&DataLinkProtocol(CookedEthernetProtocol(&interface))) { + match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherType::Ipv4))) { Ok(mut sock) => { + chan.send(()); loop { match sock.recvfrom(buf) { - Ok((len, Some(MacAddress(addr)))) => { + Ok((len, Some(~NetworkAddress(ni)))) => { println!("packet: {:?}", packet.as_slice()); println!("buf: {:?}", buf.slice(0, packet.len())); if len == packet.len() && same_ports(packet.as_slice(), buf) { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); - //assert_eq!(len, packet.len()); - assert_eq!(addr, interface.mac_address()); + assert_eq!(*ni, interface); break; } }, @@ -1338,15 +1398,20 @@ pub mod test { }, Err(_) => fail!() } + port2.recv(); }); - match RawSocket::new(&DataLinkProtocol(CookedEthernetProtocol(&interface2))) { - Ok(mut sock) => match sock.sendto(packet, Some(MacAddress(macAddr))) { - Ok(res) => assert_eq!(res as uint, packet.len()), - Err(_) => fail!() + match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherType::Ipv4))) { + Ok(mut sock) => { + port.recv(); + match sock.sendto(packet, Some(~NetworkAddress(~interface2))) { + Ok(res) => assert_eq!(res as uint, packet.len()), + Err(_) => fail!() + } }, Err(_) => fail!() } + chan2.send(()); } #[cfg(hasroot)]) iotest!(fn layer2_test() { @@ -1359,19 +1424,21 @@ pub mod test { let mut ethernetHeader = MutableEthernetHeader::new(packet.as_mut_slice(), 0); ethernetHeader.set_source(interface.mac_address()); ethernetHeader.set_destination(interface.mac_address()); - ethernetHeader.set_ethertype(Ipv4EtherType); + ethernetHeader.set_ethertype(EtherType::Ipv4); } build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(&DataLinkProtocol(EthernetProtocol(&interface))) { + match RawSocket::new(DataLinkProtocol(EthernetProtocol)) { Ok(mut sock) => match sock.recvfrom(buf) { - Ok((len, Some(MacAddress(addr)))) => { + //Ok((len, Some(MacAddress(addr)))) => { + //Ok((len, Some(..))) => { + Ok((len, Some(~NetworkAddress(ni)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert_eq!(len, packet.len()); - assert_eq!(addr, interface.mac_address()); + assert_eq!(*ni, interface); }, _ => fail!() }, @@ -1379,7 +1446,7 @@ pub mod test { } }); - match RawSocket::new(&DataLinkProtocol(EthernetProtocol(&interface2))) { + match RawSocket::new(DataLinkProtocol(EthernetProtocol)) { Ok(mut sock) => match sock.sendto(packet, None) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs index d7dc41268241c..06f3231fcc6fb 100644 --- a/src/libstd/io/test.rs +++ b/src/libstd/io/test.rs @@ -46,7 +46,7 @@ macro_rules! iotest ( fn f() $b - $($a)* #[test] fn green() { f() } + /*$($a)* #[test] fn green() { f() }*/ // FIXME $($a)* #[test] fn native() { use native; let (p, c) = Chan::new(); diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 6883b557e5f71..aac2719e48485 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -111,6 +111,7 @@ pub use libc::funcs::posix01::stat_::*; pub use libc::funcs::posix01::unistd::*; pub use libc::funcs::posix01::glob::*; pub use libc::funcs::posix01::mman::*; +pub use libc::funcs::posix01::net::*; pub use libc::funcs::posix08::unistd::*; pub use libc::funcs::bsd43::*; @@ -3931,6 +3932,15 @@ pub mod funcs { -> c_int; } } + + #[nolink] + pub mod net { + use libc::types::os::arch::c95::{c_char, c_uint}; + + extern { + pub fn if_nametoindex(ifname: *c_char) -> c_uint; + } + } } #[cfg(target_os = "win32")] @@ -4073,6 +4083,7 @@ pub mod funcs { extern { pub fn getdtablesize() -> c_int; + pub fn ioctl(d: c_int, request: c_int, ...) -> c_int; pub fn madvise(addr: *c_void, len: size_t, advice: c_int) -> c_int; pub fn mincore(addr: *c_void, len: size_t, vec: *c_uchar) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index bf752486a1f07..f1d0c385d8b0d 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -152,7 +152,7 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; - fn raw_socket_new(&mut self, protocol: &Protocol) -> Result<~RtioRawSocket, IoError>; + fn raw_socket_new(&mut self, protocol: Protocol) -> Result<~RtioRawSocket, IoError>; // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; @@ -234,8 +234,8 @@ pub trait RtioUdpSocket : RtioSocket { } pub trait RtioRawSocket { - fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, Option), IoError>; - fn sendto(&mut self, buf: &[u8], dst: Option) -> Result; + fn recvfrom<'ni>(&mut self, buf: &mut [u8]) -> Result<(uint, Option<~NetworkAddress>), IoError>; + fn sendto<'ni>(&mut self, buf: &[u8], dst: Option<~NetworkAddress>) -> Result; } pub trait RtioTimer { From c9322bddd7722a687fa78cd604a5512bd167fe74 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Mon, 10 Mar 2014 00:29:32 +0000 Subject: [PATCH 33/54] Working layer 2 socket support for Linux x86-64. --- src/libnative/io/net.rs | 4 +- src/librustuv/net.rs | 4 +- src/libstd/io/net/raw.rs | 125 ++++++++++++++++++++++++--------------- src/libstd/io/test.rs | 2 +- src/libstd/rt/rtio.rs | 4 +- 5 files changed, 85 insertions(+), 54 deletions(-) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index e36adc3f77ee2..72280cf794832 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -703,12 +703,12 @@ impl rtio::RtioRawSocket for RawSocket { //}); } - fn sendto(&mut self, buf: &[u8], dst: Option<~raw::NetworkAddress>) + fn sendto(&mut self, buf: &[u8], dst: ~raw::NetworkAddress) -> IoResult { //let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; //let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); - let (sockaddr, slen) = raw::network_addr_to_sockaddr(dst.unwrap()); + let (sockaddr, slen) = raw::network_addr_to_sockaddr(dst); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { retry( || libc::sendto(self.fd, diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index f79dede5088ec..86c8903abb975 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -923,7 +923,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } } - fn sendto(&mut self, buf: &[u8], dst: Option<~raw::NetworkAddress>) + fn sendto(&mut self, buf: &[u8], dst: ~raw::NetworkAddress) -> Result { struct Ctx<'b> { @@ -944,7 +944,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { buf: buf, result: None, socket: Some(self.socket), - addr: dst.unwrap() + addr: dst }; wait_until_woken_after(&mut cx.task, &self.uv_loop(), || { unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 6b91e5db33ac3..0849d3c7de73c 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -44,7 +44,7 @@ impl RawSocket { self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: Option<~NetworkAddress>) -> IoResult { + pub fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> IoResult { self.obj.sendto(buf, dst) } } @@ -156,16 +156,7 @@ pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~ sll_to_ni(*sll) }; - //let ni = get_network_interfaces() - // .iter() - // .next() - // .unwrap(); return Some(~NetworkAddress(ni)); - //None - // FIXME Find right interface and return that - //Some(MacAddress(MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1], - // (*sll).sll_addr[2], (*sll).sll_addr[3], - // (*sll).slluint_addr[4], (*sll).sll_addr[5]))) } else { return Some(~IpAddress(sockaddr_to_addr(cast::transmute(sa), mem::size_of::()).ip)); } @@ -340,18 +331,29 @@ impl<'p> Packet for MutableEthernetHeader<'p> { trait EthernetPacket : Packet { fn get_source(&self) -> MacAddr { - // FIXME - MacAddr(0, 0, 0, 0, 0, 0) + MacAddr( + self.packet()[self.offset() + 6], + self.packet()[self.offset() + 7], + self.packet()[self.offset() + 8], + self.packet()[self.offset() + 9], + self.packet()[self.offset() + 10], + self.packet()[self.offset() + 11] + ) } fn get_destination(&self) -> MacAddr { - // FIXME - MacAddr(0, 0, 0, 0, 0, 0) + MacAddr( + self.packet()[self.offset() + 0], + self.packet()[self.offset() + 1], + self.packet()[self.offset() + 2], + self.packet()[self.offset() + 3], + self.packet()[self.offset() + 4], + self.packet()[self.offset() + 5] + ) } fn get_ethertype(&self) -> u16 { - // FIXME - 0 + (self.packet()[self.offset() + 12] as u16 << 8) | (self.packet()[self.offset() + 13] as u16) } } @@ -369,16 +371,35 @@ impl<'p> MutableEthernetHeader<'p> { MutableEthernetHeader { packet: packet, offset: offset } } - pub fn set_source(&mut self, _mac: MacAddr) { - // FIXME + pub fn set_source(&mut self, mac: MacAddr) { + match mac { + MacAddr(a, b, c, d, e, f) => { + self.packet[self.offset + 6] = a; + self.packet[self.offset + 7] = b; + self.packet[self.offset + 8] = c; + self.packet[self.offset + 9] = d; + self.packet[self.offset + 10] = e; + self.packet[self.offset + 11] = f; + } + } } - pub fn set_destination(&mut self, _mac: MacAddr) { - // FIXME + pub fn set_destination(&mut self, mac: MacAddr) { + match mac { + MacAddr(a, b, c, d, e, f) => { + self.packet[self.offset + 0] = a; + self.packet[self.offset + 1] = b; + self.packet[self.offset + 2] = c; + self.packet[self.offset + 3] = d; + self.packet[self.offset + 4] = e; + self.packet[self.offset + 5] = f; + } + } } - pub fn set_ethertype(&mut self, _ethertype: u16) { - // FIXME + pub fn set_ethertype(&mut self, ethertype: u16) { + self.packet[self.offset + 12] = (ethertype >> 8) as u8; + self.packet[self.offset + 13] = (ethertype & 0xFF) as u8; } } @@ -1191,7 +1212,7 @@ pub mod test { }); match RawSocket::new(get_proto(ip)) { - Ok(mut sock) => match sock.sendto(message.as_bytes(), Some(~IpAddress(ip))) { + Ok(mut sock) => match sock.sendto(message.as_bytes(), ~IpAddress(ip)) { Ok(res) => assert_eq!(res as uint, message.len()), Err(_) => fail!() }, @@ -1280,10 +1301,10 @@ pub mod test { .clone() } - pub fn same_ports(packet1: &[u8], packet2: &[u8]) -> bool { + pub fn same_ports(packet1: &[u8], packet2: &[u8], offset: uint) -> bool { { - let ip1 = Ipv4Header::new(packet1, 0); - let ip2 = Ipv4Header::new(packet2, 0); + let ip1 = Ipv4Header::new(packet1, offset); + let ip2 = Ipv4Header::new(packet2, offset); // Check we have an IPv4/UDP packet if ip1.get_version() != 4 || ip2.get_version() != 4 || @@ -1293,8 +1314,8 @@ pub mod test { } } - let udp1 = UdpHeader::new(packet1, IPV4_HEADER_LEN as uint); - let udp2 = UdpHeader::new(packet2, IPV4_HEADER_LEN as uint); + let udp1 = UdpHeader::new(packet1, offset + IPV4_HEADER_LEN as uint); + let udp2 = UdpHeader::new(packet2, offset + IPV4_HEADER_LEN as uint); if udp1.get_source() == udp2.get_source() && udp1.get_destination() == udp2.get_destination() { @@ -1325,7 +1346,7 @@ pub mod test { }); match RawSocket::new(NetworkProtocol(Ipv4NetworkProtocol)) { - Ok(mut sock) => match sock.sendto(packet, Some(~IpAddress(sendAddr))) { + Ok(mut sock) => match sock.sendto(packet, ~IpAddress(sendAddr)) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() }, @@ -1355,7 +1376,7 @@ pub mod test { }); match RawSocket::new(NetworkProtocol(Ipv6NetworkProtocol)) { - Ok(mut sock) => match sock.sendto(packet, Some(~IpAddress(sendAddr))) { + Ok(mut sock) => match sock.sendto(packet, ~IpAddress(sendAddr)) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() }, @@ -1384,9 +1405,7 @@ pub mod test { loop { match sock.recvfrom(buf) { Ok((len, Some(~NetworkAddress(ni)))) => { - println!("packet: {:?}", packet.as_slice()); - println!("buf: {:?}", buf.slice(0, packet.len())); - if len == packet.len() && same_ports(packet.as_slice(), buf) { + if len == packet.len() && same_ports(packet.as_slice(), buf, 0) { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert_eq!(*ni, interface); break; @@ -1404,7 +1423,7 @@ pub mod test { match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherType::Ipv4))) { Ok(mut sock) => { port.recv(); - match sock.sendto(packet, Some(~NetworkAddress(~interface2))) { + match sock.sendto(packet, ~NetworkAddress(~interface2)) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() } @@ -1429,31 +1448,43 @@ pub mod test { build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); + let (port, chan) = Chan::new(); + let (port2, chan2) = Chan::new(); + spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; match RawSocket::new(DataLinkProtocol(EthernetProtocol)) { - Ok(mut sock) => match sock.recvfrom(buf) { - //Ok((len, Some(MacAddress(addr)))) => { - //Ok((len, Some(..))) => { - Ok((len, Some(~NetworkAddress(ni)))) => { - assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); - assert_eq!(len, packet.len()); - assert_eq!(*ni, interface); - }, - _ => fail!() + Ok(mut sock) => { + chan.send(()); + loop { + match sock.recvfrom(buf) { + Ok((len, Some(~NetworkAddress(ni)))) => { + if len == packet.len() && same_ports(packet.as_slice(), buf, ETHERNET_HEADER_LEN as uint) { + assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); + assert_eq!(*ni, interface); + break; + } + }, + _ => fail!() + } + } }, Err(_) => fail!() } + port2.recv(); }); match RawSocket::new(DataLinkProtocol(EthernetProtocol)) { - Ok(mut sock) => match sock.sendto(packet, None) { - Ok(res) => assert_eq!(res as uint, packet.len()), - Err(_) => fail!() + Ok(mut sock) => { + port.recv(); + match sock.sendto(packet, ~NetworkAddress(~interface2)) { + Ok(res) => assert_eq!(res as uint, packet.len()), + Err(_) => fail!() + } }, Err(_) => fail!() } - + chan2.send(()); } #[cfg(hasroot)]) } diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs index 06f3231fcc6fb..d7dc41268241c 100644 --- a/src/libstd/io/test.rs +++ b/src/libstd/io/test.rs @@ -46,7 +46,7 @@ macro_rules! iotest ( fn f() $b - /*$($a)* #[test] fn green() { f() }*/ // FIXME + $($a)* #[test] fn green() { f() } $($a)* #[test] fn native() { use native; let (p, c) = Chan::new(); diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index f1d0c385d8b0d..2e0a8c9a88a40 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -234,8 +234,8 @@ pub trait RtioUdpSocket : RtioSocket { } pub trait RtioRawSocket { - fn recvfrom<'ni>(&mut self, buf: &mut [u8]) -> Result<(uint, Option<~NetworkAddress>), IoError>; - fn sendto<'ni>(&mut self, buf: &[u8], dst: Option<~NetworkAddress>) -> Result; + fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, Option<~NetworkAddress>), IoError>; + fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> Result; } pub trait RtioTimer { From 3a55917676c28ff8813c961e8635d86fccd1df9a Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 12 Mar 2014 18:37:13 +0000 Subject: [PATCH 34/54] Begin work on factoring out common networking code. --- mk/crates.mk | 7 +- src/libnative/io/net.rs | 105 +++----------- src/libnetsupport/lib.rs | 274 +++++++++++++++++++++++++++++++++++ src/librustuv/addrinfo.rs | 7 +- src/librustuv/net.rs | 107 ++------------ src/libstd/io/net/raw.rs | 298 +++++--------------------------------- 6 files changed, 351 insertions(+), 447 deletions(-) create mode 100644 src/libnetsupport/lib.rs diff --git a/mk/crates.mk b/mk/crates.mk index 45b6ed1a058d0..0ffb8e1f5cc69 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -50,7 +50,7 @@ ################################################################################ TARGET_CRATES := std extra green rustuv native flate arena glob term semver \ - uuid serialize sync getopts collections num test time + uuid serialize sync getopts collections num test time netsupport HOST_CRATES := syntax rustc rustdoc fourcc CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc @@ -58,8 +58,8 @@ TOOLS := compiletest rustdoc rustc DEPS_std := native:rustrt native:compiler-rt DEPS_extra := std term sync serialize getopts collections time DEPS_green := std native:context_switch -DEPS_rustuv := std native:uv native:uv_support -DEPS_native := std +DEPS_rustuv := std native:uv native:uv_support netsupport +DEPS_native := std netsupport DEPS_syntax := std term serialize collections DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \ collections time extra @@ -79,6 +79,7 @@ DEPS_fourcc := syntax std DEPS_num := std DEPS_test := std extra collections getopts serialize term DEPS_time := std serialize +DEPS_netsupport := std TOOL_DEPS_compiletest := test green rustuv getopts TOOL_DEPS_rustdoc := rustdoc native diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 72280cf794832..74f02594e82fc 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate netsupport; +//use netsupport::netsupport::{network_addr_to_sockaddr, sockaddr_to_network_addr}; + use std::cast; use std::io::net::ip; use std::io::net::raw; @@ -27,68 +30,6 @@ use super::{IoResult, retry, keep_going}; #[cfg(windows)] pub type sock_t = libc::SOCKET; #[cfg(unix)] pub type sock_t = super::file::fd_t; -pub fn htons(u: u16) -> u16 { - mem::to_be16(u as i16) as u16 -} -pub fn ntohs(u: u16) -> u16 { - mem::from_be16(u as i16) as u16 -} - -enum InAddr { - InAddr(libc::in_addr), - In6Addr(libc::in6_addr), -} - -fn ip_to_inaddr(ip: ip::IpAddr) -> InAddr { - match ip { - ip::Ipv4Addr(a, b, c, d) => { - InAddr(libc::in_addr { - s_addr: (d as u32 << 24) | - (c as u32 << 16) | - (b as u32 << 8) | - (a as u32 << 0) - }) - } - ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { - In6Addr(libc::in6_addr { - s6_addr: [ - htons(a), - htons(b), - htons(c), - htons(d), - htons(e), - htons(f), - htons(g), - htons(h), - ] - }) - } - } -} - -fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { - unsafe { - let storage: libc::sockaddr_storage = mem::init(); - let len = match ip_to_inaddr(addr.ip) { - InAddr(inaddr) => { - let storage: *mut libc::sockaddr_in = cast::transmute(&storage); - (*storage).sin_family = libc::AF_INET as libc::sa_family_t; - (*storage).sin_port = htons(addr.port); - (*storage).sin_addr = inaddr; - mem::size_of::() - } - In6Addr(inaddr) => { - let storage: *mut libc::sockaddr_in6 = cast::transmute(&storage); - (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t; - (*storage).sin6_port = htons(addr.port); - (*storage).sin6_addr = inaddr; - mem::size_of::() - } - }; - return (storage, len); - } -} - fn socket(addr: ip::SocketAddr, ty: libc::c_int) -> IoResult { unsafe { let fam = match addr.ip { @@ -167,7 +108,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let d = (addr >> 24) as u8; Ok(ip::SocketAddr { ip: ip::Ipv4Addr(a, b, c, d), - port: ntohs(storage.sin_port), + port: netsupport::ntohs(storage.sin_port), }) } libc::AF_INET6 => { @@ -175,17 +116,17 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in6 = unsafe { cast::transmute(storage) }; - let a = ntohs(storage.sin6_addr.s6_addr[0]); - let b = ntohs(storage.sin6_addr.s6_addr[1]); - let c = ntohs(storage.sin6_addr.s6_addr[2]); - let d = ntohs(storage.sin6_addr.s6_addr[3]); - let e = ntohs(storage.sin6_addr.s6_addr[4]); - let f = ntohs(storage.sin6_addr.s6_addr[5]); - let g = ntohs(storage.sin6_addr.s6_addr[6]); - let h = ntohs(storage.sin6_addr.s6_addr[7]); + let a = netsupport::ntohs(storage.sin6_addr.s6_addr[0]); + let b = netsupport::ntohs(storage.sin6_addr.s6_addr[1]); + let c = netsupport::ntohs(storage.sin6_addr.s6_addr[2]); + let d = netsupport::ntohs(storage.sin6_addr.s6_addr[3]); + let e = netsupport::ntohs(storage.sin6_addr.s6_addr[4]); + let f = netsupport::ntohs(storage.sin6_addr.s6_addr[5]); + let g = netsupport::ntohs(storage.sin6_addr.s6_addr[6]); + let h = netsupport::ntohs(storage.sin6_addr.s6_addr[7]); Ok(ip::SocketAddr { ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), - port: ntohs(storage.sin6_port), + port: netsupport::ntohs(storage.sin6_port), }) } _ => { @@ -250,7 +191,7 @@ impl TcpStream { pub fn connect(addr: ip::SocketAddr) -> IoResult { unsafe { socket(addr, libc::SOCK_STREAM).and_then(|fd| { - let (addr, len) = addr_to_sockaddr(addr); + let (addr, len) = netsupport::addr_to_sockaddr(addr); let addrp = &addr as *libc::sockaddr_storage; let inner = Inner { fd: fd }; let ret = TcpStream { inner: UnsafeArc::new(inner) }; @@ -377,7 +318,7 @@ impl TcpListener { pub fn bind(addr: ip::SocketAddr) -> IoResult { unsafe { socket(addr, libc::SOCK_STREAM).and_then(|fd| { - let (addr, len) = addr_to_sockaddr(addr); + let (addr, len) = netsupport::addr_to_sockaddr(addr); let addrp = &addr as *libc::sockaddr_storage; let inner = Inner { fd: fd }; let ret = TcpListener { inner: UnsafeArc::new(inner) }; @@ -478,7 +419,7 @@ impl UdpSocket { pub fn bind(addr: ip::SocketAddr) -> IoResult { unsafe { socket(addr, libc::SOCK_DGRAM).and_then(|fd| { - let (addr, len) = addr_to_sockaddr(addr); + let (addr, len) = netsupport::addr_to_sockaddr(addr); let addrp = &addr as *libc::sockaddr_storage; let inner = Inner { fd: fd }; let ret = UdpSocket { inner: UnsafeArc::new(inner) }; @@ -508,8 +449,8 @@ impl UdpSocket { pub fn set_membership(&mut self, addr: ip::IpAddr, opt: libc::c_int) -> IoResult<()> { - match ip_to_inaddr(addr) { - InAddr(addr) => { + match netsupport::ip_to_inaddr(addr) { + netsupport::InAddr(addr) => { let mreq = libc::ip_mreq { imr_multiaddr: addr, // interface == INADDR_ANY @@ -517,7 +458,7 @@ impl UdpSocket { }; setsockopt(self.fd(), libc::IPPROTO_IP, opt, mreq) } - In6Addr(addr) => { + netsupport::In6Addr(addr) => { let mreq = libc::ip6_mreq { ipv6mr_multiaddr: addr, ipv6mr_interface: 0, @@ -559,7 +500,7 @@ impl rtio::RtioUdpSocket for UdpSocket { } } fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> IoResult<()> { - let (dst, len) = addr_to_sockaddr(dst); + let (dst, len) = netsupport::addr_to_sockaddr(dst); let dstp = &dst as *libc::sockaddr_storage; unsafe { let ret = retry(|| { @@ -642,7 +583,7 @@ pub struct RawSocket { fn protocol_to_libc(protocol: raw::Protocol) -> (libc::c_int, libc::c_int, libc::c_int) { - let eth_p_all: u16 = htons(0x0003); + let eth_p_all: u16 = netsupport::htons(0x0003); match protocol { raw::DataLinkProtocol(raw::EthernetProtocol) => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), @@ -695,7 +636,7 @@ impl rtio::RtioRawSocket for RawSocket { return Err(super::last_error()); } - return Ok((len as uint, raw::sockaddr_to_network_addr( + return Ok((len as uint, netsupport::sockaddr_to_network_addr( (&caddr as *libc::sockaddr_storage) as *libc::sockaddr, true) )); //return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { @@ -708,7 +649,7 @@ impl rtio::RtioRawSocket for RawSocket { { //let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; //let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); - let (sockaddr, slen) = raw::network_addr_to_sockaddr(dst); + let (sockaddr, slen) = netsupport::network_addr_to_sockaddr(dst); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { retry( || libc::sendto(self.fd, diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs new file mode 100644 index 0000000000000..7545b9957cb49 --- /dev/null +++ b/src/libnetsupport/lib.rs @@ -0,0 +1,274 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Networking support for code common to both librustuv and libnative + +#[crate_id = "netsupport#0.10-pre"]; +#[license = "MIT/ASL2"]; +#[crate_type = "rlib"]; +#[crate_type = "dylib"]; +#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://static.rust-lang.org/doc/master")]; + +use std::cast; +use std::io; +use std::io::net::ip; +use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::io::net::raw::{IpAddress, MacAddr, NetworkAddress, NetworkInterface}; +use std::iter::Iterator; +use std::libc; +use std::mem; +use std::ptr; +use std::result::Result; +use std::str::raw; +use std::vec_ng::Vec; + +pub fn htons(u: u16) -> u16 { + mem::to_be16(u as i16) as u16 +} +pub fn ntohs(u: u16) -> u16 { + mem::from_be16(u as i16) as u16 +} + +pub enum InAddr { + InAddr(libc::in_addr), + In6Addr(libc::in6_addr), +} + +pub fn ip_to_inaddr(ip: ip::IpAddr) -> InAddr { + match ip { + ip::Ipv4Addr(a, b, c, d) => { + InAddr(libc::in_addr { + s_addr: (d as u32 << 24) | + (c as u32 << 16) | + (b as u32 << 8) | + (a as u32 << 0) + }) + } + ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { + In6Addr(libc::in6_addr { + s6_addr: [ + htons(a), + htons(b), + htons(c), + htons(d), + htons(e), + htons(f), + htons(g), + htons(h), + ] + }) + } + } +} + +pub fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { + unsafe { + let storage: libc::sockaddr_storage = mem::init(); + let len = match ip_to_inaddr(addr.ip) { + InAddr(inaddr) => { + let storage: *mut libc::sockaddr_in = cast::transmute(&storage); + (*storage).sin_family = libc::AF_INET as libc::sa_family_t; + (*storage).sin_port = htons(addr.port); + (*storage).sin_addr = inaddr; + mem::size_of::() + } + In6Addr(inaddr) => { + let storage: *mut libc::sockaddr_in6 = cast::transmute(&storage); + (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t; + (*storage).sin6_port = htons(addr.port); + (*storage).sin6_addr = inaddr; + mem::size_of::() + } + }; + return (storage, len); + } +} + +pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, + len: uint) -> Result { + match storage.ss_family as libc::c_int { + libc::AF_INET => { + assert!(len as uint >= mem::size_of::()); + let storage: &libc::sockaddr_in = unsafe { + cast::transmute(storage) + }; + let addr = storage.sin_addr.s_addr as u32; + let a = (addr >> 0) as u8; + let b = (addr >> 8) as u8; + let c = (addr >> 16) as u8; + let d = (addr >> 24) as u8; + Ok(ip::SocketAddr { + ip: ip::Ipv4Addr(a, b, c, d), + port: ntohs(storage.sin_port), + }) + } + libc::AF_INET6 => { + assert!(len as uint >= mem::size_of::()); + let storage: &libc::sockaddr_in6 = unsafe { + cast::transmute(storage) + }; + let a = ntohs(storage.sin6_addr.s6_addr[0]); + let b = ntohs(storage.sin6_addr.s6_addr[1]); + let c = ntohs(storage.sin6_addr.s6_addr[2]); + let d = ntohs(storage.sin6_addr.s6_addr[3]); + let e = ntohs(storage.sin6_addr.s6_addr[4]); + let f = ntohs(storage.sin6_addr.s6_addr[5]); + let g = ntohs(storage.sin6_addr.s6_addr[6]); + let h = ntohs(storage.sin6_addr.s6_addr[7]); + Ok(ip::SocketAddr { + ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), + port: ntohs(storage.sin6_port), + }) + } + _ => { + Err(io::standard_error(io::OtherIoError)) + } + } +} + +pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~NetworkAddress> { + unsafe { + if (*sa).sa_family as libc::c_int == libc::AF_PACKET { + let sll: *libc::sockaddr_ll = cast::transmute(sa); + let ni = if useLocal { + let nis = get_network_interfaces(); + if nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).len() == 1 { + (*nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).next().unwrap()).clone() + } else { + sll_to_ni(*sll) + } + } else { + sll_to_ni(*sll) + }; + + return Some(~NetworkAddress(ni)); + } else { + return Some(~IpAddress(sockaddr_to_addr(cast::transmute(sa), + mem::size_of::() + ).unwrap().ip)); + } + } + + fn sll_to_ni(sll: libc::sockaddr_ll) -> ~NetworkInterface { + let mac = MacAddr(sll.sll_addr[0], sll.sll_addr[1], + sll.sll_addr[2], sll.sll_addr[3], + sll.sll_addr[4], sll.sll_addr[5]); + ~NetworkInterface { + name: ~"", + index: 0, + mac: Some(mac), + ipv4: None, + ipv6: None, + flags: 0 + } + } +} + +pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, uint) { + unsafe { + match na { + ~IpAddress(ip) => addr_to_sockaddr(ip::SocketAddr { ip: ip, port : 0}), + //_ => (mem::init(), 0) + ~NetworkAddress(ni) => { + let mut storage: libc::sockaddr_storage = mem::init(); + let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); + sll.sll_family = libc::AF_PACKET as libc::sa_family_t; + match ni.mac { + Some(MacAddr(a, b, c, d, e, f)) => sll.sll_addr = [a, b, c, d, e, f, 0, 0], + _ => () + } + sll.sll_halen = 6; + sll.sll_ifindex = ni.index as i32; + //sll.sll_addr = [a, b, c, d, e, f, 0, 0]; + (storage, mem::size_of::()) + } + //MacAddress(MacAddr(a, b, c, d, e, f)) => { + // let mut storage: libc::sockaddr_storage = mem::init(); + // let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); + // sll.sll_family = libc::AF_PACKET as libc::sa_family_t; + // sll.sll_addr = [a, b, c, d, e, f, 0, 0]; + // (storage, mem::size_of::()) + //} + } + } +} + +pub fn sockaddr_to_network_addrs(sa: *libc::sockaddr) + -> (Option, Option, Option) { + //(None, None, None) + match sockaddr_to_network_addr(sa, false) { + Some(~IpAddress(ip@Ipv4Addr(..))) => (None, Some(ip), None), + Some(~IpAddress(ip@Ipv6Addr(..))) => (None, None, Some(ip)), + Some(~NetworkAddress(ni)) => (ni.mac, None, None), + None => (None, None, None) + } +} + +pub fn get_network_interfaces() -> Vec<~NetworkInterface> { + let mut ifaces: Vec<~NetworkInterface> = Vec::new(); + unsafe { + let mut addrs: *libc::ifaddrs = mem::init(); + if libc::getifaddrs(&mut addrs) != 0 { + return ifaces; + } + let mut addr = addrs; + while addr != ptr::null() { + let name = raw::from_c_str((*addr).ifa_name); + let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); + let ni = ~NetworkInterface { + name: name.clone(), + index: 0, + mac: mac, + ipv4: ipv4, + ipv6: ipv6, + flags: (*addr).ifa_flags + }; + //println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); + let mut found: bool = false; + for iface in ifaces.mut_iter() { + if name == iface.name { + merge(iface, &ni); + found = true; + } + } + if !found { + ifaces.push(ni); + } + + addr = (*addr).ifa_next; + } + libc::freeifaddrs(addrs); + + for iface in ifaces.mut_iter() { + iface.index = libc::if_nametoindex(iface.name.to_c_str().unwrap()); + } + return ifaces; + } + + fn merge(old: &mut ~NetworkInterface, new: &~NetworkInterface) { + old.mac = match new.mac { + None => old.mac, + _ => new.mac + }; + old.ipv4 = match new.ipv4 { + None => old.ipv4, + _ => new.ipv4 + }; + old.ipv6 = match new.ipv6 { + None => old.ipv6, + _ => new.ipv6 + }; + old.flags = old.flags | new.flags; + } + +} + diff --git a/src/librustuv/addrinfo.rs b/src/librustuv/addrinfo.rs index 5d6af2969b8b3..cd9cbcfae484f 100644 --- a/src/librustuv/addrinfo.rs +++ b/src/librustuv/addrinfo.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate netsupport; + use ai = std::io::net::addrinfo; use std::cast; use std::libc; @@ -15,7 +17,6 @@ use std::libc::c_int; use std::ptr::null; use std::rt::task::BlockedTask; -use net; use super::{Loop, UvError, Request, wait_until_woken_after, wakeup}; use uvll; @@ -140,8 +141,8 @@ pub fn accum_addrinfo(addr: &Addrinfo) -> ~[ai::Info] { let mut addrs = ~[]; loop { - let rustaddr = net::sockaddr_to_addr(cast::transmute((*addr).ai_addr), - (*addr).ai_addrlen as uint); + let rustaddr = netsupport::sockaddr_to_addr(cast::transmute((*addr).ai_addr), + (*addr).ai_addrlen as uint).unwrap(); let mut flags = 0; each_ai_flag(|cval, aival| { diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 86c8903abb975..156c7863e49db 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate netsupport; + use std::cast; use std::io; use std::io::IoError; @@ -36,93 +38,6 @@ use uvll; //////////////////////////////////////////////////////////////////////////////// /// Generic functions related to dealing with sockaddr things //////////////////////////////////////////////////////////////////////////////// - -pub fn htons(u: u16) -> u16 { mem::to_be16(u as i16) as u16 } -pub fn ntohs(u: u16) -> u16 { mem::from_be16(u as i16) as u16 } - -pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, - len: uint) -> ip::SocketAddr { - match storage.ss_family as c_int { - libc::AF_INET => { - assert!(len as uint >= mem::size_of::()); - let storage: &libc::sockaddr_in = unsafe { - cast::transmute(storage) - }; - let addr = storage.sin_addr.s_addr as u32; - let a = (addr >> 0) as u8; - let b = (addr >> 8) as u8; - let c = (addr >> 16) as u8; - let d = (addr >> 24) as u8; - ip::SocketAddr { - ip: ip::Ipv4Addr(a, b, c, d), - port: ntohs(storage.sin_port), - } - } - libc::AF_INET6 => { - assert!(len as uint >= mem::size_of::()); - let storage: &libc::sockaddr_in6 = unsafe { - cast::transmute(storage) - }; - let a = ntohs(storage.sin6_addr.s6_addr[0]); - let b = ntohs(storage.sin6_addr.s6_addr[1]); - let c = ntohs(storage.sin6_addr.s6_addr[2]); - let d = ntohs(storage.sin6_addr.s6_addr[3]); - let e = ntohs(storage.sin6_addr.s6_addr[4]); - let f = ntohs(storage.sin6_addr.s6_addr[5]); - let g = ntohs(storage.sin6_addr.s6_addr[6]); - let h = ntohs(storage.sin6_addr.s6_addr[7]); - ip::SocketAddr { - ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), - port: ntohs(storage.sin6_port), - } - } - n => { - fail!("unknown family {}", n); - } - } -} - -fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { - unsafe { - let mut storage: libc::sockaddr_storage = mem::init(); - let len = match addr.ip { - ip::Ipv4Addr(a, b, c, d) => { - let storage: &mut libc::sockaddr_in = - cast::transmute(&mut storage); - (*storage).sin_family = libc::AF_INET as libc::sa_family_t; - (*storage).sin_port = htons(addr.port); - (*storage).sin_addr = libc::in_addr { - s_addr: (d as u32 << 24) | - (c as u32 << 16) | - (b as u32 << 8) | - (a as u32 << 0) - }; - mem::size_of::() - } - ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { - let storage: &mut libc::sockaddr_in6 = - cast::transmute(&mut storage); - storage.sin6_family = libc::AF_INET6 as libc::sa_family_t; - storage.sin6_port = htons(addr.port); - storage.sin6_addr = libc::in6_addr { - s6_addr: [ - htons(a), - htons(b), - htons(c), - htons(d), - htons(e), - htons(f), - htons(g), - htons(h), - ] - }; - mem::size_of::() - } - }; - return (storage, len); - } -} - enum SocketNameKind { TcpPeer, Tcp, @@ -145,7 +60,7 @@ fn socket_name(sk: SocketNameKind, match unsafe { getsockname(handle, sockaddr_p as *mut libc::sockaddr, &mut namelen) } { - 0 => Ok(sockaddr_to_addr(&sockaddr, namelen as uint)), + 0 => Ok(netsupport::sockaddr_to_addr(&sockaddr, namelen as uint).unwrap()), n => Err(uv_error_to_io_error(UvError(n))) } } @@ -209,7 +124,7 @@ impl TcpWatcher { struct Ctx { status: c_int, task: Option } let tcp = TcpWatcher::new(io); - let (addr, _len) = addr_to_sockaddr(address); + let (addr, _len) = netsupport::addr_to_sockaddr(address); let mut req = Request::new(uvll::UV_CONNECT); let result = unsafe { let addr_p = &addr as *libc::sockaddr_storage; @@ -342,7 +257,7 @@ impl TcpListener { outgoing: chan, incoming: port, }; - let (addr, _len) = addr_to_sockaddr(address); + let (addr, _len) = netsupport::addr_to_sockaddr(address); let res = unsafe { let addr_p = &addr as *libc::sockaddr_storage; uvll::uv_tcp_bind(l.handle, addr_p as *libc::sockaddr) @@ -467,7 +382,7 @@ impl UdpWatcher { assert_eq!(unsafe { uvll::uv_udp_init(io.uv_loop(), udp.handle) }, 0); - let (addr, _len) = addr_to_sockaddr(address); + let (addr, _len) = netsupport::addr_to_sockaddr(address); let result = unsafe { let addr_p = &addr as *libc::sockaddr_storage; uvll::uv_udp_bind(udp.handle, addr_p as *libc::sockaddr, 0u32) @@ -566,7 +481,7 @@ impl rtio::RtioUdpSocket for UdpWatcher { None } else { let len = mem::size_of::(); - Some(sockaddr_to_addr(unsafe { cast::transmute(addr) }, len)) + Some(netsupport::sockaddr_to_addr(unsafe { cast::transmute(addr) }, len).unwrap()) }; cx.result = Some((nread, addr)); wakeup(&mut cx.task); @@ -582,7 +497,7 @@ impl rtio::RtioUdpSocket for UdpWatcher { let mut req = Request::new(uvll::UV_UDP_SEND); let buf = slice_to_uv_buf(buf); - let (addr, _len) = addr_to_sockaddr(dst); + let (addr, _len) = netsupport::addr_to_sockaddr(dst); let result = unsafe { let addr_p = &addr as *libc::sockaddr_storage; uvll::uv_udp_send(req.handle, self.handle, [buf], @@ -777,7 +692,7 @@ fn last_error() -> IoError { translate_error(os::errno() as i32, true) } fn protocol_to_libc(protocol: raw::Protocol) -> (libc::c_int, libc::c_int, libc::c_int) { - let eth_p_all: u16 = htons(0x0003); + let eth_p_all: u16 = netsupport::htons(0x0003); match protocol { raw::DataLinkProtocol(raw::EthernetProtocol) => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), @@ -914,7 +829,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { return; } //let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); - let addr = raw::sockaddr_to_network_addr( + let addr = netsupport::sockaddr_to_network_addr( (&caddr as *libc::sockaddr_storage) as *libc::sockaddr, true ); cx.result = Some((len as ssize_t, addr)); @@ -979,7 +894,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { //let (addr, len) = addr_to_sockaddr( // ip::SocketAddr{ ip: cx.addr, port: 0 } // ); - let (addr, len) = raw::network_addr_to_sockaddr(cx.addr.clone()); + let (addr, len) = netsupport::network_addr_to_sockaddr(cx.addr.clone()); unsafe { libc::sendto(sock, cx.buf.as_ptr() as *c_void, diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 0849d3c7de73c..165fd81ffaac2 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -10,24 +10,18 @@ // FIXME #[allow(missing_doc)]; -#[allow(unused_imports)]; -use cast; -use c_str::ToCStr; -use std::io::net::ip; -use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; +use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; use iter::Iterator; use libc; -use mem; -use option::{Option, None, Some}; +use option::{Option}; use rt::rtio::{IoFactory, LocalIo, RtioRawSocket}; use clone::Clone; -use vec::{Vector, OwnedVector, ImmutableVector}; -use vec_ng::Vec; +use vec::{Vector, ImmutableVector}; -#[test] -use vec::{Vector, MutableVector}; +#[cfg(test)] +use vec::MutableVector; pub struct RawSocket { priv obj: ~RtioRawSocket @@ -49,247 +43,17 @@ impl RawSocket { } } -// from librustuv/net.rs -pub fn htons(u: u16) -> u16 { - mem::to_be16(u as i16) as u16 -} -pub fn ntohs(u: u16) -> u16 { - mem::from_be16(u as i16) as u16 -} -pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, - len: uint) -> ip::SocketAddr { - match storage.ss_family as libc::c_int { - libc::AF_INET => { - assert!(len as uint >= mem::size_of::()); - let storage: &libc::sockaddr_in = unsafe { - cast::transmute(storage) - }; - let addr = storage.sin_addr.s_addr as u32; - let a = (addr >> 0) as u8; - let b = (addr >> 8) as u8; - let c = (addr >> 16) as u8; - let d = (addr >> 24) as u8; - ip::SocketAddr { - ip: ip::Ipv4Addr(a, b, c, d), - port: ntohs(storage.sin_port), - } - } - libc::AF_INET6 => { - assert!(len as uint >= mem::size_of::()); - let storage: &libc::sockaddr_in6 = unsafe { - cast::transmute(storage) - }; - let a = ntohs(storage.sin6_addr.s6_addr[0]); - let b = ntohs(storage.sin6_addr.s6_addr[1]); - let c = ntohs(storage.sin6_addr.s6_addr[2]); - let d = ntohs(storage.sin6_addr.s6_addr[3]); - let e = ntohs(storage.sin6_addr.s6_addr[4]); - let f = ntohs(storage.sin6_addr.s6_addr[5]); - let g = ntohs(storage.sin6_addr.s6_addr[6]); - let h = ntohs(storage.sin6_addr.s6_addr[7]); - ip::SocketAddr { - ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), - port: ntohs(storage.sin6_port), - } - } - n => { - fail!("unknown family {}", n); - } - } -} - -fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { - unsafe { - let mut storage: libc::sockaddr_storage = mem::init(); - let len = match addr.ip { - ip::Ipv4Addr(a, b, c, d) => { - let storage: &mut libc::sockaddr_in = - cast::transmute(&mut storage); - (*storage).sin_family = libc::AF_INET as libc::sa_family_t; - (*storage).sin_port = htons(addr.port); - (*storage).sin_addr = libc::in_addr { - s_addr: (d as u32 << 24) | - (c as u32 << 16) | - (b as u32 << 8) | - (a as u32 << 0) - }; - mem::size_of::() - } - ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { - let storage: &mut libc::sockaddr_in6 = - cast::transmute(&mut storage); - storage.sin6_family = libc::AF_INET6 as libc::sa_family_t; - storage.sin6_port = htons(addr.port); - storage.sin6_addr = libc::in6_addr { - s6_addr: [ - htons(a), - htons(b), - htons(c), - htons(d), - htons(e), - htons(f), - htons(g), - htons(h), - ] - }; - mem::size_of::() - } - }; - return (storage, len); - } -} - -// /copy/paste - -pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~NetworkAddress> { - unsafe { - if (*sa).sa_family as libc::c_int == libc::AF_PACKET { - let sll: *libc::sockaddr_ll = cast::transmute(sa); - let ni = if useLocal { - let nis = get_network_interfaces(); - if nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).len() == 1 { - (*nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).next().unwrap()).clone() - } else { - sll_to_ni(*sll) - } - } else { - sll_to_ni(*sll) - }; - - return Some(~NetworkAddress(ni)); - } else { - return Some(~IpAddress(sockaddr_to_addr(cast::transmute(sa), mem::size_of::()).ip)); - } - } - - fn sll_to_ni(sll: libc::sockaddr_ll) -> ~NetworkInterface { - let mac = MacAddr(sll.sll_addr[0], sll.sll_addr[1], - sll.sll_addr[2], sll.sll_addr[3], - sll.sll_addr[4], sll.sll_addr[5]); - ~NetworkInterface { - name: ~"", - index: 0, - mac: Some(mac), - ipv4: None, - ipv6: None, - flags: 0 - } - } -} - -pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, uint) { - unsafe { - match na { - ~IpAddress(ip) => addr_to_sockaddr(ip::SocketAddr { ip: ip, port : 0}), - //_ => (mem::init(), 0) - ~NetworkAddress(ni) => { - let mut storage: libc::sockaddr_storage = mem::init(); - let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); - sll.sll_family = libc::AF_PACKET as libc::sa_family_t; - match ni.mac { - Some(MacAddr(a, b, c, d, e, f)) => sll.sll_addr = [a, b, c, d, e, f, 0, 0], - _ => () - } - sll.sll_halen = 6; - sll.sll_ifindex = ni.index as i32; - //sll.sll_addr = [a, b, c, d, e, f, 0, 0]; - (storage, mem::size_of::()) - } - //MacAddress(MacAddr(a, b, c, d, e, f)) => { - // let mut storage: libc::sockaddr_storage = mem::init(); - // let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); - // sll.sll_family = libc::AF_PACKET as libc::sa_family_t; - // sll.sll_addr = [a, b, c, d, e, f, 0, 0]; - // (storage, mem::size_of::()) - //} - } - } -} - -fn sockaddr_to_network_addrs(sa: *libc::sockaddr) - -> (Option, Option, Option) { - //(None, None, None) - match sockaddr_to_network_addr(sa, false) { - Some(~IpAddress(ip@Ipv4Addr(..))) => (None, Some(ip), None), - Some(~IpAddress(ip@Ipv6Addr(..))) => (None, None, Some(ip)), - Some(~NetworkAddress(ni)) => (ni.mac, None, None), - None => (None, None, None) - } -} - -pub fn get_network_interfaces() -> Vec<~NetworkInterface> { - use ptr; - use str::raw; - - let mut ifaces: Vec<~NetworkInterface> = Vec::new(); - unsafe { - let mut addrs: *libc::ifaddrs = mem::init(); - if libc::getifaddrs(&mut addrs) != 0 { - return ifaces; - } - let mut addr = addrs; - while addr != ptr::null() { - let name = raw::from_c_str((*addr).ifa_name); - let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); - let ni = ~NetworkInterface { - name: name.clone(), - index: 0, - mac: mac, - ipv4: ipv4, - ipv6: ipv6, - flags: (*addr).ifa_flags - }; - //println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); - let mut found: bool = false; - for iface in ifaces.mut_iter() { - if name == iface.name { - merge(iface, &ni); - found = true; - } - } - if !found { - ifaces.push(ni); - } - - addr = (*addr).ifa_next; - } - libc::freeifaddrs(addrs); - - for iface in ifaces.mut_iter() { - iface.index = libc::if_nametoindex(iface.name.to_c_str().unwrap()); - } - return ifaces; - } - - fn merge(old: &mut ~NetworkInterface, new: &~NetworkInterface) { - old.mac = match new.mac { - None => old.mac, - _ => new.mac - }; - old.ipv4 = match new.ipv4 { - None => old.ipv4, - _ => new.ipv4 - }; - old.ipv6 = match new.ipv6 { - None => old.ipv6, - _ => new.ipv6 - }; - old.flags = old.flags | new.flags; - } - -} #[deriving(Clone, Eq, Show)] pub struct NetworkInterface { - priv name: ~str, - priv index: u32, - priv mac: Option, - priv ipv4: Option, - priv ipv6: Option, - priv flags: u32, + name: ~str, + index: u32, + mac: Option, + ipv4: Option, + ipv6: Option, + flags: u32, } - impl NetworkInterface { pub fn mac_address(&self) -> MacAddr { self.mac.unwrap() @@ -300,6 +64,17 @@ impl NetworkInterface { } } +#[deriving(Clone, Eq, Show)] +pub enum NetworkAddress { + IpAddress(IpAddr), + NetworkAddress(~NetworkInterface) +} + +#[deriving(Eq, Clone, Show)] +pub enum MacAddr { + MacAddr(u8, u8, u8, u8, u8, u8) +} + trait Packet { fn packet<'p>(&'p self) -> &'p [u8]; fn offset(&self) -> uint; @@ -969,17 +744,6 @@ impl<'p> MutableUdpHeader<'p> { } } -#[deriving(Clone, Eq, Show)] -pub enum NetworkAddress { - IpAddress(IpAddr), - NetworkAddress(~NetworkInterface) -} - -#[deriving(Eq, Clone, Show)] -pub enum MacAddr { - MacAddr(u8, u8, u8, u8, u8, u8) -} - pub enum Protocol { DataLinkProtocol(DataLinkProto), NetworkProtocol(NetworkProto), @@ -1176,16 +940,21 @@ pub type IpNextHeaderProtocol = u8; #[cfg(test)] pub mod test { + extern crate netsupport; + extern crate std; + use result::{Ok, Err}; use iter::Iterator; use container::Container; use option::{Some}; use str::StrSlice; - use super::*; - use super::{Ipv4Packet,UdpPacket}; + use io::net::raw::*; + use io::net::raw::{Ipv4Packet,UdpPacket}; use task::spawn; use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; + use vec::Items; use vec::ImmutableVector; + use vec_ng::Vec; pub static ETHERNET_HEADER_LEN: u16 = 14; pub static IPV4_HEADER_LEN: u16 = 20; @@ -1292,13 +1061,16 @@ pub mod test { pub fn get_test_interface() -> NetworkInterface { use clone::Clone; + use iter::Iterator; + use vec::{Items, MoveItems, Vector, OwnedVector}; - (**get_network_interfaces() - .iter() + (**netsupport::get_network_interfaces() + .as_slice().iter() + //.move_iter() .filter(|x| x.is_loopback()) .next() .unwrap()) - .clone() + //.clone() } pub fn same_ports(packet1: &[u8], packet2: &[u8], offset: uint) -> bool { From 9a11446908a85bd97b055f16845bf4af82755b53 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 14 Mar 2014 20:36:19 +0000 Subject: [PATCH 35/54] Got it working again, horrah! --- src/libstd/io/net/raw.rs | 152 ++++++++++++++++++++++++++------------- src/libstd/lib.rs | 9 +++ 2 files changed, 110 insertions(+), 51 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 165fd81ffaac2..892d715af0a29 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -75,7 +75,7 @@ pub enum MacAddr { MacAddr(u8, u8, u8, u8, u8, u8) } -trait Packet { +pub trait Packet { fn packet<'p>(&'p self) -> &'p [u8]; fn offset(&self) -> uint; } @@ -104,7 +104,7 @@ impl<'p> Packet for MutableEthernetHeader<'p> { fn offset(&self) -> uint { self.offset } } -trait EthernetPacket : Packet { +pub trait EthernetPacket : Packet { fn get_source(&self) -> MacAddr { MacAddr( self.packet()[self.offset() + 6], @@ -202,7 +202,7 @@ impl<'p> Packet for MutableIpv4Header<'p> { fn offset(&self) -> uint { self.offset } } -trait Ipv4Packet : Packet { +pub trait Ipv4Packet : Packet { fn get_version(&self) -> u8 { self.packet()[self.offset()] >> 4 } @@ -400,8 +400,8 @@ fn ipv4_header_test() { ipHeader.set_ttl(64); assert_eq!(ipHeader.get_ttl(), 64); - ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); - assert_eq!(ipHeader.get_next_level_protocol(), IpNextHeaderProtocol::Udp); + ipHeader.set_next_level_protocol(IpNextHeaderProtocols::Udp); + assert_eq!(ipHeader.get_next_level_protocol(), IpNextHeaderProtocols::Udp); ipHeader.set_source(Ipv4Addr(192, 168, 0, 1)); assert_eq!(ipHeader.get_source(), Ipv4Addr(192, 168, 0, 1)); @@ -450,7 +450,7 @@ impl<'p> Packet for MutableIpv6Header<'p> { fn offset(&self) -> uint { self.offset } } -trait Ipv6Packet : Packet { +pub trait Ipv6Packet : Packet { fn get_version(&self) -> u8 { self.packet()[self.offset()] >> 4 } @@ -619,8 +619,8 @@ fn ipv6_header_test() { ipHeader.set_payload_length(0x0101); assert_eq!(ipHeader.get_payload_length(), 0x0101); - ipHeader.set_next_header(IpNextHeaderProtocol::Udp); - assert_eq!(ipHeader.get_next_header(), IpNextHeaderProtocol::Udp); + ipHeader.set_next_header(IpNextHeaderProtocols::Udp); + assert_eq!(ipHeader.get_next_header(), IpNextHeaderProtocols::Udp); ipHeader.set_hop_limit(1); assert_eq!(ipHeader.get_hop_limit(), 1) @@ -682,7 +682,7 @@ impl<'p> Packet for MutableUdpHeader<'p> { fn offset(&self) -> uint { self.offset } } -trait UdpPacket : Packet { +pub trait UdpPacket : Packet { fn get_source(&self) -> u16 { let s1 = self.packet()[self.offset() + 0] as u16 << 8; let s2 = self.packet()[self.offset() + 1] as u16; @@ -770,7 +770,7 @@ pub enum TransportProto { // These values should be used in the Ethernet EtherType field // // A handful of these have been selected since most are archaic and unused. -pub mod EtherType { +pub mod EtherTypes { pub static Ipv4: u16 = 0x0800; pub static Arp: u16 = 0x0806; pub static WakeOnLan: u16 = 0x0842; @@ -785,7 +785,7 @@ pub type EtherType = u16; // Above protocol numbers last updated: 2014-01-16 // These values should be used in either the IPv4 Next Level Protocol field // or the IPv6 Next Header field. -pub mod IpNextHeaderProtocol { +pub mod IpNextHeaderProtocols { pub static Hopopt: u8 = 0; // IPv6 Hop-by-Hop Option [RFC2460] pub static Icmp: u8 = 1; // Internet Control Message [RFC792] pub static Igmp: u8 = 2; // Internet Group Management [RFC1112] @@ -940,21 +940,71 @@ pub type IpNextHeaderProtocol = u8; #[cfg(test)] pub mod test { - extern crate netsupport; - extern crate std; - - use result::{Ok, Err}; - use iter::Iterator; - use container::Container; - use option::{Some}; - use str::StrSlice; - use io::net::raw::*; - use io::net::raw::{Ipv4Packet,UdpPacket}; - use task::spawn; - use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; - use vec::Items; - use vec::ImmutableVector; - use vec_ng::Vec; +// extern crate netsupport; + + use realstd::clone::Clone; + use realstd::fmt::Show; + use realstd::result::{Ok, Err}; + use realstd::iter::Iterator; + use realstd::container::Container; + use realstd::option::{Some}; + use realstd::str::StrSlice; + use realstd::io::net::raw::*; + use realstd::io::net::raw::{Ipv4Packet, UdpPacket, EtherTypes, IpNextHeaderProtocols}; + use realstd::task::spawn; + use realstd::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; + use realstd::io::net::ip; + use realstd::vec::Items; + use realstd::vec::ImmutableVector; + use realstd::vec_ng::Vec; + use realstd::cast; + use realstd::iter::Iterator; + use realstd::vec::{Items, MoveItems, Vector, OwnedVector}; + + //use io::net::raw::IpNextHeaderProtocol; + //use io::net::raw::EtherType; + //use io::net::ip; + //use fmt::Show; + use netsupport; + +macro_rules! iotest ( + { fn $name:ident() $b:block $($a:attr)* } => ( + mod $name { + #[allow(unused_imports)]; + + use realstd::io; + use realstd::prelude::*; + use realstd::io::*; + use realstd::io::fs::*; + use realstd::io::test::*; + use realstd::io::net::tcp::*; + use realstd::io::net::ip::*; + use realstd::io::net::udp::*; + use realstd::io::net::raw::*; + use std::io::net::raw::test::*; + use std::io::net::raw::EtherTypes; + #[cfg(unix)] + use realstd::io::net::unix::*; + use realstd::io::timer::*; + use realstd::io::process::*; + use realstd::unstable::running_on_valgrind; + use realstd::str; + use realstd::util; + + fn f() $b + + $($a)* #[test] fn green() { f() } + $($a)* #[test] fn native() { + use native; + let (p, c) = Chan::new(); + native::task::spawn(proc() { c.send(f()) }); + p.recv(); + } + } + ) +) + + pub static ETHERNET_HEADER_LEN: u16 = 14; pub static IPV4_HEADER_LEN: u16 = 20; @@ -972,7 +1022,7 @@ pub mod test { Ok((len, Some(~IpAddress(addr)))) => { assert_eq!(buf.slice(headerLen, message.len()), message.as_bytes()); assert_eq!(len, message.len()); - assert_eq!(addr, ip); + assert!(addr == ip, "addr != ip"); }, _ => fail!() }, @@ -990,8 +1040,8 @@ pub mod test { fn get_proto(ip: IpAddr) -> Protocol { match ip { - Ipv4Addr(..) => TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocol::Test1)), - Ipv6Addr(..) => TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocol::Test1)) + Ipv4Addr(..) => TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocols::Test1)), + Ipv6Addr(..) => TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocols::Test1)) } } } @@ -1011,7 +1061,7 @@ pub mod test { ipHeader.set_header_length(5); ipHeader.set_total_length(IPV4_HEADER_LEN + UDP_HEADER_LEN + TEST_DATA_LEN); ipHeader.set_ttl(4); - ipHeader.set_next_level_protocol(IpNextHeaderProtocol::Udp); + ipHeader.set_next_level_protocol(IpNextHeaderProtocols::Udp); ipHeader.set_source(Ipv4Addr(127, 0, 0, 1)); ipHeader.set_destination(Ipv4Addr(127, 0, 0, 1)); ipHeader.checksum(); @@ -1022,7 +1072,7 @@ pub mod test { ipHeader.set_version(6); ipHeader.set_payload_length(UDP_HEADER_LEN + TEST_DATA_LEN); - ipHeader.set_next_header(IpNextHeaderProtocol::Udp); + ipHeader.set_next_header(IpNextHeaderProtocols::Udp); ipHeader.set_hop_limit(4); ipHeader.set_source(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); ipHeader.set_destination(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); @@ -1060,17 +1110,16 @@ pub mod test { } pub fn get_test_interface() -> NetworkInterface { - use clone::Clone; - use iter::Iterator; - use vec::{Items, MoveItems, Vector, OwnedVector}; - (**netsupport::get_network_interfaces() - .as_slice().iter() - //.move_iter() - .filter(|x| x.is_loopback()) - .next() - .unwrap()) - //.clone() + unsafe { + (**netsupport::get_network_interfaces() + .as_slice().iter() + //.move_iter() + .filter(|x| x.is_loopback()) + .next() + .unwrap()) + .clone() + } } pub fn same_ports(packet1: &[u8], packet2: &[u8], offset: uint) -> bool { @@ -1080,8 +1129,8 @@ pub mod test { // Check we have an IPv4/UDP packet if ip1.get_version() != 4 || ip2.get_version() != 4 || - ip1.get_next_level_protocol() != IpNextHeaderProtocol::Udp || - ip2.get_next_level_protocol() != IpNextHeaderProtocol::Udp { + ip1.get_next_level_protocol() != IpNextHeaderProtocols::Udp || + ip2.get_next_level_protocol() != IpNextHeaderProtocols::Udp { return false; } } @@ -1109,7 +1158,7 @@ pub mod test { Ok((len, Some(~IpAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert_eq!(len, packet.len()); - assert_eq!(addr, sendAddr); + assert!(addr == sendAddr, "addr != sendAddr"); }, _ => fail!() }, @@ -1139,7 +1188,7 @@ pub mod test { Ok((len, Some(~IpAddress(addr)))) => { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert_eq!(len, packet.len()); - assert_eq!(addr, sendAddr); + assert!(addr == sendAddr, "addr != sendAddr"); }, _ => fail!() }, @@ -1159,7 +1208,8 @@ pub mod test { iotest!(fn layer2_cooked_test() { let interface = get_test_interface(); - let interface2 = interface.clone(); + let interface2 = get_test_interface(); + //let interface2 = interface.clone(); let macAddr = interface.mac_address(); let mut packet = [0u8, ..32]; @@ -1171,7 +1221,7 @@ pub mod test { spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; - match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherType::Ipv4))) { + match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherTypes::Ipv4))) { Ok(mut sock) => { chan.send(()); loop { @@ -1179,7 +1229,7 @@ pub mod test { Ok((len, Some(~NetworkAddress(ni)))) => { if len == packet.len() && same_ports(packet.as_slice(), buf, 0) { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); - assert_eq!(*ni, interface); + assert!(*ni == interface, "*ni != interface"); break; } }, @@ -1192,7 +1242,7 @@ pub mod test { port2.recv(); }); - match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherType::Ipv4))) { + match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherTypes::Ipv4))) { Ok(mut sock) => { port.recv(); match sock.sendto(packet, ~NetworkAddress(~interface2)) { @@ -1215,7 +1265,7 @@ pub mod test { let mut ethernetHeader = MutableEthernetHeader::new(packet.as_mut_slice(), 0); ethernetHeader.set_source(interface.mac_address()); ethernetHeader.set_destination(interface.mac_address()); - ethernetHeader.set_ethertype(EtherType::Ipv4); + ethernetHeader.set_ethertype(EtherTypes::Ipv4); } build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); @@ -1233,7 +1283,7 @@ pub mod test { Ok((len, Some(~NetworkAddress(ni)))) => { if len == packet.len() && same_ports(packet.as_slice(), buf, ETHERNET_HEADER_LEN as uint) { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); - assert_eq!(*ni, interface); + assert!(*ni == interface, "*ni != interface"); break; } }, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b4a891e0f0156..6f22ffde9fc8c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -73,6 +73,7 @@ #[cfg(test)] extern crate rustuv; #[cfg(test)] extern crate native; #[cfg(test)] extern crate green; +#[cfg(test)] extern crate netsupport; // Make extra accessible for benchmarking #[cfg(test)] extern crate extra = "extra"; @@ -213,20 +214,28 @@ pub mod rt; // can be resolved within libstd. #[doc(hidden)] mod std { + pub use cast; pub use clone; pub use cmp; pub use comm; + pub use container; pub use fmt; pub use hash; pub use io; + pub use iter; pub use kinds; pub use local_data; pub use logging; pub use num; pub use option; pub use os; + pub use prelude; + pub use result; pub use rt; pub use str; + pub use task; pub use to_str; pub use unstable; + pub use vec; + pub use vec_ng; } From 5a9fe2895b5ff4907106442f409a95b71153c5d9 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 14 Mar 2014 20:50:48 +0000 Subject: [PATCH 36/54] Some code cleanups. --- src/libstd/io/net/raw.rs | 105 ++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 892d715af0a29..8403e89994951 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -940,71 +940,58 @@ pub type IpNextHeaderProtocol = u8; #[cfg(test)] pub mod test { -// extern crate netsupport; - use realstd::clone::Clone; - use realstd::fmt::Show; use realstd::result::{Ok, Err}; - use realstd::iter::Iterator; use realstd::container::Container; use realstd::option::{Some}; use realstd::str::StrSlice; use realstd::io::net::raw::*; - use realstd::io::net::raw::{Ipv4Packet, UdpPacket, EtherTypes, IpNextHeaderProtocols}; + use realstd::io::net::raw::{Ipv4Packet, UdpPacket, IpNextHeaderProtocols}; use realstd::task::spawn; use realstd::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; - use realstd::io::net::ip; - use realstd::vec::Items; use realstd::vec::ImmutableVector; - use realstd::vec_ng::Vec; - use realstd::cast; use realstd::iter::Iterator; - use realstd::vec::{Items, MoveItems, Vector, OwnedVector}; + use realstd::vec::{Vector}; - //use io::net::raw::IpNextHeaderProtocol; - //use io::net::raw::EtherType; - //use io::net::ip; - //use fmt::Show; use netsupport; -macro_rules! iotest ( - { fn $name:ident() $b:block $($a:attr)* } => ( - mod $name { - #[allow(unused_imports)]; - - use realstd::io; - use realstd::prelude::*; - use realstd::io::*; - use realstd::io::fs::*; - use realstd::io::test::*; - use realstd::io::net::tcp::*; - use realstd::io::net::ip::*; - use realstd::io::net::udp::*; - use realstd::io::net::raw::*; - use std::io::net::raw::test::*; - use std::io::net::raw::EtherTypes; - #[cfg(unix)] - use realstd::io::net::unix::*; - use realstd::io::timer::*; - use realstd::io::process::*; - use realstd::unstable::running_on_valgrind; - use realstd::str; - use realstd::util; - - fn f() $b - - $($a)* #[test] fn green() { f() } - $($a)* #[test] fn native() { - use native; - let (p, c) = Chan::new(); - native::task::spawn(proc() { c.send(f()) }); - p.recv(); + // This needs to be redefined here otherwise imports do not work correctly + macro_rules! iotest ( + { fn $name:ident() $b:block $($a:attr)* } => ( + mod $name { + #[allow(unused_imports)]; + + use realstd::io; + use realstd::prelude::*; + use realstd::io::*; + use realstd::io::fs::*; + use realstd::io::test::*; + use realstd::io::net::tcp::*; + use realstd::io::net::ip::*; + use realstd::io::net::udp::*; + use realstd::io::net::raw::*; + use std::io::net::raw::test::*; + use std::io::net::raw::EtherTypes; + #[cfg(unix)] + use realstd::io::net::unix::*; + use realstd::io::timer::*; + use realstd::io::process::*; + use realstd::unstable::running_on_valgrind; + use realstd::str; + use realstd::util; + + fn f() $b + + $($a)* #[test] fn green() { f() } + $($a)* #[test] fn native() { + use native; + let (p, c) = Chan::new(); + native::task::spawn(proc() { c.send(f()) }); + p.recv(); + } } - } + ) ) -) - - pub static ETHERNET_HEADER_LEN: u16 = 14; pub static IPV4_HEADER_LEN: u16 = 20; @@ -1110,16 +1097,12 @@ macro_rules! iotest ( } pub fn get_test_interface() -> NetworkInterface { - - unsafe { - (**netsupport::get_network_interfaces() - .as_slice().iter() - //.move_iter() - .filter(|x| x.is_loopback()) - .next() - .unwrap()) - .clone() - } + (**netsupport::get_network_interfaces() + .as_slice().iter() + .filter(|x| x.is_loopback()) + .next() + .unwrap()) + .clone() } pub fn same_ports(packet1: &[u8], packet2: &[u8], offset: uint) -> bool { @@ -1209,8 +1192,6 @@ macro_rules! iotest ( iotest!(fn layer2_cooked_test() { let interface = get_test_interface(); let interface2 = get_test_interface(); - //let interface2 = interface.clone(); - let macAddr = interface.mac_address(); let mut packet = [0u8, ..32]; From 325a93c5a8374121c055b0cd92d84dacc8f591b1 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 14 Mar 2014 23:10:13 +0000 Subject: [PATCH 37/54] Move libc error handling to netsupport. --- src/libnative/io/file_unix.rs | 30 +++++---- src/libnative/io/mod.rs | 76 +-------------------- src/libnative/io/net.rs | 33 ++-------- src/libnative/io/pipe_unix.rs | 20 +++--- src/libnative/io/process.rs | 12 ++-- src/libnative/io/timer_timerfd.rs | 4 +- src/libnetsupport/lib.rs | 106 ++++++++++++++++++++++++++---- src/librustuv/net.rs | 95 ++------------------------ 8 files changed, 147 insertions(+), 229 deletions(-) diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index cf9ada97a3254..93e79c35fc085 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -10,6 +10,8 @@ //! Blocking posix-based file I/O +extern crate netsupport; + use std::sync::arc::UnsafeArc; use std::c_str::CString; use std::io::IoError; @@ -62,7 +64,7 @@ impl FileDesc { if ret == 0 { Err(io::standard_error(io::EndOfFile)) } else if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(ret as uint) } @@ -75,7 +77,7 @@ impl FileDesc { } }); if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(()) } @@ -113,7 +115,7 @@ impl rtio::RtioFileStream for FileDesc { buf.len() as libc::size_t, offset as libc::off_t) as libc::c_int }) { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), n => Ok(n as int) } } @@ -131,7 +133,7 @@ impl rtio::RtioFileStream for FileDesc { }; let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) }; if n < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(n as u64) } @@ -139,7 +141,7 @@ impl rtio::RtioFileStream for FileDesc { fn tell(&self) -> Result { let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) }; if n < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(n as u64) } @@ -248,7 +250,7 @@ impl rtio::RtioFileStream for CFile { if ret == 0 { Err(io::standard_error(io::EndOfFile)) } else if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(ret as int) } @@ -262,7 +264,7 @@ impl rtio::RtioFileStream for CFile { } }); if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(()) } @@ -282,7 +284,7 @@ impl rtio::RtioFileStream for CFile { }; let n = unsafe { libc::fseek(self.file, pos as libc::c_long, whence) }; if n < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(n as u64) } @@ -290,7 +292,7 @@ impl rtio::RtioFileStream for CFile { fn tell(&self) -> Result { let ret = unsafe { libc::ftell(self.file) }; if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(ret as u64) } @@ -329,7 +331,7 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) }; match retry(|| unsafe { libc::open(path.with_ref(|p| p), flags, mode) }) { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), fd => Ok(FileDesc::new(fd, true)), } } @@ -380,7 +382,7 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> { assert_eq!(unsafe { closedir(dir_ptr) }, 0); Ok(prune(p, paths)) } else { - Err(super::last_error()) + Err(netsupport::last_error()) } } @@ -424,7 +426,7 @@ pub fn readlink(p: &CString) -> IoResult { libc::readlink(p, buf.as_ptr() as *mut libc::c_char, len as libc::size_t) as libc::c_int }) { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), n => { assert!(n > 0); unsafe { buf.set_len(n as uint); } @@ -497,7 +499,7 @@ pub fn stat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::uninit() }; match retry(|| unsafe { libc::stat(p.with_ref(|p| p), &mut stat) }) { 0 => Ok(mkstat(&stat, p)), - _ => Err(super::last_error()), + _ => Err(netsupport::last_error()), } } @@ -505,7 +507,7 @@ pub fn lstat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::uninit() }; match retry(|| unsafe { libc::lstat(p.with_ref(|p| p), &mut stat) }) { 0 => Ok(mkstat(&stat, p)), - _ => Err(super::last_error()), + _ => Err(netsupport::last_error()), } } diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 046c13ba5c2ac..857be32fee141 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -21,6 +21,8 @@ //! play. The only dependencies of these modules are the normal system libraries //! that you would find on the respective platform. +extern crate netsupport; + use std::c_str::CString; use std::io; use std::io::IoError; @@ -89,82 +91,10 @@ fn unimpl() -> IoError { } } -fn translate_error(errno: i32, detail: bool) -> IoError { - #[cfg(windows)] - fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { - match errno { - libc::EOF => (io::EndOfFile, "end of file"), - libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"), - libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"), - libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"), - libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"), - libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"), - libc::WSAEACCES => (io::PermissionDenied, "permission denied"), - libc::WSAEWOULDBLOCK => - (io::ResourceUnavailable, "resource temporarily unavailable"), - libc::WSAENOTCONN => (io::NotConnected, "not connected"), - libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"), - libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), - libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"), - libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"), - - // libuv maps this error code to EISDIR. we do too. if it is found - // to be incorrect, we can add in some more machinery to only - // return this message when ERROR_INVALID_FUNCTION after certain - // win32 calls. - libc::ERROR_INVALID_FUNCTION => (io::InvalidInput, - "illegal operation on a directory"), - - x => { - debug!("ignoring {}: {}", x, os::last_os_error()); - (io::OtherIoError, "unknown error") - } - } - } - - #[cfg(not(windows))] - fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { - // FIXME: this should probably be a bit more descriptive... - match errno { - libc::EOF => (io::EndOfFile, "end of file"), - libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"), - libc::ECONNRESET => (io::ConnectionReset, "connection reset"), - libc::EPERM | libc::EACCES => - (io::PermissionDenied, "permission denied"), - libc::EPIPE => (io::BrokenPipe, "broken pipe"), - libc::ENOTCONN => (io::NotConnected, "not connected"), - libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"), - libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), - libc::EADDRINUSE => (io::ConnectionRefused, "address in use"), - libc::ENOENT => (io::FileNotFound, "no such file or directory"), - libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"), - - // These two constants can have the same value on some systems, but - // different values on others, so we can't use a match clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - (io::ResourceUnavailable, "resource temporarily unavailable"), - - x => { - debug!("ignoring {}: {}", x, os::last_os_error()); - (io::OtherIoError, "unknown error") - } - } - } - - let (kind, desc) = get_err(errno); - IoError { - kind: kind, - desc: desc, - detail: if detail {Some(os::last_os_error())} else {None}, - } -} - -fn last_error() -> IoError { translate_error(os::errno() as i32, true) } - // unix has nonzero values as errors fn mkerr_libc(ret: libc::c_int) -> IoResult<()> { if ret != 0 { - Err(last_error()) + Err(netsupport::last_error()) } else { Ok(()) } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 74f02594e82fc..40a90eb2c1289 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -9,7 +9,6 @@ // except according to those terms. extern crate netsupport; -//use netsupport::netsupport::{network_addr_to_sockaddr, sockaddr_to_network_addr}; use std::cast; use std::io::net::ip; @@ -37,7 +36,7 @@ fn socket(addr: ip::SocketAddr, ty: libc::c_int) -> IoResult { ip::Ipv6Addr(..) => libc::AF_INET6, }; match libc::socket(fam, ty, 0) { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), fd => Ok(fd), } } @@ -68,7 +67,7 @@ fn last_error() -> io::IoError { #[cfg(not(windows))] fn last_error() -> io::IoError { - super::last_error() + netsupport::last_error() } #[cfg(windows)] unsafe fn close(sock: sock_t) { let _ = libc::closesocket(sock); } @@ -270,7 +269,7 @@ impl rtio::RtioTcpStream for TcpStream { 0) as i64 }); if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(()) } @@ -581,32 +580,14 @@ pub struct RawSocket { priv fd: sock_t, } -fn protocol_to_libc(protocol: raw::Protocol) - -> (libc::c_int, libc::c_int, libc::c_int) { - let eth_p_all: u16 = netsupport::htons(0x0003); - match protocol { - raw::DataLinkProtocol(raw::EthernetProtocol) - => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), - raw::DataLinkProtocol(raw::CookedEthernetProtocol(proto)) - => (libc::AF_PACKET, libc::SOCK_DGRAM, proto as libc::c_int), - raw::NetworkProtocol(raw::Ipv4NetworkProtocol) - => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW), - raw::NetworkProtocol(raw::Ipv6NetworkProtocol) - => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW), - raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) - => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int), - raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) - => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int) - } -} impl RawSocket { pub fn new(protocol: raw::Protocol) -> IoResult { - let (domain, typ, proto) = protocol_to_libc(protocol); + let (domain, typ, proto) = netsupport::protocol_to_libc(protocol); let sock = unsafe { libc::socket(domain, typ, proto) }; if sock == -1 { - return Err(super::last_error()); + return Err(netsupport::last_error()); } let socket = RawSocket { fd: sock }; @@ -633,7 +614,7 @@ impl rtio::RtioRawSocket for RawSocket { &mut caddrlen)) }; if len == -1 { - return Err(super::last_error()); + return Err(netsupport::last_error()); } return Ok((len as uint, netsupport::sockaddr_to_network_addr( @@ -661,7 +642,7 @@ impl rtio::RtioRawSocket for RawSocket { }; return if len < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(len as int) }; diff --git a/src/libnative/io/pipe_unix.rs b/src/libnative/io/pipe_unix.rs index 9e81dc02cc596..554c760a9b34d 100644 --- a/src/libnative/io/pipe_unix.rs +++ b/src/libnative/io/pipe_unix.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate netsupport; + use std::c_str::CString; use std::cast; use std::io; @@ -22,7 +24,7 @@ use super::file::fd_t; fn unix_socket(ty: libc::c_int) -> IoResult { match unsafe { libc::socket(libc::AF_UNIX, ty, 0) } { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), fd => Ok(fd) } } @@ -84,7 +86,7 @@ fn connect(addr: &CString, ty: libc::c_int) -> IoResult { libc::connect(inner.fd, addrp as *libc::sockaddr, len as libc::socklen_t) }) { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), _ => Ok(inner) } } @@ -96,7 +98,7 @@ fn bind(addr: &CString, ty: libc::c_int) -> IoResult { match unsafe { libc::bind(inner.fd, addrp as *libc::sockaddr, len as libc::socklen_t) } { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), _ => Ok(inner) } } @@ -130,7 +132,7 @@ impl rtio::RtioPipe for UnixStream { if ret == 0 { Err(io::standard_error(io::EndOfFile)) } else if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(ret as uint) } @@ -144,7 +146,7 @@ impl rtio::RtioPipe for UnixStream { 0) as i64 }); if ret < 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(()) } @@ -191,7 +193,7 @@ impl UnixDatagram { storagep as *mut libc::sockaddr, &mut addrlen) as libc::c_int }); - if ret < 0 { return Err(super::last_error()) } + if ret < 0 { return Err(netsupport::last_error()) } sockaddr_to_unix(&storage, addrlen as uint).and_then(|addr| { Ok((ret as uint, addr)) }) @@ -209,7 +211,7 @@ impl UnixDatagram { len as libc::socklen_t) as libc::c_int }); match ret { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), n if n as uint != buf.len() => { Err(io::IoError { kind: io::OtherIoError, @@ -243,7 +245,7 @@ impl UnixListener { pub fn native_listen(self, backlog: int) -> IoResult { match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), _ => Ok(UnixAcceptor { listener: self }) } } @@ -272,7 +274,7 @@ impl UnixAcceptor { storagep as *mut libc::sockaddr, &mut size as *mut libc::socklen_t) as libc::c_int }) { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), fd => Ok(UnixStream { inner: UnsafeArc::new(Inner { fd: fd }) }) } } diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 6ac1f2b369244..8c8b4988f92af 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate netsupport; + use std::io; use std::libc::{pid_t, c_void, c_int}; use std::libc; @@ -161,7 +163,7 @@ unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> { libc::PROCESS_QUERY_INFORMATION, libc::FALSE, pid as libc::DWORD); if handle.is_null() { - return Err(super::last_error()) + return Err(netsupport::last_error()) } let ret = match signal { // test for existence on signal 0 @@ -169,7 +171,7 @@ unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> { let mut status = 0; let ret = libc::GetExitCodeProcess(handle, &mut status); if ret == 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else if status != libc::STILL_ACTIVE { Err(io::IoError { kind: io::OtherIoError, @@ -289,7 +291,7 @@ fn spawn_process_os(config: p::ProcessConfig, flags, envp, dirp, &mut si, &mut pi); if created == FALSE { - create_err = Some(super::last_error()); + create_err = Some(netsupport::last_error()); } }) }) @@ -465,7 +467,7 @@ fn spawn_process_os(config: p::ProcessConfig, (bytes[1] << 16) as i32 | (bytes[2] << 8) as i32 | (bytes[3] << 0) as i32; - Err(super::translate_error(errno, false)) + Err(netsupport::translate_error(errno, false)) } Err(e) => { assert!(e.kind == io::BrokenPipe || @@ -744,7 +746,7 @@ fn waitpid(pid: pid_t) -> p::ProcessExit { let mut status = 0 as c_int; match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) { - -1 => fail!("unknown waitpid error: {}", super::last_error()), + -1 => fail!("unknown waitpid error: {}", netsupport::last_error()), _ => { if imp::WIFEXITED(status) { p::ExitStatus(imp::WEXITSTATUS(status) as int) diff --git a/src/libnative/io/timer_timerfd.rs b/src/libnative/io/timer_timerfd.rs index 55301b6f7c8d6..f4b685ab9732a 100644 --- a/src/libnative/io/timer_timerfd.rs +++ b/src/libnative/io/timer_timerfd.rs @@ -28,6 +28,8 @@ //! //! As with timer_other, all units in this file are in units of millseconds. +extern crate netsupport; + use std::comm::Data; use std::libc; use std::ptr; @@ -177,7 +179,7 @@ impl Timer { pub fn new() -> IoResult { timer_helper::boot(helper); match unsafe { imp::timerfd_create(imp::CLOCK_MONOTONIC, 0) } { - -1 => Err(super::last_error()), + -1 => Err(netsupport::last_error()), n => Ok(Timer { fd: FileDesc::new(n, true), on_worker: false, }), } } diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs index 7545b9957cb49..fb25621de8e84 100644 --- a/src/libnetsupport/lib.rs +++ b/src/libnetsupport/lib.rs @@ -23,12 +23,14 @@ use std::io; use std::io::net::ip; use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::io::net::raw::{IpAddress, MacAddr, NetworkAddress, NetworkInterface}; +use std::io::net::raw; use std::iter::Iterator; use std::libc; use std::mem; +use std::os; use std::ptr; use std::result::Result; -use std::str::raw; +use strraw = std::str::raw; use std::vec_ng::Vec; pub fn htons(u: u16) -> u16 { @@ -188,23 +190,14 @@ pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, } sll.sll_halen = 6; sll.sll_ifindex = ni.index as i32; - //sll.sll_addr = [a, b, c, d, e, f, 0, 0]; (storage, mem::size_of::()) } - //MacAddress(MacAddr(a, b, c, d, e, f)) => { - // let mut storage: libc::sockaddr_storage = mem::init(); - // let sll: &mut libc::sockaddr_ll = cast::transmute(&mut storage); - // sll.sll_family = libc::AF_PACKET as libc::sa_family_t; - // sll.sll_addr = [a, b, c, d, e, f, 0, 0]; - // (storage, mem::size_of::()) - //} } } } pub fn sockaddr_to_network_addrs(sa: *libc::sockaddr) -> (Option, Option, Option) { - //(None, None, None) match sockaddr_to_network_addr(sa, false) { Some(~IpAddress(ip@Ipv4Addr(..))) => (None, Some(ip), None), Some(~IpAddress(ip@Ipv6Addr(..))) => (None, None, Some(ip)), @@ -222,7 +215,7 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { } let mut addr = addrs; while addr != ptr::null() { - let name = raw::from_c_str((*addr).ifa_name); + let name = strraw::from_c_str((*addr).ifa_name); let (mac, ipv4, ipv6) = sockaddr_to_network_addrs((*addr).ifa_addr); let ni = ~NetworkInterface { name: name.clone(), @@ -232,7 +225,6 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { ipv6: ipv6, flags: (*addr).ifa_flags }; - //println!("name: {:?}; mac: {:?}; ipv4: {:?}; ipv6: {:?};", name, mac, ipv4, ipv6); let mut found: bool = false; for iface in ifaces.mut_iter() { if name == iface.name { @@ -272,3 +264,93 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { } +pub fn protocol_to_libc(protocol: raw::Protocol) + -> (libc::c_int, libc::c_int, libc::c_int) { + let eth_p_all: u16 = htons(0x0003); + match protocol { + raw::DataLinkProtocol(raw::EthernetProtocol) + => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), + raw::DataLinkProtocol(raw::CookedEthernetProtocol(proto)) + => (libc::AF_PACKET, libc::SOCK_DGRAM, proto as libc::c_int), + raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int), + raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int) + } +} + +pub fn translate_error(errno: i32, detail: bool) -> io::IoError { + #[cfg(windows)] + fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { + match errno { + libc::EOF => (io::EndOfFile, "end of file"), + libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"), + libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"), + libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"), + libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"), + libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"), + libc::WSAEACCES => (io::PermissionDenied, "permission denied"), + libc::WSAEWOULDBLOCK => + (io::ResourceUnavailable, "resource temporarily unavailable"), + libc::WSAENOTCONN => (io::NotConnected, "not connected"), + libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"), + libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), + libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"), + libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"), + + // libuv maps this error code to EISDIR. we do too. if it is found + // to be incorrect, we can add in some more machinery to only + // return this message when ERROR_INVALID_FUNCTION after certain + // win32 calls. + libc::ERROR_INVALID_FUNCTION => (io::InvalidInput, + "illegal operation on a directory"), + + x => { + debug!("ignoring {}: {}", x, os::last_os_error()); + (io::OtherIoError, "unknown error") + } + } + } + + #[cfg(not(windows))] + fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { + // FIXME: this should probably be a bit more descriptive... + match errno { + libc::EOF => (io::EndOfFile, "end of file"), + libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"), + libc::ECONNRESET => (io::ConnectionReset, "connection reset"), + libc::EPERM | libc::EACCES => + (io::PermissionDenied, "permission denied"), + libc::EPIPE => (io::BrokenPipe, "broken pipe"), + libc::ENOTCONN => (io::NotConnected, "not connected"), + libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"), + libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), + libc::EADDRINUSE => (io::ConnectionRefused, "address in use"), + libc::ENOENT => (io::FileNotFound, "no such file or directory"), + libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"), + + // These two constants can have the same value on some systems, but + // different values on others, so we can't use a match clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + (io::ResourceUnavailable, "resource temporarily unavailable"), + + x => { + debug!("ignoring {}: {}", x, os::last_os_error()); + (io::OtherIoError, "unknown error") + } + } + } + + let (kind, desc) = get_err(errno); + io::IoError { + kind: kind, + desc: desc, + detail: if detail {Some(os::last_os_error())} else {None}, + } +} + +pub fn last_error() -> io::IoError { translate_error(os::errno() as i32, true) } diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 156c7863e49db..39087c09037b3 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -11,14 +11,12 @@ extern crate netsupport; use std::cast; -use std::io; use std::io::IoError; use std::io::net::ip; use std::io::net::raw; use std::libc::{size_t, ssize_t, c_int, c_void, c_uint}; use std::libc; use std::mem; -use std::os; use std::os::errno; use std::ptr; use std::rt::rtio; @@ -628,96 +626,15 @@ pub struct RawSocketWatcher { home: HomeHandle, } -// FIXME This is copied from libnative::io -// ---------------------------------------------------------------------------- -fn translate_error(errno: i32, detail: bool) -> IoError { - #[cfg(windows)] - fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { - match errno { - libc::EOF => (io::EndOfFile, "end of file"), - libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"), - libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"), - libc::WSAEACCES => (io::PermissionDenied, "permission denied"), - libc::WSAEWOULDBLOCK => - (io::ResourceUnavailable, "resource temporarily unavailable"), - libc::WSAENOTCONN => (io::NotConnected, "not connected"), - libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"), - libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), - libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"), - - x => { - debug!("ignoring {}: {}", x, os::last_os_error()); - (io::OtherIoError, "unknown error") - } - } - } - - #[cfg(not(windows))] - fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { - // FIXME: this should probably be a bit more descriptive... - match errno { - libc::EOF => (io::EndOfFile, "end of file"), - libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"), - libc::ECONNRESET => (io::ConnectionReset, "connection reset"), - libc::EPERM | libc::EACCES => - (io::PermissionDenied, "permission denied"), - libc::EPIPE => (io::BrokenPipe, "broken pipe"), - libc::ENOTCONN => (io::NotConnected, "not connected"), - libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"), - libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), - libc::EADDRINUSE => (io::ConnectionRefused, "address in use"), - - // These two constants can have the same value on some systems, but - // different values on others, so we can't use a match clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - (io::ResourceUnavailable, "resource temporarily unavailable"), - - x => { - debug!("ignoring {}: {}", x, os::last_os_error()); - (io::OtherIoError, "unknown error") - } - } - } - - let (kind, desc) = get_err(errno); - IoError { - kind: kind, - desc: desc, - detail: if detail {Some(os::last_os_error())} else {None}, - } -} - -fn last_error() -> IoError { translate_error(os::errno() as i32, true) } -// ---------------------------------------------------------------------------- - -fn protocol_to_libc(protocol: raw::Protocol) - -> (libc::c_int, libc::c_int, libc::c_int) { - let eth_p_all: u16 = netsupport::htons(0x0003); - match protocol { - raw::DataLinkProtocol(raw::EthernetProtocol) - => (libc::AF_PACKET, libc::SOCK_RAW, eth_p_all as libc::c_int), - raw::DataLinkProtocol(raw::CookedEthernetProtocol(proto)) - => (libc::AF_PACKET, libc::SOCK_DGRAM, proto as libc::c_int), - raw::NetworkProtocol(raw::Ipv4NetworkProtocol) - => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW), - raw::NetworkProtocol(raw::Ipv6NetworkProtocol) - => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW), - raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) - => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int), - raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) - => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int) - } -} - impl RawSocketWatcher { pub fn new(io: &mut UvIoFactory, protocol: raw::Protocol) -> Result { - let (domain, typ, proto) = protocol_to_libc(protocol); + let (domain, typ, proto) = netsupport::protocol_to_libc(protocol); let handle = unsafe { uvll::malloc_handle(uvll::UV_POLL) }; let socket = unsafe { libc::socket(domain, typ, proto) }; if socket == -1 { - return Err(last_error()); + return Err(netsupport::last_error()); } let raw = RawSocketWatcher { @@ -729,10 +646,10 @@ impl RawSocketWatcher { // Make socket non-blocking - required for libuv let flags = unsafe { libc::fcntl(raw.socket, libc::F_GETFL, 0) }; if flags == -1 { - return Err(last_error()); + return Err(netsupport::last_error()); } if unsafe { libc::fcntl(raw.socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { - return Err(last_error()); + return Err(netsupport::last_error()); } assert_eq!(unsafe { @@ -783,7 +700,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { (n, _) if n < 0 => - Err(translate_error(n as i32, true)), + Err(netsupport::translate_error(n as i32, true)), (n, addr) => Ok((n as uint, Some(addr.unwrap()))) } } @@ -866,7 +783,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }); match cx.result.take_unwrap() { n if n < 0 => - Err(translate_error(n as i32, true)), + Err(netsupport::translate_error(n as i32, true)), n => Ok(n) } } From a2190cb6da2441f959b99c6d5ba8bec69fc7e2e8 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Fri, 14 Mar 2014 23:11:10 +0000 Subject: [PATCH 38/54] Fix a last_error() for Windows. --- src/libnative/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 857be32fee141..722bd4a6cfacd 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -104,7 +104,7 @@ fn mkerr_libc(ret: libc::c_int) -> IoResult<()> { #[cfg(windows)] fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { if ret == 0 { - Err(last_error()) + Err(netsupport::last_error()) } else { Ok(()) } From 6b4ae7e9bb1c19227c6ac13798da28000f870e2c Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 00:00:57 +0000 Subject: [PATCH 39/54] Fix merge fallout. --- src/libstd/libc.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 824fcfdcd5550..f23aded3d193c 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -3928,7 +3928,6 @@ pub mod funcs { } } - #[nolink] pub mod net { use libc::types::os::arch::c95::{c_char, c_uint}; From 04f2358139a3133bae1d31fefa7074726c686844 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 00:23:00 +0000 Subject: [PATCH 40/54] Fix line length lints. --- src/libnetsupport/lib.rs | 6 +++++- src/libstd/io/net/raw.rs | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs index fb25621de8e84..5f7b3d07b8f91 100644 --- a/src/libnetsupport/lib.rs +++ b/src/libnetsupport/lib.rs @@ -144,7 +144,11 @@ pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~ let ni = if useLocal { let nis = get_network_interfaces(); if nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).len() == 1 { - (*nis.iter().filter(|x| x.index as i32 == (*sll).sll_ifindex).next().unwrap()).clone() + (*nis.iter() + .filter(|x| x.index as i32 == (*sll).sll_ifindex) + .next() + .unwrap()) + .clone() } else { sll_to_ni(*sll) } diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 8403e89994951..68dc3f4c6ba36 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -1027,8 +1027,10 @@ pub mod test { fn get_proto(ip: IpAddr) -> Protocol { match ip { - Ipv4Addr(..) => TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocols::Test1)), - Ipv6Addr(..) => TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocols::Test1)) + Ipv4Addr(..) => + TransportProtocol(Ipv4TransportProtocol(IpNextHeaderProtocols::Test1)), + Ipv6Addr(..) => + TransportProtocol(Ipv6TransportProtocol(IpNextHeaderProtocols::Test1)) } } } @@ -1262,7 +1264,8 @@ pub mod test { loop { match sock.recvfrom(buf) { Ok((len, Some(~NetworkAddress(ni)))) => { - if len == packet.len() && same_ports(packet.as_slice(), buf, ETHERNET_HEADER_LEN as uint) { + if len == packet.len() && + same_ports(packet.as_slice(), buf, ETHERNET_HEADER_LEN as uint) { assert_eq!(buf.slice(0, packet.len()), packet.as_slice()); assert!(*ni == interface, "*ni != interface"); break; From 2266880d915c26778942527954c7aa72f1351a5a Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 01:18:12 +0000 Subject: [PATCH 41/54] Chan::new() -> channel(). --- src/libstd/io/net/raw.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 68dc3f4c6ba36..a05e917565ee6 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -985,7 +985,7 @@ pub mod test { $($a)* #[test] fn green() { f() } $($a)* #[test] fn native() { use native; - let (p, c) = Chan::new(); + let (p, c) = channel(); native::task::spawn(proc() { c.send(f()) }); p.recv(); } @@ -1199,8 +1199,8 @@ pub mod test { build_udp4_packet(packet.as_mut_slice(), 0); - let (port, chan) = Chan::new(); - let (port2, chan2) = Chan::new(); + let (port, chan) = channel(); + let (port2, chan2) = channel(); spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; @@ -1253,8 +1253,8 @@ pub mod test { build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); - let (port, chan) = Chan::new(); - let (port2, chan2) = Chan::new(); + let (port, chan) = channel(); + let (port2, chan2) = channel(); spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; From e530cb68ca1fd8f058699060d8eb49366043e96d Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 01:40:17 +0000 Subject: [PATCH 42/54] More channel changes. --- src/libstd/io/net/raw.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index a05e917565ee6..81f473ba477ab 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -985,9 +985,9 @@ pub mod test { $($a)* #[test] fn green() { f() } $($a)* #[test] fn native() { use native; - let (p, c) = channel(); - native::task::spawn(proc() { c.send(f()) }); - p.recv(); + let (tx, rx) = channel(); + native::task::spawn(proc() { tx.send(f()) }); + rx.recv(); } } ) @@ -1199,14 +1199,14 @@ pub mod test { build_udp4_packet(packet.as_mut_slice(), 0); - let (port, chan) = channel(); - let (port2, chan2) = channel(); + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherTypes::Ipv4))) { Ok(mut sock) => { - chan.send(()); + tx.send(()); loop { match sock.recvfrom(buf) { Ok((len, Some(~NetworkAddress(ni)))) => { @@ -1222,12 +1222,12 @@ pub mod test { }, Err(_) => fail!() } - port2.recv(); + rx2.recv(); }); match RawSocket::new(DataLinkProtocol(CookedEthernetProtocol(EtherTypes::Ipv4))) { Ok(mut sock) => { - port.recv(); + rx.recv(); match sock.sendto(packet, ~NetworkAddress(~interface2)) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() @@ -1235,7 +1235,7 @@ pub mod test { }, Err(_) => fail!() } - chan2.send(()); + tx2.send(()); } #[cfg(hasroot)]) iotest!(fn layer2_test() { @@ -1253,14 +1253,14 @@ pub mod test { build_udp4_packet(packet.as_mut_slice(), ETHERNET_HEADER_LEN as uint); - let (port, chan) = channel(); - let (port2, chan2) = channel(); + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); spawn( proc() { let mut buf: ~[u8] = ~[0, ..128]; match RawSocket::new(DataLinkProtocol(EthernetProtocol)) { Ok(mut sock) => { - chan.send(()); + tx.send(()); loop { match sock.recvfrom(buf) { Ok((len, Some(~NetworkAddress(ni)))) => { @@ -1277,12 +1277,12 @@ pub mod test { }, Err(_) => fail!() } - port2.recv(); + rx2.recv(); }); match RawSocket::new(DataLinkProtocol(EthernetProtocol)) { Ok(mut sock) => { - port.recv(); + rx.recv(); match sock.sendto(packet, ~NetworkAddress(~interface2)) { Ok(res) => assert_eq!(res as uint, packet.len()), Err(_) => fail!() @@ -1290,7 +1290,7 @@ pub mod test { }, Err(_) => fail!() } - chan2.send(()); + tx.send(()); } #[cfg(hasroot)]) } From 433379d7d5a69dcd6a02d53452d9549dc9408f72 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 01:58:25 +0000 Subject: [PATCH 43/54] Fix mistake in channel changes. --- src/libstd/io/net/raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 81f473ba477ab..e46329c020519 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -1290,7 +1290,7 @@ pub mod test { }, Err(_) => fail!() } - tx.send(()); + tx2.send(()); } #[cfg(hasroot)]) } From 0cb24075b5124c586256c73a16d1a7074bd8c365 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 02:19:39 +0000 Subject: [PATCH 44/54] Get raw sockets compiling on FreeBSD. --- src/libnetsupport/lib.rs | 37 +++++++++++++++++++++++++++++++++++++ src/libstd/libc.rs | 15 +++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs index 5f7b3d07b8f91..6b7382b2721f4 100644 --- a/src/libnetsupport/lib.rs +++ b/src/libnetsupport/lib.rs @@ -137,6 +137,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, } } +#[cfg(target_os = "linux")] pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~NetworkAddress> { unsafe { if (*sa).sa_family as libc::c_int == libc::AF_PACKET { @@ -179,6 +180,17 @@ pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~ } } +#[cfg(not(target_os = "linux"))] +pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, _useLocal: bool) -> Option<~NetworkAddress> { + unsafe { + Some(~IpAddress(sockaddr_to_addr(cast::transmute(sa), + mem::size_of::() + ).unwrap().ip)) + } +} + + +#[cfg(target_os = "linux")] pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, uint) { unsafe { match na { @@ -200,6 +212,14 @@ pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, } } +#[cfg(not(target_os = "linux"))] +pub fn network_addr_to_sockaddr(na: ~NetworkAddress) -> (libc::sockaddr_storage, uint) { + match na { + ~IpAddress(ip) => addr_to_sockaddr(ip::SocketAddr { ip: ip, port : 0}), + _ => fail!("Layer 2 networking not supported on this OS") + } +} + pub fn sockaddr_to_network_addrs(sa: *libc::sockaddr) -> (Option, Option, Option) { match sockaddr_to_network_addr(sa, false) { @@ -268,6 +288,7 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { } +#[cfg(target_os = "linux")] pub fn protocol_to_libc(protocol: raw::Protocol) -> (libc::c_int, libc::c_int, libc::c_int) { let eth_p_all: u16 = htons(0x0003); @@ -287,6 +308,22 @@ pub fn protocol_to_libc(protocol: raw::Protocol) } } +#[cfg(not(target_os = "linux"))] +pub fn protocol_to_libc(protocol: raw::Protocol) + -> (libc::c_int, libc::c_int, libc::c_int) { + match protocol { + raw::NetworkProtocol(raw::Ipv4NetworkProtocol) + => (libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::NetworkProtocol(raw::Ipv6NetworkProtocol) + => (libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_RAW), + raw::TransportProtocol(raw::Ipv4TransportProtocol(proto)) + => (libc::AF_INET, libc::SOCK_RAW, proto as libc::c_int), + raw::TransportProtocol(raw::Ipv6TransportProtocol(proto)) + => (libc::AF_INET6, libc::SOCK_RAW, proto as libc::c_int), + _ => fail!("Layer 2 networking not supported on this OS") + } +} + pub fn translate_error(errno: i32, detail: bool) -> io::IoError { #[cfg(windows)] fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) { diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index f23aded3d193c..bb74ed5f48482 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -672,6 +672,7 @@ pub mod types { pub enum timezone {} } pub mod bsd44 { + use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -734,6 +735,16 @@ pub mod types { sun_family: sa_family_t, sun_path: [c_char, ..104] } + pub struct ifaddrs { + ifa_next: *ifaddrs, + ifa_name: *c_char, + ifa_flags: c_uint, + ifa_addr: *sockaddr, + ifa_netmask: *sockaddr, + ifa_dstaddr: *sockaddr, + ifa_data: *c_void + } + } } @@ -2900,6 +2911,8 @@ pub mod consts { pub static SO_BROADCAST: c_int = 0x0020; pub static SO_REUSEADDR: c_int = 0x0004; + pub static IFF_LOOPBACK: c_int = 0x8; + pub static SHUT_RD: c_int = 0; pub static SHUT_WR: c_int = 1; pub static SHUT_RDWR: c_int = 2; @@ -2920,6 +2933,8 @@ pub mod consts { pub static MAP_STACK : c_int = 0x0400; pub static MAP_NOSYNC : c_int = 0x0800; pub static MAP_NOCORE : c_int = 0x020000; + + pub static IPPROTO_RAW : c_int = 255; } pub mod sysconf { use libc::types::os::arch::c95::c_int; From 3c36deff20c3596823ed9295bf39d788e43bf3c8 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 02:32:15 +0000 Subject: [PATCH 45/54] Remove stray tabs from FreeBSD. --- src/libnetsupport/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs index 6b7382b2721f4..d01849f799fa5 100644 --- a/src/libnetsupport/lib.rs +++ b/src/libnetsupport/lib.rs @@ -183,9 +183,12 @@ pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, useLocal: bool) -> Option<~ #[cfg(not(target_os = "linux"))] pub fn sockaddr_to_network_addr(sa: *libc::sockaddr, _useLocal: bool) -> Option<~NetworkAddress> { unsafe { - Some(~IpAddress(sockaddr_to_addr(cast::transmute(sa), - mem::size_of::() - ).unwrap().ip)) + Some( + ~IpAddress( + sockaddr_to_addr(cast::transmute(sa), + mem::size_of::() + ).unwrap().ip) + ) } } From 591ce9abb3a6857c2b176ac7ef883e904d5bece8 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 04:57:17 +0000 Subject: [PATCH 46/54] Add remaining missing contants for FreeBSD. Ignore tests which are not expected to pass. --- src/libstd/io/net/raw.rs | 4 ++-- src/libstd/libc.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index e46329c020519..d2df59a7e29ac 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -1236,7 +1236,7 @@ pub mod test { Err(_) => fail!() } tx2.send(()); - } #[cfg(hasroot)]) + } #[cfg(hasroot)] #[ignore(cfg(not(target_os = "linux")))]) iotest!(fn layer2_test() { let interface = get_test_interface(); @@ -1291,6 +1291,6 @@ pub mod test { Err(_) => fail!() } tx2.send(()); - } #[cfg(hasroot)]) + } #[cfg(hasroot)] #[ignore(cfg(not(target_os = "linux")))]) } diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index bb74ed5f48482..3dfdceb0d914e 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2799,6 +2799,12 @@ pub mod consts { pub mod posix01 { use libc::types::os::arch::c95::{c_int, size_t}; + pub static F_DUPFD : c_int = 0; + pub static F_GETFD : c_int = 1; + pub static F_SETFD : c_int = 2; + pub static F_GETFL : c_int = 3; + pub static F_SETFL : c_int = 4; + pub static SIGTRAP : c_int = 5; pub static GLOB_APPEND : c_int = 0x0001; From f695fb0ab7a2eeb78c72ed62925d403f6b3ec6ec Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 15 Mar 2014 05:04:02 +0000 Subject: [PATCH 47/54] Added missing constants and types for OS X. --- src/libstd/libc.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 3dfdceb0d914e..587b41fff78a0 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -1253,6 +1253,7 @@ pub mod types { } pub mod bsd44 { + use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = c_int; @@ -1315,6 +1316,16 @@ pub mod types { sun_family: sa_family_t, sun_path: [c_char, ..104] } + pub struct ifaddrs { + ifa_next: *ifaddrs, + ifa_name: *c_char, + ifa_flags: c_uint, + ifa_addr: *sockaddr, + ifa_netmask: *sockaddr, + ifa_dstaddr: *sockaddr, + ifa_data: *c_void + } + } } @@ -3207,6 +3218,12 @@ pub mod consts { pub mod posix01 { use libc::types::os::arch::c95::{c_int, size_t}; + pub static F_DUPFD : c_int = 0; + pub static F_GETFD : c_int = 1; + pub static F_SETFD : c_int = 2; + pub static F_GETFL : c_int = 3; + pub static F_SETFL : c_int = 4; + pub static SIGTRAP : c_int = 5; pub static GLOB_APPEND : c_int = 0x0001; @@ -3307,6 +3324,8 @@ pub mod consts { pub static SO_BROADCAST: c_int = 0x0020; pub static SO_REUSEADDR: c_int = 0x0004; + pub static IFF_LOOPBACK: c_int = 0x8; + pub static SHUT_RD: c_int = 0; pub static SHUT_WR: c_int = 1; pub static SHUT_RDWR: c_int = 2; @@ -3326,6 +3345,8 @@ pub mod consts { pub static MAP_HASSEMAPHORE : c_int = 0x0200; pub static MAP_NOCACHE : c_int = 0x0400; pub static MAP_JIT : c_int = 0x0800; + + pub static IPPROTO_RAW : c_int = 255; } pub mod sysconf { use libc::types::os::arch::c95::c_int; From 3fa904eea984e3334801d6c5441e74b22e3f85fd Mon Sep 17 00:00:00 2001 From: Robert Clipsham <1107029c@student.gla.ac.uk> Date: Mon, 17 Mar 2014 02:04:50 +0000 Subject: [PATCH 48/54] Get raw sockets compiling on Windows. --- src/libnative/io/addrinfo.rs | 6 ++--- src/libnative/io/file_win32.rs | 26 ++++++++++++---------- src/libnative/io/net.rs | 11 +++------- src/libnative/io/pipe_win32.rs | 24 ++++++++++---------- src/libnative/io/timer_win32.rs | 4 +++- src/libnetsupport/lib.rs | 25 ++++++++++++++++++--- src/librustuv/net.rs | 39 +++++++++++++++++++++++---------- src/libstd/libc.rs | 23 ++++++++++++++++++- 8 files changed, 107 insertions(+), 51 deletions(-) diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs index ff617e5a230ed..3cb3a83c6d578 100644 --- a/src/libnative/io/addrinfo.rs +++ b/src/libnative/io/addrinfo.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate netsupport; + use ai = std::io::net::addrinfo; use std::c_str::CString; use std::cast; @@ -96,10 +98,8 @@ extern "system" { #[cfg(windows)] fn get_error(_: c_int) -> IoError { - use super::translate_error; - unsafe { - translate_error(WSAGetLastError() as i32, true) + netsupport::translate_error(WSAGetLastError() as i32, true) } } diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 8f4f9259ab7ac..d36b1940d1fa9 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -10,6 +10,8 @@ //! Blocking win32-based file I/O +extern crate netsupport; + use std::c_str::CString; use std::cast; use std::io::IoError; @@ -63,7 +65,7 @@ impl FileDesc { if ret != 0 { Ok(read as uint) } else { - Err(super::last_error()) + Err(netsupport::last_error()) } } pub fn inner_write(&mut self, buf: &[u8]) -> Result<(), IoError> { @@ -80,7 +82,7 @@ impl FileDesc { remaining -= amt as uint; cur = unsafe { cur.offset(amt as int) }; } else { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } Ok(()) @@ -130,7 +132,7 @@ impl rtio::RtioFileStream for FileDesc { if ret != 0 { Ok(read as int) } else { - Err(super::last_error()) + Err(netsupport::last_error()) } } fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> Result<(), IoError> { @@ -151,7 +153,7 @@ impl rtio::RtioFileStream for FileDesc { cur = unsafe { cur.offset(amt as int) }; offset += amt as u64; } else { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } Ok(()) @@ -166,7 +168,7 @@ impl rtio::RtioFileStream for FileDesc { let mut newpos = 0; match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, whence) { - 0 => Err(super::last_error()), + 0 => Err(netsupport::last_error()), _ => Ok(newpos as u64), } } @@ -190,7 +192,7 @@ impl rtio::RtioFileStream for FileDesc { let _ = try!(self.seek(offset, io::SeekSet)); let ret = unsafe { match libc::SetEndOfFile(self.handle()) { - 0 => Err(super::last_error()), + 0 => Err(netsupport::last_error()), _ => Ok(()) } }; @@ -300,14 +302,14 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) ptr::mut_null()) }); if handle == libc::INVALID_HANDLE_VALUE as libc::HANDLE { - Err(super::last_error()) + Err(netsupport::last_error()) } else { let fd = unsafe { libc::open_osfhandle(handle as libc::intptr_t, flags) }; if fd < 0 { let _ = unsafe { libc::CloseHandle(handle) }; - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(FileDesc::new(fd, true)) } @@ -367,7 +369,7 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> { libc::free(wfd_ptr as *mut c_void); Ok(prune(p, paths)) } else { - Err(super::last_error()) + Err(netsupport::last_error()) } }) } @@ -421,7 +423,7 @@ pub fn readlink(p: &CString) -> IoResult { }) }; if handle as int == libc::INVALID_HANDLE_VALUE as int { - return Err(super::last_error()) + return Err(netsupport::last_error()) } // Specify (sz - 1) because the documentation states that it's the size // without the null pointer @@ -434,7 +436,7 @@ pub fn readlink(p: &CString) -> IoResult { let ret = match ret { Some(ref s) if s.starts_with(r"\\?\") => Ok(Path::new(s.slice_from(4))), Some(s) => Ok(Path::new(s)), - None => Err(super::last_error()), + None => Err(netsupport::last_error()), }; assert!(unsafe { libc::CloseHandle(handle) } != 0); return ret; @@ -495,7 +497,7 @@ pub fn stat(p: &CString) -> IoResult { as_utf16_p(p.as_str().unwrap(), |up| { match unsafe { libc::wstat(up, &mut stat) } { 0 => Ok(mkstat(&stat, p)), - _ => Err(super::last_error()), + _ => Err(netsupport::last_error()), } }) } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 48c588c4349d7..58ac480875e23 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -62,7 +62,7 @@ fn last_error() -> io::IoError { extern "system" { fn WSAGetLastError() -> libc::c_int; } - super::translate_error(unsafe { WSAGetLastError() }, true) + netsupport::translate_error(unsafe { WSAGetLastError() }, true) } #[cfg(not(windows))] @@ -613,7 +613,7 @@ impl rtio::RtioRawSocket for RawSocket { let addr = &mut caddr as *mut libc::sockaddr_storage; retry( || libc::recvfrom(self.fd, buf.as_ptr() as *mut libc::c_void, - buf.len() as u64, + netsupport::net_buflen(buf), 0, addr as *mut libc::sockaddr, &mut caddrlen)) @@ -625,22 +625,17 @@ impl rtio::RtioRawSocket for RawSocket { return Ok((len as uint, netsupport::sockaddr_to_network_addr( (&caddr as *libc::sockaddr_storage) as *libc::sockaddr, true) )); - //return sockaddr_to_addr(&caddr, caddrlen as uint).and_then(|addr| { - // Ok((len as uint, Some(raw::IpAddress(addr.ip)))) - //}); } fn sendto(&mut self, buf: &[u8], dst: ~raw::NetworkAddress) -> IoResult { - //let dst_ip = match dst { Some(raw::IpAddress(ip)) => Some(ip), _ => None }; - //let (sockaddr, slen) = addr_to_sockaddr(ip::SocketAddr { ip: dst_ip.unwrap(), port: 0 }); let (sockaddr, slen) = netsupport::network_addr_to_sockaddr(dst); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; let len = unsafe { retry( || libc::sendto(self.fd, buf.as_ptr() as *libc::c_void, - buf.len() as u64, + netsupport::net_buflen(buf), 0, addr, slen as libc::socklen_t)) diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs index e5e9592eb5ab5..ca267813da5af 100644 --- a/src/libnative/io/pipe_win32.rs +++ b/src/libnative/io/pipe_win32.rs @@ -84,6 +84,8 @@ //! the test suite passing (the suite is in libstd), and that's good enough for //! me! +extern crate netsupport; + use std::c_str::CString; use std::libc; use std::os::win32::as_utf16_p; @@ -105,7 +107,7 @@ impl Event { ptr::null()) }; if event as uint == 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(Event(event)) } @@ -226,7 +228,7 @@ impl UnixStream { ptr::mut_null()) }; return if ret == 0 { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(UnixStream { inner: UnsafeArc::new(inner), @@ -243,14 +245,14 @@ impl UnixStream { // code of ERROR_PIPE_BUSY. let code = unsafe { libc::GetLastError() }; if code as int != libc::ERROR_PIPE_BUSY as int { - return Err(super::last_error()) + return Err(netsupport::last_error()) } // An example I found on microsoft's website used 20 seconds, // libuv uses 30 seconds, hence we make the obvious choice of // waiting for 25 seconds. if unsafe { libc::WaitNamedPipeW(p, 25000) } == 0 { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } }) @@ -286,10 +288,10 @@ impl rtio::RtioPipe for UnixStream { libc::TRUE) }; if ret == 0 { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } else { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } @@ -324,10 +326,10 @@ impl rtio::RtioPipe for UnixStream { libc::TRUE) }; if ret == 0 { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } else { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } offset += bytes_written as uint; @@ -361,7 +363,7 @@ impl UnixListener { as_utf16_p(addr.as_str().unwrap(), |p| { let ret = unsafe { pipe(p, true) }; if ret == libc::INVALID_HANDLE_VALUE as libc::HANDLE { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(UnixListener { handle: ret, name: addr.clone() }) } @@ -454,7 +456,7 @@ impl UnixAcceptor { } } if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD { - return Err(super::last_error()) + return Err(netsupport::last_error()) } } @@ -465,7 +467,7 @@ impl UnixAcceptor { unsafe { pipe(p, false) } }); if new_handle == libc::INVALID_HANDLE_VALUE as libc::HANDLE { - let ret = Err(super::last_error()); + let ret = Err(netsupport::last_error()); // If our disconnection fails, then there's not really a whole lot // that we can do, so fail the task. let err = unsafe { libc::DisconnectNamedPipe(handle) }; diff --git a/src/libnative/io/timer_win32.rs b/src/libnative/io/timer_win32.rs index cdfe2e0d03372..182ee2c23a283 100644 --- a/src/libnative/io/timer_win32.rs +++ b/src/libnative/io/timer_win32.rs @@ -20,6 +20,8 @@ //! Other than that, the implementation is pretty straightforward in terms of //! the other two implementations of timers with nothing *that* new showing up. +extern crate netsupport; + use std::comm::Data; use std::libc; use std::ptr; @@ -98,7 +100,7 @@ impl Timer { imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null()) }; if obj.is_null() { - Err(super::last_error()) + Err(netsupport::last_error()) } else { Ok(Timer { obj: obj, on_worker: false, }) } diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs index d01849f799fa5..667cd883dd6d7 100644 --- a/src/libnetsupport/lib.rs +++ b/src/libnetsupport/lib.rs @@ -24,15 +24,16 @@ use std::io::net::ip; use std::io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::io::net::raw::{IpAddress, MacAddr, NetworkAddress, NetworkInterface}; use std::io::net::raw; -use std::iter::Iterator; use std::libc; use std::mem; use std::os; -use std::ptr; use std::result::Result; -use strraw = std::str::raw; use std::vec_ng::Vec; +#[cfg(not(windows))] use std::iter::Iterator; +#[cfg(not(windows))] use std::ptr; +#[cfg(not(windows))] use strraw = std::str::raw; + pub fn htons(u: u16) -> u16 { mem::to_be16(u as i16) as u16 } @@ -233,6 +234,7 @@ pub fn sockaddr_to_network_addrs(sa: *libc::sockaddr) } } +#[cfg(not(windows))] pub fn get_network_interfaces() -> Vec<~NetworkInterface> { let mut ifaces: Vec<~NetworkInterface> = Vec::new(); unsafe { @@ -291,6 +293,12 @@ pub fn get_network_interfaces() -> Vec<~NetworkInterface> { } +#[cfg(windows)] +pub fn get_network_interfaces() -> Vec<~NetworkInterface> { + Vec::new() +} + + #[cfg(target_os = "linux")] pub fn protocol_to_libc(protocol: raw::Protocol) -> (libc::c_int, libc::c_int, libc::c_int) { @@ -398,3 +406,14 @@ pub fn translate_error(errno: i32, detail: bool) -> io::IoError { } pub fn last_error() -> io::IoError { translate_error(os::errno() as i32, true) } + +#[cfg(windows)] +pub fn net_buflen(buf: &[u8]) -> i32 { + buf.len() as i32 +} + +#[cfg(not(windows))] +pub fn net_buflen(buf: &[u8]) -> u64 { + buf.len() as u64 +} + diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 87f5ffbf598bc..4c07eadc068ce 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -658,6 +658,28 @@ pub struct RawSocketWatcher { home: HomeHandle, } +#[cfg(windows)] +fn make_nonblocking(socket: libc::SOCKET) -> Option { + let one: libc::c_ulong = 1; + if unsafe { libc::ioctlsocket(socket, libc::FIONBIO, &one as *libc::c_ulong) } != 0 { + Some(netsupport::last_error()) + } else { + None + } +} + +#[cfg(not(windows))] +fn make_nonblocking(socket: c_int) -> Option { + let flags = unsafe { libc::fcntl(socket, libc::F_GETFL, 0) }; + if flags == -1 { + return Some(netsupport::last_error()); + } + if unsafe { libc::fcntl(socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { + return Some(netsupport::last_error()); + } + return None; +} + impl RawSocketWatcher { pub fn new(io: &mut UvIoFactory, protocol: raw::Protocol) -> Result @@ -676,12 +698,9 @@ impl RawSocketWatcher { }; // Make socket non-blocking - required for libuv - let flags = unsafe { libc::fcntl(raw.socket, libc::F_GETFL, 0) }; - if flags == -1 { - return Err(netsupport::last_error()); - } - if unsafe { libc::fcntl(raw.socket, libc::F_SETFL, flags | libc::O_NONBLOCK) } == -1 { - return Err(netsupport::last_error()); + match make_nonblocking(raw.socket) { + Some(e) => return Err(e), + None => () } assert_eq!(unsafe { @@ -765,7 +784,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { let addr = &mut caddr as *mut libc::sockaddr_storage; libc::recvfrom(sock, cx.buf.as_ptr() as *mut c_void, - cx.buf.len() as u64, + netsupport::net_buflen(cx.buf), 0, addr as *mut libc::sockaddr, &mut caddrlen) @@ -777,7 +796,6 @@ impl rtio::RtioRawSocket for RawSocketWatcher { wakeup(&mut cx.task); return; } - //let addr = Some(raw::IpAddress(sockaddr_to_addr(&caddr, caddrlen as uint).ip)); let addr = netsupport::sockaddr_to_network_addr( (&caddr as *libc::sockaddr_storage) as *libc::sockaddr, true ); @@ -840,14 +858,11 @@ impl rtio::RtioRawSocket for RawSocketWatcher { let len = match cx.socket { Some(sock) => { - //let (addr, len) = addr_to_sockaddr( - // ip::SocketAddr{ ip: cx.addr, port: 0 } - // ); let (addr, len) = netsupport::network_addr_to_sockaddr(cx.addr.clone()); unsafe { libc::sendto(sock, cx.buf.as_ptr() as *c_void, - cx.buf.len() as u64, + netsupport::net_buflen(cx.buf), 0, (&addr as *libc::sockaddr_storage) as *libc::sockaddr, len as libc::socklen_t) diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 587b41fff78a0..16239c0961ad2 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -122,6 +122,8 @@ pub use libc::funcs::extra::*; pub use libc::funcs::extra::kernel32::*; #[cfg(target_os = "win32")] pub use libc::funcs::extra::msvcrt::*; +#[cfg(target_os = "win32")] +pub use libc::funcs::extra::winsock::*; // Explicit export lists for the intersection (provided here) mean that // you can write more-platform-agnostic code if you stick to just these @@ -1650,6 +1652,7 @@ pub mod consts { pub static AF_INET6: c_int = 23; pub static SOCK_STREAM: c_int = 1; pub static SOCK_DGRAM: c_int = 2; + pub static SOCK_RAW: c_int = 3; pub static IPPROTO_TCP: c_int = 6; pub static IPPROTO_IP: c_int = 0; pub static IPPROTO_IPV6: c_int = 41; @@ -1667,12 +1670,14 @@ pub mod consts { pub static SO_BROADCAST: c_int = 32; pub static SO_REUSEADDR: c_int = 4; + pub static IFF_LOOPBACK: c_int = 4; + pub static SHUT_RD: c_int = 0; pub static SHUT_WR: c_int = 1; pub static SHUT_RDWR: c_int = 2; } pub mod extra { - use libc::types::os::arch::c95::c_int; + use libc::types::os::arch::c95::{c_int, c_long}; use libc::types::os::arch::extra::{WORD, DWORD, BOOL}; pub static TRUE : BOOL = 1; @@ -1891,6 +1896,10 @@ pub mod consts { pub static PIPE_ACCEPT_REMOTE_CLIENTS: DWORD = 0x00000000; pub static PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008; pub static PIPE_UNLIMITED_INSTANCES: DWORD = 255; + + pub static IPPROTO_RAW : c_int = 255; + + pub static FIONBIO : c_long = -0x7FFB9982; } pub mod sysconf { } @@ -3992,6 +4001,9 @@ pub mod funcs { pub mod mman { } + + pub mod net { + } } @@ -4370,5 +4382,14 @@ pub mod funcs { flags: c_int) -> c_int; } } + + pub mod winsock { + use libc::types::os::arch::c95::{c_int, c_long, c_ulong}; + use libc::types::os::common::bsd44::SOCKET; + + extern "system" { + pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *c_ulong) -> c_int; + } + } } } From 5a3d24112de0bbbe4bc86f0390f16f27c818e911 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Mon, 17 Mar 2014 03:33:42 +0000 Subject: [PATCH 49/54] Fix merge conflicts. --- src/libnetsupport/lib.rs | 10 ++-------- src/libstd/lib.rs | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/libnetsupport/lib.rs b/src/libnetsupport/lib.rs index 667cd883dd6d7..1a9c713a2aa9a 100644 --- a/src/libnetsupport/lib.rs +++ b/src/libnetsupport/lib.rs @@ -361,10 +361,7 @@ pub fn translate_error(errno: i32, detail: bool) -> io::IoError { libc::ERROR_INVALID_FUNCTION => (io::InvalidInput, "illegal operation on a directory"), - x => { - debug!("ignoring {}: {}", x, os::last_os_error()); - (io::OtherIoError, "unknown error") - } + _ => (io::OtherIoError, "unknown error") } } @@ -390,10 +387,7 @@ pub fn translate_error(errno: i32, detail: bool) -> io::IoError { x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => (io::ResourceUnavailable, "resource temporarily unavailable"), - x => { - debug!("ignoring {}: {}", x, os::last_os_error()); - (io::OtherIoError, "unknown error") - } + _ => (io::OtherIoError, "unknown error") } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 188d96e73789f..016267aa9be3a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -225,7 +225,6 @@ mod std { pub use iter; pub use kinds; pub use local_data; - pub use logging; pub use num; pub use option; pub use os; From 129691de168114df16b8652cd26e08394339765a Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 19 Mar 2014 00:33:02 +0000 Subject: [PATCH 50/54] Correct formatting for MacAddr. --- src/libstd/io/net/raw.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index d2df59a7e29ac..12b79868e1c82 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -11,6 +11,7 @@ // FIXME #[allow(missing_doc)]; +use fmt; use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; use iter::Iterator; @@ -70,11 +71,21 @@ pub enum NetworkAddress { NetworkAddress(~NetworkInterface) } -#[deriving(Eq, Clone, Show)] +#[deriving(Eq, Clone)] pub enum MacAddr { MacAddr(u8, u8, u8, u8, u8, u8) } +impl fmt::Show for MacAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + MacAddr(a, b, c, d, e, f) => + write!(fmt.buf, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + a, b, c, d, e, f) + } + } +} + pub trait Packet { fn packet<'p>(&'p self) -> &'p [u8]; fn offset(&self) -> uint; From 60eba939958f5329b77a2bf9863f051cb033bfb5 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 19 Mar 2014 00:33:19 +0000 Subject: [PATCH 51/54] Add test cases for ethernet and IP header structs. --- src/libstd/io/net/raw.rs | 257 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 242 insertions(+), 15 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 12b79868e1c82..2814fda4c87f9 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -189,6 +189,30 @@ impl<'p> MutableEthernetHeader<'p> { } } +#[test] +fn ethernet_header_test() { + let mut packet = [0u8, ..14]; + { + let mut ethernetHeader = MutableEthernetHeader::new(packet.as_mut_slice(), 0); + + let source = MacAddr(0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc); + ethernetHeader.set_source(source); + assert_eq!(ethernetHeader.get_source(), source); + + let dest = MacAddr(0xde, 0xf0, 0x12, 0x34, 0x45, 0x67); + ethernetHeader.set_destination(dest); + assert_eq!(ethernetHeader.get_destination(), dest); + + ethernetHeader.set_ethertype(EtherTypes::Ipv6); + assert_eq!(ethernetHeader.get_ethertype(), EtherTypes::Ipv6); + } + + let refPacket = [0xde, 0xf0, 0x12, 0x34, 0x45, 0x67, /* destination */ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, /* source */ + 0x86, 0xdd /* ethertype */]; + assert_eq!(refPacket.as_slice(), packet.as_slice()); +} + pub struct Ipv4Header<'p> { priv packet: &'p [u8], priv offset: uint @@ -217,56 +241,83 @@ pub trait Ipv4Packet : Packet { fn get_version(&self) -> u8 { self.packet()[self.offset()] >> 4 } + fn get_header_length(&self) -> u8 { self.packet()[self.offset()] & 0xF } + fn get_dscp(&self) -> u8 { (self.packet()[self.offset() + 1] & 0xFC) >> 2 } + fn get_ecn(&self) -> u8 { self.packet()[self.offset() + 1] & 3 } + fn get_total_length(&self) -> u16 { let b1 = self.packet()[self.offset() + 2] as u16 << 8; let b2 = self.packet()[self.offset() + 3] as u16; b1 | b2 } + fn get_identification(&self) -> u16 { let b1 = self.packet()[self.offset() + 4] as u16 << 8; let b2 = self.packet()[self.offset() + 5] as u16; b1 | b2 } + fn get_flags(&self) -> u8 { self.packet()[self.offset() + 6] >> 5 } + fn get_fragment_offset(&self) -> u16 { let b1 = (self.packet()[self.offset() + 6] & 0x1F) as u16 << 8; let b2 = self.packet()[self.offset() + 7] as u16; b1 | b2 } + fn get_ttl(&self) -> u8 { self.packet()[self.offset() + 8] } + fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { self.packet()[self.offset() + 9] } + fn get_checksum(&self) -> u16 { let cs1 = self.packet()[self.offset() + 10] as u16 << 8; let cs2 = self.packet()[self.offset() + 11] as u16; cs1 | cs2 } + fn get_source(&self) -> IpAddr { Ipv4Addr(self.packet()[self.offset() + 12], self.packet()[self.offset() + 13], self.packet()[self.offset() + 14], self.packet()[self.offset() + 15]) } + fn get_destination(&self) -> IpAddr { Ipv4Addr(self.packet()[self.offset() + 16], self.packet()[self.offset() + 17], self.packet()[self.offset() + 18], self.packet()[self.offset() + 19]) } + + fn calculate_checksum(&mut self) -> u16 { + let len = self.offset() + self.get_header_length() as uint * 4; + let mut sum = 0u32; + let mut i = self.offset(); + while i < len { + let word = self.packet()[i] as u32 << 8 | self.packet()[i + 1] as u32; + sum = sum + word; + i = i + 2; + } + while sum >> 16 != 0 { + sum = (sum >> 16) + (sum & 0xFFFF); + } + return !sum as u16; + } } impl<'p> Ipv4Packet for Ipv4Header<'p> {} @@ -364,18 +415,8 @@ impl<'p> MutableIpv4Header<'p> { } pub fn checksum(&mut self) { - let len = self.offset + self.get_header_length() as uint * 4; - let mut sum = 0u32; - let mut i = self.offset; - while i < len { - let word = self.packet[i] as u32 << 8 | self.packet[i + 1] as u32; - sum = sum + word; - i = i + 2; - } - while sum >> 16 != 0 { - sum = (sum >> 16) + (sum & 0xFFFF); - } - self.set_checksum(!sum as u16); + let checksum = self.calculate_checksum(); + self.set_checksum(checksum); } } @@ -465,28 +506,34 @@ pub trait Ipv6Packet : Packet { fn get_version(&self) -> u8 { self.packet()[self.offset()] >> 4 } + fn get_traffic_class(&self) -> u8 { let tc1 = (self.packet()[self.offset() + 0] & 0x0F) << 4; let tc2 = self.packet()[self.offset() + 1] >> 4; tc1 | tc2 } + fn get_flow_label(&self) -> u32 { let fl1 = (self.packet()[self.offset() + 1] as u32 & 0xF) << 16; let fl2 = self.packet()[self.offset() + 2] as u32 << 8; let fl3 = self.packet()[self.offset() + 3] as u32; fl1 | fl2 | fl3 } + fn get_payload_length(&self) -> u16 { let len1 = self.packet()[self.offset() + 4] as u16 << 8; let len2 = self.packet()[self.offset() + 5] as u16; len1 | len2 } + fn get_next_header(&self) -> IpNextHeaderProtocol { self.packet()[self.offset() + 6] } + fn get_hop_limit(&self) -> u8 { self.packet()[self.offset() + 7] } + fn get_source(&self) -> IpAddr { let packet = self.packet(); let offset = self.offset(); @@ -502,6 +549,7 @@ pub trait Ipv6Packet : Packet { Ipv6Addr(a, b, c, d, e, f, g, h) } + fn get_destination(&self) -> IpAddr { let packet = self.packet(); let offset = self.offset(); @@ -699,21 +747,103 @@ pub trait UdpPacket : Packet { let s2 = self.packet()[self.offset() + 1] as u16; s1 | s2 } + fn get_destination(&self) -> u16 { let d1 = self.packet()[self.offset() + 2] as u16 << 8; let d2 = self.packet()[self.offset() + 3] as u16; d1 | d2 } + fn get_length(&self) -> u16 { let l1 = self.packet()[self.offset() + 4] as u16 << 8; let l2 = self.packet()[self.offset() + 5] as u16; l1 | l2 } + fn get_checksum(&self) -> u16 { let c1 = self.packet()[self.offset() + 6] as u16 << 8; let c2 = self.packet()[self.offset() + 7] as u16; c1 | c2 } + + fn calculate_ipv4_checksum(&self, offset: uint) -> u16 { + let mut sum = 0u32; + let mut i = offset; + + // Checksum pseudo-header + // IPv4 source + sum = sum + (self.packet()[i + 12] as u32 << 8 | self.packet()[i + 13] as u32); + sum = sum + (self.packet()[i + 14] as u32 << 8 | self.packet()[i + 15] as u32); + + // IPv4 destination + sum = sum + (self.packet()[i + 16] as u32 << 8 | self.packet()[i + 17] as u32); + sum = sum + (self.packet()[i + 18] as u32 << 8 | self.packet()[i + 19] as u32); + + // IPv4 Next level protocol + sum = sum + self.packet()[i + 9] as u32; + + // UDP Length + sum = sum + (self.packet()[self.offset() + 4] as u32 << 8 | + self.packet()[self.offset() + 5] as u32); + + // Checksum UDP header/packet + i = self.offset(); + let len = self.offset() + self.get_length() as uint; + while i < len { + let word = self.packet()[i] as u32 << 8 | self.packet()[i + 1] as u32; + sum = sum + word; + i = i + 2; + } + // If the length is odd, make sure to checksum the final byte + if len & 1 != 0 { + sum = sum + (self.packet()[len - 1] as u32 << 8); + } + while sum >> 16 != 0 { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return !sum as u16; + } + + fn calculate_ipv6_checksum(&self, offset: uint) -> u16 { + let mut sum = 0u32; + let mut i = offset + 8; + let mut len = offset + 40; + + // Checksum pseudo-header + // IPv6 source and destination + while i < len { + let word = self.packet()[i] as u32 << 8 | self.packet()[i + 1] as u32; + sum = sum + word; + i = i + 2; + } + + // IPv6 Next header + sum = sum + self.packet()[offset + 6] as u32; + + // UDP Length + sum = sum + self.get_length() as u32; + + // Checksum UDP header/packet + i = self.offset(); + len = self.offset() + self.get_length() as uint; + while i < len { + let word = self.packet()[i] as u32 << 8 | self.packet()[i + 1] as u32; + sum = sum + word; + i = i + 2; + } + // If the length is odd, make sure to checksum the final byte + if len & 1 != 0 { + sum = sum + self.packet()[len - 1] as u32 << 8; + } + + while sum >> 16 != 0 { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return !sum as u16; + } + } impl<'p> UdpPacket for UdpHeader<'p> {} @@ -750,11 +880,105 @@ impl<'p> MutableUdpHeader<'p> { self.packet[self.offset + 7] = (checksum & 0xFF) as u8; } - pub fn checksum(&mut self) { - // FIXME + pub fn ipv4_checksum(&mut self, offset: uint) { + let checksum = self.calculate_ipv4_checksum(offset); + // RFC 768, a checksum of zero is transmitted as all ones + if checksum != 0 { + self.set_checksum(checksum); + } else { + self.set_checksum(0xFFFF); + } + } + + pub fn ipv6_checksum(&mut self, offset: uint) { + let checksum = self.calculate_ipv6_checksum(offset); + if checksum != 0 { + self.set_checksum(checksum); + } else { + self.set_checksum(0xFFFF); + } + } + +} + +#[test] +fn udp_header_ipv4_test() { + let mut packet = [0u8, ..20 + 8 + 4]; + { + let mut ipHeader = MutableIpv4Header::new(packet.as_mut_slice(), 0); + ipHeader.set_next_level_protocol(IpNextHeaderProtocols::Udp); + ipHeader.set_source(Ipv4Addr(192, 168, 0, 1)); + ipHeader.set_destination(Ipv4Addr(192, 168, 0, 199)); } + + // Set data + packet[20 + 8 + 0] = 't' as u8; + packet[20 + 8 + 1] = 'e' as u8; + packet[20 + 8 + 2] = 's' as u8; + packet[20 + 8 + 3] = 't' as u8; + + { + let mut udpHeader = MutableUdpHeader::new(packet.as_mut_slice(), 20); + udpHeader.set_source(12345); + assert_eq!(udpHeader.get_source(), 12345); + + udpHeader.set_destination(54321); + assert_eq!(udpHeader.get_destination(), 54321); + + udpHeader.set_length(8 + 4); + assert_eq!(udpHeader.get_length(), 8 + 4); + + udpHeader.ipv4_checksum(0); + assert_eq!(udpHeader.get_checksum(), 0x9178); + } + + let refPacket = [0x30, 0x39, /* source */ + 0xd4, 0x31, /* destination */ + 0x00, 0x0c, /* length */ + 0x91, 0x78 /* checksum*/]; + assert_eq!(refPacket.as_slice(), packet.slice(20, 28)); } + +#[test] +fn udp_header_ipv6_test() { + let mut packet = [0u8, ..40 + 8 + 4]; + { + let mut ipHeader = MutableIpv6Header::new(packet.as_mut_slice(), 0); + ipHeader.set_next_header(IpNextHeaderProtocols::Udp); + ipHeader.set_source(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); + ipHeader.set_destination(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)); + } + + // Set data + packet[40 + 8 + 0] = 't' as u8; + packet[40 + 8 + 1] = 'e' as u8; + packet[40 + 8 + 2] = 's' as u8; + packet[40 + 8 + 3] = 't' as u8; + + { + let mut udpHeader = MutableUdpHeader::new(packet.as_mut_slice(), 20); + udpHeader.set_source(12345); + assert_eq!(udpHeader.get_source(), 12345); + + udpHeader.set_destination(54321); + assert_eq!(udpHeader.get_destination(), 54321); + + udpHeader.set_length(8 + 4); + assert_eq!(udpHeader.get_length(), 8 + 4); + + udpHeader.ipv6_checksum(0); + assert_eq!(udpHeader.get_checksum(), 0xf6f3); + } + + let refPacket = [0x30, 0x39, /* source */ + 0xd4, 0x31, /* destination */ + 0x00, 0x0c, /* length */ + 0xf6, 0xf3 /* checksum*/]; + assert_eq!(refPacket.as_slice(), packet.slice(20, 28)); +} + + pub enum Protocol { DataLinkProtocol(DataLinkProto), NetworkProtocol(NetworkProto), @@ -1084,7 +1308,6 @@ pub mod test { udpHeader.set_source(1234); // Arbitary port number udpHeader.set_destination(1234); udpHeader.set_length(UDP_HEADER_LEN + TEST_DATA_LEN); - udpHeader.checksum(); } pub fn build_udp4_packet(packet: &mut [u8], start: uint) { @@ -1096,6 +1319,8 @@ pub mod test { packet[dataStart + 1] = 'e' as u8; packet[dataStart + 2] = 's' as u8; packet[dataStart + 3] = 't' as u8; + + MutableUdpHeader::new(packet, IPV4_HEADER_LEN as uint).ipv4_checksum(start); } pub fn build_udp6_packet(packet: &mut [u8], start: uint) { @@ -1107,6 +1332,8 @@ pub mod test { packet[dataStart + 1] = 'e' as u8; packet[dataStart + 2] = 's' as u8; packet[dataStart + 3] = 't' as u8; + + MutableUdpHeader::new(packet, IPV6_HEADER_LEN as uint).ipv6_checksum(start); } pub fn get_test_interface() -> NetworkInterface { From 33e6123eb964c7c4f5526e90c5c6c39753876c80 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sun, 23 Mar 2014 04:16:06 +0000 Subject: [PATCH 52/54] Add some bounds checking. --- src/libstd/io/net/raw.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index 2814fda4c87f9..df71aeb15c3a5 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -11,6 +11,7 @@ // FIXME #[allow(missing_doc)]; +use container::Container; use fmt; use io::net::ip::{IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult}; @@ -789,13 +790,13 @@ pub trait UdpPacket : Packet { // Checksum UDP header/packet i = self.offset(); let len = self.offset() + self.get_length() as uint; - while i < len { + while i < len && i + 1 < self.packet().len() { let word = self.packet()[i] as u32 << 8 | self.packet()[i + 1] as u32; sum = sum + word; i = i + 2; } // If the length is odd, make sure to checksum the final byte - if len & 1 != 0 { + if len & 1 != 0 && len <= self.packet().len() { sum = sum + (self.packet()[len - 1] as u32 << 8); } while sum >> 16 != 0 { @@ -827,13 +828,13 @@ pub trait UdpPacket : Packet { // Checksum UDP header/packet i = self.offset(); len = self.offset() + self.get_length() as uint; - while i < len { + while i < len && i + 1 < self.packet().len() { let word = self.packet()[i] as u32 << 8 | self.packet()[i + 1] as u32; sum = sum + word; i = i + 2; } // If the length is odd, make sure to checksum the final byte - if len & 1 != 0 { + if len & 1 != 0 && len <= self.packet().len() { sum = sum + self.packet()[len - 1] as u32 << 8; } From 8d4e75055a3ecfc1c44cb14e3a8b563d16136618 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sun, 23 Mar 2014 05:01:22 +0000 Subject: [PATCH 53/54] The length returned from sendto() should be uint to be consistent with recvfrom(). --- src/libnative/io/net.rs | 4 ++-- src/librustuv/net.rs | 16 ++++++---------- src/libstd/io/net/raw.rs | 2 +- src/libstd/rt/rtio.rs | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 58ac480875e23..35b2acb9ce684 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -628,7 +628,7 @@ impl rtio::RtioRawSocket for RawSocket { } fn sendto(&mut self, buf: &[u8], dst: ~raw::NetworkAddress) - -> IoResult + -> IoResult { let (sockaddr, slen) = netsupport::network_addr_to_sockaddr(dst); let addr = (&sockaddr as *libc::sockaddr_storage) as *libc::sockaddr; @@ -644,7 +644,7 @@ impl rtio::RtioRawSocket for RawSocket { return if len < 0 { Err(netsupport::last_error()) } else { - Ok(len as int) + Ok(len as uint) }; } } diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 4c07eadc068ce..813073a4e7fdf 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -806,12 +806,12 @@ impl rtio::RtioRawSocket for RawSocketWatcher { } fn sendto(&mut self, buf: &[u8], dst: ~raw::NetworkAddress) - -> Result + -> Result { struct Ctx<'b> { task: Option, buf: &'b [u8], - result: Option, + result: Option>, socket: Option, addr: ~raw::NetworkAddress, } @@ -831,11 +831,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { wait_until_woken_after(&mut cx.task, &self.uv_loop(), || { unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) } }); - match cx.result.take_unwrap() { - n if n < 0 => - Err(netsupport::translate_error(n as i32, true)), - n => Ok(n) - } + cx.result.unwrap() } n => Err(uv_error_to_io_error(UvError(n))) }; @@ -847,7 +843,7 @@ impl rtio::RtioRawSocket for RawSocketWatcher { cast::transmute(uvll::get_data_for_uv_handle(handle)) }; if status < 0 { - cx.result = Some(status as int); + cx.result = Some(Err(uv_error_to_io_error(UvError(status)))); wakeup(&mut cx.task); return; } @@ -872,9 +868,9 @@ impl rtio::RtioRawSocket for RawSocketWatcher { }; cx.result = if len < 0 { - Some(-errno() as int) + Some(Err(netsupport::last_error())) } else { - Some(len as int) + Some(Ok(len as uint)) }; wakeup(&mut cx.task); diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index df71aeb15c3a5..d94b4077eab3c 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -40,7 +40,7 @@ impl RawSocket { self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> IoResult { + pub fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> IoResult { self.obj.sendto(buf, dst) } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 9e221e90384c6..a2c7ea5623bcc 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -236,7 +236,7 @@ pub trait RtioUdpSocket : RtioSocket { pub trait RtioRawSocket { fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, Option<~NetworkAddress>), IoError>; - fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> Result; + fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> Result; } pub trait RtioTimer { From 154b2f42f4faad8d86b6bc8b09c675950d4c371e Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Wed, 26 Mar 2014 21:55:33 +0000 Subject: [PATCH 54/54] Add documentation for io::net::raw. --- src/libstd/io/net/raw.rs | 181 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 169 insertions(+), 12 deletions(-) diff --git a/src/libstd/io/net/raw.rs b/src/libstd/io/net/raw.rs index d94b4077eab3c..cec5cddb6c7ed 100644 --- a/src/libstd/io/net/raw.rs +++ b/src/libstd/io/net/raw.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME -#[allow(missing_doc)]; +//! Raw layer two to four network connections +//! +//! This module enables the creation of raw network sockets to send and receive +//! packets at OSI layers two, three and four. + +#[deny(missing_doc)]; use container::Container; use fmt; @@ -25,55 +29,96 @@ use vec::{Vector, ImmutableVector}; #[cfg(test)] use vec::MutableVector; +/// A structure which represents a raw socket +/// +/// # Example +/// +/// Simple packet logger. +/// +/// ```rust +/// use std::io::net::raw::{DataLinkProtocol, EthernetProtocol, RawSocket}; +/// +/// let proto = DataLinkProtocol(EthernetProtocol); +/// let mut socket = RawSocket::new(proto).unwrap(); +/// loop { +/// let mut buf = [0u8, ..4096]; +/// let (len, addr) = socket.recvfrom(buf.as_mut_slice()).unwrap(); +/// handle_packet(addr, buf.slice_to(len)); +/// } +/// ``` pub struct RawSocket { priv obj: ~RtioRawSocket } impl RawSocket { + /// Create a new RawSocket using the specified protocol + /// + /// If no error is encountered, then Ok(socket) is returned. pub fn new(protocol: Protocol) -> IoResult { LocalIo::maybe_raise(|io| { io.raw_socket_new(protocol).map(|s| RawSocket { obj: s }) }) } + /// Receive data from a socket + /// + /// Returns Ok(length_of_received_data, network_address) on success. pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, Option<~NetworkAddress>)> { self.obj.recvfrom(buf) } + /// Send data on the socket + /// + /// Returns length of sent data on success pub fn sendto(&mut self, buf: &[u8], dst: ~NetworkAddress) -> IoResult { self.obj.sendto(buf, dst) } } +/// Represents a network interface and its associated addresses #[deriving(Clone, Eq, Show)] pub struct NetworkInterface { + /// The name of the interface name: ~str, + /// The interface index (operating system specific) index: u32, + /// A MAC address for the interface mac: Option, + /// An IPv4 address for the interface ipv4: Option, + /// An IPv6 address for the interface ipv6: Option, + /// Operating system specific flags for the interface flags: u32, } impl NetworkInterface { + /// Retreive the MAC address associated with the interface pub fn mac_address(&self) -> MacAddr { self.mac.unwrap() } + /// Is the interface a loopback interface? pub fn is_loopback(&self) -> bool { self.flags & (libc::IFF_LOOPBACK as u32) != 0 } } +/// Represents a network address. This is either an IP address or a network +/// interface #[deriving(Clone, Eq, Show)] pub enum NetworkAddress { + /// An IP address IpAddress(IpAddr), + /// A network interface NetworkAddress(~NetworkInterface) } +/// A MAC address #[deriving(Eq, Clone)] pub enum MacAddr { + /// A MAC address MacAddr(u8, u8, u8, u8, u8, u8) } @@ -87,16 +132,21 @@ impl fmt::Show for MacAddr { } } +/// Represents a generic network packet pub trait Packet { + /// Retreive the underlying buffer for the packet fn packet<'p>(&'p self) -> &'p [u8]; + /// Retreive the offset into the buffer that the packet starts at fn offset(&self) -> uint; } +/// A structure which represents an Ethernet header pub struct EthernetHeader<'p> { priv packet: &'p [u8], priv offset: uint } +/// A structure representing an Ethernet header which can be mutated pub struct MutableEthernetHeader<'p> { priv packet: &'p mut [u8], priv offset: uint @@ -116,7 +166,10 @@ impl<'p> Packet for MutableEthernetHeader<'p> { fn offset(&self) -> uint { self.offset } } +/// A trait implemented by anything which provides the ability to retrieve +/// fields of an Ethernet packet pub trait EthernetPacket : Packet { + /// Get the source address for an Ethernet packet fn get_source(&self) -> MacAddr { MacAddr( self.packet()[self.offset() + 6], @@ -128,6 +181,7 @@ pub trait EthernetPacket : Packet { ) } + /// Get the destination address for an Ethernet packet fn get_destination(&self) -> MacAddr { MacAddr( self.packet()[self.offset() + 0], @@ -139,6 +193,7 @@ pub trait EthernetPacket : Packet { ) } + /// Get the Ethertype field of an Ethernet packet fn get_ethertype(&self) -> u16 { (self.packet()[self.offset() + 12] as u16 << 8) | (self.packet()[self.offset() + 13] as u16) } @@ -148,16 +203,21 @@ impl<'p> EthernetPacket for EthernetHeader<'p> {} impl<'p> EthernetPacket for MutableEthernetHeader<'p> {} impl<'p> EthernetHeader<'p> { + /// Construct a new Ethernet header backed by the given buffer with the + /// provided offset pub fn new(packet: &'p [u8], offset: uint) -> EthernetHeader<'p> { EthernetHeader { packet: packet, offset: offset } } } impl<'p> MutableEthernetHeader<'p> { + /// Construct a new mutable Ethernet header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p mut [u8], offset: uint) -> MutableEthernetHeader<'p> { MutableEthernetHeader { packet: packet, offset: offset } } + /// Set the source address for an Ethernet packet pub fn set_source(&mut self, mac: MacAddr) { match mac { MacAddr(a, b, c, d, e, f) => { @@ -171,6 +231,7 @@ impl<'p> MutableEthernetHeader<'p> { } } + /// Set the destination address for an Ethernet packet pub fn set_destination(&mut self, mac: MacAddr) { match mac { MacAddr(a, b, c, d, e, f) => { @@ -184,6 +245,7 @@ impl<'p> MutableEthernetHeader<'p> { } } + /// Set the Ethertype for an Ethernet packet pub fn set_ethertype(&mut self, ethertype: u16) { self.packet[self.offset + 12] = (ethertype >> 8) as u8; self.packet[self.offset + 13] = (ethertype & 0xFF) as u8; @@ -214,11 +276,13 @@ fn ethernet_header_test() { assert_eq!(refPacket.as_slice(), packet.as_slice()); } +/// Structure representing an IPv4 header pub struct Ipv4Header<'p> { priv packet: &'p [u8], priv offset: uint } +/// Structure representing a mutable IPv4 header pub struct MutableIpv4Header<'p> { priv packet: &'p mut [u8], priv offset: uint @@ -238,59 +302,73 @@ impl<'p> Packet for MutableIpv4Header<'p> { fn offset(&self) -> uint { self.offset } } +/// Trait implemented by anything which provides an interface to read IPv4 +/// packets pub trait Ipv4Packet : Packet { + /// Get the version of the IPv4 packet. Should return 4. fn get_version(&self) -> u8 { self.packet()[self.offset()] >> 4 } + /// Get the header length field of the packet fn get_header_length(&self) -> u8 { self.packet()[self.offset()] & 0xF } + /// Get the DSCP field of the packet fn get_dscp(&self) -> u8 { (self.packet()[self.offset() + 1] & 0xFC) >> 2 } + /// Get the ECN field of the packet fn get_ecn(&self) -> u8 { self.packet()[self.offset() + 1] & 3 } + /// Get the total length of the packet fn get_total_length(&self) -> u16 { let b1 = self.packet()[self.offset() + 2] as u16 << 8; let b2 = self.packet()[self.offset() + 3] as u16; b1 | b2 } + /// Get the identification field for the packet fn get_identification(&self) -> u16 { let b1 = self.packet()[self.offset() + 4] as u16 << 8; let b2 = self.packet()[self.offset() + 5] as u16; b1 | b2 } + /// Get the flags for the packet fn get_flags(&self) -> u8 { self.packet()[self.offset() + 6] >> 5 } + /// Get the fragment offset for the packet fn get_fragment_offset(&self) -> u16 { let b1 = (self.packet()[self.offset() + 6] & 0x1F) as u16 << 8; let b2 = self.packet()[self.offset() + 7] as u16; b1 | b2 } + /// Get the TTL for the packet fn get_ttl(&self) -> u8 { self.packet()[self.offset() + 8] } + /// Get the next level protocol for the packet fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { self.packet()[self.offset() + 9] } + /// Get the checksum field for the packet fn get_checksum(&self) -> u16 { let cs1 = self.packet()[self.offset() + 10] as u16 << 8; let cs2 = self.packet()[self.offset() + 11] as u16; cs1 | cs2 } + /// Get the source IP address for the packet fn get_source(&self) -> IpAddr { Ipv4Addr(self.packet()[self.offset() + 12], self.packet()[self.offset() + 13], @@ -298,6 +376,7 @@ pub trait Ipv4Packet : Packet { self.packet()[self.offset() + 15]) } + /// Get the destination field for the packet fn get_destination(&self) -> IpAddr { Ipv4Addr(self.packet()[self.offset() + 16], self.packet()[self.offset() + 17], @@ -305,6 +384,7 @@ pub trait Ipv4Packet : Packet { self.packet()[self.offset() + 19]) } + /// Calculate the checksum for the packet fn calculate_checksum(&mut self) -> u16 { let len = self.offset() + self.get_header_length() as uint * 4; let mut sum = 0u32; @@ -325,50 +405,62 @@ impl<'p> Ipv4Packet for Ipv4Header<'p> {} impl<'p> Ipv4Packet for MutableIpv4Header<'p> {} impl<'p> Ipv4Header<'p> { + /// Construct a new IPv4 header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p [u8], offset: uint) -> Ipv4Header<'p> { Ipv4Header { packet: packet, offset: offset } } } impl<'p> MutableIpv4Header<'p> { + /// Construct a new mutable IPv4 header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p mut [u8], offset: uint) -> MutableIpv4Header<'p> { MutableIpv4Header { packet: packet, offset: offset } } + /// Set the version field for the packet pub fn set_version(&mut self, version: u8) { let ver = version << 4; self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; } + /// Set the header length field for the packet pub fn set_header_length(&mut self, ihl: u8) { let len = ihl & 0xF; self.packet[self.offset] = (self.packet[self.offset] & 0xF0) | len; } + /// Set the DSCP field for the packet pub fn set_dscp(&mut self, dscp: u8) { let cp = dscp & 0xFC; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 3) | (cp << 2); } + /// Set the ECN field for the packet pub fn set_ecn(&mut self, ecn: u8) { let cn = ecn & 3; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xFC) | cn; } + /// Set the total length field for the packet pub fn set_total_length(&mut self, len: u16) { self.packet[self.offset + 2] = (len >> 8) as u8; self.packet[self.offset + 3] = (len & 0xFF) as u8; } + /// Set the identification field for the packet pub fn set_identification(&mut self, identification: u16) { self.packet[self.offset + 4] = (identification >> 8) as u8; self.packet[self.offset + 5] = (identification & 0x00FF) as u8; } + /// Set the flags field for the packet pub fn set_flags(&mut self, flags: u8) { let fs = (flags & 7) << 5; self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0x1F) | fs; } + /// Set the fragment offset field for the packet pub fn set_fragment_offset(&mut self, offset: u16) { let fo = offset & 0x1FFF; self.packet[self.offset + 6] = (self.packet[self.offset + 6] & 0xE0) | @@ -376,14 +468,17 @@ impl<'p> MutableIpv4Header<'p> { self.packet[self.offset + 7] = (fo & 0xFF) as u8; } + /// Set the TTL field for the packet pub fn set_ttl(&mut self, ttl: u8) { self.packet[self.offset + 8] = ttl; } + /// Set the next level protocol field for the packet pub fn set_next_level_protocol(&mut self, protocol: IpNextHeaderProtocol) { self.packet[self.offset + 9] = protocol; } + /// Set the checksum field for the packet pub fn set_checksum(&mut self, checksum: u16) { let cs1 = ((checksum & 0xFF00) >> 8) as u8; let cs2 = (checksum & 0x00FF) as u8; @@ -391,6 +486,7 @@ impl<'p> MutableIpv4Header<'p> { self.packet[self.offset + 11] = cs2; } + /// Set the source address for the packet pub fn set_source(&mut self, ip: IpAddr) { match ip { Ipv4Addr(a, b, c, d) => { @@ -403,6 +499,7 @@ impl<'p> MutableIpv4Header<'p> { } } + /// Set the destination field for the packet pub fn set_destination(&mut self, ip: IpAddr) { match ip { Ipv4Addr(a, b, c, d) => { @@ -415,6 +512,8 @@ impl<'p> MutableIpv4Header<'p> { } } + /// Calculate the checksum of the packet and then set the field to the value + /// calculated pub fn checksum(&mut self) { let checksum = self.calculate_checksum(); self.set_checksum(checksum); @@ -479,11 +578,13 @@ fn ipv4_header_test() { assert_eq!(refPacket.as_slice(), packet.as_slice()); } +/// Structure representing an IPv6 header pub struct Ipv6Header<'p> { priv packet: &'p [u8], priv offset: uint } +/// Structure representing a mutable IPv6 header pub struct MutableIpv6Header<'p> { priv packet: &'p mut [u8], priv offset: uint @@ -503,17 +604,22 @@ impl<'p> Packet for MutableIpv6Header<'p> { fn offset(&self) -> uint { self.offset } } +/// Trait implemented by anything which provides an interface to read IPv6 +/// packets pub trait Ipv6Packet : Packet { + /// Get the version field for the packet. Should usually be 6. fn get_version(&self) -> u8 { self.packet()[self.offset()] >> 4 } + /// Get the traffic class field for the packet fn get_traffic_class(&self) -> u8 { let tc1 = (self.packet()[self.offset() + 0] & 0x0F) << 4; let tc2 = self.packet()[self.offset() + 1] >> 4; tc1 | tc2 } + /// Get the flow label field for the packet fn get_flow_label(&self) -> u32 { let fl1 = (self.packet()[self.offset() + 1] as u32 & 0xF) << 16; let fl2 = self.packet()[self.offset() + 2] as u32 << 8; @@ -521,20 +627,24 @@ pub trait Ipv6Packet : Packet { fl1 | fl2 | fl3 } + /// Get the payload length field for the packet fn get_payload_length(&self) -> u16 { let len1 = self.packet()[self.offset() + 4] as u16 << 8; let len2 = self.packet()[self.offset() + 5] as u16; len1 | len2 } + /// Get the next header field for the packet fn get_next_header(&self) -> IpNextHeaderProtocol { self.packet()[self.offset() + 6] } + /// Get the hop limit field for the packet fn get_hop_limit(&self) -> u8 { self.packet()[self.offset() + 7] } + /// Get the source IP address for the packet fn get_source(&self) -> IpAddr { let packet = self.packet(); let offset = self.offset(); @@ -551,6 +661,7 @@ pub trait Ipv6Packet : Packet { Ipv6Addr(a, b, c, d, e, f, g, h) } + /// Get the destination IP address for the packet fn get_destination(&self) -> IpAddr { let packet = self.packet(); let offset = self.offset(); @@ -572,27 +683,34 @@ impl<'p> Ipv6Packet for Ipv6Header<'p> {} impl<'p> Ipv6Packet for MutableIpv6Header<'p> {} impl<'p> Ipv6Header<'p> { + /// Construct a new IPv6 header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p [u8], offset: uint) -> Ipv6Header<'p> { Ipv6Header { packet: packet, offset: offset } } } impl<'p> MutableIpv6Header<'p> { + /// Construct a new mutable IPv6 header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p mut [u8], offset: uint) -> MutableIpv6Header<'p> { MutableIpv6Header { packet: packet, offset: offset } } + /// Set the version field for the packet pub fn set_version(&mut self, version: u8) { let ver = version << 4; self.packet[self.offset] = (self.packet[self.offset] & 0x0F) | ver; } + /// Set the traffic class field for the packet pub fn set_traffic_class(&mut self, tc: u8) { self.packet[self.offset + 0] = (self.packet[self.offset] & 0xF0) | (tc >> 4); self.packet[self.offset + 1] = ((tc & 0x0F) << 4) | ((self.packet[self.offset + 1] & 0xF0) >> 4); } + /// Set the flow label field for the packet pub fn set_flow_label(&mut self, label: u32) { let lbl = ((label & 0xF0000) >> 16) as u8; self.packet[self.offset + 1] = (self.packet[self.offset + 1] & 0xF0) | lbl; @@ -600,19 +718,23 @@ impl<'p> MutableIpv6Header<'p> { self.packet[self.offset + 3] = (label & 0x00FF) as u8; } + /// Set the payload length field for the packet pub fn set_payload_length(&mut self, len: u16) { self.packet[self.offset + 4] = (len >> 8) as u8; self.packet[self.offset + 5] = (len & 0xFF) as u8; } + /// Set the next header field for the packet pub fn set_next_header(&mut self, protocol: IpNextHeaderProtocol) { self.packet[self.offset + 6] = protocol; } + /// Set the hop limit field for the packet pub fn set_hop_limit(&mut self, limit: u8) { self.packet[self.offset + 7] = limit; } + /// Set the source IP address for the packet pub fn set_source(&mut self, ip: IpAddr) { match ip { Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -637,6 +759,7 @@ impl<'p> MutableIpv6Header<'p> { } } + /// Set the destination IP address for the packet pub fn set_destination(&mut self, ip: IpAddr) { match ip { Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -719,10 +842,13 @@ fn ipv6_header_test() { assert_eq!(refPacket.as_slice(), packet.as_slice()); } +/// Structure representing a UDP header pub struct UdpHeader<'p> { priv packet: &'p [u8], priv offset: uint } + +/// Structure representing a mutable UDP header pub struct MutableUdpHeader<'p> { priv packet: &'p mut [u8], priv offset: uint @@ -742,31 +868,38 @@ impl<'p> Packet for MutableUdpHeader<'p> { fn offset(&self) -> uint { self.offset } } +/// Trait implemented by anything which provides an interface to read UDP +/// packets pub trait UdpPacket : Packet { + /// Get the source port for the packet fn get_source(&self) -> u16 { let s1 = self.packet()[self.offset() + 0] as u16 << 8; let s2 = self.packet()[self.offset() + 1] as u16; s1 | s2 } + /// Get the destination port for the packet fn get_destination(&self) -> u16 { let d1 = self.packet()[self.offset() + 2] as u16 << 8; let d2 = self.packet()[self.offset() + 3] as u16; d1 | d2 } + /// Get the length field for the packet fn get_length(&self) -> u16 { let l1 = self.packet()[self.offset() + 4] as u16 << 8; let l2 = self.packet()[self.offset() + 5] as u16; l1 | l2 } + /// Get the checksum field for the packet fn get_checksum(&self) -> u16 { let c1 = self.packet()[self.offset() + 6] as u16 << 8; let c2 = self.packet()[self.offset() + 7] as u16; c1 | c2 } + /// Calculate the checksum for a packet built on IPv4 fn calculate_ipv4_checksum(&self, offset: uint) -> u16 { let mut sum = 0u32; let mut i = offset; @@ -806,6 +939,7 @@ pub trait UdpPacket : Packet { return !sum as u16; } + /// Calculate the checksum for a packet built on IPv6 fn calculate_ipv6_checksum(&self, offset: uint) -> u16 { let mut sum = 0u32; let mut i = offset + 8; @@ -851,36 +985,45 @@ impl<'p> UdpPacket for UdpHeader<'p> {} impl<'p> UdpPacket for MutableUdpHeader<'p> {} impl<'p> UdpHeader<'p> { + /// Construct a new UDP header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p [u8], offset: uint) -> UdpHeader<'p> { UdpHeader { packet: packet, offset: offset } } } impl<'p> MutableUdpHeader<'p> { + /// Construct a new mutable UDP header backed by the given buffer with + /// the provided offset pub fn new(packet: &'p mut [u8], offset: uint) -> MutableUdpHeader<'p> { MutableUdpHeader { packet: packet, offset: offset } } + /// Set the source port for the packet pub fn set_source(&mut self, port: u16) { self.packet[self.offset + 0] = (port >> 8) as u8; self.packet[self.offset + 1] = (port & 0xFF) as u8; } + /// Set the destination port for the packet pub fn set_destination(&mut self, port: u16) { self.packet[self.offset + 2] = (port >> 8) as u8; self.packet[self.offset + 3] = (port & 0xFF) as u8; } + /// Set the length field for the packet pub fn set_length(&mut self, len: u16) { self.packet[self.offset + 4] = (len >> 8) as u8; self.packet[self.offset + 5] = (len & 0xFF) as u8; } + /// Set the checksum field for the packet pub fn set_checksum(&mut self, checksum: u16) { self.packet[self.offset + 6] = (checksum >> 8) as u8; self.packet[self.offset + 7] = (checksum & 0xFF) as u8; } + /// Calculate a checksum for a packet backed by IPv6, then set the field pub fn ipv4_checksum(&mut self, offset: uint) { let checksum = self.calculate_ipv4_checksum(offset); // RFC 768, a checksum of zero is transmitted as all ones @@ -891,6 +1034,7 @@ impl<'p> MutableUdpHeader<'p> { } } + /// Calculate a checksum for a packet backed by IPv6 then, set the field pub fn ipv6_checksum(&mut self, offset: uint) { let checksum = self.calculate_ipv6_checksum(offset); if checksum != 0 { @@ -980,32 +1124,45 @@ fn udp_header_ipv6_test() { } +/// Represents a low-level protocol pub enum Protocol { + /// A data-link layer protocol such as ethernet DataLinkProtocol(DataLinkProto), + /// A network protocol such as IPv4 NetworkProtocol(NetworkProto), + /// A transport protocol such as UDP TransportProtocol(TransportProto) } +/// Represents a data-link layer protocol pub enum DataLinkProto { + /// Represents a plain Ethernet protocol EthernetProtocol, + /// Represents an Ethernet protocol with some fields filled automatically CookedEthernetProtocol(EtherType) } +/// Represents a network level protocol pub enum NetworkProto { + /// An IPv4 network protocol Ipv4NetworkProtocol, + /// An IPv6 network protocol Ipv6NetworkProtocol } +/// Represents a transport layer protocol pub enum TransportProto { + /// Represents a transport protocol built on top of IPv4 Ipv4TransportProtocol(IpNextHeaderProtocol), + /// Represents a transport protocol built on top of IPv6 Ipv6TransportProtocol(IpNextHeaderProtocol) } -// EtherTypes defined at: -// http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml -// These values should be used in the Ethernet EtherType field -// -// A handful of these have been selected since most are archaic and unused. +/// EtherTypes defined at: +/// http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml +/// These values should be used in the Ethernet EtherType field +/// +/// A handful of these have been selected since most are archaic and unused. pub mod EtherTypes { pub static Ipv4: u16 = 0x0800; pub static Arp: u16 = 0x0806; @@ -1016,11 +1173,11 @@ pub mod EtherTypes { pub type EtherType = u16; -// Protocol numbers as defined at: -// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml -// Above protocol numbers last updated: 2014-01-16 -// These values should be used in either the IPv4 Next Level Protocol field -// or the IPv6 Next Header field. +/// Protocol numbers as defined at: +/// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml +/// Above protocol numbers last updated: 2014-01-16 +/// These values should be used in either the IPv4 Next Level Protocol field +/// or the IPv6 Next Header field. pub mod IpNextHeaderProtocols { pub static Hopopt: u8 = 0; // IPv6 Hop-by-Hop Option [RFC2460] pub static Icmp: u8 = 1; // Internet Control Message [RFC792]