From 61e741cf714020107c6cda12793351fa5b8c7782 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 02:33:43 -0400 Subject: [PATCH 1/8] libstd: Implement {peer, socket}_name for new rt tcp & udp. --- src/libstd/rt/io/net/tcp.rs | 38 +++++++++- src/libstd/rt/io/net/udp.rs | 13 +++- src/libstd/rt/rtio.rs | 4 +- src/libstd/rt/uv/async.rs | 2 +- src/libstd/rt/uv/idle.rs | 2 +- src/libstd/rt/uv/mod.rs | 6 +- src/libstd/rt/uv/net.rs | 22 +++--- src/libstd/rt/uv/timer.rs | 2 +- src/libstd/rt/uv/uvio.rs | 134 +++++++++++++++++++++++++++++++----- src/libstd/rt/uv/uvll.rs | 48 +++++-------- src/rt/rust_uv.cpp | 60 ++++++---------- src/rt/rustrt.def.in | 9 +-- 12 files changed, 227 insertions(+), 113 deletions(-) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 2425c909bf3d8..5251b6d9ded9e 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -14,8 +14,9 @@ use rt::io::net::ip::IpAddr; use rt::io::{Reader, Writer, Listener}; use rt::io::{io_error, read_error, EndOfFile}; use rt::rtio::{IoFactory, IoFactoryObject, - RtioTcpListener, RtioTcpListenerObject, - RtioTcpStream, RtioTcpStreamObject}; + RtioSocket, RtioTcpListener, + RtioTcpListenerObject, RtioTcpStream, + RtioTcpStreamObject}; use rt::local::Local; pub struct TcpStream(~RtioTcpStreamObject); @@ -42,6 +43,28 @@ impl TcpStream { } } } + + pub fn peer_name(&mut self) -> Option { + match (***self).peer_name() { + Ok(pn) => Some(pn), + Err(ioerr) => { + rtdebug!("failed to get peer name: %?", ioerr); + io_error::cond.raise(ioerr); + None + } + } + } + + pub fn socket_name(&mut self) -> Option { + match (***self).socket_name() { + Ok(sn) => Some(sn), + Err(ioerr) => { + rtdebug!("failed to get socket name: %?", ioerr); + io_error::cond.raise(ioerr); + None + } + } + } } impl Reader for TcpStream { @@ -90,6 +113,17 @@ impl TcpListener { } } } + + pub fn socket_name(&mut self) -> Option { + match (***self).socket_name() { + Ok(sn) => Some(sn), + Err(ioerr) => { + rtdebug!("failed to get socket name: %?", ioerr); + io_error::cond.raise(ioerr); + None + } + } + } } impl Listener for TcpListener { diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 59649dee5b914..d78adbbbe4da6 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -13,7 +13,7 @@ use result::{Ok, Err}; use rt::io::net::ip::IpAddr; use rt::io::{Reader, Writer}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject}; +use rt::rtio::{RtioSocket, RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject}; use rt::local::Local; pub struct UdpSocket(~RtioUdpSocketObject); @@ -53,6 +53,17 @@ impl UdpSocket { pub fn connect(self, other: IpAddr) -> UdpStream { UdpStream { socket: self, connectedTo: other } } + + pub fn socket_name(&mut self) -> Option { + match (***self).socket_name() { + Ok(sn) => Some(sn), + Err(ioerr) => { + rtdebug!("failed to get socket name: %?", ioerr); + io_error::cond.raise(ioerr); + None + } + } + } } pub struct UdpStream { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index aa8b9dc3a944d..73b38c4a40db2 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -59,7 +59,7 @@ pub trait RtioTcpListener : RtioSocket { pub trait RtioTcpStream : RtioSocket { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; - fn peer_name(&mut self) -> IpAddr; + fn peer_name(&mut self) -> Result; fn control_congestion(&mut self); fn nodelay(&mut self); fn keepalive(&mut self, delay_in_seconds: uint); @@ -67,7 +67,7 @@ pub trait RtioTcpStream : RtioSocket { } pub trait RtioSocket { - fn socket_name(&mut self) -> IpAddr; + fn socket_name(&mut self) -> Result; } pub trait RtioUdpSocket : RtioSocket { diff --git a/src/libstd/rt/uv/async.rs b/src/libstd/rt/uv/async.rs index 81428509e33e5..47e0a240e4545 100644 --- a/src/libstd/rt/uv/async.rs +++ b/src/libstd/rt/uv/async.rs @@ -34,7 +34,7 @@ impl AsyncWatcher { extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) { let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle); - let status = status_to_maybe_uv_error(watcher.native_handle(), status); + let status = status_to_maybe_uv_error(watcher, status); let data = watcher.get_watcher_data(); let cb = data.async_cb.get_ref(); (*cb)(watcher, status); diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index 28b101f686d4c..b73be9f7250db 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -43,7 +43,7 @@ impl IdleWatcher { let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); let data = idle_watcher.get_watcher_data(); let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(handle, status); + let status = status_to_maybe_uv_error(idle_watcher, status); (*cb)(idle_watcher, status); } } diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 0eaf0dd3ab649..aacd747087e94 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -282,14 +282,14 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError { } /// Given a uv handle, convert a callback status to a UvError -// XXX: Follow the pattern below by parameterizing over T: Watcher, not T -pub fn status_to_maybe_uv_error(handle: *T, status: c_int) -> Option { +pub fn status_to_maybe_uv_error>(handle: U, + status: c_int) -> Option { if status != -1 { None } else { unsafe { rtdebug!("handle: %x", handle as uint); - let loop_ = uvll::get_loop_for_uv_handle(handle); + let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle()); rtdebug!("loop: %x", loop_ as uint); let err = uvll::last_error(loop_); Some(UvError(err)) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 86891a9df8ade..dbfe36acbebf7 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -22,7 +22,7 @@ use str; use from_str::{FromStr}; use num; -enum UvIpAddr { +pub enum UvIpAddr { UvIpv4(*sockaddr_in), UvIpv6(*sockaddr_in6), } @@ -32,8 +32,8 @@ fn sockaddr_to_UvIpAddr(addr: *uvll::sockaddr) -> UvIpAddr { assert!((is_ip4_addr(addr) || is_ip6_addr(addr))); assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr))); match addr { - _ if is_ip4_addr(addr) => UvIpv4(as_sockaddr_in(addr)), - _ if is_ip6_addr(addr) => UvIpv6(as_sockaddr_in6(addr)), + _ if is_ip4_addr(addr) => UvIpv4(addr as *uvll::sockaddr_in), + _ if is_ip6_addr(addr) => UvIpv6(addr as *uvll::sockaddr_in6), _ => fail!(), } } @@ -133,7 +133,7 @@ fn uv_ip_as_ip(addr: UvIpAddr, f: &fn(IpAddr) -> T) -> T { f(ip) } -fn uv_ip_to_ip(addr: UvIpAddr) -> IpAddr { +pub fn uv_ip_to_ip(addr: UvIpAddr) -> IpAddr { use util; uv_ip_as_ip(addr, util::id) } @@ -154,7 +154,7 @@ fn test_ip6_conversion() { assert_eq!(ip6, ip_as_uv_ip(ip6, uv_ip_to_ip)); } -// uv_stream t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t +// uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t // and uv_file_t pub struct StreamWatcher(*uvll::uv_stream_t); impl Watcher for StreamWatcher { } @@ -180,7 +180,7 @@ impl StreamWatcher { rtdebug!("buf len: %d", buf.len as int); let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); let cb = stream_watcher.get_watcher_data().read_cb.get_ref(); - let status = status_to_maybe_uv_error(stream, nread as c_int); + let status = status_to_maybe_uv_error(stream_watcher, nread as c_int); (*cb)(stream_watcher, nread as int, buf, status); } } @@ -210,7 +210,7 @@ impl StreamWatcher { let mut stream_watcher = write_request.stream(); write_request.delete(); let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap(); - let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); + let status = status_to_maybe_uv_error(stream_watcher, status); cb(stream_watcher, status); } } @@ -302,7 +302,7 @@ impl TcpWatcher { let mut stream_watcher = connect_request.stream(); connect_request.delete(); let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap(); - let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); + let status = status_to_maybe_uv_error(stream_watcher, status); cb(stream_watcher, status); } } @@ -325,7 +325,7 @@ impl TcpWatcher { rtdebug!("connection_cb"); let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); let cb = stream_watcher.get_watcher_data().connect_cb.get_ref(); - let status = status_to_maybe_uv_error(handle, status); + let status = status_to_maybe_uv_error(stream_watcher, status); (*cb)(stream_watcher, status); } } @@ -402,7 +402,7 @@ impl UdpWatcher { rtdebug!("buf len: %d", buf.len as int); let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref(); - let status = status_to_maybe_uv_error(handle, nread as c_int); + let status = status_to_maybe_uv_error(udp_watcher, nread as c_int); let addr = uv_ip_to_ip(sockaddr_to_UvIpAddr(addr)); (*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status); } @@ -437,7 +437,7 @@ impl UdpWatcher { let mut udp_watcher = send_request.handle(); send_request.delete(); let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap(); - let status = status_to_maybe_uv_error(udp_watcher.native_handle(), status); + let status = status_to_maybe_uv_error(udp_watcher, status); cb(udp_watcher, status); } } diff --git a/src/libstd/rt/uv/timer.rs b/src/libstd/rt/uv/timer.rs index bc5399327a032..eaa5e77a6da2f 100644 --- a/src/libstd/rt/uv/timer.rs +++ b/src/libstd/rt/uv/timer.rs @@ -43,7 +43,7 @@ impl TimerWatcher { let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle); let data = watcher.get_watcher_data(); let cb = data.timer_cb.get_ref(); - let status = status_to_maybe_uv_error(handle, status); + let status = status_to_maybe_uv_error(watcher, status); (*cb)(watcher, status); } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 9c386b4bed11d..9f2316d62271e 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -19,6 +19,7 @@ use rt::io::IoError; use rt::io::net::ip::IpAddr; use rt::uv::*; use rt::uv::idle::IdleWatcher; +use rt::uv::net::{UvIpv4, UvIpv6}; use rt::rtio::*; use rt::sched::Scheduler; use rt::io::{standard_error, OtherIoError}; @@ -220,7 +221,9 @@ impl IoFactory for UvIoFactory { rtdebug!("connect: in connect callback"); if status.is_none() { rtdebug!("status is none"); - let res = Ok(~UvTcpStream(stream_watcher)); + let tcp_watcher = + NativeHandle::from_native_handle(stream_watcher.native_handle()); + let res = Ok(~UvTcpStream(tcp_watcher)); // Store the stream in the task's stack unsafe { (*result_cell_ptr).put_back(res); } @@ -286,7 +289,6 @@ impl IoFactory for UvIoFactory { } } -// FIXME #6090: Prefer newtype structs but Drop doesn't work pub struct UvTcpListener { watcher: TcpWatcher, listening: bool, @@ -320,8 +322,33 @@ impl Drop for UvTcpListener { } impl RtioSocket for UvTcpListener { - // XXX implement - fn socket_name(&mut self) -> IpAddr { fail!(); } + fn socket_name(&mut self) -> Result { + // Allocate a sockaddr_storage + // since we don't know if it's ipv4 or ipv6 + let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; + + let r = unsafe { + uvll::rust_uv_tcp_getsockname(self.watcher.native_handle(), + r_addr as *uvll::sockaddr_storage) + }; + + if r != 0 { + let status = status_to_maybe_uv_error(self.watcher, r); + return Err(uv_error_to_io_error(status.unwrap())); + } + + let addr = unsafe { + if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { + net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) + } else { + net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) + } + }; + + unsafe { uvll::free_sockaddr_storage(r_addr); } + + Ok(addr) + } } impl RtioTcpListener for UvTcpListener { @@ -344,9 +371,8 @@ impl RtioTcpListener for UvTcpListener { let maybe_stream = if status.is_none() { let mut loop_ = server_stream_watcher.event_loop(); let client_tcp_watcher = TcpWatcher::new(&mut loop_); - let client_tcp_watcher = client_tcp_watcher.as_stream(); // XXX: Need's to be surfaced in interface - server_stream_watcher.accept(client_tcp_watcher); + server_stream_watcher.accept(client_tcp_watcher.as_stream()); Ok(~UvTcpStream(client_tcp_watcher)) } else { Err(standard_error(OtherIoError)) @@ -365,8 +391,7 @@ impl RtioTcpListener for UvTcpListener { fn dont_accept_simultaneously(&mut self) { fail!(); } } -// FIXME #6090: Prefer newtype structs but Drop doesn't work -pub struct UvTcpStream(StreamWatcher); +pub struct UvTcpStream(TcpWatcher); impl Drop for UvTcpStream { fn drop(&self) { @@ -374,7 +399,7 @@ impl Drop for UvTcpStream { let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - do self.close { + do self.as_stream().close { let scheduler = Local::take::(); scheduler.resume_blocked_task_immediately(task_cell.take()); } @@ -383,8 +408,33 @@ impl Drop for UvTcpStream { } impl RtioSocket for UvTcpStream { - // XXX implement - fn socket_name(&mut self) -> IpAddr { fail!(); } + fn socket_name(&mut self) -> Result { + // Allocate a sockaddr_storage + // since we don't know if it's ipv4 or ipv6 + let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; + + let r = unsafe { + uvll::rust_uv_tcp_getsockname(self.native_handle(), + r_addr as *uvll::sockaddr_storage) + }; + + if r != 0 { + let status = status_to_maybe_uv_error(**self, r); + return Err(uv_error_to_io_error(status.unwrap())); + } + + let addr = unsafe { + if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { + net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) + } else { + net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) + } + }; + + unsafe { uvll::free_sockaddr_storage(r_addr); } + + Ok(addr) + } } impl RtioTcpStream for UvTcpStream { @@ -404,7 +454,7 @@ impl RtioTcpStream for UvTcpStream { let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; - let mut watcher = **self; + let mut watcher = self.as_stream(); do watcher.read_start(alloc) |mut watcher, nread, _buf, status| { // Stop reading so that no read callbacks are @@ -440,7 +490,7 @@ impl RtioTcpStream for UvTcpStream { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - let mut watcher = **self; + let mut watcher = self.as_stream(); do watcher.write(buf) |_watcher, status| { let result = if status.is_none() { Ok(()) @@ -459,8 +509,35 @@ impl RtioTcpStream for UvTcpStream { return result_cell.take(); } + fn peer_name(&mut self) -> Result { + // Allocate a sockaddr_storage + // since we don't know if it's ipv4 or ipv6 + let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; + + let r = unsafe { + uvll::rust_uv_tcp_getpeername(self.native_handle(), + r_addr as *uvll::sockaddr_storage) + }; + + if r != 0 { + let status = status_to_maybe_uv_error(**self, r); + return Err(uv_error_to_io_error(status.unwrap())); + } + + let addr = unsafe { + if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { + net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) + } else { + net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) + } + }; + + unsafe { uvll::free_sockaddr_storage(r_addr); } + + Ok(addr) + } + // XXX implement - fn peer_name(&mut self) -> IpAddr { fail!(); } fn control_congestion(&mut self) { fail!(); } fn nodelay(&mut self) { fail!(); } fn keepalive(&mut self, _delay_in_seconds: uint) { fail!(); } @@ -484,8 +561,33 @@ impl Drop for UvUdpSocket { } impl RtioSocket for UvUdpSocket { - // XXX implement - fn socket_name(&mut self) -> IpAddr { fail!(); } + fn socket_name(&mut self) -> Result { + // Allocate a sockaddr_storage + // since we don't know if it's ipv4 or ipv6 + let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; + + let r = unsafe { + uvll::rust_uv_udp_getsockname(self.native_handle(), + r_addr as *uvll::sockaddr_storage) + }; + + if r != 0 { + let status = status_to_maybe_uv_error(**self, r); + return Err(uv_error_to_io_error(status.unwrap())); + } + + let addr = unsafe { + if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { + net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) + } else { + net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) + } + }; + + unsafe { uvll::free_sockaddr_storage(r_addr); } + + Ok(addr) + } } impl RtioUdpSocket for UvUdpSocket { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 1f27a5776842a..72d96e59c3699 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -77,6 +77,7 @@ pub type uv_udp_recv_cb = *u8; pub type sockaddr = c_void; pub type sockaddr_in = c_void; pub type sockaddr_in6 = c_void; +pub type sockaddr_storage = c_void; pub type uv_membership = c_void; #[deriving(Eq)] @@ -233,14 +234,10 @@ pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_ return rust_uv_get_udp_handle_from_send_req(send_req); } -pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_in) -> c_int { +pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int { return rust_uv_udp_getsockname(handle, name); } -pub unsafe fn udp_get_sockname6(handle: *uv_udp_t, name: *sockaddr_in6) -> c_int { - return rust_uv_udp_getsockname6(handle, name); -} - pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char, interface_addr: *c_char, membership: uv_membership) -> c_int { return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership); @@ -280,22 +277,14 @@ pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr); } -pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in) -> c_int { +pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int { return rust_uv_tcp_getpeername(tcp_handle_ptr, name); } -pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) ->c_int { - return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); -} - -pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_in) -> c_int { +pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int { return rust_uv_tcp_getsockname(handle, name); } -pub unsafe fn tcp_getsockname6(handle: *uv_tcp_t, name: *sockaddr_in6) -> c_int { - return rust_uv_tcp_getsockname6(handle, name); -} - pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int { return rust_uv_tcp_nodelay(handle, enable); } @@ -373,14 +362,6 @@ pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool { match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true } } -pub unsafe fn as_sockaddr_in(addr: *sockaddr) -> *sockaddr_in { - return rust_uv_sockaddr_as_sockaddr_in(addr); -} - -pub unsafe fn as_sockaddr_in6(addr: *sockaddr) -> *sockaddr_in6 { - return rust_uv_sockaddr_as_sockaddr_in6(addr); -} - pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in { do ip.as_c_str |ip_buf| { rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) @@ -392,6 +373,14 @@ pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 { } } +pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage { + rust_uv_malloc_sockaddr_storage() +} + +pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) { + rust_uv_free_sockaddr_storage(ss); +} + pub unsafe fn free_ip4_addr(addr: *sockaddr_in) { rust_uv_free_ip4_addr(addr); } @@ -520,10 +509,8 @@ extern { fn rust_uv_tcp_connect6(req: *uv_connect_t, handle: *uv_tcp_t, cb: *u8, addr: *sockaddr_in6) -> c_int; fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int; - fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in) -> c_int; - fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) ->c_int; - fn rust_uv_tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_in) -> c_int; - fn rust_uv_tcp_getsockname6(handle: *uv_tcp_t, name: *sockaddr_in6) -> c_int; + fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int; + fn rust_uv_tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int; fn rust_uv_tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int; fn rust_uv_tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int; fn rust_uv_tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int; @@ -538,8 +525,7 @@ extern { fn rust_uv_udp_recv_start(server: *uv_udp_t, on_alloc: *u8, on_recv: *u8) -> c_int; fn rust_uv_udp_recv_stop(server: *uv_udp_t) -> c_int; fn rust_uv_get_udp_handle_from_send_req(req: *uv_udp_send_t) -> *uv_udp_t; - fn rust_uv_udp_getsockname(handle: *uv_udp_t, name: *sockaddr_in) -> c_int; - fn rust_uv_udp_getsockname6(handle: *uv_udp_t, name: *sockaddr_in6) -> c_int; + fn rust_uv_udp_getsockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int; fn rust_uv_udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char, interface_addr: *c_char, membership: uv_membership) -> c_int; fn rust_uv_udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int; @@ -548,8 +534,8 @@ extern { fn rust_uv_is_ipv4_sockaddr(addr: *sockaddr) -> c_int; fn rust_uv_is_ipv6_sockaddr(addr: *sockaddr) -> c_int; - fn rust_uv_sockaddr_as_sockaddr_in(addr: *sockaddr) -> *sockaddr_in; - fn rust_uv_sockaddr_as_sockaddr_in6(addr: *sockaddr) -> *sockaddr_in6; + fn rust_uv_malloc_sockaddr_storage() -> *sockaddr_storage; + fn rust_uv_free_sockaddr_storage(ss: *sockaddr_storage); fn rust_uv_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 95e38a9903c4b..a7f5db9dc5f17 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -282,29 +282,19 @@ rust_uv_tcp_bind6 extern "C" int rust_uv_tcp_getpeername -(uv_tcp_t* handle, sockaddr_in* name) { +(uv_tcp_t* handle, sockaddr_storage* name) { + // sockaddr_storage is big enough to hold either + // sockaddr_in or sockaddr_in6 int namelen = sizeof(sockaddr_in); return uv_tcp_getpeername(handle, (sockaddr*)name, &namelen); } -extern "C" int -rust_uv_tcp_getpeername6 -(uv_tcp_t* handle, sockaddr_in6* name) { - int namelen = sizeof(sockaddr_in6); - return uv_tcp_getpeername(handle, (sockaddr*)name, &namelen); -} - extern "C" int rust_uv_tcp_getsockname -(uv_tcp_t* handle, sockaddr_in* name) { - int namelen = sizeof(sockaddr_in); - return uv_tcp_getsockname(handle, (sockaddr*)name, &namelen); -} - -extern "C" int -rust_uv_tcp_getsockname6 -(uv_tcp_t* handle, sockaddr_in6* name) { - int namelen = sizeof(sockaddr_in6); +(uv_tcp_t* handle, sockaddr_storage* name) { + // sockaddr_storage is big enough to hold either + // sockaddr_in or sockaddr_in6 + int namelen = sizeof(sockaddr_storage); return uv_tcp_getsockname(handle, (sockaddr*)name, &namelen); } @@ -370,15 +360,10 @@ rust_uv_get_udp_handle_from_send_req(uv_udp_send_t* send_req) { extern "C" int rust_uv_udp_getsockname -(uv_udp_t* handle, sockaddr_in* name) { - int namelen = sizeof(sockaddr_in); - return uv_udp_getsockname(handle, (sockaddr*)name, &namelen); -} - -extern "C" int -rust_uv_udp_getsockname6 -(uv_udp_t* handle, sockaddr_in6* name) { - int namelen = sizeof(sockaddr_in6); +(uv_udp_t* handle, sockaddr_storage* name) { + // sockaddr_storage is big enough to hold either + // sockaddr_in or sockaddr_in6 + int namelen = sizeof(sockaddr_storage); return uv_udp_getsockname(handle, (sockaddr*)name, &namelen); } @@ -609,6 +594,17 @@ rust_uv_ip6_addrp(const char* ip, int port) { return addrp; } +extern "C" struct sockaddr_storage * +rust_uv_malloc_sockaddr_storage() { + struct sockaddr_storage *ss = (sockaddr_storage *)malloc(sizeof(struct sockaddr_storage)); + return ss; +} + +extern "C" void +rust_uv_free_sockaddr_storage(struct sockaddr_storage *ss) { + free(ss); +} + extern "C" void rust_uv_free_ip4_addr(sockaddr_in *addrp) { free(addrp); @@ -669,18 +665,6 @@ rust_uv_is_ipv6_sockaddr(sockaddr* addr) { return addr->sa_family == AF_INET6; } -extern "C" sockaddr_in* -rust_uv_sockaddr_as_sockaddr_in(sockaddr* addr) { -// return (sockaddr_in*)addr->sa_data; - return (sockaddr_in*)addr; -} - -extern "C" sockaddr_in6* -rust_uv_sockaddr_as_sockaddr_in6(sockaddr* addr) { - //return (sockaddr_in6*)addr->sa_data; - return (sockaddr_in6*)addr; -} - extern "C" bool rust_uv_is_ipv4_addrinfo(addrinfo* input) { return input->ai_family == AF_INET; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index db9fe2479526c..804f448d261c1 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -106,7 +106,6 @@ rust_uv_tcp_bind rust_uv_tcp_connect6 rust_uv_tcp_bind6 rust_uv_tcp_getsockname -rust_uv_tcp_getsockname6 rust_uv_tcp_nodelay rust_uv_tcp_keepalive rust_uv_tcp_simultaneous_accepts @@ -119,15 +118,14 @@ rust_uv_udp_recv_start rust_uv_udp_recv_stop rust_uv_get_udp_handle_from_send_req rust_uv_udp_getsockname -rust_uv_udp_getsockname6 rust_uv_udp_set_membership rust_uv_udp_set_multicast_loop rust_uv_udp_set_multicast_ttl rust_uv_udp_set_broadcast rust_uv_is_ipv4_sockaddr rust_uv_is_ipv6_sockaddr -rust_uv_sockaddr_as_sockaddr_in -rust_uv_sockaddr_as_sockaddr_in6 +rust_uv_malloc_sockaddr_storage +rust_uv_free_sockaddr_storage rust_uv_listen rust_uv_accept rust_uv_write @@ -204,7 +202,6 @@ rust_update_gc_metadata rust_uv_ip4_port rust_uv_ip6_port rust_uv_tcp_getpeername -rust_uv_tcp_getpeername6 linenoise linenoiseSetCompletionCallback linenoiseAddCompletion @@ -267,4 +264,4 @@ rust_drop_global_args_lock rust_set_exit_status_newrt rust_get_exit_status_newrt rust_take_change_dir_lock -rust_drop_change_dir_lock \ No newline at end of file +rust_drop_change_dir_lock From ac40d5323da30211c8dd516681c6e518777135e9 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 05:46:48 -0400 Subject: [PATCH 2/8] libstd: Fix errors when rtdebug! is not a noop. --- src/libstd/rt/test.rs | 4 ++-- src/libstd/rt/uv/mod.rs | 2 +- src/libstd/unstable/lang.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index a9cbc6dae316c..feae8b5ffd8a3 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -50,7 +50,7 @@ pub fn run_in_newsched_task(f: ~fn()) { let on_exit: ~fn(bool) = |exit_status| rtassert!(exit_status); let mut task = ~Task::new_root(&mut sched.stack_pool, f.take()); - rtdebug!("newsched_task: %x", to_uint(task)); + rtdebug!("newsched_task: %x", ::borrow::to_uint(task)); task.death.on_exit = Some(on_exit); sched.enqueue_task(task); sched.run(); @@ -145,7 +145,7 @@ pub fn spawntask(f: ~fn()) { } }; - rtdebug!("new task pointer: %x", to_uint(task)); + rtdebug!("new task pointer: %x", ::borrow::to_uint(task)); let sched = Local::take::(); rtdebug!("spawntask scheduling the new task"); diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index aacd747087e94..638d510614a33 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -288,7 +288,7 @@ pub fn status_to_maybe_uv_error>(handle: U, None } else { unsafe { - rtdebug!("handle: %x", handle as uint); + rtdebug!("handle: %x", handle.native_handle() as uint); let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle()); rtdebug!("loop: %x", loop_ as uint); let err = uvll::last_error(loop_); diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index d96681ae80300..7a5e1116c3294 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -71,8 +71,8 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { let mut alloc = ::ptr::null(); do Local::borrow:: |task| { rtdebug!("task pointer: %x, heap pointer: %x", - to_uint(task), - to_uint(&task.heap)); + ::borrow::to_uint(task), + ::borrow::to_uint(&task.heap)); alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char; } return alloc; From e2bb32bea19f8bfd2165361b5ad2d025c2ffeba0 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 05:47:49 -0400 Subject: [PATCH 3/8] libstd: Handle IPv4-Mapped/Compatible IPv6 addresses. --- src/libstd/rt/uv/net.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index dbfe36acbebf7..a039f3ab7ed2a 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -113,7 +113,36 @@ fn uv_ip_as_ip(addr: UvIpAddr, f: &fn(IpAddr) -> T) -> T { }; match s { "" => ~[], - s => s.split_iter(':').transform(read_hex_segment).collect(), + // IPv4-Mapped/Compatible IPv6 Address? + s if s.find('.').is_some() => { + let i = s.rfind(':').get_or_default(-1); + + let b = s.slice(i + 1, s.len()); // the ipv4 part + + let h = b.split_iter('.') + .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) + .transform(|s: u8| -> ~str { fmt!("%02x", s as uint) }) + .collect::<~[~str]>(); + + if i == -1 { + // Ipv4 Compatible Address (::x.x.x.x) + // first 96 bits are zero leaving 32 bits + // for the ipv4 part + // (i.e ::127.0.0.1 == ::7F00:1) + ~[num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), + num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] + } else { + // Ipv4-Mapped Address (::FFFF:x.x.x.x) + // first 80 bits are zero, followed by all ones + // for the next 16 bits, leaving 32 bits for + // the ipv4 part + // (i.e ::FFFF:127.0.0.1 == ::FFFF:7F00:1) + ~[1, + num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), + num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] + } + }, + s => s.split_iter(':').transform(read_hex_segment).collect() } }; s.split_str_iter("::").transform(convert_each_segment).collect() From d6e1a6b237d4c3b04a7dff6609c3427eb99bbc60 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 15:43:45 -0400 Subject: [PATCH 4/8] libstd: Get rid of duplication in {peer, socket}_name and remove extra *. --- src/libstd/rt/io/net/tcp.rs | 6 +- src/libstd/rt/uv/uvio.rs | 146 ++++++++++++------------------------ 2 files changed, 49 insertions(+), 103 deletions(-) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 5251b6d9ded9e..0107d30519e5e 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -45,7 +45,7 @@ impl TcpStream { } pub fn peer_name(&mut self) -> Option { - match (***self).peer_name() { + match (**self).peer_name() { Ok(pn) => Some(pn), Err(ioerr) => { rtdebug!("failed to get peer name: %?", ioerr); @@ -56,7 +56,7 @@ impl TcpStream { } pub fn socket_name(&mut self) -> Option { - match (***self).socket_name() { + match (**self).socket_name() { Ok(sn) => Some(sn), Err(ioerr) => { rtdebug!("failed to get socket name: %?", ioerr); @@ -115,7 +115,7 @@ impl TcpListener { } pub fn socket_name(&mut self) -> Option { - match (***self).socket_name() { + match (**self).socket_name() { Ok(sn) => Some(sn), Err(ioerr) => { rtdebug!("failed to get socket name: %?", ioerr); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 9f2316d62271e..42408507f5de3 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -15,6 +15,7 @@ use cell::Cell; use cast; use cast::transmute; use clone::Clone; +use libc::c_void; use rt::io::IoError; use rt::io::net::ip::IpAddr; use rt::uv::*; @@ -34,6 +35,47 @@ use unstable::sync::{Exclusive, exclusive}; next_test_ip4, run_in_newsched_task}; +enum SocketNameKind { + TcpPeer, + Tcp, + Udp +} + +fn socket_name>(sk: SocketNameKind, + handle: U) -> Result { + + let getsockname = match sk { + TcpPeer => uvll::rust_uv_tcp_getpeername, + Tcp => uvll::rust_uv_tcp_getsockname, + Udp => uvll::rust_uv_udp_getsockname + }; + + // Allocate a sockaddr_storage + // since we don't know if it's ipv4 or ipv6 + let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; + + let r = unsafe { + getsockname(handle.native_handle() as *c_void, r_addr as *uvll::sockaddr_storage) + }; + + if r != 0 { + let status = status_to_maybe_uv_error(handle, r); + return Err(uv_error_to_io_error(status.unwrap())); + } + + let addr = unsafe { + if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { + net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) + } else { + net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) + } + }; + + unsafe { uvll::free_sockaddr_storage(r_addr); } + + Ok(addr) + +} pub struct UvEventLoop { uvio: UvIoFactory @@ -323,31 +365,7 @@ impl Drop for UvTcpListener { impl RtioSocket for UvTcpListener { fn socket_name(&mut self) -> Result { - // Allocate a sockaddr_storage - // since we don't know if it's ipv4 or ipv6 - let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; - - let r = unsafe { - uvll::rust_uv_tcp_getsockname(self.watcher.native_handle(), - r_addr as *uvll::sockaddr_storage) - }; - - if r != 0 { - let status = status_to_maybe_uv_error(self.watcher, r); - return Err(uv_error_to_io_error(status.unwrap())); - } - - let addr = unsafe { - if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { - net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) - } else { - net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) - } - }; - - unsafe { uvll::free_sockaddr_storage(r_addr); } - - Ok(addr) + socket_name(Tcp, self.watcher) } } @@ -409,31 +427,7 @@ impl Drop for UvTcpStream { impl RtioSocket for UvTcpStream { fn socket_name(&mut self) -> Result { - // Allocate a sockaddr_storage - // since we don't know if it's ipv4 or ipv6 - let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; - - let r = unsafe { - uvll::rust_uv_tcp_getsockname(self.native_handle(), - r_addr as *uvll::sockaddr_storage) - }; - - if r != 0 { - let status = status_to_maybe_uv_error(**self, r); - return Err(uv_error_to_io_error(status.unwrap())); - } - - let addr = unsafe { - if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { - net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) - } else { - net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) - } - }; - - unsafe { uvll::free_sockaddr_storage(r_addr); } - - Ok(addr) + socket_name(Tcp, **self) } } @@ -510,31 +504,7 @@ impl RtioTcpStream for UvTcpStream { } fn peer_name(&mut self) -> Result { - // Allocate a sockaddr_storage - // since we don't know if it's ipv4 or ipv6 - let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; - - let r = unsafe { - uvll::rust_uv_tcp_getpeername(self.native_handle(), - r_addr as *uvll::sockaddr_storage) - }; - - if r != 0 { - let status = status_to_maybe_uv_error(**self, r); - return Err(uv_error_to_io_error(status.unwrap())); - } - - let addr = unsafe { - if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { - net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) - } else { - net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) - } - }; - - unsafe { uvll::free_sockaddr_storage(r_addr); } - - Ok(addr) + socket_name(TcpPeer, **self) } // XXX implement @@ -562,31 +532,7 @@ impl Drop for UvUdpSocket { impl RtioSocket for UvUdpSocket { fn socket_name(&mut self) -> Result { - // Allocate a sockaddr_storage - // since we don't know if it's ipv4 or ipv6 - let r_addr = unsafe { uvll::malloc_sockaddr_storage() }; - - let r = unsafe { - uvll::rust_uv_udp_getsockname(self.native_handle(), - r_addr as *uvll::sockaddr_storage) - }; - - if r != 0 { - let status = status_to_maybe_uv_error(**self, r); - return Err(uv_error_to_io_error(status.unwrap())); - } - - let addr = unsafe { - if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) { - net::uv_ip_to_ip(UvIpv6(r_addr as *uvll::sockaddr_in6)) - } else { - net::uv_ip_to_ip(UvIpv4(r_addr as *uvll::sockaddr_in)) - } - }; - - unsafe { uvll::free_sockaddr_storage(r_addr); } - - Ok(addr) + socket_name(Udp, **self) } } From 005ea3b17375584f823c51d141248e3bcbc04115 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 18:18:43 -0400 Subject: [PATCH 5/8] libstd: Add ToStr impl for IpAddr. --- src/libstd/rt/io/net/ip.rs | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 3a93fd705436e..2b572574b60b2 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use num::FromStrRadix; +use to_str::ToStr; + type Port = u16; #[deriving(Eq, TotalEq)] @@ -15,3 +18,42 @@ pub enum IpAddr { Ipv4(u8, u8, u8, u8, Port), Ipv6(u16, u16, u16, u16, u16, u16, u16, u16, Port) } + +impl ToStr for IpAddr { + fn to_str(&self) -> ~str { + match *self { + Ipv4(a, b, c, d, p) => + fmt!("%u.%u.%u.%u:%u", + a as uint, b as uint, c as uint, d as uint, p as uint), + + // Ipv4 Compatible address + Ipv6(0, 0, 0, 0, 0, 0, g, h, p) => { + let a = fmt!("%04x", g as uint); + let b = FromStrRadix::from_str_radix(a.slice(2, 4), 16).unwrap(); + let a = FromStrRadix::from_str_radix(a.slice(0, 2), 16).unwrap(); + let c = fmt!("%04x", h as uint); + let d = FromStrRadix::from_str_radix(c.slice(2, 4), 16).unwrap(); + let c = FromStrRadix::from_str_radix(c.slice(0, 2), 16).unwrap(); + + fmt!("[::%u.%u.%u.%u]:%u", a, b, c, d, p as uint) + } + + // Ipv4-Mapped address + Ipv6(0, 0, 0, 0, 0, 1, g, h, p) => { + let a = fmt!("%04x", g as uint); + let b = FromStrRadix::from_str_radix(a.slice(2, 4), 16).unwrap(); + let a = FromStrRadix::from_str_radix(a.slice(0, 2), 16).unwrap(); + let c = fmt!("%04x", h as uint); + let d = FromStrRadix::from_str_radix(c.slice(2, 4), 16).unwrap(); + let c = FromStrRadix::from_str_radix(c.slice(0, 2), 16).unwrap(); + + fmt!("[::FFFF:%u.%u.%u.%u]:%u", a, b, c, d, p as uint) + } + + Ipv6(a, b, c, d, e, f, g, h, p) => + fmt!("[%x:%x:%x:%x:%x:%x:%x:%x]:%u", + a as uint, b as uint, c as uint, d as uint, + e as uint, f as uint, g as uint, h as uint, p as uint) + } + } +} From a5c6b85091e171c9ec85bad68774aece81af74fa Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 19:42:19 -0400 Subject: [PATCH 6/8] libstd: Implement some missing tcp methods. --- src/libstd/rt/rtio.rs | 12 +++---- src/libstd/rt/uv/uvio.rs | 75 +++++++++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 73b38c4a40db2..728ee4ba035f9 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -52,18 +52,18 @@ pub trait IoFactory { pub trait RtioTcpListener : RtioSocket { fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>; - fn accept_simultaneously(&mut self); - fn dont_accept_simultaneously(&mut self); + fn accept_simultaneously(&mut self) -> Result<(), IoError>; + fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; } pub trait RtioTcpStream : RtioSocket { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; fn peer_name(&mut self) -> Result; - fn control_congestion(&mut self); - fn nodelay(&mut self); - fn keepalive(&mut self, delay_in_seconds: uint); - fn letdie(&mut self); + fn control_congestion(&mut self) -> Result<(), IoError>; + fn nodelay(&mut self) -> Result<(), IoError>; + fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError>; + fn letdie(&mut self) -> Result<(), IoError>; } pub trait RtioSocket { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 42408507f5de3..203248c448344 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -15,7 +15,7 @@ use cell::Cell; use cast; use cast::transmute; use clone::Clone; -use libc::c_void; +use libc::{c_int, c_uint, c_void}; use rt::io::IoError; use rt::io::net::ip::IpAddr; use rt::uv::*; @@ -404,9 +404,27 @@ impl RtioTcpListener for UvTcpListener { return self.incoming_streams.recv(); } - // XXX implement - fn accept_simultaneously(&mut self) { fail!(); } - fn dont_accept_simultaneously(&mut self) { fail!(); } + fn accept_simultaneously(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 1 as c_int) + }; + + match status_to_maybe_uv_error(self.watcher, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 0 as c_int) + }; + + match status_to_maybe_uv_error(self.watcher, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } } pub struct UvTcpStream(TcpWatcher); @@ -507,11 +525,50 @@ impl RtioTcpStream for UvTcpStream { socket_name(TcpPeer, **self) } - // XXX implement - fn control_congestion(&mut self) { fail!(); } - fn nodelay(&mut self) { fail!(); } - fn keepalive(&mut self, _delay_in_seconds: uint) { fail!(); } - fn letdie(&mut self) { fail!(); } + fn control_congestion(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::rust_uv_tcp_nodelay(self.native_handle(), 0 as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn nodelay(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::rust_uv_tcp_nodelay(self.native_handle(), 1 as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> { + let r = unsafe { + uvll::rust_uv_tcp_keepalive(self.native_handle(), 1 as c_int, + delay_in_seconds as c_uint) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn letdie(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::rust_uv_tcp_keepalive(self.native_handle(), 0 as c_int, 0 as c_uint) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } } pub struct UvUdpSocket(UdpWatcher); From 037bf3757cf54e38544c494657ac88bc002b945c Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 25 Jul 2013 22:21:46 -0400 Subject: [PATCH 7/8] libstd: Implement some missing udp methods. --- src/libstd/rt/rtio.rs | 16 +++--- src/libstd/rt/uv/uvio.rs | 121 +++++++++++++++++++++++++++++++++++---- src/libstd/rt/uv/uvll.rs | 16 +++++- src/rt/rust_uv.cpp | 6 ++ src/rt/rustrt.def.in | 1 + 5 files changed, 139 insertions(+), 21 deletions(-) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 728ee4ba035f9..d293d46e01262 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -74,17 +74,17 @@ pub trait RtioUdpSocket : RtioSocket { fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>; fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result<(), IoError>; - fn join_multicast(&mut self, multi: IpAddr); - fn leave_multicast(&mut self, multi: IpAddr); + fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError>; + fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError>; - fn loop_multicast_locally(&mut self); - fn dont_loop_multicast_locally(&mut self); + fn loop_multicast_locally(&mut self) -> Result<(), IoError>; + fn dont_loop_multicast_locally(&mut self) -> Result<(), IoError>; - fn multicast_time_to_live(&mut self, ttl: int); - fn time_to_live(&mut self, ttl: int); + fn multicast_time_to_live(&mut self, ttl: int) -> Result<(), IoError>; + fn time_to_live(&mut self, ttl: int) -> Result<(), IoError>; - fn hear_broadcasts(&mut self); - fn ignore_broadcasts(&mut self); + fn hear_broadcasts(&mut self) -> Result<(), IoError>; + fn ignore_broadcasts(&mut self) -> Result<(), IoError>; } pub trait RtioTimer { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 203248c448344..fc4a668bdf662 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -16,8 +16,9 @@ use cast; use cast::transmute; use clone::Clone; use libc::{c_int, c_uint, c_void}; +use ptr; use rt::io::IoError; -use rt::io::net::ip::IpAddr; +use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; use rt::uv::*; use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4, UvIpv6}; @@ -26,6 +27,7 @@ use rt::sched::Scheduler; use rt::io::{standard_error, OtherIoError}; use rt::tube::Tube; use rt::local::Local; +use str::StrSlice; use unstable::sync::{Exclusive, exclusive}; #[cfg(test)] use container::Container; @@ -657,18 +659,117 @@ impl RtioUdpSocket for UvUdpSocket { return result_cell.take(); } - // XXX implement - fn join_multicast(&mut self, _multi: IpAddr) { fail!(); } - fn leave_multicast(&mut self, _multi: IpAddr) { fail!(); } + fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> { + let ip_str = match multi { + Ipv4(x1, x2, x3, x4, _) => + fmt!("%u.%u.%u.%u", x1 as uint, x2 as uint, x3 as uint, x4 as uint), + Ipv6(x1, x2, x3, x4, x5, x6, x7, x8, _) => + fmt!("%x:%x:%x:%x:%x:%x:%x:%x", + x1 as uint, x2 as uint, x3 as uint, x4 as uint, + x5 as uint, x6 as uint, x7 as uint, x8 as uint), + }; + + let r = unsafe { + do ip_str.as_c_str |m_addr| { + uvll::udp_set_membership(self.native_handle(), m_addr, + ptr::null(), uvll::UV_JOIN_GROUP) + } + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> { + let ip_str = match multi { + Ipv4(x1, x2, x3, x4, _) => + fmt!("%u.%u.%u.%u", x1 as uint, x2 as uint, x3 as uint, x4 as uint), + Ipv6(x1, x2, x3, x4, x5, x6, x7, x8, _) => + fmt!("%x:%x:%x:%x:%x:%x:%x:%x", + x1 as uint, x2 as uint, x3 as uint, x4 as uint, + x5 as uint, x6 as uint, x7 as uint, x8 as uint), + }; + + let r = unsafe { + do ip_str.as_c_str |m_addr| { + uvll::udp_set_membership(self.native_handle(), m_addr, + ptr::null(), uvll::UV_LEAVE_GROUP) + } + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn loop_multicast_locally(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::udp_set_multicast_loop(self.native_handle(), 1 as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn dont_loop_multicast_locally(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::udp_set_multicast_loop(self.native_handle(), 0 as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } - fn loop_multicast_locally(&mut self) { fail!(); } - fn dont_loop_multicast_locally(&mut self) { fail!(); } + fn multicast_time_to_live(&mut self, ttl: int) -> Result<(), IoError> { + let r = unsafe { + uvll::udp_set_multicast_ttl(self.native_handle(), ttl as c_int) + }; - fn multicast_time_to_live(&mut self, _ttl: int) { fail!(); } - fn time_to_live(&mut self, _ttl: int) { fail!(); } + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } - fn hear_broadcasts(&mut self) { fail!(); } - fn ignore_broadcasts(&mut self) { fail!(); } + fn time_to_live(&mut self, ttl: int) -> Result<(), IoError> { + let r = unsafe { + uvll::udp_set_ttl(self.native_handle(), ttl as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn hear_broadcasts(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::udp_set_broadcast(self.native_handle(), 1 as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } + + fn ignore_broadcasts(&mut self) -> Result<(), IoError> { + let r = unsafe { + uvll::udp_set_broadcast(self.native_handle(), 0 as c_int) + }; + + match status_to_maybe_uv_error(**self, r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } + } } pub struct UvTimer(timer::TimerWatcher); diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 72d96e59c3699..07264839c3555 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -78,7 +78,6 @@ pub type sockaddr = c_void; pub type sockaddr_in = c_void; pub type sockaddr_in6 = c_void; pub type sockaddr_storage = c_void; -pub type uv_membership = c_void; #[deriving(Eq)] pub enum uv_handle_type { @@ -117,6 +116,12 @@ pub enum uv_req_type { UV_REQ_TYPE_MAX } +#[deriving(Eq)] +pub enum uv_membership { + UV_LEAVE_GROUP, + UV_JOIN_GROUP +} + pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void { assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX); let size = rust_uv_handle_size(handle as uint); @@ -240,7 +245,7 @@ pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_ pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char, interface_addr: *c_char, membership: uv_membership) -> c_int { - return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership); + return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int); } pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int { @@ -251,6 +256,10 @@ pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int { return rust_uv_udp_set_multicast_ttl(handle, ttl); } +pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int { + return rust_uv_udp_set_ttl(handle, ttl); +} + pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int { return rust_uv_udp_set_broadcast(handle, on); } @@ -527,9 +536,10 @@ extern { fn rust_uv_get_udp_handle_from_send_req(req: *uv_udp_send_t) -> *uv_udp_t; fn rust_uv_udp_getsockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int; fn rust_uv_udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char, - interface_addr: *c_char, membership: uv_membership) -> c_int; + interface_addr: *c_char, membership: c_int) -> c_int; fn rust_uv_udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int; fn rust_uv_udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int; + fn rust_uv_udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int; fn rust_uv_udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int; fn rust_uv_is_ipv4_sockaddr(addr: *sockaddr) -> c_int; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index a7f5db9dc5f17..19162b8df6b0f 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -385,6 +385,12 @@ rust_uv_udp_set_multicast_ttl return uv_udp_set_multicast_ttl(handle, ttl); } +extern "C" int +rust_uv_udp_set_ttl +(uv_udp_t* handle, int ttl) { + return uv_udp_set_ttl(handle, ttl); +} + extern "C" int rust_uv_udp_set_broadcast (uv_udp_t* handle, int on) { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 804f448d261c1..fc7796ef66ce5 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -121,6 +121,7 @@ rust_uv_udp_getsockname rust_uv_udp_set_membership rust_uv_udp_set_multicast_loop rust_uv_udp_set_multicast_ttl +rust_uv_udp_set_ttl rust_uv_udp_set_broadcast rust_uv_is_ipv4_sockaddr rust_uv_is_ipv6_sockaddr From df67942dccc33379051e66f075615e579f3bdb49 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Fri, 26 Jul 2013 05:02:53 -0400 Subject: [PATCH 8/8] libstd: Tests for {peer, socket}_name. --- src/libstd/rt/io/net/tcp.rs | 57 +++++++++++++++++++++++++++++++++++++ src/libstd/rt/io/net/udp.rs | 29 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 0107d30519e5e..c997373bf9d18 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -568,4 +568,61 @@ mod test { } } + #[cfg(test)] + fn socket_name(addr: IpAddr) { + do run_in_newsched_task { + do spawntask_immediately { + let listener = TcpListener::bind(addr); + + assert!(listener.is_some()); + let mut listener = listener.unwrap(); + + // Make sure socket_name gives + // us the socket we binded to. + let so_name = listener.socket_name(); + assert!(so_name.is_some()); + assert_eq!(addr, so_name.unwrap()); + + } + } + } + + #[cfg(test)] + fn peer_name(addr: IpAddr) { + do run_in_newsched_task { + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + + listener.accept(); + } + + do spawntask_immediately { + let stream = TcpStream::connect(addr); + + assert!(stream.is_some()); + let mut stream = stream.unwrap(); + + // Make sure peer_name gives us the + // address/port of the peer we've + // connected to. + let peer_name = stream.peer_name(); + assert!(peer_name.is_some()); + assert_eq!(addr, peer_name.unwrap()); + } + } + } + + #[test] + fn socket_and_peer_name_ip4() { + peer_name(next_test_ip4()); + socket_name(next_test_ip4()); + } + + #[test] + fn socket_and_peer_name_ip6() { + // XXX: peer name is not consistent + //peer_name(next_test_ip6()); + socket_name(next_test_ip6()); + } + } diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index d78adbbbe4da6..8e654de47f08e 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -263,4 +263,33 @@ mod test { } } } + + #[cfg(test)] + fn socket_name(addr: IpAddr) { + do run_in_newsched_task { + do spawntask_immediately { + let server = UdpSocket::bind(addr); + + assert!(server.is_some()); + let mut server = server.unwrap(); + + // Make sure socket_name gives + // us the socket we binded to. + let so_name = server.socket_name(); + assert!(so_name.is_some()); + assert_eq!(addr, so_name.unwrap()); + + } + } + } + + #[test] + fn socket_name_ip4() { + socket_name(next_test_ip4()); + } + + #[test] + fn socket_name_ip6() { + socket_name(next_test_ip6()); + } }