From eb11274919f96331bc21702ce95e77e973d76109 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 12 Jun 2013 14:15:44 -0700 Subject: [PATCH 01/32] Removing redundant libuv bindings --- src/libstd/rt/uvio.rs | 459 ------------------------------------------ src/libstd/rt/uvll.rs | 443 ---------------------------------------- 2 files changed, 902 deletions(-) delete mode 100644 src/libstd/rt/uvio.rs delete mode 100644 src/libstd/rt/uvll.rs diff --git a/src/libstd/rt/uvio.rs b/src/libstd/rt/uvio.rs deleted file mode 100644 index 24bffd8d1cd..00000000000 --- a/src/libstd/rt/uvio.rs +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2013 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::*; -use result::*; - -use super::io::net::ip::IpAddr; -use super::uv::*; -use super::rtio::*; -use ops::Drop; -use old_iter::CopyableIter; -use cell::{Cell, empty_cell}; -use cast::transmute; -use super::sched::{Scheduler, local_sched}; - -#[cfg(test)] use container::Container; -#[cfg(test)] use uint; -#[cfg(test)] use unstable::run_in_bare_thread; -#[cfg(test)] use super::test::*; - -pub struct UvEventLoop { - uvio: UvIoFactory -} - -pub impl UvEventLoop { - fn new() -> UvEventLoop { - UvEventLoop { - uvio: UvIoFactory(Loop::new()) - } - } - - /// A convenience constructor - fn new_scheduler() -> Scheduler { - Scheduler::new(~UvEventLoop::new()) - } -} - -impl Drop for UvEventLoop { - fn finalize(&self) { - // XXX: Need mutable finalizer - let this = unsafe { - transmute::<&UvEventLoop, &mut UvEventLoop>(self) - }; - this.uvio.uv_loop().close(); - } -} - -impl EventLoop for UvEventLoop { - - fn run(&mut self) { - self.uvio.uv_loop().run(); - } - - fn callback(&mut self, f: ~fn()) { - let mut idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); - do idle_watcher.start |idle_watcher, status| { - assert!(status.is_none()); - let mut idle_watcher = idle_watcher; - idle_watcher.stop(); - idle_watcher.close(); - f(); - } - } - - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { - Some(&mut self.uvio) - } -} - -#[test] -fn test_callback_run_once() { - do run_in_bare_thread { - let mut event_loop = UvEventLoop::new(); - let mut count = 0; - let count_ptr: *mut int = &mut count; - do event_loop.callback { - unsafe { *count_ptr += 1 } - } - event_loop.run(); - assert!(count == 1); - } -} - -pub struct UvIoFactory(Loop); - -pub impl UvIoFactory { - fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { - match self { &UvIoFactory(ref mut ptr) => ptr } - } -} - -impl IoFactory for UvIoFactory { - // Connect to an address and return a new stream - // NB: This blocks the task waiting on the connection. - // It would probably be better to return a future - fn connect(&mut self, addr: IpAddr) -> Option<~StreamObject> { - // Create a cell in the task to hold the result. We will fill - // the cell before resuming the task. - let result_cell = empty_cell(); - let result_cell_ptr: *Cell> = &result_cell; - - let scheduler = local_sched::take(); - assert!(scheduler.in_task_context()); - - // Block this task and take ownership, switch to scheduler context - do scheduler.deschedule_running_task_and_then |task| { - - rtdebug!("connect: entered scheduler context"); - do local_sched::borrow |scheduler| { - assert!(!scheduler.in_task_context()); - } - let mut tcp_watcher = TcpWatcher::new(self.uv_loop()); - let task_cell = Cell(task); - - // Wait for a connection - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("connect: in connect callback"); - let maybe_stream = if status.is_none() { - rtdebug!("status is none"); - Some(~UvStream(stream_watcher)) - } else { - rtdebug!("status is some"); - stream_watcher.close(||()); - None - }; - - // Store the stream in the task's stack - unsafe { (*result_cell_ptr).put_back(maybe_stream); } - - // Context switch - let scheduler = local_sched::take(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } - - fn bind(&mut self, addr: IpAddr) -> Option<~TcpListenerObject> { - let mut watcher = TcpWatcher::new(self.uv_loop()); - watcher.bind(addr); - return Some(~UvTcpListener(watcher)); - } -} - -pub struct UvTcpListener(TcpWatcher); - -impl UvTcpListener { - fn watcher(&self) -> TcpWatcher { - match self { &UvTcpListener(w) => w } - } - - fn close(&self) { - // XXX: Need to wait until close finishes before returning - self.watcher().as_stream().close(||()); - } -} - -impl Drop for UvTcpListener { - fn finalize(&self) { - // XXX: Again, this never gets called. Use .close() instead - //self.watcher().as_stream().close(||()); - } -} - -impl TcpListener for UvTcpListener { - - fn listen(&mut self) -> Option<~StreamObject> { - rtdebug!("entering listen"); - let result_cell = empty_cell(); - let result_cell_ptr: *Cell> = &result_cell; - - let server_tcp_watcher = self.watcher(); - - let scheduler = local_sched::take(); - assert!(scheduler.in_task_context()); - - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - let mut server_tcp_watcher = server_tcp_watcher; - do server_tcp_watcher.listen |server_stream_watcher, status| { - let maybe_stream = if status.is_none() { - let mut server_stream_watcher = server_stream_watcher; - let mut loop_ = loop_from_watcher(&server_stream_watcher); - let client_tcp_watcher = TcpWatcher::new(&mut loop_).as_stream(); - // XXX: Needs to be surfaced in interface - server_stream_watcher.accept(client_tcp_watcher); - Some(~UvStream::new(client_tcp_watcher)) - } else { - None - }; - - unsafe { (*result_cell_ptr).put_back(maybe_stream); } - - rtdebug!("resuming task from listen"); - // Context switch - let scheduler = local_sched::take(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } -} - -pub struct UvStream(StreamWatcher); - -impl UvStream { - fn new(watcher: StreamWatcher) -> UvStream { - UvStream(watcher) - } - - fn watcher(&self) -> StreamWatcher { - match self { &UvStream(w) => w } - } - - // XXX: finalize isn't working for ~UvStream??? - fn close(&self) { - // XXX: Need to wait until this finishes before returning - self.watcher().close(||()); - } -} - -impl Drop for UvStream { - fn finalize(&self) { - rtdebug!("closing stream"); - //self.watcher().close(||()); - } -} - -impl Stream for UvStream { - fn read(&mut self, buf: &mut [u8]) -> Result { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell> = &result_cell; - - let scheduler = local_sched::take(); - assert!(scheduler.in_task_context()); - let watcher = self.watcher(); - let buf_ptr: *&mut [u8] = &buf; - do scheduler.deschedule_running_task_and_then |task| { - rtdebug!("read: entered scheduler context"); - do local_sched::borrow |scheduler| { - assert!(!scheduler.in_task_context()); - } - let mut watcher = watcher; - let task_cell = Cell(task); - // XXX: We shouldn't reallocate these callbacks every - // call to read - let alloc: AllocCallback = |_| unsafe { - slice_to_uv_buf(*buf_ptr) - }; - do watcher.read_start(alloc) |watcher, nread, _buf, status| { - - // Stop reading so that no read callbacks are - // triggered before the user calls `read` again. - // XXX: Is there a performance impact to calling - // stop here? - let mut watcher = watcher; - watcher.read_stop(); - - let result = if status.is_none() { - assert!(nread >= 0); - Ok(nread as uint) - } else { - Err(()) - }; - - unsafe { (*result_cell_ptr).put_back(result); } - - let scheduler = local_sched::take(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } - - fn write(&mut self, buf: &[u8]) -> Result<(), ()> { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell> = &result_cell; - let scheduler = local_sched::take(); - assert!(scheduler.in_task_context()); - let watcher = self.watcher(); - let buf_ptr: *&[u8] = &buf; - do scheduler.deschedule_running_task_and_then |task| { - let mut watcher = watcher; - let task_cell = Cell(task); - let buf = unsafe { &*buf_ptr }; - // XXX: OMGCOPIES - let buf = buf.to_vec(); - do watcher.write(buf) |_watcher, status| { - let result = if status.is_none() { - Ok(()) - } else { - Err(()) - }; - - unsafe { (*result_cell_ptr).put_back(result); } - - let scheduler = local_sched::take(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } -} - -#[test] -fn test_simple_io_no_connect() { - do run_in_newsched_task { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let addr = next_test_ip4(); - let maybe_chan = io.connect(addr); - assert!(maybe_chan.is_none()); - } -} - -#[test] -fn test_simple_tcp_server_and_client() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - // Start the server first so it's listening when we connect - do spawntask_immediately { - unsafe { - let io = local_sched::unsafe_borrow_io(); - let mut listener = io.bind(addr).unwrap(); - let mut stream = listener.listen().unwrap(); - let mut buf = [0, .. 2048]; - let nread = stream.read(buf).unwrap(); - assert!(nread == 8); - for uint::range(0, nread) |i| { - rtdebug!("%u", buf[i] as uint); - assert!(buf[i] == i as u8); - } - stream.close(); - listener.close(); - } - } - - do spawntask_immediately { - unsafe { - let io = local_sched::unsafe_borrow_io(); - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - } - } - } -} - -#[test] #[ignore(reason = "busted")] -fn test_read_and_block() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let mut listener = io.bind(addr).unwrap(); - let mut stream = listener.listen().unwrap(); - let mut buf = [0, .. 2048]; - - let expected = 32; - let mut current = 0; - let mut reads = 0; - - while current < expected { - let nread = stream.read(buf).unwrap(); - for uint::range(0, nread) |i| { - let val = buf[i] as uint; - assert!(val == current % 8); - current += 1; - } - reads += 1; - - let scheduler = local_sched::take(); - // Yield to the other task in hopes that it - // will trigger a read callback while we are - // not ready for it - do scheduler.deschedule_running_task_and_then |task| { - let task = Cell(task); - do local_sched::borrow |scheduler| { - scheduler.task_queue.push_back(task.take()); - } - } - } - - // Make sure we had multiple reads - assert!(reads > 1); - - stream.close(); - listener.close(); - } - - do spawntask_immediately { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - } - - } -} - -#[test] -fn test_read_read_read() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: uint = 500000; - - do spawntask_immediately { - unsafe { - let io = local_sched::unsafe_borrow_io(); - let mut listener = io.bind(addr).unwrap(); - let mut stream = listener.listen().unwrap(); - let buf = [1, .. 2048]; - let mut total_bytes_written = 0; - while total_bytes_written < MAX { - stream.write(buf); - total_bytes_written += buf.len(); - } - stream.close(); - listener.close(); - } - } - - do spawntask_immediately { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let mut stream = io.connect(addr).unwrap(); - let mut buf = [0, .. 2048]; - let mut total_bytes_read = 0; - while total_bytes_read < MAX { - let nread = stream.read(buf).unwrap(); - rtdebug!("read %u bytes", nread as uint); - total_bytes_read += nread; - for uint::range(0, nread) |i| { - assert!(buf[i] == 1); - } - } - rtdebug!("read %u bytes total", total_bytes_read as uint); - stream.close(); - } - } -} diff --git a/src/libstd/rt/uvll.rs b/src/libstd/rt/uvll.rs deleted file mode 100644 index 0d298bde6b5..00000000000 --- a/src/libstd/rt/uvll.rs +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright 2012 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. - -/*! - * Low-level bindings to the libuv library. - * - * This module contains a set of direct, 'bare-metal' wrappers around - * the libuv C-API. - * - * We're not bothering yet to redefine uv's structs as Rust structs - * because they are quite large and change often between versions. - * The maintenance burden is just too high. Instead we use the uv's - * `uv_handle_size` and `uv_req_size` to find the correct size of the - * structs and allocate them on the heap. This can be revisited later. - * - * There are also a collection of helper functions to ease interacting - * with the low-level API. - * - * As new functionality, existant in uv.h, is added to the rust stdlib, - * the mappings should be added in this module. - */ - -#[allow(non_camel_case_types)]; // C types - -use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t}; -use libc::{malloc, free}; -use prelude::*; - -pub struct uv_err_t { - code: c_int, - sys_errno_: c_int -} - -pub struct uv_buf_t { - base: *u8, - len: libc::size_t, -} - -pub type uv_handle_t = c_void; -pub type uv_loop_t = c_void; -pub type uv_idle_t = c_void; -pub type uv_tcp_t = c_void; -pub type uv_connect_t = c_void; -pub type uv_write_t = c_void; -pub type uv_async_t = c_void; -pub type uv_timer_t = c_void; -pub type uv_stream_t = c_void; -pub type uv_fs_t = c_void; - -pub type uv_idle_cb = *u8; - -pub type sockaddr_in = c_void; -pub type sockaddr_in6 = c_void; - -#[deriving(Eq)] -pub enum uv_handle_type { - UV_UNKNOWN_HANDLE, - UV_ASYNC, - UV_CHECK, - UV_FS_EVENT, - UV_FS_POLL, - UV_HANDLE, - UV_IDLE, - UV_NAMED_PIPE, - UV_POLL, - UV_PREPARE, - UV_PROCESS, - UV_STREAM, - UV_TCP, - UV_TIMER, - UV_TTY, - UV_UDP, - UV_SIGNAL, - UV_FILE, - UV_HANDLE_TYPE_MAX -} - -#[deriving(Eq)] -pub enum uv_req_type { - UV_UNKNOWN_REQ, - UV_REQ, - UV_CONNECT, - UV_WRITE, - UV_SHUTDOWN, - UV_UDP_SEND, - UV_FS, - UV_WORK, - UV_GETADDRINFO, - UV_REQ_TYPE_MAX -} - -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); - let p = malloc(size); - assert!(p.is_not_null()); - return p; -} - -pub unsafe fn free_handle(v: *c_void) { - free(v) -} - -pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { - assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX); - let size = rust_uv_req_size(req as uint); - let p = malloc(size); - assert!(p.is_not_null()); - return p; -} - -pub unsafe fn free_req(v: *c_void) { - free(v) -} - -#[test] -fn handle_sanity_check() { - unsafe { - assert!(UV_HANDLE_TYPE_MAX as uint == rust_uv_handle_type_max()); - } -} - -#[test] -fn request_sanity_check() { - unsafe { - assert!(UV_REQ_TYPE_MAX as uint == rust_uv_req_type_max()); - } -} - -pub unsafe fn loop_new() -> *c_void { - return rust_uv_loop_new(); -} - -pub unsafe fn loop_delete(loop_handle: *c_void) { - rust_uv_loop_delete(loop_handle); -} - -pub unsafe fn run(loop_handle: *c_void) { - rust_uv_run(loop_handle); -} - -pub unsafe fn close(handle: *T, cb: *u8) { - rust_uv_close(handle as *c_void, cb); -} - -pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) { - rust_uv_walk(loop_handle, cb, arg); -} - -pub unsafe fn idle_new() -> *uv_idle_t { - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - rust_uv_idle_delete(handle) -} - -pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int { - rust_uv_idle_init(loop_handle, handle) -} - -pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int { - rust_uv_idle_start(handle, cb) -} - -pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int { - rust_uv_idle_stop(handle) -} - -pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { - return rust_uv_tcp_init(loop_handle, handle); -} - -// FIXME ref #2064 -pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in6, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int { - return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int { - 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 { - 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 listen(stream: *T, backlog: c_int, cb: *u8) -> c_int { - return rust_uv_listen(stream as *c_void, backlog, cb); -} - -pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { - return rust_uv_accept(server as *c_void, client as *c_void); -} - -pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(buf_in); - let buf_cnt = buf_in.len() as i32; - return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); -} -pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { - return rust_uv_read_start(stream as *c_void, on_alloc, on_read); -} - -pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int { - return rust_uv_read_stop(stream as *c_void); -} - -pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t { - return rust_uv_last_error(loop_handle); -} - -pub unsafe fn strerror(err: *uv_err_t) -> *c_char { - return rust_uv_strerror(err); -} -pub unsafe fn err_name(err: *uv_err_t) -> *c_char { - return rust_uv_err_name(err); -} - -pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int { - return rust_uv_async_init(loop_handle, async_handle, cb); -} - -pub unsafe fn async_send(async_handle: *uv_async_t) { - return rust_uv_async_send(async_handle); -} -pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t { - let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t }; - let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf); - rust_uv_buf_init(out_buf_ptr, input, len as size_t); - return out_buf; -} - -pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int { - return rust_uv_timer_init(loop_ptr, timer_ptr); -} -pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint, - repeat: uint) -> c_int { - return rust_uv_timer_start(timer_ptr, cb, timeout as c_uint, repeat as c_uint); -} -pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int { - return rust_uv_timer_stop(timer_ptr); -} - -pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) - } -} -pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int) - } -} - -pub unsafe fn free_ip4_addr(addr: *sockaddr_in) { - rust_uv_free_ip4_addr(addr); -} - -pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) { - rust_uv_free_ip6_addr(addr); -} - -// data access helpers -pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *c_void { - return rust_uv_get_loop_for_uv_handle(handle as *c_void); -} -pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t { - return rust_uv_get_stream_handle_from_connect_req(connect); -} -pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t { - return rust_uv_get_stream_handle_from_write_req(write_req); -} -pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void { - rust_uv_get_data_for_uv_loop(loop_ptr) -} -pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) { - rust_uv_set_data_for_uv_loop(loop_ptr, data); -} -pub unsafe fn get_data_for_uv_handle(handle: *T) -> *c_void { - return rust_uv_get_data_for_uv_handle(handle as *c_void); -} -pub unsafe fn set_data_for_uv_handle(handle: *T, data: *U) { - rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void); -} -pub unsafe fn get_data_for_req(req: *T) -> *c_void { - return rust_uv_get_data_for_req(req as *c_void); -} -pub unsafe fn set_data_for_req(req: *T, data: *U) { - rust_uv_set_data_for_req(req as *c_void, data as *c_void); -} -pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 { - return rust_uv_get_base_from_buf(buf); -} -pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t { - return rust_uv_get_len_from_buf(buf); -} -pub unsafe fn malloc_buf_base_of(suggested_size: size_t) -> *u8 { - return rust_uv_malloc_buf_base_of(suggested_size); -} -pub unsafe fn free_base_of_buf(buf: uv_buf_t) { - rust_uv_free_base_of_buf(buf); -} - -pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str { - let err = last_error(uv_loop); - let err_ptr = ptr::to_unsafe_ptr(&err); - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - return fmt!("LIBUV ERROR: name: %s msg: %s", - err_name, err_msg); -} - -pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data { - let err = last_error(uv_loop); - let err_ptr = ptr::to_unsafe_ptr(&err); - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - uv_err_data { err_name: err_name, err_msg: err_msg } -} - -pub struct uv_err_data { - err_name: ~str, - err_msg: ~str, -} - -extern { - - fn rust_uv_handle_size(type_: uintptr_t) -> size_t; - fn rust_uv_req_size(type_: uintptr_t) -> size_t; - fn rust_uv_handle_type_max() -> uintptr_t; - fn rust_uv_req_type_max() -> uintptr_t; - - // libuv public API - fn rust_uv_loop_new() -> *c_void; - fn rust_uv_loop_delete(lp: *c_void); - fn rust_uv_run(loop_handle: *c_void); - fn rust_uv_close(handle: *c_void, cb: *u8); - fn rust_uv_walk(loop_handle: *c_void, cb: *u8, arg: *c_void); - - fn rust_uv_idle_new() -> *uv_idle_t; - fn rust_uv_idle_delete(handle: *uv_idle_t); - fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; - fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; - fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; - - fn rust_uv_async_send(handle: *uv_async_t); - fn rust_uv_async_init(loop_handle: *c_void, - async_handle: *uv_async_t, - cb: *u8) -> c_int; - fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int; - // FIXME ref #2604 .. ? - fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t); - fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t; - // FIXME ref #2064 - fn rust_uv_strerror(err: *uv_err_t) -> *c_char; - // FIXME ref #2064 - fn rust_uv_err_name(err: *uv_err_t) -> *c_char; - fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in; - fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6; - fn rust_uv_free_ip4_addr(addr: *sockaddr_in); - fn rust_uv_free_ip6_addr(addr: *sockaddr_in6); - fn rust_uv_ip4_name(src: *sockaddr_in, dst: *u8, size: size_t) -> c_int; - fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int; - fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint; - fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint; - // FIXME ref #2064 - fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in6) -> c_int; - // FIXME ref #2064 - 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_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; - fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; - fn rust_uv_write(req: *c_void, - stream: *c_void, - buf_in: *uv_buf_t, - buf_cnt: c_int, - cb: *u8) -> c_int; - fn rust_uv_read_start(stream: *c_void, - on_alloc: *u8, - on_read: *u8) -> c_int; - fn rust_uv_read_stop(stream: *c_void) -> c_int; - fn rust_uv_timer_init(loop_handle: *c_void, - timer_handle: *uv_timer_t) -> c_int; - fn rust_uv_timer_start(timer_handle: *uv_timer_t, - cb: *u8, - timeout: c_uint, - repeat: c_uint) -> c_int; - fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; - - fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8; - fn rust_uv_free_base_of_buf(buf: uv_buf_t); - fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; - fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; - fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void; - fn rust_uv_get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void; - fn rust_uv_set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void); - fn rust_uv_get_data_for_uv_handle(handle: *c_void) -> *c_void; - fn rust_uv_set_data_for_uv_handle(handle: *c_void, data: *c_void); - fn rust_uv_get_data_for_req(req: *c_void) -> *c_void; - fn rust_uv_set_data_for_req(req: *c_void, data: *c_void); - fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; - fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t; -} From 39a575fb43d2ba0511d295b7e1a9178b4919e348 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 12 Jun 2013 16:01:50 -0700 Subject: [PATCH 02/32] Added libuv UDP function bindings. --- src/libstd/rt/uv/uvll.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index ddc9040d730..8a3f02cb59b 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -56,12 +56,14 @@ pub type uv_handle_t = c_void; 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_connect_t = c_void; pub type uv_write_t = c_void; pub type uv_async_t = c_void; pub type uv_timer_t = c_void; pub type uv_stream_t = c_void; pub type uv_fs_t = c_void; +pub type uv_udp_send_t = c_void; pub type uv_idle_cb = *u8; @@ -183,6 +185,40 @@ pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int { rust_uv_idle_stop(handle) } +pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int { + return rust_uv_udp_init(loop_handle, handle); +} + +pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int { + return rust_uv_udp_bind(server, addr, flags); +} + +pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int { + return rust_uv_udp_bind6(server, addr, flags); +} + +pub unsafe fn udp_send(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], + addr: *sockaddr_in, cb: *u8) -> c_int { + let buf_ptr = vec::raw::to_ptr(buf_in); + let buf_cnt = buf_in.len() as i32; + return rust_uv_udp_send(req, handle, buf_ptr, buf_cnt, addr, cb); +} + +pub unsafe fn udp_send6(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], + addr: *sockaddr_in6, cb: *u8) -> c_int { + let buf_ptr = vec::raw::to_ptr(buf_in); + let buf_cnt = buf_in.len() as i32; + return rust_uv_udp_send(req, handle, buf_ptr, buf_cnt, addr, cb); +} + +pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: *u8, on_recv: *u8) -> c_int { + return rust_uv_udp_recv_start(server, on_alloc, on_recv); +} + +pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int { + return rust_uv_udp_recv_stop(server); +} + pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { return rust_uv_tcp_init(loop_handle, handle); } @@ -417,6 +453,17 @@ extern { name: *sockaddr_in) -> c_int; fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) ->c_int; + + fn rust_uv_udp_init(loop_handle: *uv_loop_t, handle_ptr: *uv_udp_t) -> c_int; + fn rust_uv_udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int; + fn rust_uv_udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int; + fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, + buf_cnt: c_int, addr: *sockaddr_in, cb: *u8) -> c_int; + fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, + buf_cnt: c_int, addr: *sockaddr_in6, cb: *u8) -> c_int; + 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_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; fn rust_uv_write(req: *c_void, From 5393e43b5355284cf24f8afcc2088473fa5a318a Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Thu, 13 Jun 2013 12:51:32 -0700 Subject: [PATCH 03/32] Corrected libuv UDP bindings. --- src/libstd/rt/uv/uvll.rs | 4 ++-- src/rt/rust_uv.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/rt/rustrt.def.in | 9 ++++++++- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 8a3f02cb59b..cebd498aa02 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -201,14 +201,14 @@ pub unsafe fn udp_send(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], addr: *sockaddr_in, cb: *u8) -> c_int { let buf_ptr = vec::raw::to_ptr(buf_in); let buf_cnt = buf_in.len() as i32; - return rust_uv_udp_send(req, handle, buf_ptr, buf_cnt, addr, cb); + return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); } pub unsafe fn udp_send6(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], addr: *sockaddr_in6, cb: *u8) -> c_int { let buf_ptr = vec::raw::to_ptr(buf_in); let buf_cnt = buf_in.len() as i32; - return rust_uv_udp_send(req, handle, buf_ptr, buf_cnt, addr, cb); + return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); } pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: *u8, on_recv: *u8) -> c_int { diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index fefcbbcacf7..67a2f614b69 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -293,6 +293,43 @@ rust_uv_tcp_getpeername6 return uv_tcp_getpeername(handle, (sockaddr*)name, &namelen); } +extern "C" int +rust_uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + return uv_udp_init(loop, handle); +} + +extern "C" int +rust_uv_udp_bind(uv_udp_t* server, sockaddr_in* addr_ptr, unsigned flags) { + return uv_udp_bind(server, *addr_ptr, flags); +} + +extern "C" int +rust_uv_udp_bind6(uv_udp_t* server, sockaddr_in6* addr_ptr, unsigned flags) { + return uv_udp_bind6(server, *addr_ptr, flags); +} + +extern "C" int +rust_uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t* buf_in, + int buf_cnt, sockaddr_in* addr_ptr, uv_udp_send_cb cb) { + return uv_udp_send(req, handle, buf_in, buf_cnt, *addr_ptr, cb); +} + +extern "C" int +rust_uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t* buf_in, + int buf_cnt, sockaddr_in6* addr_ptr, uv_udp_send_cb cb) { + return uv_udp_send6(req, handle, buf_in, buf_cnt, *addr_ptr, cb); +} + +extern "C" int +rust_uv_udp_recv_start(uv_udp_t* server, uv_alloc_cb on_alloc, uv_udp_recv_cb on_read) { + return uv_udp_recv_start(server, on_alloc, on_read); +} + +extern "C" int +rust_uv_udp_recv_stop(uv_udp_t* server) { + return uv_udp_recv_stop(server); +} + extern "C" int rust_uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 9b49583519e..cb7189c5a83 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -104,6 +104,13 @@ rust_uv_tcp_connect rust_uv_tcp_bind rust_uv_tcp_connect6 rust_uv_tcp_bind6 +rust_uv_udp_init +rust_uv_udp_bind +rust_uv_udp_bind6 +rust_uv_udp_send +rust_uv_udp_send6 +rust_uv_udp_recv_start +rust_uv_udp_recv_stop rust_uv_listen rust_uv_accept rust_uv_write @@ -239,4 +246,4 @@ rust_valgrind_stack_deregister rust_take_env_lock rust_drop_env_lock rust_update_log_settings -rust_get_num_cpus \ No newline at end of file +rust_get_num_cpus From 74e72551930d4c58e747a60e2b39d3010e40d0ae Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Fri, 14 Jun 2013 11:39:46 -0700 Subject: [PATCH 04/32] Added a utility function to extract the udp handle from udp send requests. --- src/rt/rust_uv.cpp | 5 +++++ src/rt/rustrt.def.in | 1 + 2 files changed, 6 insertions(+) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 67a2f614b69..2fb9dc2f1a2 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -330,6 +330,11 @@ rust_uv_udp_recv_stop(uv_udp_t* server) { return uv_udp_recv_stop(server); } +extern "C" uv_udp_t* +rust_uv_get_udp_handle_from_send_req(uv_udp_send_t* send_req) { + return send_req->handle; +} + extern "C" int rust_uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index cb7189c5a83..4d7fa589f6f 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -111,6 +111,7 @@ rust_uv_udp_send rust_uv_udp_send6 rust_uv_udp_recv_start rust_uv_udp_recv_stop +rust_uv_get_udp_handle_from_send_req rust_uv_listen rust_uv_accept rust_uv_write From 03fe59aefa6ec84531335fd93e8dbf44dee65570 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Fri, 14 Jun 2013 11:54:56 -0700 Subject: [PATCH 05/32] added bindings to extract udp handle from udp send requests --- src/libstd/rt/uv/uvll.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index cebd498aa02..4c0791b3b5c 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -66,6 +66,9 @@ pub type uv_fs_t = c_void; pub type uv_udp_send_t = c_void; pub type uv_idle_cb = *u8; +pub type uv_alloc_cb = *u8; +pub type uv_udp_send_cb = *u8; +pub type uv_udp_recv_cb = *u8; pub type sockaddr_in = c_void; pub type sockaddr_in6 = c_void; @@ -198,20 +201,20 @@ pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) - } pub unsafe fn udp_send(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], - addr: *sockaddr_in, cb: *u8) -> c_int { + addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int { let buf_ptr = vec::raw::to_ptr(buf_in); let buf_cnt = buf_in.len() as i32; return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); } pub unsafe fn udp_send6(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], - addr: *sockaddr_in6, cb: *u8) -> c_int { + addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int { let buf_ptr = vec::raw::to_ptr(buf_in); let buf_cnt = buf_in.len() as i32; return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); } -pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: *u8, on_recv: *u8) -> c_int { +pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb, on_recv: uv_udp_recv_cb) -> c_int { return rust_uv_udp_recv_start(server, on_alloc, on_recv); } @@ -219,6 +222,10 @@ pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int { return rust_uv_udp_recv_stop(server); } +pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t { + return rust_uv_get_udp_handle_from_send_req(send_req); +} + pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { return rust_uv_tcp_init(loop_handle, handle); } @@ -269,7 +276,7 @@ pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u let buf_cnt = buf_in.len() as i32; return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); } -pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { +pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int { return rust_uv_read_start(stream as *c_void, on_alloc, on_read); } @@ -463,6 +470,7 @@ extern { buf_cnt: c_int, addr: *sockaddr_in6, cb: *u8) -> c_int; 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_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; From a7f92c92ed07588c3bde3cc38e64b9289ea682f5 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Fri, 14 Jun 2013 12:04:11 -0700 Subject: [PATCH 06/32] Added a UdpWatcher and UdpSendRequest with associated callbacks --- src/libstd/rt/uv/mod.rs | 15 +++- src/libstd/rt/uv/net.rs | 174 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 184 insertions(+), 5 deletions(-) diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 5f9e5660814..f7cc5c6cc8b 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -54,7 +54,7 @@ use rt::io::IoError; #[cfg(test)] use unstable::run_in_bare_thread; pub use self::file::FsRequest; -pub use self::net::{StreamWatcher, TcpWatcher}; +pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher}; pub use self::idle::IdleWatcher; pub use self::timer::TimerWatcher; pub use self::async::AsyncWatcher; @@ -128,6 +128,8 @@ pub type ConnectionCallback = ~fn(StreamWatcher, Option); pub type FsCallback = ~fn(FsRequest, Option); pub type TimerCallback = ~fn(TimerWatcher, Option); pub type AsyncCallback = ~fn(AsyncWatcher, Option); +pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, Ipv4, uint, Option); +pub type UdpSendCallback = ~fn(UdpWatcher, Option); /// Callbacks used by StreamWatchers, set as custom data on the foreign handle @@ -139,7 +141,9 @@ struct WatcherData { alloc_cb: Option, idle_cb: Option, timer_cb: Option, - async_cb: Option + async_cb: Option, + udp_recv_cb: Option, + udp_send_cb: Option } pub trait WatcherInterop { @@ -169,7 +173,9 @@ impl> WatcherInterop for W { alloc_cb: None, idle_cb: None, timer_cb: None, - async_cb: None + async_cb: None, + udp_recv_cb: None, + udp_send_cb: None }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(self.native_handle(), data); @@ -309,6 +315,9 @@ pub fn status_to_maybe_uv_error(handle: *T, status: c_int) -> Option /// The uv buffer type pub type Buf = uvll::uv_buf_t; +/// The uv IPv4 type +pub type Ipv4 = uvll::sockaddr_in; + /// Borrow a slice to a Buf pub fn slice_to_uv_buf(v: &[u8]) -> Buf { let data = vec::raw::to_ptr(v); diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 68b871e6b31..4079a2f7b77 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -9,10 +9,10 @@ // except according to those terms. use prelude::*; -use libc::{size_t, ssize_t, c_int, c_void}; +use libc::{size_t, ssize_t, c_int, c_void, c_uint}; use rt::uv::uvll; use rt::uv::uvll::*; -use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback}; +use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback}; use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, status_to_maybe_uv_error}; use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; @@ -254,6 +254,142 @@ impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher { } } +pub struct UdpWatcher(*uvll::uv_udp_t); +impl Watcher for UdpWatcher { } + +pub impl UdpWatcher { + fn new(loop_: &mut Loop) -> UdpWatcher { + unsafe { + let handle = malloc_handle(UV_UDP); + assert!(handle.is_not_null()); + assert_eq!(0, uvll::udp_init(loop_.native_handle(), handle)); + let mut watcher: UdpWatcher = NativeHandle::from_native_handle(handle); + watcher.install_watcher_data(); + return watcher; + } + } + + fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { + match address { + Ipv4(*) => { + do ip4_as_uv_ip4(address) |addr| { + let result = unsafe { + uvll::udp_bind(self.native_handle(), addr, 0u32) + }; + if result == 0 { + Ok(()) + } else { + Err(last_uv_error(self)) + } + } + } + _ => fail!() // TODO ipv6 + } + } + + fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) { + { + let data = self.get_watcher_data(); + data.alloc_cb = Some(alloc); + data.udp_recv_cb = Some(cb); + } + + let handle = self.native_handle(); + unsafe { uvll::read_start(handle, alloc_cb, recv_cb); } + + extern fn alloc_cb(handle: *uvll::uv_udp_t, suggested_size: size_t) -> Buf { + let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); + let data = udp_watcher.get_watcher_data(); + let alloc_cb = data.alloc_cb.get_ref(); + return (*alloc_cb)(suggested_size as uint); + } + + /* TODO the socket address should actually be a pointer to either a sockaddr_in or sockaddr_in6. + In libuv, the udp_recv callback takes a struct *sockaddr */ + extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf, + address: *uvll::sockaddr_in, flags: c_uint) { + rtdebug!("buf addr: %x", buf.base as uint); + rtdebug!("buf len: %d", buf.len as int); + let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); + let data = udp_watcher.get_watcher_data(); + let cb = data.udp_recv_cb.get_ref(); + let status = status_to_maybe_uv_error(handle, nread as c_int); + unsafe { (*cb)(udp_watcher, nread as int, buf, *address, flags as uint, status) }; + } + } + + fn recv_stop(&mut self) { + let handle = self.native_handle(); + unsafe { uvll::udp_recv_stop(handle); } + } + + fn send(&mut self, buf: Buf, address: IpAddr, cb: UdpSendCallback) { + { + let data = self.get_watcher_data(); + assert!(data.udp_send_cb.is_none()); + data.udp_send_cb = Some(cb); + } + + let req = UdpSendRequest::new(); + let bufs = [buf]; + match address { + Ipv4(*) => { + do ip4_as_uv_ip4(address) |addr| { + unsafe { + assert!(0 == uvll::udp_send(req.native_handle(), + self.native_handle(), + bufs, addr, send_cb)); + } + } + } + _ => fail!() // TODO ipv6 + } + + extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) { + let send_request: UdpSendRequest = NativeHandle::from_native_handle(req); + let mut udp_watcher = send_request.handle(); + send_request.delete(); + let cb = { + let data = udp_watcher.get_watcher_data(); + let cb = data.udp_send_cb.swap_unwrap(); + cb + }; + let status = status_to_maybe_uv_error(udp_watcher.native_handle(), status); + cb(udp_watcher, status); + } + } + + fn close(self, cb: NullCallback) { + { + let mut this = self; + let data = this.get_watcher_data(); + assert!(data.close_cb.is_none()); + data.close_cb = Some(cb); + } + + unsafe { uvll::close(self.native_handle(), close_cb); } + + extern fn close_cb(handle: *uvll::uv_udp_t) { + let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); + { + let data = udp_watcher.get_watcher_data(); + data.close_cb.swap_unwrap()(); + } + udp_watcher.drop_watcher_data(); + unsafe { free_handle(handle as *c_void) } + } + } +} + +impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher { + fn from_native_handle(handle: *uvll::uv_udp_t) -> UdpWatcher { + UdpWatcher(handle) + } + fn native_handle(&self) -> *uvll::uv_udp_t { + match self { &UdpWatcher(ptr) => ptr } + } +} + // uv_connect_t is a subclass of uv_req_t struct ConnectRequest(*uvll::uv_connect_t); impl Request for ConnectRequest { } @@ -327,6 +463,40 @@ impl NativeHandle<*uvll::uv_write_t> for WriteRequest { } } +pub struct UdpSendRequest(*uvll::uv_udp_send_t); + +impl Request for UdpSendRequest { } + +pub impl UdpSendRequest { + fn new() -> UdpSendRequest { + let send_handle = unsafe { + malloc_req(UV_UDP_SEND) + }; + assert!(send_handle.is_not_null()); + let send_handle = send_handle as *uvll::uv_udp_send_t; + UdpSendRequest(send_handle) + } + + fn handle(&self) -> UdpWatcher { + unsafe { + let udp_handle = uvll::get_udp_handle_from_send_req(self.native_handle()); + NativeHandle::from_native_handle(udp_handle) + } + } + + fn delete(self) { + unsafe { free_req(self.native_handle() as *c_void) } + } +} + +impl NativeHandle<*uvll::uv_udp_send_t> for UdpSendRequest { + fn from_native_handle(handle: *uvll::uv_udp_send_t) -> UdpSendRequest { + UdpSendRequest(handle) + } + fn native_handle(&self) -> *uvll::uv_udp_send_t { + match self { &UdpSendRequest(ptr) => ptr } + } +} #[cfg(test)] mod test { From 9687437d4543c2395b92ebcb910fcaf9d8b2cd44 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 17 Jun 2013 12:31:30 -0700 Subject: [PATCH 07/32] added wrappers about uv_ip{4,6}_{port,name} --- src/libstd/rt/uv/uvll.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 4c0791b3b5c..06315c4cb38 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -339,6 +339,22 @@ pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) { rust_uv_free_ip6_addr(addr); } +pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int { + return rust_uv_ip4_name(addr, dst, size); +} + +pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int { + return rust_uv_ip6_name(addr, dst, size); +} + +pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint { + return rust_uv_ip4_port(addr); +} + +pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint { + return rust_uv_ip6_port(addr); +} + // data access helpers pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *c_void { return rust_uv_get_loop_for_uv_handle(handle as *c_void); From b51d1885befe2779fa3fdc9e2a9bafa4ef3d5cf2 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 17 Jun 2013 12:32:21 -0700 Subject: [PATCH 08/32] Added a RtioUdpStream trait --- src/libstd/rt/rtio.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index fa657555f3a..0eebbb61e5b 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -22,6 +22,7 @@ pub type RemoteCallbackObject = uvio::UvRemoteCallback; pub type IoFactoryObject = uvio::UvIoFactory; pub type RtioTcpStreamObject = uvio::UvTcpStream; pub type RtioTcpListenerObject = uvio::UvTcpListener; +pub type RtioUdpStreamObject = uvio::UvUdpStream; pub trait EventLoop { fn run(&mut self); @@ -44,6 +45,7 @@ pub trait RemoteCallback { pub trait IoFactory { fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError>; fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError>; + // TODO fn udp_connect(&mut self, addr: IpAddr) -> Result<~RtioUdpStreamObject, IoError>; } pub trait RtioTcpListener { @@ -54,3 +56,8 @@ pub trait RtioTcpStream { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; } + +pub trait RtioUdpStream { + fn read(&mut self, buf: &mut [u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; +} From 7e022c590fb0fb6083be7825df90045505e6fe47 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 17 Jun 2013 12:33:10 -0700 Subject: [PATCH 09/32] added a function to convert C's ipv4 data structure into the Rust ipv4 data structure. --- src/libstd/rt/uv/net.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 4079a2f7b77..0b77bd83958 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -38,6 +38,14 @@ fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { } } +pub fn uv_ip4_to_ip4(addr: *sockaddr_in) -> IpAddr { + let ip4_size = 16; + let buf = vec::from_elem(ip4_size, 0u8); + unsafe { ip4_name(addr, &buf[0], ip4_size as u64) }; + let port = unsafe { ip4_port(addr) }; + Ipv4(buf[0], buf[1], buf[2], buf[3], port as u16) +} + // 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); From 47443753f1197877f51f4a66d3475f8c9e4d5bc2 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 17 Jun 2013 12:33:46 -0700 Subject: [PATCH 10/32] added Eq and TotalEq instances for IpAddr --- src/libstd/rt/io/net/ip.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index df1dfe4d38a..f885c7f2788 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -8,7 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cmp::{Eq, TotalEq, eq}; + pub enum IpAddr { Ipv4(u8, u8, u8, u8, u16), Ipv6 } + +impl Eq for IpAddr { + fn eq(&self, other: &IpAddr) -> bool { + match (*self, *other) { + (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => a == f && b == g && c == h && d == i && e == j, + (Ipv6, Ipv6) => fail!(), + _ => false + } + } + fn ne(&self, other: &IpAddr) -> bool { + !eq(self, other) + } +} + +impl TotalEq for IpAddr { + fn equals(&self, other: &IpAddr) -> bool { + *self == *other + } +} From e42f28c05cb8e579d06492c49822944946341c9f Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 17 Jun 2013 12:34:58 -0700 Subject: [PATCH 11/32] stated to implement UdpStream --- src/libstd/rt/io/net/udp.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index bb5457e334d..6275eff9249 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -8,13 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::*; -use super::super::*; -use super::ip::IpAddr; +use option::{Option}; +use rt::io::net::ip::IpAddr; +use rt::io::{Reader, Writer, Listener}; +use rt::rtio::{RtioUdpStreamObject}; -pub struct UdpStream; +pub struct UdpStream { + rtstream: ~RtioUdpStreamObject +} impl UdpStream { + fn new(s: ~RtioUdpStreamObject) -> UdpStream { + UdpStream { + rtstream: s + } + } + pub fn connect(_addr: IpAddr) -> Option { fail!() } From 33ae193a3c1a156e73bf6880366c9785dd4b7393 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 17 Jun 2013 12:35:27 -0700 Subject: [PATCH 12/32] Started to implemented UdpStream --- src/libstd/rt/uv/uvio.rs | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 0f98ab11513..1274dbc3220 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -433,6 +433,86 @@ impl RtioTcpStream for UvTcpStream { } } +pub struct UvUdpStream { + watcher: UdpWatcher, + address: IpAddr +} + +impl UvUdpStream { + fn watcher(&self) -> UdpWatcher { self.watcher } + fn address(&self) -> IpAddr { self.address } +} + +impl Drop for UvUdpStream { + fn finalize(&self) { + rtdebug!("closing udp stream"); + let watcher = self.watcher(); + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell(task); + do watcher.close { + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + } +} + +impl RtioUdpStream for UvUdpStream { + fn read(&mut self, buf: &mut [u8]) -> Result { + let result_cell = empty_cell(); + let result_cell_ptr: *Cell> = &result_cell; + + let scheduler = Local::take::(); + assert!(scheduler.in_task_context()); + let watcher = self.watcher(); + let connection_address = self.address(); + let buf_ptr: *&mut [u8] = &buf; + do scheduler.deschedule_running_task_and_then |sched, task| { + rtdebug!("read: entered scheduler context"); + assert!(!sched.in_task_context()); + let mut watcher = watcher; + let task_cell = Cell(task); + // XXX: see note in RtioTcpStream implementation for UvTcpStream + let alloc: AllocCallback = |_| unsafe { + slice_to_uv_buf(*buf_ptr) + }; + do watcher.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { + let _ = flags; // TODO actually use flags + + // XXX: see note in RtioTcpStream implementation for UvTcpStream + let mut watcher = watcher; + watcher.recv_stop(); + + let incoming_address = net::uv_ip4_to_ip4(&addr); + let result = if status.is_none() { + assert!(nread >= 0); + if incoming_address != connection_address { + Ok(0u) + } else { + Ok(nread as uint) + } + } else { + Err(uv_error_to_io_error(status.unwrap())) + }; + + unsafe { (*result_cell_ptr).put_back(result); } + + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + + fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + let _ = buf; + fail!() + } +} + #[test] fn test_simple_io_no_connect() { do run_in_newsched_task { From d777ba01cbfc01d1241722e2c27fcd4a4650a300 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 19 Jun 2013 15:20:28 -0700 Subject: [PATCH 13/32] Wrote the Eq instance of IpAddr in a slightly different way. --- src/libstd/rt/io/net/ip.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index f885c7f2788..84abc058c33 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cmp::{Eq, TotalEq, eq}; +use std::cmp::{Eq, TotalEq}; pub enum IpAddr { Ipv4(u8, u8, u8, u8, u16), @@ -18,13 +18,13 @@ pub enum IpAddr { impl Eq for IpAddr { fn eq(&self, other: &IpAddr) -> bool { match (*self, *other) { - (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => a == f && b == g && c == h && d == i && e == j, + (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => (a,b,c,d,e) == (f,g,h,i,j), (Ipv6, Ipv6) => fail!(), _ => false } } fn ne(&self, other: &IpAddr) -> bool { - !eq(self, other) + !(self == other) } } From 083c692565340791b06ab67d66c4c95d63b222cb Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 19 Jun 2013 15:39:18 -0700 Subject: [PATCH 14/32] Changed visibility from being on the impl to being on methods per language syntax change. --- src/libstd/rt/uv/net.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 5491b82b725..c88d96bd230 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -17,6 +17,7 @@ use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, status_to_maybe_uv_error}; use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; use rt::uv::last_uv_error; +use vec; fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { match addr { @@ -161,7 +162,7 @@ pub struct TcpWatcher(*uvll::uv_tcp_t); impl Watcher for TcpWatcher { } impl TcpWatcher { - pub fn new(loop_: &mut Loop) -> TcpWatcher { + pub fn new(loop_: &Loop) -> TcpWatcher { unsafe { let handle = malloc_handle(UV_TCP); assert!(handle.is_not_null()); @@ -264,8 +265,8 @@ impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher { pub struct UdpWatcher(*uvll::uv_udp_t); impl Watcher for UdpWatcher { } -pub impl UdpWatcher { - fn new(loop_: &mut Loop) -> UdpWatcher { +impl UdpWatcher { + pub fn new(loop_: &mut Loop) -> UdpWatcher { unsafe { let handle = malloc_handle(UV_UDP); assert!(handle.is_not_null()); @@ -276,7 +277,7 @@ pub impl UdpWatcher { } } - fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { + pub fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { match address { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { @@ -294,7 +295,7 @@ pub impl UdpWatcher { } } - fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) { + pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) { { let data = self.get_watcher_data(); data.alloc_cb = Some(alloc); @@ -325,12 +326,12 @@ pub impl UdpWatcher { } } - fn recv_stop(&mut self) { + pub fn recv_stop(&mut self) { let handle = self.native_handle(); unsafe { uvll::udp_recv_stop(handle); } } - fn send(&mut self, buf: Buf, address: IpAddr, cb: UdpSendCallback) { + pub fn send(&mut self, buf: Buf, address: IpAddr, cb: UdpSendCallback) { { let data = self.get_watcher_data(); assert!(data.udp_send_cb.is_none()); @@ -366,7 +367,7 @@ pub impl UdpWatcher { } } - fn close(self, cb: NullCallback) { + pub fn close(self, cb: NullCallback) { { let mut this = self; let data = this.get_watcher_data(); @@ -470,11 +471,10 @@ impl NativeHandle<*uvll::uv_write_t> for WriteRequest { } pub struct UdpSendRequest(*uvll::uv_udp_send_t); - impl Request for UdpSendRequest { } -pub impl UdpSendRequest { - fn new() -> UdpSendRequest { +impl UdpSendRequest { + pub fn new() -> UdpSendRequest { let send_handle = unsafe { malloc_req(UV_UDP_SEND) }; @@ -483,14 +483,14 @@ pub impl UdpSendRequest { UdpSendRequest(send_handle) } - fn handle(&self) -> UdpWatcher { + pub fn handle(&self) -> UdpWatcher { unsafe { let udp_handle = uvll::get_udp_handle_from_send_req(self.native_handle()); NativeHandle::from_native_handle(udp_handle) } } - fn delete(self) { + pub fn delete(self) { unsafe { free_req(self.native_handle() as *c_void) } } } From ac49b74e8254b3129694f5a5425dbda4ffc4b186 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 19 Jun 2013 17:23:55 -0700 Subject: [PATCH 15/32] socket based UDP io --- src/libstd/rt/io/net/udp.rs | 103 ++++++++++++++++++++++++-------- src/libstd/rt/rtio.rs | 14 ++--- src/libstd/rt/uv/uvio.rs | 114 +++++++++++++++++++++++------------- 3 files changed, 159 insertions(+), 72 deletions(-) diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 6275eff9249..ac5a118f22a 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -8,47 +8,100 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::{Option}; +use option::{Option, Some, None}; +use result::{Ok, Err}; use rt::io::net::ip::IpAddr; -use rt::io::{Reader, Writer, Listener}; -use rt::rtio::{RtioUdpStreamObject}; +use rt::io::{Reader, Writer}; +use rt::io::{io_error, read_error, EndOfFile}; +use rt::rtio::{RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject}; +use rt::local::Local; -pub struct UdpStream { - rtstream: ~RtioUdpStreamObject +pub struct UdpSocket { + rtsocket: ~RtioUdpSocketObject } -impl UdpStream { - fn new(s: ~RtioUdpStreamObject) -> UdpStream { - UdpStream { - rtstream: s +impl UdpSocket { + fn new(s: ~RtioUdpSocketObject) -> UdpSocket { + UdpSocket { rtsocket: s } + } + + pub fn bind(addr: IpAddr) -> Option { + let socket = unsafe { + let io = Local::unsafe_borrow::(); + (*io).udp_bind(addr) + }; + match socket { + Ok(s) => { Some(UdpSocket { rtsocket: s }) } + Err(ioerr) => { + io_error::cond.raise(ioerr); + return None; + } } } - pub fn connect(_addr: IpAddr) -> Option { - fail!() + pub fn recvfrom(&self, buf: &mut [u8]) -> Option<(uint, IpAddr)> { + match (*self.rtsocket).recvfrom(buf) { + Ok((nread, src)) => Some((nread, src)), + Err(ioerr) => { + // EOF is indicated by returning None + // XXX do we ever find EOF reading UDP packets? + if ioerr.kind != EndOfFile { + read_error::cond.raise(ioerr); + } + None + } + } + } + + pub fn sendto(&self, buf: &[u8], dst: IpAddr) { + match (*self.rtsocket).sendto(buf, dst) { + Ok(_) => (), + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } + } + + // XXX convert ~self to self eventually + pub fn connect(~self, other: IpAddr) -> UdpStream { + UdpStream { socket: self, connectedTo: other } + } +} + +pub struct UdpStream { + socket: ~UdpSocket, + connectedTo: IpAddr +} + +impl UdpStream { + pub fn as_socket(&self, f: &fn(&UdpSocket) -> T) -> T { + f(self.socket) + } + + pub fn disconnect(self) -> ~UdpSocket { + let UdpStream { socket: s, _ } = self; + s } } impl Reader for UdpStream { - fn read(&mut self, _buf: &mut [u8]) -> Option { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option { + let conn = self.connectedTo; + do self.as_socket |sock| { + sock.recvfrom(buf) + .map_consume(|(nread,src)| if src == conn {nread} else {0}) + } + } fn eof(&mut self) -> bool { fail!() } } impl Writer for UdpStream { - fn write(&mut self, _buf: &[u8]) { fail!() } + fn write(&mut self, buf: &[u8]) { + do self.as_socket |sock| { + sock.sendto(buf, self.connectedTo); + } + } fn flush(&mut self) { fail!() } } - -pub struct UdpListener; - -impl UdpListener { - pub fn bind(_addr: IpAddr) -> Option { - fail!() - } -} - -impl Listener for UdpListener { - fn accept(&mut self) -> Option { fail!() } -} diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 0eebbb61e5b..e38c952f744 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -22,7 +22,7 @@ pub type RemoteCallbackObject = uvio::UvRemoteCallback; pub type IoFactoryObject = uvio::UvIoFactory; pub type RtioTcpStreamObject = uvio::UvTcpStream; pub type RtioTcpListenerObject = uvio::UvTcpListener; -pub type RtioUdpStreamObject = uvio::UvUdpStream; +pub type RtioUdpSocketObject = uvio::UvUdpSocket; pub trait EventLoop { fn run(&mut self); @@ -45,7 +45,7 @@ pub trait RemoteCallback { pub trait IoFactory { fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError>; fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError>; - // TODO fn udp_connect(&mut self, addr: IpAddr) -> Result<~RtioUdpStreamObject, IoError>; + fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError>; } pub trait RtioTcpListener { @@ -53,11 +53,11 @@ pub trait RtioTcpListener { } pub trait RtioTcpStream { - fn read(&mut self, buf: &mut [u8]) -> Result; - fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; + fn read(&self, buf: &mut [u8]) -> Result; + fn write(&self, buf: &[u8]) -> Result<(), IoError>; } -pub trait RtioUdpStream { - fn read(&mut self, buf: &mut [u8]) -> Result; - fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; +pub trait RtioUdpSocket { + fn recvfrom(&self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>; + fn sendto(&self, buf: &[u8], dst: IpAddr) -> Result<(), IoError>; } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index eba84e537f9..828078f4865 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -25,6 +25,7 @@ use rt::io::{standard_error, OtherIoError}; use rt::tube::Tube; use rt::local::Local; use unstable::sync::{Exclusive, exclusive}; +use rt::uv::net::uv_ip4_to_ip4; #[cfg(test)] use container::Container; #[cfg(test)] use uint; @@ -260,6 +261,24 @@ impl IoFactory for UvIoFactory { } } } + + fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError> { + let mut watcher = UdpWatcher::new(self.uv_loop()); + match watcher.bind(addr) { + Ok(_) => Ok(~UvUdpSocket { watcher: watcher }), + Err(uverr) => { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do watcher.close { + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + Err(uv_error_to_io_error(uverr)) + } + } + } } // FIXME #6090: Prefer newtype structs but Drop doesn't work @@ -358,7 +377,7 @@ impl Drop for UvTcpStream { } impl RtioTcpStream for UvTcpStream { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&self, buf: &mut [u8]) -> Result { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -403,7 +422,7 @@ impl RtioTcpStream for UvTcpStream { return result_cell.take(); } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&self, buf: &[u8]) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; let scheduler = Local::take::(); @@ -433,23 +452,21 @@ impl RtioTcpStream for UvTcpStream { } } -pub struct UvUdpStream { - watcher: UdpWatcher, - address: IpAddr +pub struct UvUdpSocket { + watcher: UdpWatcher } -impl UvUdpStream { +impl UvUdpSocket { fn watcher(&self) -> UdpWatcher { self.watcher } - fn address(&self) -> IpAddr { self.address } } -impl Drop for UvUdpStream { +impl Drop for UvUdpSocket { fn finalize(&self) { - rtdebug!("closing udp stream"); + rtdebug!("closing udp socket"); let watcher = self.watcher(); let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell(task); + let task_cell = Cell::new(task); do watcher.close { let scheduler = Local::take::(); scheduler.resume_task_immediately(task_cell.take()); @@ -458,40 +475,31 @@ impl Drop for UvUdpStream { } } -impl RtioUdpStream for UvUdpStream { - fn read(&mut self, buf: &mut [u8]) -> Result { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell> = &result_cell; +impl RtioUdpSocket for UvUdpSocket { + fn recvfrom(&self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError> { + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; let scheduler = Local::take::(); assert!(scheduler.in_task_context()); let watcher = self.watcher(); - let connection_address = self.address(); let buf_ptr: *&mut [u8] = &buf; do scheduler.deschedule_running_task_and_then |sched, task| { - rtdebug!("read: entered scheduler context"); + rtdebug!("recvfrom: entered scheduler context"); assert!(!sched.in_task_context()); let mut watcher = watcher; - let task_cell = Cell(task); - // XXX: see note in RtioTcpStream implementation for UvTcpStream - let alloc: AllocCallback = |_| unsafe { - slice_to_uv_buf(*buf_ptr) - }; - do watcher.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { - let _ = flags; // TODO actually use flags + let task_cell = Cell::new(task); + let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; + do watcher.recv_start(alloc) |watcher, nread, buf, addr, flags, status| { + let _ = flags; // TODO + let _ = buf; // TODO - // XXX: see note in RtioTcpStream implementation for UvTcpStream let mut watcher = watcher; watcher.recv_stop(); - let incoming_address = net::uv_ip4_to_ip4(&addr); let result = if status.is_none() { assert!(nread >= 0); - if incoming_address != connection_address { - Ok(0u) - } else { - Ok(nread as uint) - } + Ok((nread as uint, uv_ip4_to_ip4(&addr))) } else { Err(uv_error_to_io_error(status.unwrap())) }; @@ -505,11 +513,37 @@ impl RtioUdpStream for UvUdpStream { assert!(!result_cell.is_empty()); return result_cell.take(); - } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { - let _ = buf; - fail!() + } + fn sendto(&self, buf: &[u8], dst: IpAddr) -> Result<(), IoError> { + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let scheduler = Local::take::(); + assert!(scheduler.in_task_context()); + let watcher = self.watcher(); + let buf_ptr: *&[u8] = &buf; + do scheduler.deschedule_running_task_and_then |_, task| { + let mut watcher = watcher; + let task_cell = Cell::new(task); + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + do watcher.send(buf, dst) |watcher, status| { + let _ = watcher; // TODO + + let result = if status.is_none() { + Ok(()) + } else { + Err(uv_error_to_io_error(status.unwrap())) + }; + + unsafe { (*result_cell_ptr).put_back(result); } + + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + + assert!(!result_cell.is_empty()); + return result_cell.take(); } } @@ -535,7 +569,7 @@ fn test_simple_tcp_server_and_client() { unsafe { let io = Local::unsafe_borrow::(); let mut listener = (*io).tcp_bind(addr).unwrap(); - let mut stream = listener.accept().unwrap(); + let stream = listener.accept().unwrap(); let mut buf = [0, .. 2048]; let nread = stream.read(buf).unwrap(); assert_eq!(nread, 8); @@ -549,7 +583,7 @@ fn test_simple_tcp_server_and_client() { do spawntask_immediately { unsafe { let io = Local::unsafe_borrow::(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let stream = (*io).tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); } } @@ -564,7 +598,7 @@ fn test_read_and_block() { do spawntask_immediately { let io = unsafe { Local::unsafe_borrow::() }; let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() }; - let mut stream = listener.accept().unwrap(); + let stream = listener.accept().unwrap(); let mut buf = [0, .. 2048]; let expected = 32; @@ -597,7 +631,7 @@ fn test_read_and_block() { do spawntask_immediately { unsafe { let io = Local::unsafe_borrow::(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let stream = (*io).tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); @@ -618,7 +652,7 @@ fn test_read_read_read() { unsafe { let io = Local::unsafe_borrow::(); let mut listener = (*io).tcp_bind(addr).unwrap(); - let mut stream = listener.accept().unwrap(); + let stream = listener.accept().unwrap(); let buf = [1, .. 2048]; let mut total_bytes_written = 0; while total_bytes_written < MAX { @@ -631,7 +665,7 @@ fn test_read_read_read() { do spawntask_immediately { unsafe { let io = Local::unsafe_borrow::(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let stream = (*io).tcp_connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; while total_bytes_read < MAX { From 36c0e04e57f165681408baeb0149f9a164479599 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 19 Jun 2013 17:39:02 -0700 Subject: [PATCH 16/32] derived instances of Eq and TotalEq for IpAddr rather than implement them manually. --- src/libstd/rt/io/net/ip.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 84abc058c33..d71b891350e 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -8,28 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cmp::{Eq, TotalEq}; - +#[deriving(Eq, TotalEq)] pub enum IpAddr { Ipv4(u8, u8, u8, u8, u16), Ipv6 } - -impl Eq for IpAddr { - fn eq(&self, other: &IpAddr) -> bool { - match (*self, *other) { - (Ipv4(a,b,c,d,e), Ipv4(f,g,h,i,j)) => (a,b,c,d,e) == (f,g,h,i,j), - (Ipv6, Ipv6) => fail!(), - _ => false - } - } - fn ne(&self, other: &IpAddr) -> bool { - !(self == other) - } -} - -impl TotalEq for IpAddr { - fn equals(&self, other: &IpAddr) -> bool { - *self == *other - } -} From 794923c99511398bc90400e380dd11770ec8e614 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 11:43:40 -0700 Subject: [PATCH 17/32] UDP networking with tests --- src/libstd/rt/io/net/udp.rs | 103 +++++++++++++++++++++- src/libstd/rt/uv/mod.rs | 6 +- src/libstd/rt/uv/net.rs | 146 ++++++++++++++++++++++++------- src/libstd/rt/uv/uvio.rs | 170 +++++++++++++++++++++++++++++++----- src/libstd/rt/uv/uvll.rs | 2 +- 5 files changed, 366 insertions(+), 61 deletions(-) diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index ac5a118f22a..97c09525d35 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -44,7 +44,6 @@ impl UdpSocket { Ok((nread, src)) => Some((nread, src)), Err(ioerr) => { // EOF is indicated by returning None - // XXX do we ever find EOF reading UDP packets? if ioerr.kind != EndOfFile { read_error::cond.raise(ioerr); } @@ -86,10 +85,12 @@ impl UdpStream { impl Reader for UdpStream { fn read(&mut self, buf: &mut [u8]) -> Option { - let conn = self.connectedTo; do self.as_socket |sock| { - sock.recvfrom(buf) - .map_consume(|(nread,src)| if src == conn {nread} else {0}) + match sock.recvfrom(buf) { + Some((_nread, src)) if src != self.connectedTo => Some(0), + Some((nread, _src)) => Some(nread), + None => None, + } } } @@ -105,3 +106,97 @@ impl Writer for UdpStream { fn flush(&mut self) { fail!() } } + +#[cfg(test)] +mod test { + use super::*; + use rt::test::*; + use rt::io::net::ip::Ipv4; + use rt::io::*; + use option::{Some, None}; + + #[test] #[ignore] + fn bind_error() { + do run_in_newsched_task { + let mut called = false; + do io_error::cond.trap(|e| { + assert!(e.kind == PermissionDenied); + called = true; + }).in { + let addr = Ipv4(0, 0, 0, 0, 1); + let socket = UdpSocket::bind(addr); + assert!(socket.is_none()); + } + assert!(called); + } + } + + #[test] + fn socket_smoke_test() { + do run_in_newsched_task { + let server_ip = next_test_ip4(); + let client_ip = next_test_ip4(); + + do spawntask_immediately { + match UdpSocket::bind(server_ip) { + Some(server) => { + let mut buf = [0]; + match server.recvfrom(buf) { + Some((nread, src)) => { + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + assert_eq!(src, client_ip); + } + None => fail!() + } + } + None => fail!() + } + } + + do spawntask_immediately { + match UdpSocket::bind(client_ip) { + Some(client) => client.sendto([99], server_ip), + None => fail!() + } + } + } + } + + #[test] + fn stream_smoke_test() { + do run_in_newsched_task { + let server_ip = next_test_ip4(); + let client_ip = next_test_ip4(); + + do spawntask_immediately { + match UdpSocket::bind(server_ip) { + Some(server) => { + let server = ~server; + let mut stream = server.connect(client_ip); + let mut buf = [0]; + match stream.read(buf) { + Some(nread) => { + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + } + None => fail!() + } + } + None => fail!() + } + } + + do spawntask_immediately { + match UdpSocket::bind(client_ip) { + Some(client) => { + let client = ~client; + let mut stream = client.connect(server_ip); + stream.write([99]); + } + None => fail!() + } + } + } + } +} diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index a6a8edafe60..e39a6384bc6 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -46,6 +46,7 @@ use libc::{c_void, c_int, size_t, malloc, free}; use cast::transmute; use ptr::null; use unstable::finally::Finally; +use rt::io::net::ip::IpAddr; use rt::io::IoError; @@ -126,7 +127,7 @@ pub type ConnectionCallback = ~fn(StreamWatcher, Option); pub type FsCallback = ~fn(FsRequest, Option); pub type TimerCallback = ~fn(TimerWatcher, Option); pub type AsyncCallback = ~fn(AsyncWatcher, Option); -pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, Ipv4, uint, Option); +pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, IpAddr, uint, Option); pub type UdpSendCallback = ~fn(UdpWatcher, Option); @@ -298,9 +299,6 @@ pub fn status_to_maybe_uv_error(handle: *T, status: c_int) -> Option /// The uv buffer type pub type Buf = uvll::uv_buf_t; -/// The uv IPv4 type -pub type Ipv4 = uvll::sockaddr_in; - /// Borrow a slice to a Buf pub fn slice_to_uv_buf(v: &[u8]) -> Buf { let data = vec::raw::to_ptr(v); diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index c88d96bd230..6a0f6f156b7 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -18,8 +18,12 @@ use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; use rt::uv::last_uv_error; use vec; +use str; +use from_str::{FromStr}; -fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { +//#[cfg(test)] use rt::test::*; + +pub fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { match addr { Ipv4(a, b, c, d, p) => { unsafe { @@ -41,12 +45,21 @@ fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { pub fn uv_ip4_to_ip4(addr: *sockaddr_in) -> IpAddr { let ip4_size = 16; - let buf = vec::from_elem(ip4_size, 0u8); - unsafe { ip4_name(addr, &buf[0], ip4_size as u64) }; + let buf = vec::from_elem(ip4_size + 1 /*null terminated*/, 0u8); + unsafe { ip4_name(addr, vec::raw::to_ptr(buf), ip4_size as u64) }; let port = unsafe { ip4_port(addr) }; - Ipv4(buf[0], buf[1], buf[2], buf[3], port as u16) + let ip_str = str::from_bytes_slice(buf).trim_right_chars(&'\x00'); + let ip: ~[u8] = ip_str.split_iter('.') + .transform(|s: &str| -> u8 { + let x = FromStr::from_str(s); + assert!(x.is_some()); + x.unwrap() }) + .collect(); + assert!(ip.len() >= 4); + Ipv4(ip[0], ip[1], ip[2], ip[3], port as u16) } + // 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); @@ -266,7 +279,7 @@ pub struct UdpWatcher(*uvll::uv_udp_t); impl Watcher for UdpWatcher { } impl UdpWatcher { - pub fn new(loop_: &mut Loop) -> UdpWatcher { + pub fn new(loop_: &Loop) -> UdpWatcher { unsafe { let handle = malloc_handle(UV_UDP); assert!(handle.is_not_null()); @@ -277,7 +290,7 @@ impl UdpWatcher { } } - pub fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { + pub fn bind(&self, address: IpAddr) -> Result<(), UvError> { match address { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { @@ -295,58 +308,59 @@ impl UdpWatcher { } } - pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) { + pub fn recv_start(&self, alloc: AllocCallback, cb: UdpReceiveCallback) { { - let data = self.get_watcher_data(); + let mut this = *self; + let data = this.get_watcher_data(); data.alloc_cb = Some(alloc); data.udp_recv_cb = Some(cb); } let handle = self.native_handle(); - unsafe { uvll::read_start(handle, alloc_cb, recv_cb); } + unsafe { uvll::udp_recv_start(handle, alloc_cb, recv_cb); } extern fn alloc_cb(handle: *uvll::uv_udp_t, suggested_size: size_t) -> Buf { let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); - let data = udp_watcher.get_watcher_data(); - let alloc_cb = data.alloc_cb.get_ref(); + let alloc_cb = udp_watcher.get_watcher_data().alloc_cb.get_ref(); return (*alloc_cb)(suggested_size as uint); } /* TODO the socket address should actually be a pointer to either a sockaddr_in or sockaddr_in6. In libuv, the udp_recv callback takes a struct *sockaddr */ extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf, - address: *uvll::sockaddr_in, flags: c_uint) { + addr: *uvll::sockaddr_in, flags: c_uint) { rtdebug!("buf addr: %x", buf.base as uint); rtdebug!("buf len: %d", buf.len as int); let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); let data = udp_watcher.get_watcher_data(); let cb = data.udp_recv_cb.get_ref(); let status = status_to_maybe_uv_error(handle, nread as c_int); - unsafe { (*cb)(udp_watcher, nread as int, buf, *address, flags as uint, status) }; + let address = uv_ip4_to_ip4(addr); + unsafe { (*cb)(udp_watcher, nread as int, buf, address, flags as uint, status) }; } } - pub fn recv_stop(&mut self) { + pub fn recv_stop(&self) { let handle = self.native_handle(); unsafe { uvll::udp_recv_stop(handle); } } - pub fn send(&mut self, buf: Buf, address: IpAddr, cb: UdpSendCallback) { + pub fn send(&self, buf: Buf, address: IpAddr, cb: UdpSendCallback) { { - let data = self.get_watcher_data(); + let mut this = *self; + let data = this.get_watcher_data(); assert!(data.udp_send_cb.is_none()); data.udp_send_cb = Some(cb); } let req = UdpSendRequest::new(); - let bufs = [buf]; match address { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { unsafe { assert!(0 == uvll::udp_send(req.native_handle(), self.native_handle(), - bufs, addr, send_cb)); + [buf], addr, send_cb)); } } } @@ -357,11 +371,7 @@ impl UdpWatcher { let send_request: UdpSendRequest = NativeHandle::from_native_handle(req); let mut udp_watcher = send_request.handle(); send_request.delete(); - let cb = { - let data = udp_watcher.get_watcher_data(); - let cb = data.udp_send_cb.swap_unwrap(); - cb - }; + let cb = udp_watcher.get_watcher_data().udp_send_cb.swap_unwrap(); let status = status_to_maybe_uv_error(udp_watcher.native_handle(), status); cb(udp_watcher, status); } @@ -379,10 +389,7 @@ impl UdpWatcher { extern fn close_cb(handle: *uvll::uv_udp_t) { let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); - { - let data = udp_watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); - } + udp_watcher.get_watcher_data().close_cb.swap_unwrap()(); udp_watcher.drop_watcher_data(); unsafe { free_handle(handle as *c_void) } } @@ -475,9 +482,7 @@ impl Request for UdpSendRequest { } impl UdpSendRequest { pub fn new() -> UdpSendRequest { - let send_handle = unsafe { - malloc_req(UV_UDP_SEND) - }; + let send_handle = unsafe { malloc_req(UV_UDP_SEND) }; assert!(send_handle.is_not_null()); let send_handle = send_handle as *uvll::uv_udp_send_t; UdpSendRequest(send_handle) @@ -485,8 +490,7 @@ impl UdpSendRequest { pub fn handle(&self) -> UdpWatcher { unsafe { - let udp_handle = uvll::get_udp_handle_from_send_req(self.native_handle()); - NativeHandle::from_native_handle(udp_handle) + NativeHandle::from_native_handle(uvll::get_udp_handle_from_send_req(self.native_handle())) } } @@ -516,6 +520,12 @@ mod test { use rt::uv::{Loop, AllocCallback}; use rt::uv::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf}; + #[test] + fn test_ip4_conversion() { + let ip4 = next_test_ip4(); + assert_eq!(ip4, ip4_as_uv_ip4(ip4, uv_ip4_to_ip4)); + } + #[test] fn connect_close() { do run_in_bare_thread() { @@ -534,6 +544,19 @@ mod test { } } + #[test] + fn udp_bind_close() { + do run_in_bare_thread() { + let mut loop_ = Loop::new(); + let udp_watcher = { UdpWatcher::new(&mut loop_) }; + let addr = next_test_ip4(); + udp_watcher.bind(addr); + udp_watcher.close(||()); + loop_.run(); + loop_.close(); + } + } + #[test] fn listen() { do run_in_bare_thread() { @@ -609,4 +632,63 @@ mod test { loop_.close(); } } + + #[test] + fn udp_recv() { + do run_in_bare_thread() { + static MAX: int = 10; + let mut loop_ = Loop::new(); + let server_addr = next_test_ip4(); + let client_addr = next_test_ip4(); + + let server = UdpWatcher::new(&loop_); + assert!(server.bind(server_addr).is_ok()); + + rtdebug!("starting read"); + let alloc: AllocCallback = |size| { + vec_to_uv_buf(vec::from_elem(size, 0)) + }; + + do server.recv_start(alloc) |server, nread, buf, src, flags, status| { + server.recv_stop(); + rtdebug!("i'm reading!"); + assert!(status.is_none()); + assert_eq!(flags, 0); + assert_eq!(src, client_addr); + + let buf = vec_from_uv_buf(buf); + let mut count = 0; + rtdebug!("got %d bytes", nread); + + let buf = buf.unwrap(); + for buf.slice(0, nread as uint).iter().advance() |&byte| { + assert!(byte == count as u8); + rtdebug!("%u", byte as uint); + count += 1; + } + assert_eq!(count, MAX); + + server.close(||{}); + } + + do Thread::start { + let mut loop_ = Loop::new(); + let client = UdpWatcher::new(&loop_); + assert!(client.bind(client_addr).is_ok()); + let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let buf = slice_to_uv_buf(msg); + do client.send(buf, server_addr) |client, status| { + rtdebug!("writing"); + assert!(status.is_none()); + client.close(||{}); + } + + loop_.run(); + loop_.close(); + }; + + loop_.run(); + loop_.close(); + } + } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 828078f4865..127fac6244e 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -25,7 +25,6 @@ use rt::io::{standard_error, OtherIoError}; use rt::tube::Tube; use rt::local::Local; use unstable::sync::{Exclusive, exclusive}; -use rt::uv::net::uv_ip4_to_ip4; #[cfg(test)] use container::Container; #[cfg(test)] use uint; @@ -263,7 +262,7 @@ impl IoFactory for UvIoFactory { } fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError> { - let mut watcher = UdpWatcher::new(self.uv_loop()); + let /*mut*/ watcher = UdpWatcher::new(self.uv_loop()); match watcher.bind(addr) { Ok(_) => Ok(~UvUdpSocket { watcher: watcher }), Err(uverr) => { @@ -487,21 +486,19 @@ impl RtioUdpSocket for UvUdpSocket { do scheduler.deschedule_running_task_and_then |sched, task| { rtdebug!("recvfrom: entered scheduler context"); assert!(!sched.in_task_context()); - let mut watcher = watcher; let task_cell = Cell::new(task); let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.recv_start(alloc) |watcher, nread, buf, addr, flags, status| { - let _ = flags; // TODO - let _ = buf; // TODO + do watcher.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { + let _ = flags; // TODO add handling for partials? - let mut watcher = watcher; watcher.recv_stop(); - let result = if status.is_none() { - assert!(nread >= 0); - Ok((nread as uint, uv_ip4_to_ip4(&addr))) - } else { - Err(uv_error_to_io_error(status.unwrap())) + let result = match status { + None => { + assert!(nread >= 0); + Ok((nread as uint, addr)) + } + Some(err) => Err(uv_error_to_io_error(err)) }; unsafe { (*result_cell_ptr).put_back(result); } @@ -513,8 +510,8 @@ impl RtioUdpSocket for UvUdpSocket { assert!(!result_cell.is_empty()); return result_cell.take(); - } + fn sendto(&self, buf: &[u8], dst: IpAddr) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -523,16 +520,13 @@ impl RtioUdpSocket for UvUdpSocket { let watcher = self.watcher(); let buf_ptr: *&[u8] = &buf; do scheduler.deschedule_running_task_and_then |_, task| { - let mut watcher = watcher; let task_cell = Cell::new(task); let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.send(buf, dst) |watcher, status| { - let _ = watcher; // TODO + do watcher.send(buf, dst) |_watcher, status| { - let result = if status.is_none() { - Ok(()) - } else { - Err(uv_error_to_io_error(status.unwrap())) + let result = match status { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)), }; unsafe { (*result_cell_ptr).put_back(result); } @@ -559,6 +553,18 @@ fn test_simple_io_no_connect() { } } +#[test] +fn test_simple_udp_io_bind_only() { + do run_in_newsched_task { + unsafe { + let io = Local::unsafe_borrow::(); + let addr = next_test_ip4(); + let maybe_socket = (*io).udp_bind(addr); + assert!(maybe_socket.is_ok()); + } + } +} + #[test] fn test_simple_tcp_server_and_client() { do run_in_newsched_task { @@ -590,6 +596,37 @@ fn test_simple_tcp_server_and_client() { } } +#[test] +fn test_simple_udp_server_and_client() { + do run_in_newsched_task { + let server_addr = next_test_ip4(); + let client_addr = next_test_ip4(); + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let server_socket = (*io).udp_bind(server_addr).unwrap(); + let mut buf = [0, .. 2048]; + let (nread,src) = server_socket.recvfrom(buf).unwrap(); + assert_eq!(nread, 8); + for uint::range(0, nread) |i| { + rtdebug!("%u", buf[i] as uint); + assert_eq!(buf[i], i as u8); + } + assert_eq!(src, client_addr); + } + } + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let client_socket = (*io).udp_bind(client_addr).unwrap(); + client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr); + } + } + } +} + #[test] #[ignore(reason = "busted")] fn test_read_and_block() { do run_in_newsched_task { @@ -681,3 +718,96 @@ fn test_read_read_read() { } } } + +#[test] +fn test_udp_twice() { + do run_in_newsched_task { + let server_addr = next_test_ip4(); + let client_addr = next_test_ip4(); + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let client = (*io).udp_bind(client_addr).unwrap(); + assert!(client.sendto([1], server_addr).is_ok()); + assert!(client.sendto([2], server_addr).is_ok()); + } + } + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let server = (*io).udp_bind(server_addr).unwrap(); + let mut buf1 = [0]; + let mut buf2 = [0]; + let (nread1, src1) = server.recvfrom(buf1).unwrap(); + let (nread2, src2) = server.recvfrom(buf2).unwrap(); + assert_eq!(nread1, 1); + assert_eq!(nread2, 1); + assert_eq!(src1, client_addr); + assert_eq!(src2, client_addr); + assert_eq!(buf1[0], 1); + assert_eq!(buf2[0], 2); + } + } + } +} + +#[test] +fn test_udp_many_read() { + do run_in_newsched_task { + let server_out_addr = next_test_ip4(); + let server_in_addr = next_test_ip4(); + let client_out_addr = next_test_ip4(); + let client_in_addr = next_test_ip4(); + static MAX: uint = 500_000; + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let server_out = (*io).udp_bind(server_out_addr).unwrap(); + let server_in = (*io).udp_bind(server_in_addr).unwrap(); + let msg = [1, .. 2048]; + let mut total_bytes_sent = 0; + let mut buf = [1]; + while buf[0] == 1 { + // send more data + assert!(server_out.sendto(msg, client_in_addr).is_ok()); + total_bytes_sent += msg.len(); + // check if the client has received enough + let res = server_in.recvfrom(buf); + assert!(res.is_ok()); + let (nread, src) = res.unwrap(); + assert_eq!(nread, 1); + assert_eq!(src, client_out_addr); + } + assert!(total_bytes_sent >= MAX); + } + } + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let client_out = (*io).udp_bind(client_out_addr).unwrap(); + let client_in = (*io).udp_bind(client_in_addr).unwrap(); + let mut total_bytes_recv = 0; + let mut buf = [0, .. 2048]; + while total_bytes_recv < MAX { + // ask for more + assert!(client_out.sendto([1], server_in_addr).is_ok()); + // wait for data + let res = client_in.recvfrom(buf); + assert!(res.is_ok()); + let (nread, src) = res.unwrap(); + assert_eq!(src, server_out_addr); + total_bytes_recv += nread; + for uint::range(0, nread) |i| { + assert_eq!(buf[i], 1); + } + } + // tell the server we're done + assert!(client_out.sendto([0], server_in_addr).is_ok()); + } + } + } +} diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index b73db77f3bb..3bfc123dc85 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -215,7 +215,7 @@ pub unsafe fn udp_send6(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int { let buf_ptr = vec::raw::to_ptr(buf_in); let buf_cnt = buf_in.len() as i32; - return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); + return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); } pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb, on_recv: uv_udp_recv_cb) -> c_int { From 1af20163586d13f505492865f70fe9767f35a306 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 11:59:47 -0700 Subject: [PATCH 18/32] removed unncessary unsafe block that was stopping compliation. --- src/libstd/rt/uv/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 6a0f6f156b7..34388b3dc15 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -336,7 +336,7 @@ impl UdpWatcher { let cb = data.udp_recv_cb.get_ref(); let status = status_to_maybe_uv_error(handle, nread as c_int); let address = uv_ip4_to_ip4(addr); - unsafe { (*cb)(udp_watcher, nread as int, buf, address, flags as uint, status) }; + (*cb)(udp_watcher, nread as int, buf, address, flags as uint, status); } } From f202713b73559941ad64c539dc10b71655879403 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 14:40:36 -0700 Subject: [PATCH 19/32] satisfy the formatting check --- src/libstd/rt/io/net/udp.rs | 4 ++-- src/libstd/rt/uv/net.rs | 23 +++++++++++++---------- src/libstd/rt/uv/uvio.rs | 4 ++-- src/libstd/rt/uv/uvll.rs | 3 ++- src/rt/rust_uv.cpp | 4 ++-- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 97c09525d35..d85fb062430 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -84,7 +84,7 @@ impl UdpStream { } impl Reader for UdpStream { - fn read(&mut self, buf: &mut [u8]) -> Option { + fn read(&mut self, buf: &mut [u8]) -> Option { do self.as_socket |sock| { match sock.recvfrom(buf) { Some((_nread, src)) if src != self.connectedTo => Some(0), @@ -131,7 +131,7 @@ mod test { } } - #[test] + #[test] fn socket_smoke_test() { do run_in_newsched_task { let server_ip = next_test_ip4(); diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 34388b3dc15..eac70d5219a 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -50,12 +50,12 @@ pub fn uv_ip4_to_ip4(addr: *sockaddr_in) -> IpAddr { let port = unsafe { ip4_port(addr) }; let ip_str = str::from_bytes_slice(buf).trim_right_chars(&'\x00'); let ip: ~[u8] = ip_str.split_iter('.') - .transform(|s: &str| -> u8 { - let x = FromStr::from_str(s); + .transform(|s: &str| -> u8 { + let x = FromStr::from_str(s); assert!(x.is_some()); x.unwrap() }) .collect(); - assert!(ip.len() >= 4); + assert!(ip.len() >= 4); Ipv4(ip[0], ip[1], ip[2], ip[3], port as u16) } @@ -304,7 +304,7 @@ impl UdpWatcher { } } } - _ => fail!() // TODO ipv6 + _ => fail!() // NOTE ipv6 } } @@ -325,9 +325,10 @@ impl UdpWatcher { return (*alloc_cb)(suggested_size as uint); } - /* TODO the socket address should actually be a pointer to either a sockaddr_in or sockaddr_in6. + /* NOTE the socket address should actually be a pointer to + either a sockaddr_in or sockaddr_in6. In libuv, the udp_recv callback takes a struct *sockaddr */ - extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf, + extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf, addr: *uvll::sockaddr_in, flags: c_uint) { rtdebug!("buf addr: %x", buf.base as uint); rtdebug!("buf len: %d", buf.len as int); @@ -364,7 +365,7 @@ impl UdpWatcher { } } } - _ => fail!() // TODO ipv6 + _ => fail!() // NOTE ipv6 } extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) { @@ -490,7 +491,9 @@ impl UdpSendRequest { pub fn handle(&self) -> UdpWatcher { unsafe { - NativeHandle::from_native_handle(uvll::get_udp_handle_from_send_req(self.native_handle())) + NativeHandle::from_native_handle( + uvll::get_udp_handle_from_send_req( + self.native_handle())) } } @@ -544,7 +547,7 @@ mod test { } } - #[test] + #[test] fn udp_bind_close() { do run_in_bare_thread() { let mut loop_ = Loop::new(); @@ -633,7 +636,7 @@ mod test { } } - #[test] + #[test] fn udp_recv() { do run_in_bare_thread() { static MAX: int = 10; diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 127fac6244e..6b4cb66ed99 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -489,7 +489,7 @@ impl RtioUdpSocket for UvUdpSocket { let task_cell = Cell::new(task); let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; do watcher.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { - let _ = flags; // TODO add handling for partials? + let _ = flags; // NOTE add handling for partials? watcher.recv_stop(); @@ -596,7 +596,7 @@ fn test_simple_tcp_server_and_client() { } } -#[test] +#[test] fn test_simple_udp_server_and_client() { do run_in_newsched_task { let server_addr = next_test_ip4(); diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 3bfc123dc85..841a9bf8ef7 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -218,7 +218,8 @@ pub unsafe fn udp_send6(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t], return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb); } -pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb, on_recv: uv_udp_recv_cb) -> c_int { +pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb, + on_recv: uv_udp_recv_cb) -> c_int { return rust_uv_udp_recv_start(server, on_alloc, on_recv); } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 2fb9dc2f1a2..6032ed1a6bd 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -309,13 +309,13 @@ rust_uv_udp_bind6(uv_udp_t* server, sockaddr_in6* addr_ptr, unsigned flags) { } extern "C" int -rust_uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t* buf_in, +rust_uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t* buf_in, int buf_cnt, sockaddr_in* addr_ptr, uv_udp_send_cb cb) { return uv_udp_send(req, handle, buf_in, buf_cnt, *addr_ptr, cb); } extern "C" int -rust_uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t* buf_in, +rust_uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t* buf_in, int buf_cnt, sockaddr_in6* addr_ptr, uv_udp_send_cb cb) { return uv_udp_send6(req, handle, buf_in, buf_cnt, *addr_ptr, cb); } From 2c5cfe1037d618153b39597e0e1e62d95c8e4760 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 16:02:51 -0700 Subject: [PATCH 20/32] removed obsolete FIXMEs. formatting changes. --- src/libstd/rt/uv/uvll.rs | 74 ++++++++++++---------------------------- 1 file changed, 22 insertions(+), 52 deletions(-) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 841a9bf8ef7..7035cb6a5e8 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -235,27 +235,20 @@ pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { return rust_uv_tcp_init(loop_handle, handle); } -// FIXME ref #2064 -pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); +pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, + addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int { + return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr); } -// FIXME ref #2064 -pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in6, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); + +pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, + addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int { + return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr); } -// FIXME ref #2064 + pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int { return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr); } -// FIXME ref #2064 + pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int { return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr); } @@ -444,16 +437,11 @@ extern { fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; fn rust_uv_async_send(handle: *uv_async_t); - fn rust_uv_async_init(loop_handle: *c_void, - async_handle: *uv_async_t, - cb: *u8) -> c_int; + fn rust_uv_async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int; fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int; - // FIXME ref #2604 .. ? fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t); fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t; - // FIXME ref #2064 fn rust_uv_strerror(err: *uv_err_t) -> *c_char; - // FIXME ref #2064 fn rust_uv_err_name(err: *uv_err_t) -> *c_char; fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in; fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6; @@ -463,52 +451,34 @@ extern { fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int; fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint; fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint; - // FIXME ref #2064 - fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, + fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, after_cb: *u8, addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, + fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, after_cb: *u8, addr: *sockaddr_in6) -> c_int; - // FIXME ref #2064 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_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_udp_init(loop_handle: *uv_loop_t, handle_ptr: *uv_udp_t) -> c_int; fn rust_uv_udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int; fn rust_uv_udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int; - fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, - buf_cnt: c_int, addr: *sockaddr_in, cb: *u8) -> c_int; - fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, - buf_cnt: c_int, addr: *sockaddr_in6, cb: *u8) -> c_int; + fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, buf_cnt: c_int, + addr: *sockaddr_in, cb: *u8) -> c_int; + fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, buf_cnt: c_int, + addr: *sockaddr_in6, cb: *u8) -> c_int; 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_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; - fn rust_uv_write(req: *c_void, - stream: *c_void, - buf_in: *uv_buf_t, - buf_cnt: c_int, + fn rust_uv_write(req: *c_void, stream: *c_void, buf_in: *uv_buf_t, buf_cnt: c_int, cb: *u8) -> c_int; - fn rust_uv_read_start(stream: *c_void, - on_alloc: *u8, - on_read: *u8) -> c_int; + fn rust_uv_read_start(stream: *c_void, on_alloc: *u8, on_read: *u8) -> c_int; fn rust_uv_read_stop(stream: *c_void) -> c_int; - fn rust_uv_timer_init(loop_handle: *c_void, - timer_handle: *uv_timer_t) -> c_int; - fn rust_uv_timer_start(timer_handle: *uv_timer_t, - cb: *u8, - timeout: libc::uint64_t, + fn rust_uv_timer_init(loop_handle: *c_void, timer_handle: *uv_timer_t) -> c_int; + fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: *u8, timeout: libc::uint64_t, repeat: libc::uint64_t) -> c_int; fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; From d0c812f2a8064a9ea1b6a309343c00a5c18c9ce4 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 16:03:24 -0700 Subject: [PATCH 21/32] IPv6 struct --- src/libstd/rt/io/net/ip.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index d71b891350e..3a93fd70543 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +type Port = u16; + #[deriving(Eq, TotalEq)] pub enum IpAddr { - Ipv4(u8, u8, u8, u8, u16), - Ipv6 + Ipv4(u8, u8, u8, u8, Port), + Ipv6(u16, u16, u16, u16, u16, u16, u16, u16, Port) } From c5b19f0bf9c2f32f368b0f2565a06ae0271a96c1 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 16:04:09 -0700 Subject: [PATCH 22/32] changed outdated match on IpAddr --- src/libstd/rt/uv/net.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index eac70d5219a..9ddc99af699 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -15,14 +15,12 @@ use rt::uv::uvll::*; use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback}; use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, status_to_maybe_uv_error}; -use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; +use rt::io::net::ip::{IpAddr, Ipv4}; use rt::uv::last_uv_error; use vec; use str; use from_str::{FromStr}; -//#[cfg(test)] use rt::test::*; - pub fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { match addr { Ipv4(a, b, c, d, p) => { @@ -39,7 +37,7 @@ pub fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { } } } - Ipv6 => fail!() + _ => fail!() // NOTE ipv6 } } From f60468629566ae896e90039f89ef5bb63f920aef Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 17:04:28 -0700 Subject: [PATCH 23/32] converted UvUdpSocket into a newtype struct --- src/libstd/rt/uv/uvio.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 6b4cb66ed99..905087103fc 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -264,7 +264,7 @@ impl IoFactory for UvIoFactory { fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError> { let /*mut*/ watcher = UdpWatcher::new(self.uv_loop()); match watcher.bind(addr) { - Ok(_) => Ok(~UvUdpSocket { watcher: watcher }), + Ok(_) => Ok(~UvUdpSocket(watcher)), Err(uverr) => { let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { @@ -451,22 +451,15 @@ impl RtioTcpStream for UvTcpStream { } } -pub struct UvUdpSocket { - watcher: UdpWatcher -} - -impl UvUdpSocket { - fn watcher(&self) -> UdpWatcher { self.watcher } -} +pub struct UvUdpSocket(UdpWatcher); impl Drop for UvUdpSocket { fn finalize(&self) { rtdebug!("closing udp socket"); - let watcher = self.watcher(); let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - do watcher.close { + do self.close { let scheduler = Local::take::(); scheduler.resume_task_immediately(task_cell.take()); } @@ -481,14 +474,13 @@ impl RtioUdpSocket for UvUdpSocket { let scheduler = Local::take::(); assert!(scheduler.in_task_context()); - let watcher = self.watcher(); let buf_ptr: *&mut [u8] = &buf; do scheduler.deschedule_running_task_and_then |sched, task| { rtdebug!("recvfrom: entered scheduler context"); assert!(!sched.in_task_context()); let task_cell = Cell::new(task); let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { + do self.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { let _ = flags; // NOTE add handling for partials? watcher.recv_stop(); @@ -517,12 +509,11 @@ impl RtioUdpSocket for UvUdpSocket { let result_cell_ptr: *Cell> = &result_cell; let scheduler = Local::take::(); assert!(scheduler.in_task_context()); - let watcher = self.watcher(); let buf_ptr: *&[u8] = &buf; do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.send(buf, dst) |_watcher, status| { + do self.send(buf, dst) |_watcher, status| { let result = match status { None => Ok(()), From 34b1135b59b15d66a2c5db77563f5b6a13deec15 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 25 Jun 2013 17:05:59 -0700 Subject: [PATCH 24/32] Converted UdpSocket into a newtype struct and (dis)connecting uses move semantics rather than ~. --- src/libstd/rt/io/net/udp.rs | 39 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index d85fb062430..2452441b965 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -16,31 +16,24 @@ use rt::io::{io_error, read_error, EndOfFile}; use rt::rtio::{RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject}; use rt::local::Local; -pub struct UdpSocket { - rtsocket: ~RtioUdpSocketObject -} +pub struct UdpSocket(~RtioUdpSocketObject); impl UdpSocket { - fn new(s: ~RtioUdpSocketObject) -> UdpSocket { - UdpSocket { rtsocket: s } - } + fn new(s: ~RtioUdpSocketObject) -> UdpSocket { UdpSocket(s) } pub fn bind(addr: IpAddr) -> Option { - let socket = unsafe { - let io = Local::unsafe_borrow::(); - (*io).udp_bind(addr) - }; + let socket = unsafe { (*Local::unsafe_borrow::()).udp_bind(addr) }; match socket { - Ok(s) => { Some(UdpSocket { rtsocket: s }) } + Ok(s) => Some(UdpSocket::new(s)), Err(ioerr) => { io_error::cond.raise(ioerr); - return None; + None } } } pub fn recvfrom(&self, buf: &mut [u8]) -> Option<(uint, IpAddr)> { - match (*self.rtsocket).recvfrom(buf) { + match (**self).recvfrom(buf) { Ok((nread, src)) => Some((nread, src)), Err(ioerr) => { // EOF is indicated by returning None @@ -53,34 +46,26 @@ impl UdpSocket { } pub fn sendto(&self, buf: &[u8], dst: IpAddr) { - match (*self.rtsocket).sendto(buf, dst) { + match (**self).sendto(buf, dst) { Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } + Err(ioerr) => io_error::cond.raise(ioerr), } } - // XXX convert ~self to self eventually - pub fn connect(~self, other: IpAddr) -> UdpStream { + pub fn connect(self, other: IpAddr) -> UdpStream { UdpStream { socket: self, connectedTo: other } } } pub struct UdpStream { - socket: ~UdpSocket, + socket: UdpSocket, connectedTo: IpAddr } impl UdpStream { - pub fn as_socket(&self, f: &fn(&UdpSocket) -> T) -> T { - f(self.socket) - } + pub fn as_socket(&self, f: &fn(&UdpSocket) -> T) -> T { f(&self.socket) } - pub fn disconnect(self) -> ~UdpSocket { - let UdpStream { socket: s, _ } = self; - s - } + pub fn disconnect(self) -> UdpSocket { self.socket } } impl Reader for UdpStream { From d0dc6970d8b8bb0e6cc358ec169daa70d99e1d15 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 26 Jun 2013 09:37:16 -0700 Subject: [PATCH 25/32] removed unecessary method --- src/libstd/rt/io/net/udp.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 2452441b965..c66f7d8ce06 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -19,12 +19,10 @@ use rt::local::Local; pub struct UdpSocket(~RtioUdpSocketObject); impl UdpSocket { - fn new(s: ~RtioUdpSocketObject) -> UdpSocket { UdpSocket(s) } - pub fn bind(addr: IpAddr) -> Option { let socket = unsafe { (*Local::unsafe_borrow::()).udp_bind(addr) }; match socket { - Ok(s) => Some(UdpSocket::new(s)), + Ok(s) => Some(UdpSocket(s)), Err(ioerr) => { io_error::cond.raise(ioerr); None From 87ecfb74357b669308a6e337ebc766af8a03b554 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 26 Jun 2013 09:37:48 -0700 Subject: [PATCH 26/32] converted TCP interface to newtype structs --- src/libstd/rt/io/net/tcp.rs | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 3607f781da3..947fade096b 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -18,15 +18,11 @@ use rt::rtio::{IoFactory, IoFactoryObject, RtioTcpStream, RtioTcpStreamObject}; use rt::local::Local; -pub struct TcpStream { - rtstream: ~RtioTcpStreamObject -} +pub struct TcpStream(~RtioTcpStreamObject); impl TcpStream { fn new(s: ~RtioTcpStreamObject) -> TcpStream { - TcpStream { - rtstream: s - } + TcpStream(s) } pub fn connect(addr: IpAddr) -> Option { @@ -38,13 +34,11 @@ impl TcpStream { }; match stream { - Ok(s) => { - Some(TcpStream::new(s)) - } + Ok(s) => Some(TcpStream::new(s)), Err(ioerr) => { rtdebug!("failed to connect: %?", ioerr); io_error::cond.raise(ioerr); - return None; + None } } } @@ -52,8 +46,7 @@ impl TcpStream { impl Reader for TcpStream { fn read(&mut self, buf: &mut [u8]) -> Option { - let bytes_read = self.rtstream.read(buf); - match bytes_read { + match (**self).read(buf) { Ok(read) => Some(read), Err(ioerr) => { // EOF is indicated by returning None @@ -70,8 +63,7 @@ impl Reader for TcpStream { impl Writer for TcpStream { fn write(&mut self, buf: &[u8]) { - let res = self.rtstream.write(buf); - match res { + match (**self).write(buf) { Ok(_) => (), Err(ioerr) => { io_error::cond.raise(ioerr); @@ -82,9 +74,7 @@ impl Writer for TcpStream { fn flush(&mut self) { fail!() } } -pub struct TcpListener { - rtlistener: ~RtioTcpListenerObject, -} +pub struct TcpListener(~RtioTcpListenerObject); impl TcpListener { pub fn bind(addr: IpAddr) -> Option { @@ -93,11 +83,7 @@ impl TcpListener { (*io).tcp_bind(addr) }; match listener { - Ok(l) => { - Some(TcpListener { - rtlistener: l - }) - } + Ok(l) => Some(TcpListener(l)), Err(ioerr) => { io_error::cond.raise(ioerr); return None; @@ -108,8 +94,7 @@ impl TcpListener { impl Listener for TcpListener { fn accept(&mut self) -> Option { - let rtstream = self.rtlistener.accept(); - match rtstream { + match (**self).accept() { Ok(s) => { Some(TcpStream::new(s)) } From ce97bd4c8b841165bb22cb0be566a9b66931165a Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 26 Jun 2013 10:17:10 -0700 Subject: [PATCH 27/32] cleaned up uv/net --- src/libstd/rt/uv/net.rs | 100 +++++++++++++--------------------------- 1 file changed, 32 insertions(+), 68 deletions(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 9ddc99af699..8c5f9fdbd4a 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -44,8 +44,8 @@ pub fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { pub fn uv_ip4_to_ip4(addr: *sockaddr_in) -> IpAddr { let ip4_size = 16; let buf = vec::from_elem(ip4_size + 1 /*null terminated*/, 0u8); - unsafe { ip4_name(addr, vec::raw::to_ptr(buf), ip4_size as u64) }; - let port = unsafe { ip4_port(addr) }; + unsafe { uvll::ip4_name(addr, vec::raw::to_ptr(buf), ip4_size as u64) }; + let port = unsafe { uvll::ip4_port(addr) }; let ip_str = str::from_bytes_slice(buf).trim_right_chars(&'\x00'); let ip: ~[u8] = ip_str.split_iter('.') .transform(|s: &str| -> u8 { @@ -71,13 +71,11 @@ impl StreamWatcher { data.read_cb = Some(cb); } - let handle = self.native_handle(); - unsafe { uvll::read_start(handle, alloc_cb, read_cb); } + unsafe { uvll::read_start(self.native_handle(), alloc_cb, read_cb); } extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf { let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); - let data = stream_watcher.get_watcher_data(); - let alloc_cb = data.alloc_cb.get_ref(); + let alloc_cb = stream_watcher.get_watcher_data().alloc_cb.get_ref(); return (*alloc_cb)(suggested_size as uint); } @@ -85,8 +83,7 @@ impl StreamWatcher { rtdebug!("buf addr: %x", buf.base as uint); rtdebug!("buf len: %d", buf.len as int); let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); - let data = stream_watcher.get_watcher_data(); - let cb = data.read_cb.get_ref(); + let cb = stream_watcher.get_watcher_data().read_cb.get_ref(); let status = status_to_maybe_uv_error(stream, nread as c_int); (*cb)(stream_watcher, nread as int, buf, status); } @@ -108,22 +105,15 @@ impl StreamWatcher { } let req = WriteRequest::new(); - let bufs = [buf]; unsafe { - assert!(0 == uvll::write(req.native_handle(), - self.native_handle(), - bufs, write_cb)); + assert_eq!(0, uvll::write(req.native_handle(), self.native_handle(), [buf], write_cb)); } extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = write_request.stream(); write_request.delete(); - let cb = { - let data = stream_watcher.get_watcher_data(); - let cb = data.write_cb.swap_unwrap(); - cb - }; + let cb = stream_watcher.get_watcher_data().write_cb.swap_unwrap(); let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } @@ -132,9 +122,7 @@ impl StreamWatcher { pub fn accept(&mut self, stream: StreamWatcher) { let self_handle = self.native_handle() as *c_void; let stream_handle = stream.native_handle() as *c_void; - unsafe { - assert_eq!(0, uvll::accept(self_handle, stream_handle)); - } + assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } ); } pub fn close(self, cb: NullCallback) { @@ -149,10 +137,7 @@ impl StreamWatcher { extern fn close_cb(handle: *uvll::uv_stream_t) { let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - { - let data = stream_watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); - } + stream_watcher.get_watcher_data().close_cb.swap_unwrap()(); stream_watcher.drop_watcher_data(); unsafe { free_handle(handle as *c_void) } } @@ -160,8 +145,7 @@ impl StreamWatcher { } impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher { - fn from_native_handle( - handle: *uvll::uv_stream_t) -> StreamWatcher { + fn from_native_handle(handle: *uvll::uv_stream_t) -> StreamWatcher { StreamWatcher(handle) } fn native_handle(&self) -> *uvll::uv_stream_t { @@ -188,9 +172,7 @@ impl TcpWatcher { match address { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { - let result = unsafe { - uvll::tcp_bind(self.native_handle(), addr) - }; + let result = unsafe { uvll::tcp_bind(self.native_handle(), addr) }; if result == 0 { Ok(()) } else { @@ -212,9 +194,9 @@ impl TcpWatcher { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { rtdebug!("connect_t: %x", connect_handle as uint); - assert!(0 == uvll::tcp_connect(connect_handle, - self.native_handle(), - addr, connect_cb)); + assert_eq!(0, + uvll::tcp_connect(connect_handle, self.native_handle(), + addr, connect_cb)); } } _ => fail!() @@ -225,10 +207,7 @@ impl TcpWatcher { let connect_request: ConnectRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = connect_request.stream(); connect_request.delete(); - let cb: ConnectionCallback = { - let data = stream_watcher.get_watcher_data(); - data.connect_cb.swap_unwrap() - }; + let cb = stream_watcher.get_watcher_data().connect_cb.swap_unwrap(); let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } @@ -245,15 +224,13 @@ impl TcpWatcher { unsafe { static BACKLOG: c_int = 128; // XXX should be configurable // XXX: This can probably fail - assert!(0 == uvll::listen(self.native_handle(), - BACKLOG, connection_cb)); + assert_eq!(0, uvll::listen(self.native_handle(), BACKLOG, connection_cb)); } extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { rtdebug!("connection_cb"); let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let data = stream_watcher.get_watcher_data(); - let cb = data.connect_cb.get_ref(); + let cb = stream_watcher.get_watcher_data().connect_cb.get_ref(); let status = status_to_maybe_uv_error(handle, status); (*cb)(stream_watcher, status); } @@ -314,8 +291,7 @@ impl UdpWatcher { data.udp_recv_cb = Some(cb); } - let handle = self.native_handle(); - unsafe { uvll::udp_recv_start(handle, alloc_cb, recv_cb); } + unsafe { uvll::udp_recv_start(self.native_handle(), alloc_cb, recv_cb); } extern fn alloc_cb(handle: *uvll::uv_udp_t, suggested_size: size_t) -> Buf { let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); @@ -331,17 +307,14 @@ impl UdpWatcher { rtdebug!("buf addr: %x", buf.base as uint); rtdebug!("buf len: %d", buf.len as int); let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); - let data = udp_watcher.get_watcher_data(); - let cb = data.udp_recv_cb.get_ref(); + 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 address = uv_ip4_to_ip4(addr); - (*cb)(udp_watcher, nread as int, buf, address, flags as uint, status); + (*cb)(udp_watcher, nread as int, buf, uv_ip4_to_ip4(addr), flags as uint, status); } } pub fn recv_stop(&self) { - let handle = self.native_handle(); - unsafe { uvll::udp_recv_stop(handle); } + unsafe { uvll::udp_recv_stop(self.native_handle()); } } pub fn send(&self, buf: Buf, address: IpAddr, cb: UdpSendCallback) { @@ -357,7 +330,7 @@ impl UdpWatcher { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { unsafe { - assert!(0 == uvll::udp_send(req.native_handle(), + assert_eq!(0, uvll::udp_send(req.native_handle(), self.native_handle(), [buf], addr, send_cb)); } @@ -411,12 +384,9 @@ impl Request for ConnectRequest { } impl ConnectRequest { fn new() -> ConnectRequest { - let connect_handle = unsafe { - malloc_req(UV_CONNECT) - }; + let connect_handle = unsafe { malloc_req(UV_CONNECT) }; assert!(connect_handle.is_not_null()); - let connect_handle = connect_handle as *uvll::uv_connect_t; - ConnectRequest(connect_handle) + ConnectRequest(connect_handle as *uvll::uv_connect_t) } fn stream(&self) -> StreamWatcher { @@ -432,8 +402,7 @@ impl ConnectRequest { } impl NativeHandle<*uvll::uv_connect_t> for ConnectRequest { - fn from_native_handle( - handle: *uvll:: uv_connect_t) -> ConnectRequest { + fn from_native_handle(handle: *uvll:: uv_connect_t) -> ConnectRequest { ConnectRequest(handle) } fn native_handle(&self) -> *uvll::uv_connect_t { @@ -447,12 +416,9 @@ impl Request for WriteRequest { } impl WriteRequest { pub fn new() -> WriteRequest { - let write_handle = unsafe { - malloc_req(UV_WRITE) - }; + let write_handle = unsafe { malloc_req(UV_WRITE) }; assert!(write_handle.is_not_null()); - let write_handle = write_handle as *uvll::uv_write_t; - WriteRequest(write_handle) + WriteRequest(write_handle as *uvll::uv_write_t) } pub fn stream(&self) -> StreamWatcher { @@ -483,16 +449,14 @@ impl UdpSendRequest { pub fn new() -> UdpSendRequest { let send_handle = unsafe { malloc_req(UV_UDP_SEND) }; assert!(send_handle.is_not_null()); - let send_handle = send_handle as *uvll::uv_udp_send_t; - UdpSendRequest(send_handle) + UdpSendRequest(send_handle as *uvll::uv_udp_send_t) } pub fn handle(&self) -> UdpWatcher { - unsafe { - NativeHandle::from_native_handle( - uvll::get_udp_handle_from_send_req( - self.native_handle())) - } + let send_request_handle = unsafe { + uvll::get_udp_handle_from_send_req(self.native_handle()) + }; + NativeHandle::from_native_handle(send_request_handle) } pub fn delete(self) { From 42f3f069fa1963cdf19117e57a83089889a64f37 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 26 Jun 2013 13:48:49 -0700 Subject: [PATCH 28/32] changed NOTE to TODO --- src/libstd/rt/uv/net.rs | 8 ++++---- src/libstd/rt/uv/uvio.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 8c5f9fdbd4a..dc766b2d7f8 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -37,7 +37,7 @@ pub fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { } } } - _ => fail!() // NOTE ipv6 + _ => fail!() // TODO ipv6 } } @@ -279,7 +279,7 @@ impl UdpWatcher { } } } - _ => fail!() // NOTE ipv6 + _ => fail!() // TODO ipv6 } } @@ -299,7 +299,7 @@ impl UdpWatcher { return (*alloc_cb)(suggested_size as uint); } - /* NOTE the socket address should actually be a pointer to + /* TODO the socket address should actually be a pointer to either a sockaddr_in or sockaddr_in6. In libuv, the udp_recv callback takes a struct *sockaddr */ extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf, @@ -336,7 +336,7 @@ impl UdpWatcher { } } } - _ => fail!() // NOTE ipv6 + _ => fail!() // TODO ipv6 } extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 905087103fc..1ae6cd8b17b 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -481,7 +481,7 @@ impl RtioUdpSocket for UvUdpSocket { let task_cell = Cell::new(task); let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; do self.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { - let _ = flags; // NOTE add handling for partials? + let _ = flags; // TODO add handling for partials? watcher.recv_stop(); From e6c57793be2cf7aabfa96aeada77935cc0351067 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 2 Jul 2013 16:40:57 -0700 Subject: [PATCH 29/32] IPv6 support for UDP and TCP. --- src/libstd/rt/io/net/tcp.rs | 207 +++++++++++++++++- src/libstd/rt/io/net/udp.rs | 73 ++++++- src/libstd/rt/rtio.rs | 30 ++- src/libstd/rt/test.rs | 9 +- src/libstd/rt/uv/net.rs | 423 ++++++++++++++++++++++++++++-------- src/libstd/rt/uv/uvio.rs | 69 ++++-- src/libstd/rt/uv/uvll.rs | 92 +++++++- src/rt/rust_uv.cpp | 94 ++++++++ src/rt/rustrt.def.in | 15 ++ 9 files changed, 879 insertions(+), 133 deletions(-) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 947fade096b..2425c909bf3 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -148,7 +148,7 @@ mod test { } #[test] - fn smoke_test() { + fn smoke_test_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); @@ -168,7 +168,27 @@ mod test { } #[test] - fn read_eof() { + fn smoke_test_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + let mut stream = listener.accept(); + let mut buf = [0]; + stream.read(buf); + assert!(buf[0] == 99); + } + + do spawntask_immediately { + let mut stream = TcpStream::connect(addr); + stream.write([99]); + } + } + } + + #[test] + fn read_eof_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); @@ -188,7 +208,27 @@ mod test { } #[test] - fn read_eof_twice() { + fn read_eof_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + let mut stream = listener.accept(); + let mut buf = [0]; + let nread = stream.read(buf); + assert!(nread.is_none()); + } + + do spawntask_immediately { + let _stream = TcpStream::connect(addr); + // Close + } + } + } + + #[test] + fn read_eof_twice_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); @@ -210,7 +250,29 @@ mod test { } #[test] - fn write_close() { + fn read_eof_twice_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + let mut stream = listener.accept(); + let mut buf = [0]; + let nread = stream.read(buf); + assert!(nread.is_none()); + let nread = stream.read(buf); + assert!(nread.is_none()); + } + + do spawntask_immediately { + let _stream = TcpStream::connect(addr); + // Close + } + } + } + + #[test] + fn write_close_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); @@ -239,7 +301,36 @@ mod test { } #[test] - fn multiple_connect_serial() { + fn write_close_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + let mut stream = listener.accept(); + let buf = [0]; + loop { + let mut stop = false; + do io_error::cond.trap(|e| { + // NB: ECONNRESET on linux, EPIPE on mac + assert!(e.kind == ConnectionReset || e.kind == BrokenPipe); + stop = true; + }).in { + stream.write(buf); + } + if stop { break } + } + } + + do spawntask_immediately { + let _stream = TcpStream::connect(addr); + // Close + } + } + } + + #[test] + fn multiple_connect_serial_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); let max = 10; @@ -264,7 +355,32 @@ mod test { } #[test] - fn multiple_connect_interleaved_greedy_schedule() { + fn multiple_connect_serial_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + let max = 10; + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + for max.times { + let mut stream = listener.accept(); + let mut buf = [0]; + stream.read(buf); + assert_eq!(buf[0], 99); + } + } + + do spawntask_immediately { + for max.times { + let mut stream = TcpStream::connect(addr); + stream.write([99]); + } + } + } + } + + #[test] + fn multiple_connect_interleaved_greedy_schedule_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); static MAX: int = 10; @@ -303,7 +419,46 @@ mod test { } #[test] - fn multiple_connect_interleaved_lazy_schedule() { + fn multiple_connect_interleaved_greedy_schedule_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + static MAX: int = 10; + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + for int::range(0, MAX) |i| { + let stream = Cell::new(listener.accept()); + rtdebug!("accepted"); + // Start another task to handle the connection + do spawntask_immediately { + let mut stream = stream.take(); + let mut buf = [0]; + stream.read(buf); + assert!(buf[0] == i as u8); + rtdebug!("read"); + } + } + } + + connect(0, addr); + + fn connect(i: int, addr: IpAddr) { + if i == MAX { return } + + do spawntask_immediately { + rtdebug!("connecting"); + let mut stream = TcpStream::connect(addr); + // Connect again before writing + connect(i + 1, addr); + rtdebug!("writing"); + stream.write([i as u8]); + } + } + } + } + + #[test] + fn multiple_connect_interleaved_lazy_schedule_ip4() { do run_in_newsched_task { let addr = next_test_ip4(); static MAX: int = 10; @@ -340,5 +495,43 @@ mod test { } } } + #[test] + fn multiple_connect_interleaved_lazy_schedule_ip6() { + do run_in_newsched_task { + let addr = next_test_ip6(); + static MAX: int = 10; + + do spawntask_immediately { + let mut listener = TcpListener::bind(addr); + for int::range(0, MAX) |_| { + let stream = Cell::new(listener.accept()); + rtdebug!("accepted"); + // Start another task to handle the connection + do spawntask_later { + let mut stream = stream.take(); + let mut buf = [0]; + stream.read(buf); + assert!(buf[0] == 99); + rtdebug!("read"); + } + } + } + + connect(0, addr); + + fn connect(i: int, addr: IpAddr) { + if i == MAX { return } + + do spawntask_later { + rtdebug!("connecting"); + let mut stream = TcpStream::connect(addr); + // Connect again before writing + connect(i + 1, addr); + rtdebug!("writing"); + stream.write([99]); + } + } + } + } } diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index c66f7d8ce06..f3b52783573 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -115,7 +115,7 @@ mod test { } #[test] - fn socket_smoke_test() { + fn socket_smoke_test_ip4() { do run_in_newsched_task { let server_ip = next_test_ip4(); let client_ip = next_test_ip4(); @@ -147,7 +147,39 @@ mod test { } #[test] - fn stream_smoke_test() { + fn socket_smoke_test_ip6() { + do run_in_newsched_task { + let server_ip = next_test_ip6(); + let client_ip = next_test_ip6(); + + do spawntask_immediately { + match UdpSocket::bind(server_ip) { + Some(server) => { + let mut buf = [0]; + match server.recvfrom(buf) { + Some((nread, src)) => { + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + assert_eq!(src, client_ip); + } + None => fail!() + } + } + None => fail!() + } + } + + do spawntask_immediately { + match UdpSocket::bind(client_ip) { + Some(client) => client.sendto([99], server_ip), + None => fail!() + } + } + } + } + + #[test] + fn stream_smoke_test_ip4() { do run_in_newsched_task { let server_ip = next_test_ip4(); let client_ip = next_test_ip4(); @@ -182,4 +214,41 @@ mod test { } } } + + #[test] + fn stream_smoke_test_ip6() { + do run_in_newsched_task { + let server_ip = next_test_ip6(); + let client_ip = next_test_ip6(); + + do spawntask_immediately { + match UdpSocket::bind(server_ip) { + Some(server) => { + let server = ~server; + let mut stream = server.connect(client_ip); + let mut buf = [0]; + match stream.read(buf) { + Some(nread) => { + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + } + None => fail!() + } + } + None => fail!() + } + } + + do spawntask_immediately { + match UdpSocket::bind(client_ip) { + Some(client) => { + let client = ~client; + let mut stream = client.connect(server_ip); + stream.write([99]); + } + None => fail!() + } + } + } + } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index e38c952f744..bcbdea03234 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -23,6 +23,7 @@ pub type IoFactoryObject = uvio::UvIoFactory; pub type RtioTcpStreamObject = uvio::UvTcpStream; pub type RtioTcpListenerObject = uvio::UvTcpListener; pub type RtioUdpSocketObject = uvio::UvUdpSocket; +pub type RtioTcpSocketObject = (); // TODO pub trait EventLoop { fn run(&mut self); @@ -48,16 +49,39 @@ pub trait IoFactory { fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError>; } -pub trait RtioTcpListener { +pub trait RtioTcpListener : RtioSocket { fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>; + fn accept_simultaneously(&self); + fn dont_accept_simultaneously(&self); } -pub trait RtioTcpStream { +pub trait RtioTcpStream : RtioSocket { fn read(&self, buf: &mut [u8]) -> Result; fn write(&self, buf: &[u8]) -> Result<(), IoError>; + fn peer_name(&self) -> IpAddr; + fn control_congestion(&self); + fn nodelay(&self); + fn keepalive(&self, delay_in_seconds: uint); + fn letdie(&self); } -pub trait RtioUdpSocket { +pub trait RtioSocket { + fn socket_name(&self) -> IpAddr; +} + +pub trait RtioUdpSocket : RtioSocket { fn recvfrom(&self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>; fn sendto(&self, buf: &[u8], dst: IpAddr) -> Result<(), IoError>; + + fn join_multicast(&self, multi: IpAddr); + fn leave_multicast(&self, multi: IpAddr); + + fn loop_multicast_locally(&self); + fn dont_loop_multicast_locally(&self); + + fn multicast_time_to_live(&self, ttl: int); + fn time_to_live(&self, ttl: int); + + fn hear_broadcasts(&self); + fn ignore_broadcasts(&self); } diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index b0e49684014..e1b338e2cad 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -17,7 +17,7 @@ use iterator::IteratorUtil; use vec::{OwnedVector, MutableVector}; use result::{Result, Ok, Err}; use unstable::run_in_bare_thread; -use super::io::net::ip::{IpAddr, Ipv4}; +use super::io::net::ip::{IpAddr, Ipv4, Ipv6}; use rt::comm::oneshot; use rt::task::Task; use rt::thread::Thread; @@ -405,11 +405,16 @@ pub fn next_test_port() -> u16 { } } -/// Get a unique localhost:port pair starting at 9600 +/// Get a unique IPv4 localhost:port pair starting at 9600 pub fn next_test_ip4() -> IpAddr { Ipv4(127, 0, 0, 1, next_test_port()) } +/// Get a unique IPv6 localhost:port pair starting at 9600 +pub fn next_test_ip6() -> IpAddr { + Ipv6(0, 0, 0, 0, 0, 0, 0, 1, next_test_port()) +} + /// Get a constant that represents the number of times to repeat stress tests. Default 1. pub fn stress_factor() -> uint { use os::getenv; diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index dc766b2d7f8..4c3cde7d6df 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -15,48 +15,144 @@ use rt::uv::uvll::*; use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback}; use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, status_to_maybe_uv_error}; -use rt::io::net::ip::{IpAddr, Ipv4}; +use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; use rt::uv::last_uv_error; use vec; use str; use from_str::{FromStr}; +use num; -pub fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { - match addr { - Ipv4(a, b, c, d, p) => { - unsafe { - let addr = malloc_ip4_addr(fmt!("%u.%u.%u.%u", - a as uint, - b as uint, - c as uint, - d as uint), p as int); - do (|| { - f(addr) - }).finally { - free_ip4_addr(addr); - } - } +enum UvIpAddr { + UvIpv4(*sockaddr_in), + UvIpv6(*sockaddr_in6), +} + +fn sockaddr_to_UvIpAddr(addr: *uvll::sockaddr) -> UvIpAddr { + unsafe { + 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)), + _ => fail!(), } - _ => fail!() // TODO ipv6 } } -pub fn uv_ip4_to_ip4(addr: *sockaddr_in) -> IpAddr { - let ip4_size = 16; - let buf = vec::from_elem(ip4_size + 1 /*null terminated*/, 0u8); - unsafe { uvll::ip4_name(addr, vec::raw::to_ptr(buf), ip4_size as u64) }; - let port = unsafe { uvll::ip4_port(addr) }; - let ip_str = str::from_bytes_slice(buf).trim_right_chars(&'\x00'); - let ip: ~[u8] = ip_str.split_iter('.') - .transform(|s: &str| -> u8 { - let x = FromStr::from_str(s); - assert!(x.is_some()); - x.unwrap() }) - .collect(); - assert!(ip.len() >= 4); - Ipv4(ip[0], ip[1], ip[2], ip[3], port as u16) +fn ip_as_uv_ip(addr: IpAddr, f: &fn(UvIpAddr) -> T) -> T { + let malloc = match addr { + Ipv4(*) => malloc_ip4_addr, + Ipv6(*) => malloc_ip6_addr, + }; + let wrap = match addr { + Ipv4(*) => UvIpv4, + Ipv6(*) => UvIpv6, + }; + let ip_str = match addr { + 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 port = match addr { + Ipv4(_, _, _, _, p) | Ipv6(_, _, _, _, _, _, _, _, p) => p as int + }; + let free = match addr { + Ipv4(*) => free_ip4_addr, + Ipv6(*) => free_ip6_addr, + }; + + let addr = unsafe { malloc(ip_str, port) }; + do (|| { + f(wrap(addr)) + }).finally { + unsafe { free(addr) }; + } } +fn uv_ip_as_ip(addr: UvIpAddr, f: &fn(IpAddr) -> T) -> T { + let ip_size = match addr { + UvIpv4(*) => 4/*groups of*/ * 3/*digits separated by*/ + 3/*periods*/, + UvIpv6(*) => 8/*groups of*/ * 4/*hex digits separated by*/ + 7 /*colons*/, + }; + let ip_name = { + let buf = vec::from_elem(ip_size + 1 /*null terminated*/, 0u8); + unsafe { + match addr { + UvIpv4(addr) => uvll::ip4_name(addr, vec::raw::to_ptr(buf), ip_size as u64), + UvIpv6(addr) => uvll::ip6_name(addr, vec::raw::to_ptr(buf), ip_size as u64), + } + }; + buf + }; + let ip_port = unsafe { + let port = match addr { + UvIpv4(addr) => uvll::ip4_port(addr), + UvIpv6(addr) => uvll::ip6_port(addr), + }; + port as u16 + }; + let ip_str = str::from_bytes_slice(ip_name).trim_right_chars(&'\x00'); + let ip = match addr { + UvIpv4(*) => { + let ip: ~[u8] = + ip_str.split_iter('.') + .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) + .collect(); + assert_eq!(ip.len(), 4); + Ipv4(ip[0], ip[1], ip[2], ip[3], ip_port) + }, + UvIpv6(*) => { + let ip: ~[u16] = { + let read_hex_segment = |s: &str| -> u16 { + num::FromStrRadix::from_str_radix(s, 16u).unwrap() + }; + let convert_each_segment = |s: &str| -> ~[u16] { + match s { + "" => ~[], + s => s.split_iter(':').transform(read_hex_segment).collect(), + } + }; + let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] { + s.split_str_iter("::").transform(convert_each_segment).collect() + }; + match expand_shorthand_and_convert(ip_str) { + [x] => x, // no shorthand found + [l, r] => l + vec::from_elem(8 - l.len() - r.len(), 0u16) + r, // fill the gap + _ => fail!(), // impossible. only one shorthand allowed. + } + }; + assert_eq!(ip.len(), 8); + Ipv6(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip_port) + }, + }; + + // finally run the closure + f(ip) +} + +fn uv_ip_to_ip(addr: UvIpAddr) -> IpAddr { + use util; + uv_ip_as_ip(addr, util::id) +} + +#[cfg(test)] +#[test] +fn test_ip4_conversion() { + use rt; + let ip4 = rt::test::next_test_ip4(); + assert_eq!(ip4, ip_as_uv_ip(ip4, uv_ip_to_ip)); +} + +#[cfg(test)] +#[test] +fn test_ip6_conversion() { + use rt; + let ip6 = rt::test::next_test_ip6(); + 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 // and uv_file_t @@ -169,18 +265,17 @@ impl TcpWatcher { } pub fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - let result = unsafe { uvll::tcp_bind(self.native_handle(), addr) }; - if result == 0 { - Ok(()) - } else { - Err(last_uv_error(self)) - } + do ip_as_uv_ip(address) |addr| { + let result = unsafe { + match addr { + UvIpv4(addr) => uvll::tcp_bind(self.native_handle(), addr), + UvIpv6(addr) => uvll::tcp_bind6(self.native_handle(), addr), } + }; + match result { + 0 => Ok(()), + _ => Err(last_uv_error(self)), } - _ => fail!() } } @@ -190,16 +285,13 @@ impl TcpWatcher { self.get_watcher_data().connect_cb = Some(cb); let connect_handle = ConnectRequest::new().native_handle(); - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - rtdebug!("connect_t: %x", connect_handle as uint); - assert_eq!(0, - uvll::tcp_connect(connect_handle, self.native_handle(), - addr, connect_cb)); - } - } - _ => fail!() + rtdebug!("connect_t: %x", connect_handle as uint); + do ip_as_uv_ip(address) |addr| { + let result = match addr { + UvIpv4(addr) => uvll::tcp_connect(connect_handle, self.native_handle(), addr, connect_cb), + UvIpv6(addr) => uvll::tcp_connect6(connect_handle, self.native_handle(), addr, connect_cb), + }; + assert_eq!(0, result); } extern fn connect_cb(req: *uvll::uv_connect_t, status: c_int) { @@ -266,20 +358,17 @@ impl UdpWatcher { } pub fn bind(&self, address: IpAddr) -> Result<(), UvError> { - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - let result = unsafe { - uvll::udp_bind(self.native_handle(), addr, 0u32) - }; - if result == 0 { - Ok(()) - } else { - Err(last_uv_error(self)) - } + do ip_as_uv_ip(address) |addr| { + let result = unsafe { + match addr { + UvIpv4(addr) => uvll::udp_bind(self.native_handle(), addr, 0u32), + UvIpv6(addr) => uvll::udp_bind6(self.native_handle(), addr, 0u32), } + }; + match result { + 0 => Ok(()), + _ => Err(last_uv_error(self)), } - _ => fail!() // TODO ipv6 } } @@ -299,17 +388,15 @@ impl UdpWatcher { return (*alloc_cb)(suggested_size as uint); } - /* TODO the socket address should actually be a pointer to - either a sockaddr_in or sockaddr_in6. - In libuv, the udp_recv callback takes a struct *sockaddr */ extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf, - addr: *uvll::sockaddr_in, flags: c_uint) { + addr: *uvll::sockaddr, flags: c_uint) { rtdebug!("buf addr: %x", buf.base as uint); 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); - (*cb)(udp_watcher, nread as int, buf, uv_ip4_to_ip4(addr), flags as uint, status); + let addr = uv_ip_to_ip(sockaddr_to_UvIpAddr(addr)); + (*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status); } } @@ -326,17 +413,14 @@ impl UdpWatcher { } let req = UdpSendRequest::new(); - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - unsafe { - assert_eq!(0, uvll::udp_send(req.native_handle(), - self.native_handle(), - [buf], addr, send_cb)); - } + do ip_as_uv_ip(address) |addr| { + let result = unsafe { + match addr { + UvIpv4(addr) => uvll::udp_send(req.native_handle(), self.native_handle(), [buf], addr, send_cb), + UvIpv6(addr) => uvll::udp_send6(req.native_handle(), self.native_handle(), [buf], addr, send_cb), } - } - _ => fail!() // TODO ipv6 + }; + assert_eq!(0, result); } extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) { @@ -486,13 +570,7 @@ mod test { use rt::uv::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf}; #[test] - fn test_ip4_conversion() { - let ip4 = next_test_ip4(); - assert_eq!(ip4, ip4_as_uv_ip4(ip4, uv_ip4_to_ip4)); - } - - #[test] - fn connect_close() { + fn connect_close_ip4() { do run_in_bare_thread() { let mut loop_ = Loop::new(); let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; @@ -510,7 +588,25 @@ mod test { } #[test] - fn udp_bind_close() { + fn connect_close_ip6() { + do run_in_bare_thread() { + let mut loop_ = Loop::new(); + let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; + // Connect to a port where nobody is listening + let addr = next_test_ip6(); + do tcp_watcher.connect(addr) |stream_watcher, status| { + rtdebug!("tcp_watcher.connect!"); + assert!(status.is_some()); + assert_eq!(status.get().name(), ~"ECONNREFUSED"); + stream_watcher.close(||()); + } + loop_.run(); + loop_.close(); + } + } + + #[test] + fn udp_bind_close_ip4() { do run_in_bare_thread() { let mut loop_ = Loop::new(); let udp_watcher = { UdpWatcher::new(&mut loop_) }; @@ -523,7 +619,20 @@ mod test { } #[test] - fn listen() { + fn udp_bind_close_ip6() { + do run_in_bare_thread() { + let mut loop_ = Loop::new(); + let udp_watcher = { UdpWatcher::new(&mut loop_) }; + let addr = next_test_ip6(); + udp_watcher.bind(addr); + udp_watcher.close(||()); + loop_.run(); + loop_.close(); + } + } + + #[test] + fn listen_ip4() { do run_in_bare_thread() { static MAX: int = 10; let mut loop_ = Loop::new(); @@ -532,10 +641,82 @@ mod test { server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); - do server_tcp_watcher.listen |server_stream_watcher, status| { + do server_tcp_watcher.listen |mut server_stream_watcher, status| { + rtdebug!("listened!"); + assert!(status.is_none()); + let mut loop_ = loop_; + let client_tcp_watcher = TcpWatcher::new(&mut loop_); + let mut client_tcp_watcher = client_tcp_watcher.as_stream(); + server_stream_watcher.accept(client_tcp_watcher); + let count_cell = Cell::new(0); + let server_stream_watcher = server_stream_watcher; + rtdebug!("starting read"); + let alloc: AllocCallback = |size| { + vec_to_uv_buf(vec::from_elem(size, 0)) + }; + do client_tcp_watcher.read_start(alloc) |stream_watcher, nread, buf, status| { + + rtdebug!("i'm reading!"); + let buf = vec_from_uv_buf(buf); + let mut count = count_cell.take(); + if status.is_none() { + rtdebug!("got %d bytes", nread); + let buf = buf.unwrap(); + for buf.slice(0, nread as uint).each |byte| { + assert!(*byte == count as u8); + rtdebug!("%u", *byte as uint); + count += 1; + } + } else { + assert_eq!(count, MAX); + do stream_watcher.close { + server_stream_watcher.close(||()); + } + } + count_cell.put_back(count); + } + } + + let _client_thread = do Thread::start { + rtdebug!("starting client thread"); + let mut loop_ = Loop::new(); + let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; + do tcp_watcher.connect(addr) |mut stream_watcher, status| { + rtdebug!("connecting"); + assert!(status.is_none()); + let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9]; + let buf = slice_to_uv_buf(msg); + let msg_cell = Cell::new(msg); + do stream_watcher.write(buf) |stream_watcher, status| { + rtdebug!("writing"); + assert!(status.is_none()); + let msg_cell = Cell::new(msg_cell.take()); + stream_watcher.close(||ignore(msg_cell.take())); + } + } + loop_.run(); + loop_.close(); + }; + + let mut loop_ = loop_; + loop_.run(); + loop_.close(); + } + } + + #[test] + fn listen_ip6() { + do run_in_bare_thread() { + static MAX: int = 10; + let mut loop_ = Loop::new(); + let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; + let addr = next_test_ip6(); + server_tcp_watcher.bind(addr); + let loop_ = loop_; + rtdebug!("listening"); + do server_tcp_watcher.listen |mut server_stream_watcher, status| { rtdebug!("listened!"); assert!(status.is_none()); - let mut server_stream_watcher = server_stream_watcher; let mut loop_ = loop_; let client_tcp_watcher = TcpWatcher::new(&mut loop_); let mut client_tcp_watcher = client_tcp_watcher.as_stream(); @@ -574,10 +755,9 @@ mod test { rtdebug!("starting client thread"); let mut loop_ = Loop::new(); let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - do tcp_watcher.connect(addr) |stream_watcher, status| { + do tcp_watcher.connect(addr) |mut stream_watcher, status| { rtdebug!("connecting"); assert!(status.is_none()); - let mut stream_watcher = stream_watcher; let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9]; let buf = slice_to_uv_buf(msg); let msg_cell = Cell::new(msg); @@ -599,7 +779,7 @@ mod test { } #[test] - fn udp_recv() { + fn udp_recv_ip4() { do run_in_bare_thread() { static MAX: int = 10; let mut loop_ = Loop::new(); @@ -656,4 +836,63 @@ mod test { loop_.close(); } } + + #[test] + fn udp_recv_ip6() { + do run_in_bare_thread() { + static MAX: int = 10; + let mut loop_ = Loop::new(); + let server_addr = next_test_ip6(); + let client_addr = next_test_ip6(); + + let server = UdpWatcher::new(&loop_); + assert!(server.bind(server_addr).is_ok()); + + rtdebug!("starting read"); + let alloc: AllocCallback = |size| { + vec_to_uv_buf(vec::from_elem(size, 0)) + }; + + do server.recv_start(alloc) |server, nread, buf, src, flags, status| { + server.recv_stop(); + rtdebug!("i'm reading!"); + assert!(status.is_none()); + assert_eq!(flags, 0); + assert_eq!(src, client_addr); + + let buf = vec_from_uv_buf(buf); + let mut count = 0; + rtdebug!("got %d bytes", nread); + + let buf = buf.unwrap(); + for buf.slice(0, nread as uint).iter().advance() |&byte| { + assert!(byte == count as u8); + rtdebug!("%u", byte as uint); + count += 1; + } + assert_eq!(count, MAX); + + server.close(||{}); + } + + do Thread::start { + let mut loop_ = Loop::new(); + let client = UdpWatcher::new(&loop_); + assert!(client.bind(client_addr).is_ok()); + let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let buf = slice_to_uv_buf(msg); + do client.send(buf, server_addr) |client, status| { + rtdebug!("writing"); + assert!(status.is_none()); + client.close(||{}); + } + + loop_.run(); + loop_.close(); + }; + + loop_.run(); + loop_.close(); + } + } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 1ae6cd8b17b..e1ff8ba1e22 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -60,9 +60,8 @@ impl EventLoop for UvEventLoop { fn callback(&mut self, f: ~fn()) { let mut idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); - do idle_watcher.start |idle_watcher, status| { + do idle_watcher.start |mut idle_watcher, status| { assert!(status.is_none()); - let mut idle_watcher = idle_watcher; idle_watcher.stop(); idle_watcher.close(||()); f(); @@ -218,7 +217,7 @@ impl IoFactory for UvIoFactory { rtdebug!("connect: in connect callback"); if status.is_none() { rtdebug!("status is none"); - let res = Ok(~UvTcpStream { watcher: stream_watcher }); + let res = Ok(~UvTcpStream(stream_watcher)); // Store the stream in the task's stack unsafe { (*result_cell_ptr).put_back(res); } @@ -313,6 +312,11 @@ impl Drop for UvTcpListener { } } +impl RtioSocket for UvTcpListener { + // TODO + fn socket_name(&self) -> IpAddr { fail!(); } +} + impl RtioTcpListener for UvTcpListener { fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { @@ -329,15 +333,14 @@ impl RtioTcpListener for UvTcpListener { let incoming_streams_cell = Cell::new(incoming_streams_cell.take()); let mut server_tcp_watcher = server_tcp_watcher; - do server_tcp_watcher.listen |server_stream_watcher, status| { + do server_tcp_watcher.listen |mut server_stream_watcher, status| { let maybe_stream = if status.is_none() { - let mut server_stream_watcher = server_stream_watcher; 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); - Ok(~UvTcpStream { watcher: client_tcp_watcher }) + Ok(~UvTcpStream(client_tcp_watcher)) } else { Err(standard_error(OtherIoError)) }; @@ -349,25 +352,22 @@ impl RtioTcpListener for UvTcpListener { return self.incoming_streams.recv(); } + + // TODO + fn accept_simultaneously(&self) { fail!(); } + fn dont_accept_simultaneously(&self) { fail!(); } } // FIXME #6090: Prefer newtype structs but Drop doesn't work -pub struct UvTcpStream { - watcher: StreamWatcher -} - -impl UvTcpStream { - fn watcher(&self) -> StreamWatcher { self.watcher } -} +pub struct UvTcpStream(StreamWatcher); impl Drop for UvTcpStream { fn finalize(&self) { rtdebug!("closing tcp stream"); - let watcher = self.watcher(); let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - do watcher.close { + do self.close { let scheduler = Local::take::(); scheduler.resume_task_immediately(task_cell.take()); } @@ -375,6 +375,11 @@ impl Drop for UvTcpStream { } } +impl RtioSocket for UvTcpStream { + // TODO + fn socket_name(&self) -> IpAddr { fail!(); } +} + impl RtioTcpStream for UvTcpStream { fn read(&self, buf: &mut [u8]) -> Result { let result_cell = Cell::new_empty(); @@ -382,25 +387,23 @@ impl RtioTcpStream for UvTcpStream { let scheduler = Local::take::(); assert!(scheduler.in_task_context()); - let watcher = self.watcher(); let buf_ptr: *&mut [u8] = &buf; do scheduler.deschedule_running_task_and_then |sched, task| { rtdebug!("read: entered scheduler context"); assert!(!sched.in_task_context()); - let mut watcher = watcher; let task_cell = Cell::new(task); // XXX: We shouldn't reallocate these callbacks every // call to read let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.read_start(alloc) |watcher, nread, _buf, status| { + let mut watcher = **self; + do watcher.read_start(alloc) |mut watcher, nread, _buf, status| { // Stop reading so that no read callbacks are // triggered before the user calls `read` again. // XXX: Is there a performance impact to calling // stop here? - let mut watcher = watcher; watcher.read_stop(); let result = if status.is_none() { @@ -426,12 +429,11 @@ impl RtioTcpStream for UvTcpStream { let result_cell_ptr: *Cell> = &result_cell; let scheduler = Local::take::(); assert!(scheduler.in_task_context()); - let watcher = self.watcher(); let buf_ptr: *&[u8] = &buf; do scheduler.deschedule_running_task_and_then |_, task| { - let mut watcher = watcher; let task_cell = Cell::new(task); let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let mut watcher = **self; do watcher.write(buf) |_watcher, status| { let result = if status.is_none() { Ok(()) @@ -449,6 +451,13 @@ impl RtioTcpStream for UvTcpStream { assert!(!result_cell.is_empty()); return result_cell.take(); } + + // TODO + fn peer_name(&self) -> IpAddr { fail!(); } + fn control_congestion(&self) { fail!(); } + fn nodelay(&self) { fail!(); } + fn keepalive(&self, _delay_in_seconds: uint) { fail!(); } + fn letdie(&self) { fail!(); } } pub struct UvUdpSocket(UdpWatcher); @@ -467,6 +476,11 @@ impl Drop for UvUdpSocket { } } +impl RtioSocket for UvUdpSocket { + // TODO + fn socket_name(&self) -> IpAddr { fail!(); } +} + impl RtioUdpSocket for UvUdpSocket { fn recvfrom(&self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError> { let result_cell = Cell::new_empty(); @@ -530,6 +544,19 @@ impl RtioUdpSocket for UvUdpSocket { assert!(!result_cell.is_empty()); return result_cell.take(); } + + // TODO + fn join_multicast(&self, _multi: IpAddr) { fail!(); } + fn leave_multicast(&self, _multi: IpAddr) { fail!(); } + + fn loop_multicast_locally(&self) { fail!(); } + fn dont_loop_multicast_locally(&self) { fail!(); } + + fn multicast_time_to_live(&self, _ttl: int) { fail!(); } + fn time_to_live(&self, _ttl: int) { fail!(); } + + fn hear_broadcasts(&self) { fail!(); } + fn ignore_broadcasts(&self) { fail!(); } } #[test] diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 7035cb6a5e8..62bf8f27af9 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -74,8 +74,10 @@ pub type uv_alloc_cb = *u8; pub type uv_udp_send_cb = *u8; 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 uv_membership = c_void; #[deriving(Eq)] pub enum uv_handle_type { @@ -231,6 +233,31 @@ 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 { + 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); +} + +pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int { + return rust_uv_udp_set_multicast_loop(handle, on); +} + +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_broadcast(handle: *uv_udp_t, on: c_int) -> c_int { + return rust_uv_udp_set_broadcast(handle, on); +} + pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { return rust_uv_tcp_init(loop_handle, handle); } @@ -261,6 +288,26 @@ pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) - return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); } +pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_in) -> 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); +} + +pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int { + return rust_uv_tcp_keepalive(handle, enable, delay); +} + +pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int { + return rust_uv_tcp_simultaneous_accepts(handle, enable); +} + pub unsafe fn listen(stream: *T, backlog: c_int, cb: *u8) -> c_int { return rust_uv_listen(stream as *c_void, backlog, cb); } @@ -318,6 +365,22 @@ pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int { return rust_uv_timer_stop(timer_ptr); } +pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool { + match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true } +} + +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 str::as_c_str(ip) |ip_buf| { rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) @@ -451,25 +514,42 @@ extern { fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int; fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint; fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint; - fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, after_cb: *u8, + fn rust_uv_tcp_connect(req: *uv_connect_t, handle: *uv_tcp_t, cb: *u8, addr: *sockaddr_in) -> c_int; fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; - fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, after_cb: *u8, + 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_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; fn rust_uv_udp_init(loop_handle: *uv_loop_t, handle_ptr: *uv_udp_t) -> c_int; fn rust_uv_udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int; fn rust_uv_udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int; - fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, buf_cnt: c_int, - addr: *sockaddr_in, cb: *u8) -> c_int; - fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, buf_cnt: c_int, - addr: *sockaddr_in6, cb: *u8) -> c_int; + fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, + buf_cnt: c_int, addr: *sockaddr_in, cb: *u8) -> c_int; + fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t, + buf_cnt: c_int, addr: *sockaddr_in6, cb: *u8) -> c_int; 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_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; + fn rust_uv_udp_set_multicast_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; + 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_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 6032ed1a6bd..32ccc9ba4a8 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -293,6 +293,38 @@ rust_uv_tcp_getpeername6 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); + return uv_tcp_getsockname(handle, (sockaddr*)name, &namelen); +} + +extern "C" int +rust_uv_tcp_nodelay +(uv_tcp_t* handle, int enable) { + return uv_tcp_nodelay(handle, enable); +} + +extern "C" int +rust_uv_tcp_keepalive +(uv_tcp_t* handle, int enable, unsigned int delay) { + return uv_tcp_keepalive(handle, enable, delay); +} + +extern "C" int +rust_uv_tcp_simultaneous_accepts +(uv_tcp_t* handle, int enable) { + return uv_tcp_simultaneous_accepts(handle, enable); +} + extern "C" int rust_uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { return uv_udp_init(loop, handle); @@ -335,6 +367,44 @@ rust_uv_get_udp_handle_from_send_req(uv_udp_send_t* send_req) { return send_req->handle; } +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); + return uv_udp_getsockname(handle, (sockaddr*)name, &namelen); +} + +extern "C" int +rust_uv_udp_set_membership +(uv_udp_t* handle, const char* m_addr, const char* i_addr, uv_membership membership) { + return uv_udp_set_membership(handle, m_addr, i_addr, membership); +} + +extern "C" int +rust_uv_udp_set_multicast_loop +(uv_udp_t* handle, int on) { + return uv_udp_set_multicast_loop(handle, on); +} + +extern "C" int +rust_uv_udp_set_multicast_ttl +(uv_udp_t* handle, int ttl) { + return uv_udp_set_multicast_ttl(handle, ttl); +} + +extern "C" int +rust_uv_udp_set_broadcast +(uv_udp_t* handle, int on) { + return uv_udp_set_broadcast(handle, on); +} + extern "C" int rust_uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { @@ -587,10 +657,34 @@ extern "C" void rust_uv_freeaddrinfo(addrinfo* res) { uv_freeaddrinfo(res); } + +extern "C" int +rust_uv_is_ipv4_sockaddr(sockaddr* addr) { + return addr->sa_family == AF_INET; +} + +extern "C" int +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; } + extern "C" bool rust_uv_is_ipv6_addrinfo(addrinfo* input) { return input->ai_family == AF_INET6; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index b604f60cba6..e8a46cf5a65 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -105,6 +105,11 @@ rust_uv_tcp_connect 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 rust_uv_udp_init rust_uv_udp_bind rust_uv_udp_bind6 @@ -113,6 +118,16 @@ rust_uv_udp_send6 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_listen rust_uv_accept rust_uv_write From b60cf0c5b0cf36625083c2624df9fb35d0af3578 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Tue, 2 Jul 2013 17:27:46 -0700 Subject: [PATCH 30/32] converted TODOs into XXXs --- src/libstd/rt/rtio.rs | 1 - src/libstd/rt/uv/uvio.rs | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index bcbdea03234..6bf352ee144 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -23,7 +23,6 @@ pub type IoFactoryObject = uvio::UvIoFactory; pub type RtioTcpStreamObject = uvio::UvTcpStream; pub type RtioTcpListenerObject = uvio::UvTcpListener; pub type RtioUdpSocketObject = uvio::UvUdpSocket; -pub type RtioTcpSocketObject = (); // TODO pub trait EventLoop { fn run(&mut self); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index aa1f0fbc194..e9bbe3bb6fb 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -316,7 +316,7 @@ impl Drop for UvTcpListener { } impl RtioSocket for UvTcpListener { - // TODO + // XXX implement fn socket_name(&self) -> IpAddr { fail!(); } } @@ -356,7 +356,7 @@ impl RtioTcpListener for UvTcpListener { return self.incoming_streams.recv(); } - // TODO + // XXX implement fn accept_simultaneously(&self) { fail!(); } fn dont_accept_simultaneously(&self) { fail!(); } } @@ -379,7 +379,7 @@ impl Drop for UvTcpStream { } impl RtioSocket for UvTcpStream { - // TODO + // XXX implement fn socket_name(&self) -> IpAddr { fail!(); } } @@ -455,7 +455,7 @@ impl RtioTcpStream for UvTcpStream { return result_cell.take(); } - // TODO + // XXX implement fn peer_name(&self) -> IpAddr { fail!(); } fn control_congestion(&self) { fail!(); } fn nodelay(&self) { fail!(); } @@ -480,7 +480,7 @@ impl Drop for UvUdpSocket { } impl RtioSocket for UvUdpSocket { - // TODO + // XXX implement fn socket_name(&self) -> IpAddr { fail!(); } } @@ -498,7 +498,7 @@ impl RtioUdpSocket for UvUdpSocket { let task_cell = Cell::new(task); let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) }; do self.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| { - let _ = flags; // TODO add handling for partials? + let _ = flags; // XXX add handling for partials? watcher.recv_stop(); @@ -548,7 +548,7 @@ impl RtioUdpSocket for UvUdpSocket { return result_cell.take(); } - // TODO + // XXX implement fn join_multicast(&self, _multi: IpAddr) { fail!(); } fn leave_multicast(&self, _multi: IpAddr) { fail!(); } From 6b2abcaa0f4b8f0fdbd0f8dcac5089159f0051da Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 8 Jul 2013 14:19:19 -0700 Subject: [PATCH 31/32] renamed finalize to drop in Drop impl for UvUdpSocket --- src/libstd/rt/uv/uvio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 3f2706e7a99..5d0c64c6867 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -466,7 +466,7 @@ impl RtioTcpStream for UvTcpStream { pub struct UvUdpSocket(UdpWatcher); impl Drop for UvUdpSocket { - fn finalize(&self) { + fn drop(&self) { rtdebug!("closing udp socket"); let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { From 5e0be468528fdcf977aa1de6ba553b55303ec56a Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Mon, 8 Jul 2013 14:19:39 -0700 Subject: [PATCH 32/32] changed .each() to .iter().advance() --- src/libstd/rt/uv/net.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 72a9a6cdd5c..2707b9ce7d7 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -106,16 +106,16 @@ fn uv_ip_as_ip(addr: UvIpAddr, f: &fn(IpAddr) -> T) -> T { }, UvIpv6(*) => { let ip: ~[u16] = { - let read_hex_segment = |s: &str| -> u16 { - num::FromStrRadix::from_str_radix(s, 16u).unwrap() - }; - let convert_each_segment = |s: &str| -> ~[u16] { - match s { - "" => ~[], - s => s.split_iter(':').transform(read_hex_segment).collect(), - } - }; let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] { + let convert_each_segment = |s: &str| -> ~[u16] { + let read_hex_segment = |s: &str| -> u16 { + num::FromStrRadix::from_str_radix(s, 16u).unwrap() + }; + match s { + "" => ~[], + s => s.split_iter(':').transform(read_hex_segment).collect(), + } + }; s.split_str_iter("::").transform(convert_each_segment).collect() }; match expand_shorthand_and_convert(ip_str) { @@ -662,7 +662,7 @@ mod test { if status.is_none() { rtdebug!("got %d bytes", nread); let buf = buf.unwrap(); - for buf.slice(0, nread as uint).each |byte| { + for buf.slice(0, nread as uint).iter().advance() |byte| { assert!(*byte == count as u8); rtdebug!("%u", *byte as uint); count += 1;