From 498b3ff57f7269e62765e53c5987791ff5621d6a Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Thu, 28 Jun 2012 22:55:44 -0700 Subject: [PATCH 01/45] Register snapshots. --- src/snapshots.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index fe90dae15cffb..3e344f6b398d2 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,10 @@ +S 2012-06-28 810677e + macos-x86_64 ee659583a09bb8466985428e4baa16498eedf4fb + macos-i386 8e97646a4a87c239ce5075c24b8bfb490dd90cf9 + linux-x86_64 0520e6f907981b6900a1b98eee43d5416c47c801 + linux-i386 fa960de5a5e21a822aca6c2924426bef2cc74367 + winnt-i386 d331a09b93fa6081908a8f1c06e4d67565256074 + S 2012-06-26 b9d3ad0 macos-x86_64 48206274146453f19f35be553469ac40d6319884 macos-i386 042bc8d4275947e74f65e52eda30eb0780e8f385 From 7aa43b2599b353dc3e26f5ecc2aef30bc1883145 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Thu, 28 Jun 2012 23:36:00 -0700 Subject: [PATCH 02/45] Make fmt use a bitmask instead of a vector of flags. Closes #1993. --- mk/target.mk | 2 +- src/libcore/extfmt.rs | 24 ++++++++++-------------- src/libsyntax/ext/fmt.rs | 22 +++++++++++----------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/mk/target.mk b/mk/target.mk index 5ddc825d335bd..7cfa44f52bd94 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -9,7 +9,7 @@ # the snapshot runtime (resp. corelib) rather than the runtime # (resp. corelib) from the working directory. USE_SNAPSHOT_RUNTIME=0 -USE_SNAPSHOT_CORELIB=0 +USE_SNAPSHOT_CORELIB=1 USE_SNAPSHOT_STDLIB=0 define TARGET_STAGE_N diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs index d738b4f661510..e7263243323d7 100644 --- a/src/libcore/extfmt.rs +++ b/src/libcore/extfmt.rs @@ -264,19 +264,17 @@ mod ct { // conditions can be evaluated at compile-time. For now though it's cleaner to // implement it 0this way, I think. mod rt { - enum flag { - flag_left_justify, - flag_left_zero_pad, - flag_space_for_sign, - flag_sign_always, - flag_alternate, - } + const flag_none : u32 = 0u32; + const flag_left_justify : u32 = 0b00000000000000000000000000000001u32; + const flag_left_zero_pad : u32 = 0b00000000000000000000000000000010u32; + const flag_space_for_sign : u32 = 0b00000000000000000000000000000100u32; + const flag_sign_always : u32 = 0b00000000000000000000000000001000u32; + const flag_alternate : u32 = 0b00000000000000000000000000010000u32; + enum count { count_is(int), count_implied, } enum ty { ty_default, ty_bits, ty_hex_upper, ty_hex_lower, ty_octal, } - // FIXME (#1993): May not want to use a vector here for flags; instead - // just use a bool per flag. - type conv = {flags: [flag]/~, width: count, precision: count, ty: ty}; + type conv = {flags: u32, width: count, precision: count, ty: ty}; fn conv_int(cv: conv, i: int) -> str { let radix = 10u; @@ -307,7 +305,6 @@ mod rt { let s = if b { "true" } else { "false" }; // run the boolean conversion through the string conversion logic, // giving it the same rules for precision, etc. - ret conv_str(cv, s); } fn conv_char(cv: conv, c: char) -> str { @@ -430,9 +427,8 @@ mod rt { } ret padstr + s; } - fn have_flag(flags: [flag]/~, f: flag) -> bool { - for vec::each(flags) {|candidate| if candidate == f { ret true; } } - ret false; + fn have_flag(flags: u32, f: u32) -> bool { + flags & f != 0 } } diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 09ebc0b79cd6b..bac880b60a8c8 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -50,19 +50,19 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, fn make_rt_conv_expr(cx: ext_ctxt, sp: span, cnv: conv) -> @ast::expr { fn make_flags(cx: ext_ctxt, sp: span, flags: [flag]/~) -> @ast::expr { - let mut flagexprs: [@ast::expr]/~ = []/~; + let mut tmp_expr = make_rt_path_expr(cx, sp, @"flag_none"); for flags.each {|f| - let mut fstr; - alt f { - flag_left_justify { fstr = "flag_left_justify"; } - flag_left_zero_pad { fstr = "flag_left_zero_pad"; } - flag_space_for_sign { fstr = "flag_space_for_sign"; } - flag_sign_always { fstr = "flag_sign_always"; } - flag_alternate { fstr = "flag_alternate"; } - } - vec::push(flagexprs, make_rt_path_expr(cx, sp, @fstr)); + let fstr = alt f { + flag_left_justify { "flag_left_justify" } + flag_left_zero_pad { "flag_left_zero_pad" } + flag_space_for_sign { "flag_space_for_sign" } + flag_sign_always { "flag_sign_always" } + flag_alternate { "flag_alternate" } + }; + tmp_expr = mk_binary(cx, sp, ast::bitor, tmp_expr, + make_rt_path_expr(cx, sp, @fstr)); } - ret mk_uniq_vec_e(cx, sp, flagexprs); + ret tmp_expr; } fn make_count(cx: ext_ctxt, sp: span, cnt: count) -> @ast::expr { alt cnt { From f1f34b6316a9debad23696bd90537dfb285bce37 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 27 May 2012 09:48:59 -0700 Subject: [PATCH 03/45] std: kludge export of net_ip in std.rc until submodule export is sorted --- src/libstd/std.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 2effb04cd3f77..3470727121755 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -15,7 +15,7 @@ use core(vers = "0.2"); import core::*; -export net, net_tcp; +export net, net_tcp, net_ip; export uv, uv_ll, uv_iotask, uv_global_loop; export c_vec, util, timer; export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap; From 691eb970f5bd405ed0ec49700ac04330781d61ff Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 27 May 2012 09:49:33 -0700 Subject: [PATCH 04/45] std: import/export cleanup in net_tcp --- src/libstd/net_tcp.rs | 86 ++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 8c637f0089ecc..81171dc51ae4d 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -7,8 +7,10 @@ import uv::iotask; import uv::iotask::iotask; import comm::methods; import future_spawn = future::spawn; -import future::future; -import result::{result,err,ok,extensions}; +// FIXME: should be able to replace w/ result::{result, extensions}; +import result::*; +import libc::size_t; +import str::extensions; // data export tcp_socket, tcp_conn_port, tcp_err_data; @@ -20,7 +22,7 @@ export new_listener, conn_recv, conn_recv_spawn, conn_peek; // tcp client stuff export connect; // helper methods -export conn_port_methods, sock_methods; +export methods; #[nolink] native mod rustrt { @@ -775,44 +777,46 @@ fn listen_for_conn(host_ip: ip::ip_addr, port: uint, backlog: uint, } } } - -#[doc=" -Convenience methods extending `net::tcp::tcp_conn_port` -"] -impl conn_port_methods for tcp_conn_port { - fn recv() -> result::result { conn_recv(self) } - fn recv_spawn(+cb: fn~(result::result)) - { conn_recv_spawn(self, cb); } - fn peek() -> bool { conn_peek(self) } -} - -#[doc=" -Convenience methods extending `net::tcp::tcp_socket` -"] -impl sock_methods for tcp_socket { - fn read_start() -> result::result>, tcp_err_data> { - read_start(self) - } - fn read_stop() -> - result::result<(), tcp_err_data> { - read_stop(self) - } - fn read(timeout_msecs: uint) -> - result::result<[u8]/~, tcp_err_data> { - read(self, timeout_msecs) +mod methods { + #[doc=" + Convenience methods extending `net::tcp::tcp_conn_port` + "] + impl methods_tcp_conn_port for tcp_conn_port { + fn recv() -> result::result { + conn_recv(self) } + fn recv_spawn(cb: fn~(result::result)) + { conn_recv_spawn(self, cb); } + fn peek() -> bool { conn_peek(self) } } - fn read_future(timeout_msecs: uint) -> - future> { - read_future(self, timeout_msecs) - } - fn write(raw_write_data: [u8]/~) - -> result::result<(), tcp_err_data> { - write(self, raw_write_data) - } - fn write_future(raw_write_data: [u8]/~) - -> future> { - write_future(self, raw_write_data) + + #[doc=" + Convenience methods extending `net::tcp::tcp_socket` + "] + impl methods_tcp_socket for tcp_socket { + fn read_start() -> result::result>, tcp_err_data> { + read_start(self) + } + fn read_stop() -> + result::result<(), tcp_err_data> { + read_stop(self) + } + fn read(timeout_msecs: uint) -> + result::result<[u8]/~, tcp_err_data> { + read(self, timeout_msecs) + } + fn read_future(timeout_msecs: uint) -> + future::future> { + read_future(self, timeout_msecs) + } + fn write(raw_write_data: [u8]/~) + -> result::result<(), tcp_err_data> { + write(self, raw_write_data) + } + fn write_future(raw_write_data: [u8]/~) + -> future::future> { + write_future(self, raw_write_data) + } } } // INTERNAL API @@ -1171,7 +1175,7 @@ crust fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t, } crust fn on_alloc_cb(handle: *libc::c_void, - ++suggested_size: libc::size_t) + ++suggested_size: size_t) -> uv::ll::uv_buf_t unsafe { log(debug, "tcp read on_alloc_cb!"); let char_ptr = uv::ll::malloc_buf_base_of(suggested_size); From bec5cf27c4abe1627d7cc7646330f6e0ba142982 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 27 May 2012 22:50:11 -0700 Subject: [PATCH 05/45] std: mod cleanup, impl/test for conn. refused err + mem leak fix --- src/libstd/net_tcp.rs | 135 +++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 35 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 81171dc51ae4d..fde1ef490b5ed 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -12,8 +12,10 @@ import result::*; import libc::size_t; import str::extensions; -// data -export tcp_socket, tcp_conn_port, tcp_err_data; +// tcp interfaces +export tcp_socket, tcp_conn_port; +// errors +export tcp_err_data, tcp_connect_err_data; // operations on a tcp_socket export write, write_future, read_start, read_stop; // tcp server stuff @@ -22,6 +24,7 @@ export new_listener, conn_recv, conn_recv_spawn, conn_peek; // tcp client stuff export connect; // helper methods +import methods = net_tcp_methods; export methods; #[nolink] @@ -43,25 +46,7 @@ class tcp_socket { new(socket_data: @tcp_socket_data) { self.socket_data = socket_data; } drop { unsafe { - let closed_po = comm::port::<()>(); - let closed_ch = comm::chan(closed_po); - let close_data = { - closed_ch: closed_ch - }; - let close_data_ptr = ptr::addr_of(close_data); - let stream_handle_ptr = (*(self.socket_data)).stream_handle_ptr; - iotask::interact((*(self.socket_data)).iotask) {|loop_ptr| - log(debug, #fmt("interact dtor for tcp_socket stream %? loop %?", - stream_handle_ptr, loop_ptr)); - uv::ll::set_data_for_uv_handle(stream_handle_ptr, - close_data_ptr); - uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb); - }; - comm::recv(closed_po); - log(debug, #fmt("about to free socket_data at %?", self.socket_data)); - rustrt::rust_uv_current_kernel_free(stream_handle_ptr - as *libc::c_void); - log(debug, "exiting dtor for tcp_socket"); + tear_down_socket_data(socket_data) } } } @@ -90,6 +75,17 @@ type tcp_err_data = { err_name: str, err_msg: str }; +enum tcp_connect_err_data { + #[doc=" + Some unplanned-for error. The first and second fields correspond + to libuv's `err_name` and `err_msg` fields, respectively. + "] + generic_connect_err(str, str), + #[doc=" + Invalid IP or invalid port + "] + connection_refused +} #[doc=" Initiate a client connection over TCP/IP @@ -108,7 +104,7 @@ of failure, a `tcp_err_data` will be returned "] fn connect(input_ip: ip::ip_addr, port: uint, iotask: iotask) - -> result::result unsafe { + -> result::result unsafe { let result_po = comm::port::(); let closed_signal_po = comm::port::<()>(); let conn_data = { @@ -198,7 +194,14 @@ fn connect(input_ip: ip::ip_addr, port: uint, conn_failure(err_data) { comm::recv(closed_signal_po); log(debug, "tcp::connect - received failure on result_po"); - result::err(err_data.to_tcp_err()) + // still have to free the malloc'd stream handle.. + rustrt::rust_uv_current_kernel_free(stream_handle_ptr + as *libc::c_void); + let tcp_conn_err = alt err_data.err_name { + "ECONNREFUSED" { connection_refused } + _ { generic_connect_err(err_data.err_name, err_data.err_msg) } + }; + result::err(tcp_conn_err) } } } @@ -777,7 +780,8 @@ fn listen_for_conn(host_ip: ip::ip_addr, port: uint, backlog: uint, } } } -mod methods { + +mod net_tcp_methods { #[doc=" Convenience methods extending `net::tcp::tcp_conn_port` "] @@ -821,6 +825,28 @@ mod methods { } // INTERNAL API +fn tear_down_socket_data(socket_data: @tcp_socket_data) unsafe { + let closed_po = comm::port::<()>(); + let closed_ch = comm::chan(closed_po); + let close_data = { + closed_ch: closed_ch + }; + let close_data_ptr = ptr::addr_of(close_data); + let stream_handle_ptr = (*socket_data).stream_handle_ptr; + iotask::interact((*socket_data).iotask) {|loop_ptr| + log(debug, #fmt("interact dtor for tcp_socket stream %? loop %?", + stream_handle_ptr, loop_ptr)); + uv::ll::set_data_for_uv_handle(stream_handle_ptr, + close_data_ptr); + uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb); + }; + comm::recv(closed_po); + log(debug, #fmt("about to free socket_data at %?", socket_data)); + rustrt::rust_uv_current_kernel_free(stream_handle_ptr + as *libc::c_void); + log(debug, "exiting dtor for tcp_socket"); +} + // shared implementation for tcp::read fn read_common_impl(socket_data: *tcp_socket_data, timeout_msecs: uint) -> result::result<[u8]/~,tcp_err_data> unsafe { @@ -1308,6 +1334,10 @@ mod test { fn test_gl_tcp_server_listener_and_client_ipv4() unsafe { impl_gl_tcp_ipv4_server_listener_and_client(); } + #[test] + fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe { + impl_gl_tcp_ipv4_client_error_connection_refused(); + } } #[cfg(target_arch="x86")] mod impl32 { @@ -1321,6 +1351,11 @@ mod test { fn test_gl_tcp_server_listener_and_client_ipv4() unsafe { impl_gl_tcp_ipv4_server_listener_and_client(); } + #[test] + #[ignore(cfg(target_os = "linux"))] + fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe { + impl_gl_tcp_ipv4_client_error_connection_refused(); + } } } fn impl_gl_tcp_ipv4_server_and_client() { @@ -1351,7 +1386,7 @@ mod test { comm::recv(cont_po); // client log(debug, "server started, firing up client.."); - let actual_resp = comm::listen {|client_ch| + let actual_resp_result = comm::listen {|client_ch| run_tcp_test_client( server_ip, server_port, @@ -1359,6 +1394,8 @@ mod test { client_ch, hl_loop) }; + assert actual_resp_result.is_success(); + let actual_resp = actual_resp_result.get(); let actual_req = comm::recv(server_result_po); log(debug, #fmt("REQ: expected: '%s' actual: '%s'", expected_req, actual_req)); @@ -1395,7 +1432,7 @@ mod test { comm::recv(cont_po); // client log(debug, "server started, firing up client.."); - let actual_resp = comm::listen {|client_ch| + let actual_resp_result = comm::listen {|client_ch| run_tcp_test_client( server_ip, server_port, @@ -1403,6 +1440,8 @@ mod test { client_ch, hl_loop) }; + assert actual_resp_result.is_success(); + let actual_resp = actual_resp_result.get(); let actual_req = comm::recv(server_result_po); log(debug, #fmt("REQ: expected: '%s' actual: '%s'", expected_req, actual_req)); @@ -1411,6 +1450,29 @@ mod test { assert str::contains(actual_req, expected_req); assert str::contains(actual_resp, expected_resp); } + fn impl_gl_tcp_ipv4_client_error_connection_refused() { + let hl_loop = uv::global_loop::get(); + let server_ip = "127.0.0.1"; + let server_port = 8890u; + let expected_req = "ping"; + // client + log(debug, "firing up client.."); + let actual_resp_result = comm::listen {|client_ch| + run_tcp_test_client( + server_ip, + server_port, + expected_req, + client_ch, + hl_loop) + }; + alt actual_resp_result.get_err() { + connection_refused { + } + _ { + fail "unknown error.. expected connection_refused" + } + } + } fn run_tcp_test_server(server_ip: str, server_port: uint, resp: str, server_ch: comm::chan, @@ -1453,7 +1515,7 @@ mod test { let sock = result::unwrap(accept_result); log(debug, "SERVER: successfully accepted"+ "connection!"); - let received_req_bytes = sock.read(0u); + let received_req_bytes = read(sock, 0u); alt received_req_bytes { result::ok(data) { server_ch.send( @@ -1522,7 +1584,7 @@ mod test { log(debug, "SERVER: successfully accepted"+ "connection!"); let received_req_bytes = - sock.read(0u); + read(sock, 0u); alt received_req_bytes { result::ok(data) { server_ch.send( @@ -1543,8 +1605,8 @@ mod test { fn run_tcp_test_client(server_ip: str, server_port: uint, resp: str, client_ch: comm::chan, - iotask: iotask) -> str { - + iotask: iotask) -> result::result { let server_ip_addr = ip::v4::parse_addr(server_ip); log(debug, "CLIENT: starting.."); @@ -1552,9 +1614,7 @@ mod test { if result::is_err(connect_result) { log(debug, "CLIENT: failed to connect"); let err_data = result::get_err(connect_result); - log(debug, #fmt("CLIENT: connect err name: %s msg: %s", - err_data.err_name, err_data.err_msg)); - "" + err(err_data) } else { let sock = result::unwrap(connect_result); @@ -1563,20 +1623,25 @@ mod test { let read_result = sock.read(0u); if read_result.is_err() { log(debug, "CLIENT: failure to read"); - "" + ok("") } else { client_ch.send(str::from_bytes(read_result.get())); let ret_val = client_ch.recv(); log(debug, #fmt("CLIENT: after client_ch recv ret: '%s'", ret_val)); - ret_val + ok(ret_val) } } } +<<<<<<< HEAD fn tcp_write_single(sock: tcp_socket, val: [u8]/~) { let write_result_future = sock.write_future(val); +======= + fn tcp_write_single(sock: tcp_socket, val: [u8]) { + let write_result_future = write_future(sock, val); +>>>>>>> std: mod cleanup, impl/test for conn. refused err + mem leak fix let write_result = write_result_future.get(); if result::is_err(write_result) { log(debug, "tcp_write_single: write failed!"); From 178a42e1e1d43beb3f0b1d750da5233af522c3df Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 29 May 2012 05:47:21 -0700 Subject: [PATCH 06/45] std: dump the tcp::new_listener server API --- src/libstd/net_tcp.rs | 209 ++---------------------------------------- 1 file changed, 7 insertions(+), 202 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index fde1ef490b5ed..1f732978f4bac 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -13,14 +13,13 @@ import libc::size_t; import str::extensions; // tcp interfaces -export tcp_socket, tcp_conn_port; +export tcp_socket; // errors export tcp_err_data, tcp_connect_err_data; // operations on a tcp_socket export write, write_future, read_start, read_stop; // tcp server stuff export listen_for_conn, accept; -export new_listener, conn_recv, conn_recv_spawn, conn_peek; // tcp client stuff export connect; // helper methods @@ -51,23 +50,6 @@ class tcp_socket { } } -class tcp_conn_port { - let conn_data: @tcp_conn_port_data; - new(conn_data: @tcp_conn_port_data) { self.conn_data = conn_data; } - drop unsafe { - let conn_data_ptr = ptr::addr_of(*(self.conn_data)); - let server_stream_ptr = ptr::addr_of((*conn_data_ptr).server_stream); - let stream_closed_po = (*(self.conn_data)).stream_closed_po; - let iotask = (*conn_data_ptr).iotask; - iotask::interact(iotask) {|loop_ptr| - log(debug, #fmt("dtor for tcp_conn_port loop: %?", - loop_ptr)); - uv::ll::close(server_stream_ptr, tcp_nl_close_cb); - } - comm::recv(stream_closed_po); - } -} - #[doc=" Contains raw, string-based, error information returned from libuv "] @@ -351,6 +333,7 @@ fn read_future(sock: tcp_socket, timeout_msecs: uint) } #[doc=" +<<<<<<< HEAD Bind to a given IP/port and listen for new connections # Arguments @@ -527,6 +510,8 @@ fn conn_peek(server_port: tcp_conn_port) -> bool { } #[doc=" +======= +>>>>>>> std: dump the tcp::new_listener server API Bind an incoming client connection to a `net::tcp::tcp_socket` # Notes @@ -782,17 +767,6 @@ fn listen_for_conn(host_ip: ip::ip_addr, port: uint, backlog: uint, } mod net_tcp_methods { - #[doc=" - Convenience methods extending `net::tcp::tcp_conn_port` - "] - impl methods_tcp_conn_port for tcp_conn_port { - fn recv() -> result::result { - conn_recv(self) } - fn recv_spawn(cb: fn~(result::result)) - { conn_recv_spawn(self, cb); } - fn peek() -> bool { conn_peek(self) } - } - #[doc=" Convenience methods extending `net::tcp::tcp_socket` "] @@ -993,6 +967,7 @@ fn write_common_impl(socket_data_ptr: *tcp_socket_data, } } +<<<<<<< HEAD // various recv_* can use a tcp_conn_port can re-use this.. fn conn_port_new_tcp_socket( stream_handle_ptr: *uv::ll::uv_tcp_t, @@ -1022,21 +997,12 @@ fn conn_port_new_tcp_socket( result::ok(tcp_socket(client_socket_data)) } +======= +>>>>>>> std: dump the tcp::new_listener server API enum tcp_new_connection { new_tcp_conn(*uv::ll::uv_tcp_t) } -type tcp_conn_port_data = { - server_stream: uv::ll::uv_tcp_t, - stream_closed_po: comm::port<()>, - stream_closed_ch: comm::chan<()>, - iotask: iotask, - new_conn_po: comm::port>, - new_conn_ch: comm::chan> -}; - type tcp_listen_fc_data = { server_stream_ptr: *uv::ll::uv_tcp_t, stream_closed_ch: comm::chan<()>, @@ -1075,66 +1041,11 @@ crust fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t, } } -crust fn tcp_nl_close_cb(handle: *uv::ll::uv_tcp_t) unsafe { - let conn_data_ptr = uv::ll::get_data_for_uv_handle( - handle) as *tcp_conn_port_data; - comm::send((*conn_data_ptr).stream_closed_ch, ()); -} - fn malloc_uv_tcp_t() -> *uv::ll::uv_tcp_t unsafe { rustrt::rust_uv_current_kernel_malloc( rustrt::rust_uv_helper_uv_tcp_t_size()) as *uv::ll::uv_tcp_t } -crust fn tcp_nl_on_connection_cb(server_handle_ptr: *uv::ll::uv_tcp_t, - status: libc::c_int) unsafe { - let server_data_ptr = uv::ll::get_data_for_uv_handle(server_handle_ptr) - as *tcp_conn_port_data; - let new_conn_ch = (*server_data_ptr).new_conn_ch; - let loop_ptr = uv::ll::get_loop_for_uv_handle(server_handle_ptr); - alt status { - 0i32 { - let client_stream_handle_ptr = malloc_uv_tcp_t(); - *(client_stream_handle_ptr as *mut uv::ll::uv_tcp_t) = - uv::ll::tcp_t(); - alt uv::ll::tcp_init(loop_ptr, client_stream_handle_ptr) { - 0i32 { - log(debug, "uv_tcp_init successful for client stream"); - alt uv::ll::accept( - server_handle_ptr as *libc::c_void, - client_stream_handle_ptr as *libc::c_void) { - 0i32 { - log(debug, "successfully accepted client connection"); - comm::send(new_conn_ch, - result::ok(client_stream_handle_ptr)); - } - _ { - log(debug, "failed to accept client conn"); - comm::send( - new_conn_ch, - result::err(uv::ll::get_last_err_data(loop_ptr) - .to_tcp_err())); - } - } - } - _ { - log(debug, "failed to init client stream"); - comm::send( - new_conn_ch, - result::err(uv::ll::get_last_err_data(loop_ptr) - .to_tcp_err())); - } - } - } - _ { - comm::send( - new_conn_ch, - result::err(uv::ll::get_last_err_data(loop_ptr) - .to_tcp_err())); - } - } -} - enum tcp_connect_result { tcp_connected(tcp_socket), tcp_connect_error(tcp_err_data) @@ -1331,10 +1242,6 @@ mod test { impl_gl_tcp_ipv4_server_and_client(); } #[test] - fn test_gl_tcp_server_listener_and_client_ipv4() unsafe { - impl_gl_tcp_ipv4_server_listener_and_client(); - } - #[test] fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe { impl_gl_tcp_ipv4_client_error_connection_refused(); } @@ -1348,11 +1255,6 @@ mod test { } #[test] #[ignore(cfg(target_os = "linux"))] - fn test_gl_tcp_server_listener_and_client_ipv4() unsafe { - impl_gl_tcp_ipv4_server_listener_and_client(); - } - #[test] - #[ignore(cfg(target_os = "linux"))] fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe { impl_gl_tcp_ipv4_client_error_connection_refused(); } @@ -1404,52 +1306,6 @@ mod test { assert str::contains(actual_req, expected_req); assert str::contains(actual_resp, expected_resp); } - fn impl_gl_tcp_ipv4_server_listener_and_client() { - let hl_loop = uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 8889u; - let expected_req = "ping"; - let expected_resp = "pong"; - - let server_result_po = comm::port::(); - let server_result_ch = comm::chan(server_result_po); - - let cont_po = comm::port::<()>(); - let cont_ch = comm::chan(cont_po); - // server - task::spawn_sched(task::manual_threads(1u)) {|| - let actual_req = comm::listen {|server_ch| - run_tcp_test_server_listener( - server_ip, - server_port, - expected_resp, - server_ch, - cont_ch, - hl_loop) - }; - server_result_ch.send(actual_req); - }; - comm::recv(cont_po); - // client - log(debug, "server started, firing up client.."); - let actual_resp_result = comm::listen {|client_ch| - run_tcp_test_client( - server_ip, - server_port, - expected_req, - client_ch, - hl_loop) - }; - assert actual_resp_result.is_success(); - let actual_resp = actual_resp_result.get(); - let actual_req = comm::recv(server_result_po); - log(debug, #fmt("REQ: expected: '%s' actual: '%s'", - expected_req, actual_req)); - log(debug, #fmt("RESP: expected: '%s' actual: '%s'", - expected_resp, actual_resp)); - assert str::contains(actual_req, expected_req); - assert str::contains(actual_resp, expected_resp); - } fn impl_gl_tcp_ipv4_client_error_connection_refused() { let hl_loop = uv::global_loop::get(); let server_ip = "127.0.0.1"; @@ -1552,57 +1408,6 @@ mod test { ret_val } - fn run_tcp_test_server_listener(server_ip: str, - server_port: uint, resp: str, - server_ch: comm::chan, - cont_ch: comm::chan<()>, - iotask: iotask) -> str { - - task::spawn_sched(task::manual_threads(1u)) {|| - let server_ip_addr = ip::v4::parse_addr(server_ip); - let new_listener_result = - new_listener(server_ip_addr, server_port, 128u, iotask); - if result::is_err(new_listener_result) { - let err_data = result::get_err(new_listener_result); - log(debug, #fmt("SERVER: exited abnormally name %s msg %s", - err_data.err_name, err_data.err_msg)); - fail "couldn't set up new listener"; - } - let server_port = result::unwrap(new_listener_result); - cont_ch.send(()); - // receive a single new connection.. normally this'd be - // in a loop {}, but we're just going to take a single - // client.. get their req, write a resp and then exit - let new_conn_result = server_port.recv(); - if result::is_err(new_conn_result) { - let err_data = result::get_err(new_conn_result); - log(debug, #fmt("SERVER: exited abnormally name %s msg %s", - err_data.err_name, err_data.err_msg)); - fail "couldn't recv new conn"; - } - let sock = result::unwrap(new_conn_result); - log(debug, "SERVER: successfully accepted"+ - "connection!"); - let received_req_bytes = - read(sock, 0u); - alt received_req_bytes { - result::ok(data) { - server_ch.send( - str::from_bytes(data)); - log(debug, "SERVER: before write"); - tcp_write_single(sock, str::bytes(resp)); - log(debug, "SERVER: after write.. die"); - } - result::err(err_data) { - server_ch.send(""); - } - } - }; - let ret_val = server_ch.recv(); - log(debug, #fmt("SERVER: exited and got ret val: '%s'", ret_val)); - ret_val - } - fn run_tcp_test_client(server_ip: str, server_port: uint, resp: str, client_ch: comm::chan, iotask: iotask) -> result::result Date: Tue, 29 May 2012 15:15:04 -0700 Subject: [PATCH 07/45] std: some cleanup in net::tcp rename listen_to_conn->listen --- src/libstd/net_tcp.rs | 59 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 1f732978f4bac..6f1b1fd525847 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -19,7 +19,7 @@ export tcp_err_data, tcp_connect_err_data; // operations on a tcp_socket export write, write_future, read_start, read_stop; // tcp server stuff -export listen_for_conn, accept; +export listen, accept; // tcp client stuff export connect; // helper methods @@ -676,7 +676,7 @@ a `result` instance containing empty data of type `()` on a successful/normal shutdown, and a `tcp_err_data` record in the event of listen exiting because of an error "] -fn listen_for_conn(host_ip: ip::ip_addr, port: uint, backlog: uint, +fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, iotask: iotask, on_establish_cb: fn~(comm::chan>), +new_connect_cb: fn~(tcp_new_connection, @@ -697,47 +697,48 @@ fn listen_for_conn(host_ip: ip::ip_addr, port: uint, backlog: uint, }; let server_data_ptr = ptr::addr_of(server_data); - let setup_po = comm::port::>(); - let setup_ch = comm::chan(setup_po); - iotask::interact(iotask) {|loop_ptr| - let tcp_addr = ipv4_ip_addr_to_sockaddr_in(host_ip, - port); - alt uv::ll::tcp_init(loop_ptr, server_stream_ptr) { - 0i32 { - alt uv::ll::tcp_bind(server_stream_ptr, - ptr::addr_of(tcp_addr)) { + let setup_result = comm::listen {|setup_ch| + iotask::interact(iotask) {|loop_ptr| + let tcp_addr = ipv4_ip_addr_to_sockaddr_in(host_ip, + port); + alt uv::ll::tcp_init(loop_ptr, server_stream_ptr) { 0i32 { - alt uv::ll::listen(server_stream_ptr, - backlog as libc::c_int, - tcp_lfc_on_connection_cb) { + alt uv::ll::tcp_bind(server_stream_ptr, + ptr::addr_of(tcp_addr)) { 0i32 { - uv::ll::set_data_for_uv_handle( - server_stream_ptr, - server_data_ptr); - comm::send(setup_ch, none); + alt uv::ll::listen(server_stream_ptr, + backlog as libc::c_int, + tcp_lfc_on_connection_cb) { + 0i32 { + uv::ll::set_data_for_uv_handle( + server_stream_ptr, + server_data_ptr); + comm::send(setup_ch, none); + } + _ { + log(debug, "failure to uv_listen()"); + let err_data = uv::ll::get_last_err_data(loop_ptr); + comm::send(setup_ch, some(err_data)); + } + } } _ { - log(debug, "failure to uv_listen()"); + log(debug, "failure to uv_tcp_bind"); let err_data = uv::ll::get_last_err_data(loop_ptr); comm::send(setup_ch, some(err_data)); } } } _ { - log(debug, "failure to uv_tcp_bind"); + log(debug, "failure to uv_tcp_init"); let err_data = uv::ll::get_last_err_data(loop_ptr); comm::send(setup_ch, some(err_data)); } } - } - _ { - log(debug, "failure to uv_tcp_init"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - comm::send(setup_ch, some(err_data)); - } - } + }; + setup_ch.recv() }; - alt comm::recv(setup_po) { + alt setup_result { some(err_data) { // we failed to bind/list w/ libuv result::err(err_data.to_tcp_err()) @@ -1338,7 +1339,7 @@ mod test { task::spawn_sched(task::manual_threads(1u)) {|| let server_ip_addr = ip::v4::parse_addr(server_ip); let listen_result = - listen_for_conn(server_ip_addr, server_port, 128u, + listen(server_ip_addr, server_port, 128u, iotask, // on_establish_cb -- called when listener is set up {|kill_ch| From f2df66da80ae5fee73f2eed643b5152e120767af Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 29 May 2012 15:50:10 -0700 Subject: [PATCH 08/45] std: factor main body of tcp::listen into reusable listen_common --- src/libstd/net_tcp.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 6f1b1fd525847..66f287683bbaa 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -682,6 +682,22 @@ fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, +new_connect_cb: fn~(tcp_new_connection, comm::chan>)) -> result::result<(), tcp_err_data> unsafe { + listen_common(host_ip, port, backlog, iotask, on_establish_cb) + // on_connect_cb + {|handle| + let server_data_ptr = uv::ll::get_data_for_uv_handle(handle) + as *tcp_listen_fc_data; + let new_conn = new_tcp_conn(handle); + let kill_ch = (*server_data_ptr).kill_ch; + new_connect_cb(new_conn, kill_ch); + } +} + +fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, + iotask: iotask, + on_establish_cb: fn~(comm::chan>), + -on_connect_cb: fn~(*uv::ll::uv_tcp_t)) + -> result::result<(), tcp_err_data> unsafe { let stream_closed_po = comm::port::<()>(); let kill_po = comm::port::>(); let kill_ch = comm::chan(kill_po); @@ -691,7 +707,7 @@ fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, server_stream_ptr: server_stream_ptr, stream_closed_ch: comm::chan(stream_closed_po), kill_ch: kill_ch, - new_connect_cb: new_connect_cb, + on_connect_cb: on_connect_cb, iotask: iotask, mut active: true }; @@ -1008,8 +1024,7 @@ type tcp_listen_fc_data = { server_stream_ptr: *uv::ll::uv_tcp_t, stream_closed_ch: comm::chan<()>, kill_ch: comm::chan>, - new_connect_cb: fn~(tcp_new_connection, - comm::chan>), + on_connect_cb: fn~(*uv::ll::uv_tcp_t), iotask: iotask, mut active: bool }; @@ -1028,8 +1043,7 @@ crust fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t, if (*server_data_ptr).active { alt status { 0i32 { - let new_conn = new_tcp_conn(handle); - (*server_data_ptr).new_connect_cb(new_conn, kill_ch); + (*server_data_ptr).on_connect_cb(handle); } _ { let loop_ptr = uv::ll::get_loop_for_uv_handle(handle); From 0ca1ecaf6eb9077b2ec32fc33b23f7b586b7b070 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 5 Jun 2012 06:40:39 -0700 Subject: [PATCH 09/45] std: EADDRINUSE and EACCES err tests for tcp server + more cleanup .. confounded resolve! --- src/libstd/net_tcp.rs | 600 +++++++++++++++++++----------------------- 1 file changed, 278 insertions(+), 322 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 66f287683bbaa..b51058b24998e 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -23,8 +23,7 @@ export listen, accept; // tcp client stuff export connect; // helper methods -import methods = net_tcp_methods; -export methods; +export methods_tcp_socket; #[nolink] native mod rustrt { @@ -57,6 +56,38 @@ type tcp_err_data = { err_name: str, err_msg: str }; +#[doc=" +Details returned as part of a `result::err` result from `tcp::listen` +"] +enum tcp_listen_err_data { + #[doc=" + Some unplanned-for error. The first and second fields correspond + to libuv's `err_name` and `err_msg` fields, respectively. + "] + generic_listen_err(str, str), + #[doc=" + Failed to bind to the requested IP/Port, because it is already in use. + + # Possible Causes + + * Attempting to bind to a port already bound to another listener + "] + address_in_use, + #[doc=" + Request to bind to an IP/Port was denied by the system. + + # Possible Causes + + * Attemping to binding to an IP/Port as a non-Administrator + on Windows Vista+ + * Attempting to bind, as a non-priv'd + user, to 'privileged' ports (< 1024) on *nix + "] + access_denied +} +#[doc=" +Details returned as part of a `result::err` result from `tcp::connect` +"] enum tcp_connect_err_data { #[doc=" Some unplanned-for error. The first and second fields correspond @@ -333,185 +364,6 @@ fn read_future(sock: tcp_socket, timeout_msecs: uint) } #[doc=" -<<<<<<< HEAD -Bind to a given IP/port and listen for new connections - -# Arguments - -* `host_ip` - a `net::ip::ip_addr` representing a unique IP -(versions 4 or 6) -* `port` - a uint representing the port to listen on -* `backlog` - a uint representing the number of incoming connections -to cache in memory -* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on - -# Returns - -A `result` instance containing either a `tcp_conn_port` which can used -to listen for, and accept, new connections, or a `tcp_err_data` if -failure to create the tcp listener occurs -"] -fn new_listener(host_ip: ip::ip_addr, port: uint, backlog: uint, - iotask: iotask) - -> result::result unsafe { - let stream_closed_po = comm::port::<()>(); - let stream_closed_ch = comm::chan(stream_closed_po); - let new_conn_po = comm::port::>(); - let new_conn_ch = comm::chan(new_conn_po); - // FIXME (#2656): This shared box should not be captured in the i/o - // task Make it a unique pointer. - let server_data: @tcp_conn_port_data = @{ - server_stream: uv::ll::tcp_t(), - stream_closed_po: stream_closed_po, - stream_closed_ch: stream_closed_ch, - iotask: iotask, - new_conn_po: new_conn_po, - new_conn_ch: new_conn_ch - }; - let server_data_ptr = ptr::addr_of(*server_data); - let server_stream_ptr = ptr::addr_of((*server_data_ptr) - .server_stream); - - let setup_po = comm::port::>(); - let setup_ch = comm::chan(setup_po); - iotask::interact(iotask) {|loop_ptr| - let tcp_addr = ipv4_ip_addr_to_sockaddr_in(host_ip, - port); - alt uv::ll::tcp_init(loop_ptr, server_stream_ptr) { - 0i32 { - alt uv::ll::tcp_bind(server_stream_ptr, - ptr::addr_of(tcp_addr)) { - 0i32 { - alt uv::ll::listen(server_stream_ptr, - backlog as libc::c_int, - tcp_nl_on_connection_cb) { - 0i32 { - uv::ll::set_data_for_uv_handle( - server_stream_ptr, - server_data_ptr); - comm::send(setup_ch, none); - } - _ { - log(debug, "failure to uv_listen()"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - comm::send(setup_ch, some(err_data)); - } - } - } - _ { - log(debug, "failure to uv_tcp_bind"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - comm::send(setup_ch, some(err_data)); - } - } - } - _ { - log(debug, "failure to uv_tcp_init"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - comm::send(setup_ch, some(err_data)); - } - } - }; - alt comm::recv(setup_po) { - some(err_data) { - // we failed to bind/list w/ libuv - result::err(err_data.to_tcp_err()) - } - none { - result::ok(tcp_conn_port(server_data)) - } - } -} - -#[doc=" -Block on a `net::tcp::tcp_conn_port` until a new connection arrives - -This function behaves similarly to `comm::recv()` - -# Arguments - -* server_port -- a `net::tcp::tcp_conn_port` that you wish to listen -on for an incoming connection - -# Returns - -A `result` object containing a `net::tcp::tcp_socket`, ready for immediate -use, as the `ok` varient, or a `net::tcp::tcp_err_data` for the `err` -variant -"] -fn conn_recv(server_port: tcp_conn_port) - -> result::result { - let new_conn_po = (*(server_port.conn_data)).new_conn_po; - let iotask = (*(server_port.conn_data)).iotask; - let new_conn_result = comm::recv(new_conn_po); - alt new_conn_result { - ok(client_stream_ptr) { - conn_port_new_tcp_socket(client_stream_ptr, iotask) - } - err(err_data) { - result::err(err_data) - } - } -} - -#[doc=" -Identical to `net::tcp::conn_recv`, but ran on a new task - -The recv'd tcp_socket is created with a new task on the current scheduler, -and given as a parameter to the provided callback - -# Arguments - -* `server_port` -- a `net::tcp::tcp_conn_port` that you wish to listen -on for an incoming connection -* `cb` -- a callback that will be ran, in a new task on the current scheduler, -once a new connection is recv'd. Its parameter: - * A `result` object containing a `net::tcp::tcp_socket`, ready for immediate - use, as the `ok` varient, or a `net::tcp::tcp_err_data` for the `err` - variant -"] -fn conn_recv_spawn(server_port: tcp_conn_port, - +cb: fn~(result::result)) { - let new_conn_po = (*(server_port.conn_data)).new_conn_po; - let iotask = (*(server_port.conn_data)).iotask; - let new_conn_result = comm::recv(new_conn_po); - task::spawn {|| - let sock_create_result = alt new_conn_result { - ok(client_stream_ptr) { - conn_port_new_tcp_socket(client_stream_ptr, iotask) - } - err(err_data) { - result::err(err_data) - } - }; - cb(sock_create_result); - }; -} - -#[doc=" -Check if a `net::tcp::tcp_conn_port` has one-or-more pending, new connections - -This function behaves similarly to `comm::peek()` - -# Arguments - -* `server_port` -- a `net::tcp::tcp_conn_port` representing a server -connection - -# Returns - -`true` if there are one-or-more pending connections, `false` if there are -none. -"] -fn conn_peek(server_port: tcp_conn_port) -> bool { - let new_conn_po = (*(server_port.conn_data)).new_conn_po; - comm::peek(new_conn_po) -} - -#[doc=" -======= ->>>>>>> std: dump the tcp::new_listener server API Bind an incoming client connection to a `net::tcp::tcp_socket` # Notes @@ -681,7 +533,7 @@ fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, on_establish_cb: fn~(comm::chan>), +new_connect_cb: fn~(tcp_new_connection, comm::chan>)) - -> result::result<(), tcp_err_data> unsafe { + -> result::result<(), tcp_listen_err_data> unsafe { listen_common(host_ip, port, backlog, iotask, on_establish_cb) // on_connect_cb {|handle| @@ -697,7 +549,7 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, iotask: iotask, on_establish_cb: fn~(comm::chan>), -on_connect_cb: fn~(*uv::ll::uv_tcp_t)) - -> result::result<(), tcp_err_data> unsafe { + -> result::result<(), tcp_listen_err_data> unsafe { let stream_closed_po = comm::port::<()>(); let kill_po = comm::port::>(); let kill_ch = comm::chan(kill_po); @@ -719,6 +571,9 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, port); alt uv::ll::tcp_init(loop_ptr, server_stream_ptr) { 0i32 { + uv::ll::set_data_for_uv_handle( + server_stream_ptr, + server_data_ptr); alt uv::ll::tcp_bind(server_stream_ptr, ptr::addr_of(tcp_addr)) { 0i32 { @@ -726,9 +581,6 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, backlog as libc::c_int, tcp_lfc_on_connection_cb) { 0i32 { - uv::ll::set_data_for_uv_handle( - server_stream_ptr, - server_data_ptr); comm::send(setup_ch, none); } _ { @@ -756,8 +608,29 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, }; alt setup_result { some(err_data) { - // we failed to bind/list w/ libuv - result::err(err_data.to_tcp_err()) + iotask::interact(iotask) {|loop_ptr| + log(debug, #fmt("tcp::listen post-kill recv hl interact %?", + loop_ptr)); + (*server_data_ptr).active = false; + uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); + }; + stream_closed_po.recv(); + alt err_data.err_name { + "EACCES" { + log(debug, "Got EACCES error"); + result::err(access_denied) + } + "EADDRINUSE" { + log(debug, "Got EADDRINUSE error"); + result::err(address_in_use) + } + _ { + log(debug, #fmt("Got '%s' '%s' libuv error", + err_data.err_name, err_data.err_msg)); + result::err( + generic_listen_err(err_data.err_name, err_data.err_msg)) + } + } } none { on_establish_cb(kill_ch); @@ -768,11 +641,12 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, (*server_data_ptr).active = false; uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); }; - comm::recv(stream_closed_po); + stream_closed_po.recv(); alt kill_result { // some failure post bind/listen some(err_data) { - result::err(err_data) + result::err(generic_listen_err(err_data.err_name, + err_data.err_msg)) } // clean exit none { @@ -783,35 +657,33 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, } } -mod net_tcp_methods { - #[doc=" - Convenience methods extending `net::tcp::tcp_socket` - "] - impl methods_tcp_socket for tcp_socket { - fn read_start() -> result::result>, tcp_err_data> { - read_start(self) - } - fn read_stop() -> - result::result<(), tcp_err_data> { - read_stop(self) - } - fn read(timeout_msecs: uint) -> - result::result<[u8]/~, tcp_err_data> { - read(self, timeout_msecs) - } - fn read_future(timeout_msecs: uint) -> - future::future> { - read_future(self, timeout_msecs) - } - fn write(raw_write_data: [u8]/~) - -> result::result<(), tcp_err_data> { - write(self, raw_write_data) - } - fn write_future(raw_write_data: [u8]/~) - -> future::future> { - write_future(self, raw_write_data) - } +#[doc=" +Convenience methods extending `net::tcp::tcp_socket` +"] +impl methods_tcp_socket for tcp_socket { + fn read_start() -> result::result>, tcp_err_data> { + read_start(self) + } + fn read_stop() -> + result::result<(), tcp_err_data> { + read_stop(self) + } + fn read(timeout_msecs: uint) -> + result::result<[u8]/~, tcp_err_data> { + read(self, timeout_msecs) + } + fn read_future(timeout_msecs: uint) -> + future::future> { + read_future(self, timeout_msecs) + } + fn write(raw_write_data: [u8]/~) + -> result::result<(), tcp_err_data> { + write(self, raw_write_data) + } + fn write_future(raw_write_data: [u8]/~) + -> future::future> { + write_future(self, raw_write_data) } } // INTERNAL API @@ -984,38 +856,6 @@ fn write_common_impl(socket_data_ptr: *tcp_socket_data, } } -<<<<<<< HEAD -// various recv_* can use a tcp_conn_port can re-use this.. -fn conn_port_new_tcp_socket( - stream_handle_ptr: *uv::ll::uv_tcp_t, - iotask: iotask) - -> result::result unsafe { - // tcp_nl_on_connection_cb - let reader_po = comm::port::>(); - let client_socket_data = @{ - reader_po : reader_po, - reader_ch : comm::chan(reader_po), - stream_handle_ptr : stream_handle_ptr, - connect_req : uv::ll::connect_t(), - write_req : uv::ll::write_t(), - iotask : iotask - }; - let client_socket_data_ptr = ptr::addr_of(*client_socket_data); - comm::listen {|cont_ch| - iotask::interact(iotask) {|loop_ptr| - log(debug, #fmt("in interact cb 4 conn_port_new_tcp.. loop %?", - loop_ptr)); - uv::ll::set_data_for_uv_handle(stream_handle_ptr, - client_socket_data_ptr); - cont_ch.send(()); - }; - cont_ch.recv() - }; - result::ok(tcp_socket(client_socket_data)) -} - -======= ->>>>>>> std: dump the tcp::new_listener server API enum tcp_new_connection { new_tcp_conn(*uv::ll::uv_tcp_t) } @@ -1260,6 +1100,18 @@ mod test { fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe { impl_gl_tcp_ipv4_client_error_connection_refused(); } + #[test] + fn test_gl_tcp_server_address_in_use() unsafe { + impl_gl_tcp_ipv4_server_address_in_use(); + } + #[test] + // FIXME: this probably needs to be ignored on windows. + // ... need to verify (someday we'll have 64bit windows! :) + //#[ignore(cfg(target_os = "win32"))] + fn test_gl_tcp_server_access_denied() unsafe { + impl_gl_tcp_ipv4_server_access_denied(); + } + } #[cfg(target_arch="x86")] mod impl32 { @@ -1273,6 +1125,19 @@ mod test { fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe { impl_gl_tcp_ipv4_client_error_connection_refused(); } + #[test] + #[ignore(cfg(target_os = "linux"))] + fn test_gl_tcp_server_address_in_use() unsafe { + impl_gl_tcp_ipv4_server_address_in_use(); + } + #[test] + #[ignore(cfg(target_os = "linux"))] + // FIXME: this probably needs to be ignored on windows. + // ... need to verify + //#[ignore(cfg(target_os = "win32"))] + fn test_gl_tcp_server_access_denied() unsafe { + impl_gl_tcp_ipv4_server_access_denied(); + } } } fn impl_gl_tcp_ipv4_server_and_client() { @@ -1324,7 +1189,7 @@ mod test { fn impl_gl_tcp_ipv4_client_error_connection_refused() { let hl_loop = uv::global_loop::get(); let server_ip = "127.0.0.1"; - let server_port = 8890u; + let server_port = 8889u; let expected_req = "ping"; // client log(debug, "firing up client.."); @@ -1344,85 +1209,181 @@ mod test { } } } + fn impl_gl_tcp_ipv4_server_address_in_use() { + let hl_loop = uv::global_loop::get(); + let server_ip = "127.0.0.1"; + let server_port = 8890u; + let expected_req = "ping"; + let expected_resp = "pong"; + + let server_result_po = comm::port::(); + let server_result_ch = comm::chan(server_result_po); + + let cont_po = comm::port::<()>(); + let cont_ch = comm::chan(cont_po); + // server + task::spawn_sched(task::manual_threads(1u)) {|| + let actual_req = comm::listen {|server_ch| + run_tcp_test_server( + server_ip, + server_port, + expected_resp, + server_ch, + cont_ch, + hl_loop) + }; + server_result_ch.send(actual_req); + }; + comm::recv(cont_po); + // this one should fail.. + let listen_err = run_tcp_test_server_fail( + server_ip, + server_port, + hl_loop); + // client.. just doing this so that the first server tears down + log(debug, "server started, firing up client.."); + comm::listen {|client_ch| + run_tcp_test_client( + server_ip, + server_port, + expected_req, + client_ch, + hl_loop) + }; + alt listen_err { + address_in_use { + assert true; + } + _ { + fail "expected address_in_use listen error,"+ + "but got a different error varient. check logs."; + } + } + } + fn impl_gl_tcp_ipv4_server_access_denied() { + let hl_loop = uv::global_loop::get(); + let server_ip = "127.0.0.1"; + let server_port = 80u; + // this one should fail.. + let listen_err = run_tcp_test_server_fail( + server_ip, + server_port, + hl_loop); + alt listen_err { + access_denied { + assert true; + } + _ { + fail "expected address_in_use listen error,"+ + "but got a different error varient. check logs."; + } + } + } fn run_tcp_test_server(server_ip: str, server_port: uint, resp: str, server_ch: comm::chan, cont_ch: comm::chan<()>, iotask: iotask) -> str { - - task::spawn_sched(task::manual_threads(1u)) {|| - let server_ip_addr = ip::v4::parse_addr(server_ip); - let listen_result = - listen(server_ip_addr, server_port, 128u, - iotask, - // on_establish_cb -- called when listener is set up - {|kill_ch| - log(debug, #fmt("establish_cb %?", - kill_ch)); - comm::send(cont_ch, ()); - }, - // risky to run this on the loop, but some users - // will want the POWER - {|new_conn, kill_ch| - log(debug, "SERVER: new connection!"); - comm::listen {|cont_ch| - task::spawn_sched(task::manual_threads(1u)) {|| - log(debug, "SERVER: starting worker for new req"); - - let accept_result = accept(new_conn); - log(debug, "SERVER: after accept()"); - if result::is_err(accept_result) { - log(debug, "SERVER: error accept connection"); - let err_data = result::get_err(accept_result); + let server_ip_addr = ip::v4::parse_addr(server_ip); + let listen_result = listen(server_ip_addr, server_port, 128u, iotask, + // on_establish_cb -- called when listener is set up + {|kill_ch| + log(debug, #fmt("establish_cb %?", + kill_ch)); + comm::send(cont_ch, ()); + }, + // risky to run this on the loop, but some users + // will want the POWER + {|new_conn, kill_ch| + log(debug, "SERVER: new connection!"); + comm::listen {|cont_ch| + task::spawn_sched(task::manual_threads(1u)) {|| + log(debug, "SERVER: starting worker for new req"); + + let accept_result = accept(new_conn); + log(debug, "SERVER: after accept()"); + if result::is_err(accept_result) { + log(debug, "SERVER: error accept connection"); + let err_data = result::get_err(accept_result); + comm::send(kill_ch, some(err_data)); + log(debug, + "SERVER/WORKER: send on err cont ch"); + cont_ch.send(()); + } + else { + log(debug, + "SERVER/WORKER: send on cont ch"); + cont_ch.send(()); + let sock = result::unwrap(accept_result); + log(debug, "SERVER: successfully accepted"+ + "connection!"); + let received_req_bytes = read(sock, 0u); + alt received_req_bytes { + result::ok(data) { + server_ch.send( + str::from_bytes(data)); + log(debug, "SERVER: before write"); + tcp_write_single(sock, str::bytes(resp)); + log(debug, "SERVER: after write.. die"); + comm::send(kill_ch, none); + } + result::err(err_data) { + log(debug, #fmt("SERVER: error recvd: %s %s", + err_data.err_name, err_data.err_msg)); comm::send(kill_ch, some(err_data)); - log(debug, - "SERVER/WORKER: send on err cont ch"); - cont_ch.send(()); - } - else { - log(debug, - "SERVER/WORKER: send on cont ch"); - cont_ch.send(()); - let sock = result::unwrap(accept_result); - log(debug, "SERVER: successfully accepted"+ - "connection!"); - let received_req_bytes = read(sock, 0u); - alt received_req_bytes { - result::ok(data) { - server_ch.send( - str::from_bytes(data)); - log(debug, "SERVER: before write"); - tcp_write_single(sock, str::bytes(resp)); - log(debug, "SERVER: after write.. die"); - comm::send(kill_ch, none); - } - result::err(err_data) { - log(debug, #fmt("SERVER: error recvd: %s %s", - err_data.err_name, err_data.err_msg)); - comm::send(kill_ch, some(err_data)); - server_ch.send(""); - } - } - log(debug, "SERVER: worker spinning down"); + server_ch.send(""); + } } + log(debug, "SERVER: worker spinning down"); } - log(debug, "SERVER: waiting to recv on cont_ch"); - cont_ch.recv() - }; - log(debug, "SERVER: recv'd on cont_ch..leaving listen cb"); - }); - // err check on listen_result - if result::is_err(listen_result) { - let err_data = result::get_err(listen_result); - log(debug, #fmt("SERVER: exited abnormally name %s msg %s", - err_data.err_name, err_data.err_msg)); + } + log(debug, "SERVER: waiting to recv on cont_ch"); + cont_ch.recv() + }; + log(debug, "SERVER: recv'd on cont_ch..leaving listen cb"); + }); + // err check on listen_result + if result::is_err(listen_result) { + alt result::get_err(listen_result) { + generic_listen_err(name, msg) { + fail #fmt("SERVER: exited abnormally name %s msg %s", + name, msg); + } + access_denied { + fail "SERVER: exited abnormally, got access denied.."; + } + address_in_use { + fail "SERVER: exited abnormally, got address in use..."; + } } - }; + } let ret_val = server_ch.recv(); log(debug, #fmt("SERVER: exited and got ret val: '%s'", ret_val)); ret_val } + fn run_tcp_test_server_fail(server_ip: str, server_port: uint, + iotask: iotask) -> tcp_listen_err_data { + let server_ip_addr = ip::v4::parse_addr(server_ip); + let listen_result = listen(server_ip_addr, server_port, 128u, iotask, + // on_establish_cb -- called when listener is set up + {|kill_ch| + log(debug, #fmt("establish_cb %?", + kill_ch)); + }, + {|new_conn, kill_ch| + fail #fmt("SERVER: shouldn't be called.. %? %?", + new_conn, kill_ch); + }); + // err check on listen_result + if result::is_failure(listen_result) { + result::get_err(listen_result) + } + else { + fail "SERVER: did not fail as expected" + } + } + fn run_tcp_test_client(server_ip: str, server_port: uint, resp: str, client_ch: comm::chan, iotask: iotask) -> result::result>>>>>> std: mod cleanup, impl/test for conn. refused err + mem leak fix let write_result = write_result_future.get(); if result::is_err(write_result) { log(debug, "tcp_write_single: write failed!"); From aa476925c339cde1afff119c83ef8b1682e85637 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 5 Jun 2012 07:12:12 -0700 Subject: [PATCH 10/45] std: doc and misc cleanup in net::tcp * updated rustdoc info for several functions * changed read_stop to take control of the port returned by read_start * made write_future do an explicit data copy with the binary vector it is passed --- src/libstd/net_tcp.rs | 56 +++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index b51058b24998e..ae9556eec5012 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -105,15 +105,16 @@ Initiate a client connection over TCP/IP # Arguments -* `ip` - The IP address (versions 4 or 6) of the remote host +* `input_ip` - The IP address (versions 4 or 6) of the remote host * `port` - the unsigned integer of the desired remote host port * `iotask` - a `uv::iotask` that the tcp request will run on # Returns -A `result` that, if the operation succeeds, contains a `tcp_socket` that -can be used to send and receive data to/from the remote host. In the event -of failure, a `tcp_err_data` will be returned +A `result` that, if the operation succeeds, contains a `net::net::tcp_socket` +that can be used to send and receive data to/from the remote host. In the +event of failure, a `net::tcp::tcp_connect_err_data` instance will be +returned "] fn connect(input_ip: ip::ip_addr, port: uint, iotask: iotask) @@ -244,9 +245,12 @@ Write binary data to tcp stream; Returns a `future::future` value immediately # Safety -This function can produce unsafe results if the call to `write_future` is -made, the `future::future` value returned is never resolved via -`future::get`, and then the `tcp_socket` passed in to `write_future` leaves +This function can produce unsafe results if: + +1. the call to `write_future` is made +2. the `future::future` value returned is never resolved via +`future::get` +3. and then the `tcp_socket` passed in to `write_future` leaves scope and is destructed before the task that runs the libuv write operation completes. @@ -270,7 +274,8 @@ fn write_future(sock: tcp_socket, raw_write_data: [u8]/~) -> future> unsafe { let socket_data_ptr = ptr::addr_of(*(sock.socket_data)); future_spawn {|| - write_common_impl(socket_data_ptr, raw_write_data) + let data_copy = copy(raw_write_data); + write_common_impl(socket_data_ptr, data_copy) } } @@ -301,9 +306,11 @@ Stop reading from an open TCP connection; used with `read_start` * `sock` - a `net::tcp::tcp_socket` that you wish to stop reading on "] -fn read_stop(sock: tcp_socket) -> +fn read_stop(sock: tcp_socket, + -read_port: comm::port>) -> result::result<(), tcp_err_data> unsafe { - let socket_data = ptr::addr_of(*(sock.socket_data)); + log(debug, #fmt("taking the read_port out of commission %?", read_port)); + let socket_data = ptr::addr_of(**sock); read_stop_common_impl(socket_data) } @@ -388,7 +395,15 @@ Here, the `new_conn` is used in conjunction with `accept` from within a task spawned by the `new_connect_cb` passed into `listen` ~~~~~~~~~~~ -net::tcp::listen(remote_ip, remote_port, backlog) {|new_conn, kill_ch| +net::tcp::listen(remote_ip, remote_port, backlog) + // this callback is ran once after the connection is successfully + // set up + {|kill_ch| + // pass the kill_ch to your main loop or wherever you want + // to be able to externally kill the server from + } + // this callback is ran when a new connection arrives + {|new_conn, kill_ch| let cont_po = comm::port::>(); let cont_ch = comm::chan(cont_po); task::spawn {|| @@ -418,13 +433,11 @@ net::tcp::listen(remote_ip, remote_port, backlog) {|new_conn, kill_ch| # Returns -* Success - * On success, this function will return a `net::tcp::tcp_socket` as the - `ok` variant of a `result`. The `net::tcp::tcp_socket` is anchored within - the task that `accept` was called within for its lifetime. -* Failure - * On failure, this function will return a `net::tcp::tcp_err_data` record - as the `err` variant of a `result`. +On success, this function will return a `net::tcp::tcp_socket` as the +`ok` variant of a `result`. The `net::tcp::tcp_socket` is anchored within +the task that `accept` was called within for its lifetime. On failure, +this function will return a `net::tcp::tcp_err_data` record +as the `err` variant of a `result`. "] fn accept(new_conn: tcp_new_connection) -> result::result unsafe { @@ -525,7 +538,7 @@ callback's arguments are: # returns a `result` instance containing empty data of type `()` on a -successful/normal shutdown, and a `tcp_err_data` record in the event +successful/normal shutdown, and a `tcp_listen_err_data` enum in the event of listen exiting because of an error "] fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, @@ -665,9 +678,10 @@ impl methods_tcp_socket for tcp_socket { result::result<[u8]/~, tcp_err_data>>, tcp_err_data> { read_start(self) } - fn read_stop() -> + fn read_stop(-read_port: + comm::port>) -> result::result<(), tcp_err_data> { - read_stop(self) + read_stop(self, read_port) } fn read(timeout_msecs: uint) -> result::result<[u8]/~, tcp_err_data> { From 03c661d8acb2e39f1f2be599d6f2e7043f6ed6d3 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 7 Jun 2012 16:41:26 -0700 Subject: [PATCH 11/45] core: export vec::unshift --- src/libcore/vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index e12a62fc41db7..152f1ed5daf6b 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -31,6 +31,7 @@ export splitn; export rsplit; export rsplitn; export shift; +export unshift; export pop; export push, push_all, push_all_move; export grow; From 0b7302f8157553ae4796a535025039bfcbdeccfa Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 7 Jun 2012 16:42:39 -0700 Subject: [PATCH 12/45] std: add buffered wrapper to tcp_socket + io::reader impl. no tests, yet. need to do some other work, in the subsequent commit, to add io::writer, then tests. --- src/libstd/net_tcp.rs | 106 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index ae9556eec5012..692f73467b4bf 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -18,6 +18,8 @@ export tcp_socket; export tcp_err_data, tcp_connect_err_data; // operations on a tcp_socket export write, write_future, read_start, read_stop; +// buffered socket +export socket_buf; // tcp server stuff export listen, accept; // tcp client stuff @@ -49,6 +51,16 @@ class tcp_socket { } } +#[doc=" +A buffered wrapper for `net::tcp::tcp_socket` + +It is created with a call to `net::tcp::socket_buf()` and has impls that +satisfy both the `io::reader` and `io::writer` ifaces. +"] +resource tcp_socket_buf(data: @tcp_buffered_socket_data) { + log(debug, #fmt("dtor for tcp_socket_buf.. %?", data)); +} + #[doc=" Contains raw, string-based, error information returned from libuv "] @@ -670,6 +682,25 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, } } +#[doc=" +Convert a `net::tcp::tcp_socket` to a `net::tcp::tcp_socket_buf`. + +This function takes ownership of a `net::tcp::tcp_socket`, returning it +stored within a buffered wrapper, which can be converted to a `io::reader` +or `io::writer` + +# Arguments + +* `sock` -- a `net::tcp::tcp_socket` that you want to buffer + +# Returns + +A buffered wrapper that you can cast as an `io::reader` or `io::writer` +"] +fn socket_buf(-sock: tcp_socket) -> tcp_socket_buf { + tcp_socket_buf(@{ sock: sock, mut buf: [] }) +} + #[doc=" Convenience methods extending `net::tcp::tcp_socket` "] @@ -700,6 +731,74 @@ impl methods_tcp_socket for tcp_socket { write_future(self, raw_write_data) } } + +#[doc=" +Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` +"] +impl tcp_socket_buf of io::reader for tcp_socket_buf { + fn read_bytes(amt: uint) -> [u8] { + let has_amt_available = + vec::len((*self).buf) >= amt; + if has_amt_available { + // no arbitrary-length shift in vec::? + let mut ret_buf = []; + while vec::len(ret_buf) < amt { + ret_buf += [vec::shift((*self).buf)]; + } + ret_buf + } + else { + let read_result = read((*self).sock, 0u); + if read_result.is_failure() { + // failure case.. no good answer, yet. + [] + } + else { + let new_chunk = result::unwrap(read_result); + (*self).buf += new_chunk; + self.read_bytes(amt) + } + } + } + fn read_byte() -> int { + self.read_bytes(1u)[0] as int + } + fn unread_byte(amt: int) { + vec::unshift((*self).buf, amt as u8); + } + fn eof() -> bool { + false // noop + } + fn seek(dist: int, seek: io::seek_style) { + log(debug, #fmt("tcp_socket_buf seek stub %? %?", dist, seek)); + // noop + } + fn tell() -> uint { + 0u // noop + } +} + +/* +#[doc=" +Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` +"] +impl tcp_socket_buf of io::writer for tcp_socket_buf { + fn write(data: [const u8]/&) { + (*self).sock.write(iter::to_vec(data as [u8]/&)); + } + fn seek(dist: int, seek: io::seek_style) { + log(debug, #fmt("tcp_socket_buf seek stub %? %?", dist, seek)); + // noop + } + fn tell() -> uint { + 0u + } + fn flush() -> int { + 0 + } +} +*/ + // INTERNAL API fn tear_down_socket_data(socket_data: @tcp_socket_data) unsafe { @@ -826,6 +925,8 @@ fn read_start_common_impl(socket_data: *tcp_socket_data) } } +// helper to convert a "class" vector of [u8] to a *[uv::ll::uv_buf_t] + // shared implementation used by write and write_future fn write_common_impl(socket_data_ptr: *tcp_socket_data, raw_write_data: [u8]/~) @@ -1083,6 +1184,11 @@ type tcp_socket_data = { iotask: iotask }; +type tcp_buffered_socket_data = { + sock: tcp_socket, + mut buf: [u8] +}; + // convert rust ip_addr to libuv's native representation fn ipv4_ip_addr_to_sockaddr_in(input_ip: ip::ip_addr, port: uint) -> uv::ll::sockaddr_in unsafe { From d9ff6e9ea5e1d45256783e9bafa7513ef55f70c7 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 7 Jun 2012 21:22:35 -0700 Subject: [PATCH 13/45] std: rework signature of tcp::write common impl to make io::writer possible --- src/libstd/net_tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 692f73467b4bf..e8541cb991b2c 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -287,7 +287,7 @@ fn write_future(sock: tcp_socket, raw_write_data: [u8]/~) let socket_data_ptr = ptr::addr_of(*(sock.socket_data)); future_spawn {|| let data_copy = copy(raw_write_data); - write_common_impl(socket_data_ptr, data_copy) + write_common_impl(socket_data_ptr, data_copy); } } From 2c890a1a0ddf5a52d7f8f1d5f1c0703d7c84a80b Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 7 Jun 2012 22:06:42 -0700 Subject: [PATCH 14/45] std: finish impl of io::writer for tcp_socket_buf --- src/libstd/net_tcp.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index e8541cb991b2c..cc329513ab2ef 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -778,13 +778,17 @@ impl tcp_socket_buf of io::reader for tcp_socket_buf { } } -/* #[doc=" Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` "] impl tcp_socket_buf of io::writer for tcp_socket_buf { - fn write(data: [const u8]/&) { - (*self).sock.write(iter::to_vec(data as [u8]/&)); + fn write(data: [const u8]/&) unsafe { + let socket_data_ptr = ptr::addr_of(**((*self).sock)); + let write_buf_vec = vec::unpack_const_slice(data) {|ptr, len| + [ uv::ll::buf_init(ptr as *u8, len) ] + }; + let write_buf_vec_ptr = ptr::addr_of(write_buf_vec); + write_common_impl(socket_data_ptr, write_buf_vec_ptr); } fn seek(dist: int, seek: io::seek_style) { log(debug, #fmt("tcp_socket_buf seek stub %? %?", dist, seek)); @@ -797,7 +801,6 @@ impl tcp_socket_buf of io::writer for tcp_socket_buf { 0 } } -*/ // INTERNAL API From 4acbe3623b50ceeddec8618113d3280ce4aebcaf Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 7 Jun 2012 22:10:18 -0700 Subject: [PATCH 15/45] std: renaming impl for tcp_socket and reshuffle/cleanup for tcp_socket_buf --- src/libstd/net_tcp.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index cc329513ab2ef..b6820690171b9 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -14,18 +14,16 @@ import str::extensions; // tcp interfaces export tcp_socket; +// buffered socket +export tcp_socket_buf, socket_buf; // errors export tcp_err_data, tcp_connect_err_data; // operations on a tcp_socket export write, write_future, read_start, read_stop; -// buffered socket -export socket_buf; // tcp server stuff export listen, accept; // tcp client stuff export connect; -// helper methods -export methods_tcp_socket; #[nolink] native mod rustrt { @@ -704,7 +702,7 @@ fn socket_buf(-sock: tcp_socket) -> tcp_socket_buf { #[doc=" Convenience methods extending `net::tcp::tcp_socket` "] -impl methods_tcp_socket for tcp_socket { +impl tcp_socket for tcp_socket { fn read_start() -> result::result>, tcp_err_data> { read_start(self) From 03f64fe2074ff342f84095d46e72349d210bbc87 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sat, 9 Jun 2012 20:44:15 -0700 Subject: [PATCH 16/45] core: adding str::as_slice .. most likely broken --- src/libcore/str.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 35d2edd608ae5..2c0f4b4a96b80 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -23,6 +23,7 @@ export as_buf, as_c_str, unpack_slice, + as_slice, // Adding things to and removing things from a string push_char, @@ -1620,6 +1621,16 @@ pure fn unpack_slice(s: str/&, f: fn(*u8, uint) -> T) -> T { } } +pure fn as_slice(s: str, + start: uint, end: uint, + f: fn(str/&) -> T) -> T unsafe { + assert (start <= end); + assert (end <= len(s)); + let p = ptr::addr_of(s); + f(::unsafe::reinterpret_cast( + (ptr::offset(p, start), (end - start) * sys::size_of::()))) +} + #[doc = " Reserves capacity for exactly `n` bytes in the given string, not including the null terminator. From 57931c075eb393faa470d418b3ddd1719e7eea75 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sat, 9 Jun 2012 20:46:29 -0700 Subject: [PATCH 17/45] std: test impl for using tcp_socket_buf and its reader/writer impls. fails. needs work. probably the slice code and/or the way that the tcp_socket_buf is wrapped in a shared box --- src/libstd/net_tcp.rs | 96 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index b6820690171b9..06829312849da 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -733,7 +733,7 @@ impl tcp_socket for tcp_socket { #[doc=" Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` "] -impl tcp_socket_buf of io::reader for tcp_socket_buf { +impl tcp_socket_buf of io::reader for @tcp_socket_buf { fn read_bytes(amt: uint) -> [u8] { let has_amt_available = vec::len((*self).buf) >= amt; @@ -748,7 +748,9 @@ impl tcp_socket_buf of io::reader for tcp_socket_buf { else { let read_result = read((*self).sock, 0u); if read_result.is_failure() { - // failure case.. no good answer, yet. + let err_data = read_result.get_err(); + log(debug, #fmt("ERROR sock_buf as io::reader.read err %? %?", + err_data.err_name, err_data.err_msg)); [] } else { @@ -779,14 +781,19 @@ impl tcp_socket_buf of io::reader for tcp_socket_buf { #[doc=" Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` "] -impl tcp_socket_buf of io::writer for tcp_socket_buf { +impl tcp_socket_buf of io::writer for @tcp_socket_buf { fn write(data: [const u8]/&) unsafe { let socket_data_ptr = ptr::addr_of(**((*self).sock)); let write_buf_vec = vec::unpack_const_slice(data) {|ptr, len| [ uv::ll::buf_init(ptr as *u8, len) ] }; let write_buf_vec_ptr = ptr::addr_of(write_buf_vec); - write_common_impl(socket_data_ptr, write_buf_vec_ptr); + let w_result = write_common_impl(socket_data_ptr, write_buf_vec_ptr); + if w_result.is_failure() { + let err_data = w_result.get_err(); + log(debug, #fmt("ERROR sock_buf as io::writer.writer err: %? %?", + err_data.err_name, err_data.err_msg)); + } } fn seek(dist: int, seek: io::seek_style) { log(debug, #fmt("tcp_socket_buf seek stub %? %?", dist, seek)); @@ -1204,7 +1211,7 @@ fn ipv4_ip_addr_to_sockaddr_in(input_ip: ip::ip_addr, } } -#[cfg(test)] +//#[cfg(test)] mod test { // FIXME don't run on fbsd or linux 32 bit (#2064) #[cfg(target_os="win32")] @@ -1232,6 +1239,10 @@ mod test { fn test_gl_tcp_server_access_denied() unsafe { impl_gl_tcp_ipv4_server_access_denied(); } + #[test] + fn test_gl_tcp_ipv4_server_client_reader_writer() { + impl_gl_tcp_ipv4_server_client_reader_writer(); + } } #[cfg(target_arch="x86")] @@ -1259,6 +1270,11 @@ mod test { fn test_gl_tcp_server_access_denied() unsafe { impl_gl_tcp_ipv4_server_access_denied(); } + #[test] + #[ignore(cfg(target_os = "linux"))] + fn test_gl_tcp_ipv4_server_client_reader_writer() { + impl_gl_tcp_ipv4_server_client_reader_writer(); + } } } fn impl_gl_tcp_ipv4_server_and_client() { @@ -1400,6 +1416,73 @@ mod test { } } } + fn impl_gl_tcp_ipv4_server_client_reader_writer() { + let iotask = uv::global_loop::get(); + let server_ip = "127.0.0.1"; + let server_port = 8891u; + let expected_req = "ping"; + let expected_resp = "pong"; + + let server_result_po = comm::port::(); + let server_result_ch = comm::chan(server_result_po); + + let cont_po = comm::port::<()>(); + let cont_ch = comm::chan(cont_po); + // server + task::spawn_sched(task::manual_threads(1u)) {|| + let actual_req = comm::listen {|server_ch| + run_tcp_test_server( + server_ip, + server_port, + expected_resp, + server_ch, + cont_ch, + iotask) + }; + server_result_ch.send(actual_req); + }; + comm::recv(cont_po); + // client + let server_addr = ip::v4::parse_addr(server_ip); + let conn_result = connect(server_addr, server_port, iotask); + if result::is_failure(conn_result) { + assert false; + } + let sock_buf = @socket_buf(result::unwrap(conn_result)); + buf_write(sock_buf as io::writer, expected_req); + + // so contrived! + let actual_resp = str::as_bytes(expected_resp) {|resp_buf| + buf_read(sock_buf as io::reader, + vec::len(resp_buf)) + }; + + let actual_req = comm::recv(server_result_po); + log(debug, #fmt("REQ: expected: '%s' actual: '%s'", + expected_req, actual_req)); + log(debug, #fmt("RESP: expected: '%s' actual: '%s'", + expected_resp, actual_resp)); + assert str::contains(actual_req, expected_req); + assert str::contains(actual_resp, expected_resp); + } + + fn buf_write(+w: io::writer, val: str) { + log(debug, #fmt("BUF_WRITE: val len %?", str::len(val))); + str::as_slice(val, 0u, str::len(val) -1u) {|val_slice| + str::byte_slice(val_slice) {|b_slice| + log(debug, #fmt("BUF_WRITE: b_slice len %?", + vec::len(b_slice))); + w.write(b_slice) + } + } + } + + fn buf_read(+r: io::reader, len: uint) -> str { + let new_bytes = r.read_bytes(len); + log(debug, #fmt("in buf_read.. new_bytes len: %?", + vec::len(new_bytes))); + str::from_bytes(new_bytes) + } fn run_tcp_test_server(server_ip: str, server_port: uint, resp: str, server_ch: comm::chan, @@ -1441,6 +1524,9 @@ mod test { let received_req_bytes = read(sock, 0u); alt received_req_bytes { result::ok(data) { + log(debug, "SERVER: got REQ str::from_bytes.."); + log(debug, #fmt("SERVER: REQ data len: %?", + vec::len(data))); server_ch.send( str::from_bytes(data)); log(debug, "SERVER: before write"); From 756d0d06a84fec6e666cabafe4c0d0c88d11f01d Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 10 Jun 2012 08:30:43 -0700 Subject: [PATCH 18/45] core: str::as_slice is unneeded, yay! fixes std::net::tcp socket_buf test i mistook an "unconstrained type" error, due to type-inference messup because i didnt have return vals in some closure wired-up right, for being due to not having a str as a str/& (a str will actually auto-coerce to a str/&, so str::as_slice was erroneously added. my bad). --- src/libcore/str.rs | 11 ----------- src/libstd/net_tcp.rs | 12 +++++------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 2c0f4b4a96b80..35d2edd608ae5 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -23,7 +23,6 @@ export as_buf, as_c_str, unpack_slice, - as_slice, // Adding things to and removing things from a string push_char, @@ -1621,16 +1620,6 @@ pure fn unpack_slice(s: str/&, f: fn(*u8, uint) -> T) -> T { } } -pure fn as_slice(s: str, - start: uint, end: uint, - f: fn(str/&) -> T) -> T unsafe { - assert (start <= end); - assert (end <= len(s)); - let p = ptr::addr_of(s); - f(::unsafe::reinterpret_cast( - (ptr::offset(p, start), (end - start) * sys::size_of::()))) -} - #[doc = " Reserves capacity for exactly `n` bytes in the given string, not including the null terminator. diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 06829312849da..6718e3729f74a 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -1456,7 +1456,7 @@ mod test { buf_read(sock_buf as io::reader, vec::len(resp_buf)) }; - + let actual_req = comm::recv(server_result_po); log(debug, #fmt("REQ: expected: '%s' actual: '%s'", expected_req, actual_req)); @@ -1468,12 +1468,10 @@ mod test { fn buf_write(+w: io::writer, val: str) { log(debug, #fmt("BUF_WRITE: val len %?", str::len(val))); - str::as_slice(val, 0u, str::len(val) -1u) {|val_slice| - str::byte_slice(val_slice) {|b_slice| - log(debug, #fmt("BUF_WRITE: b_slice len %?", - vec::len(b_slice))); - w.write(b_slice) - } + str::byte_slice(val) {|b_slice| + log(debug, #fmt("BUF_WRITE: b_slice len %?", + vec::len(b_slice))); + w.write(b_slice) } } From 76d4eb1744f427202c4c85f6981662d603042522 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 12 Jun 2012 08:38:22 -0700 Subject: [PATCH 19/45] rt: add remaining ip string parser/formatter helpers from uv --- src/rt/rust_uv.cpp | 20 ++++++++++++++++++++ src/rt/rustrt.def.in | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 1873ae33e9c16..7e719a5f45005 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -301,6 +301,10 @@ rust_uv_helper_sockaddr_in_size() { return sizeof(sockaddr_in); } extern "C" size_t +rust_uv_helper_sockaddr_in6_size() { + return sizeof(sockaddr_in6); +} +extern "C" size_t rust_uv_helper_uv_async_t_size() { return sizeof(uv_async_t); } @@ -441,6 +445,22 @@ rust_uv_ip4_addr(const char* ip, int port) { LOG(task, stdlib, "after creating .. port: %d", addr.sin_port); return addr; } +extern "C" struct sockaddr_in6 +rust_uv_ip6_addr(const char* ip, int port) { + rust_task* task = rust_get_current_task(); + LOG(task, stdlib, "before creating addr_ptr.. ip %s" \ + "port %d", ip, port); + struct sockaddr_in6 addr = uv_ip6_addr(ip, port); + return addr; +} +extern "C" int +rust_uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { + return uv_ip4_name(src, dst, size); +} +extern "C" int +rust_uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { + return uv_ip6_name(src, dst, size); +} extern "C" uintptr_t* rust_uv_get_kernel_global_chan_ptr() { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 0be74d20e24d3..b8086531ac7d5 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -111,6 +111,9 @@ rust_uv_last_error rust_uv_strerror rust_uv_err_name rust_uv_ip4_addr +rust_uv_ip4_name +rust_uv_ip6_addr +rust_uv_ip6_name rust_uv_tcp_connect rust_uv_tcp_bind rust_uv_listen @@ -126,6 +129,7 @@ rust_uv_helper_uv_buf_t_size rust_uv_helper_uv_write_t_size rust_uv_helper_uv_err_t_size rust_uv_helper_sockaddr_in_size +rust_uv_helper_sockaddr_in6_size rust_uv_helper_uv_async_t_size rust_uv_helper_uv_timer_t_size rust_uv_get_stream_handle_from_connect_req From 7455ead4db9cda1a430b61c5b63ede69436297fc Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 12 Jun 2012 08:41:06 -0700 Subject: [PATCH 20/45] std: mapping additional libuv ip string helpers.. add test for sockaddr_in6 .. but the test is kind of broken.. it appears that rust pads structs for alignment purposes? I can't get the struct to == 28.. that appears to be the native size of sockaddr_in6.. so we have a size 32 struct, for now. --- src/libstd/uv_ll.rs | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index db0dcf7f4f458..42dd5b93ea95b 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -223,10 +223,10 @@ type sockaddr_in = { mut sin_zero: (u8, u8, u8, u8, u8, u8, u8, u8) }; -// unix size: 28 .. make due w/ 32 +// unix size: 28 .. FIXME: stuck with 32 becuse of rust padding structs? type sockaddr_in6 = { a0: *u8, a1: *u8, - a2: *u8, a3: (u8, u8, u8, u8) + a2: *u8, a3: *u8 }; mod uv_ll_struct_stubgen { @@ -500,6 +500,12 @@ native mod rustrt { fn rust_uv_err_name(err: *uv_err_t) -> *libc::c_char; fn rust_uv_ip4_addr(ip: *u8, port: libc::c_int) -> sockaddr_in; + fn rust_uv_ip6_addr(ip: *u8, port: libc::c_int) + -> sockaddr_in6; + fn rust_uv_ip4_name(src: *sockaddr_in, dst: *u8, size: libc::size_t) + -> libc::c_int; + fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: libc::size_t) + -> libc::c_int; // FIXME ref #2064 fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t, @@ -558,6 +564,7 @@ native mod rustrt { fn rust_uv_helper_uv_write_t_size() -> libc::c_uint; fn rust_uv_helper_uv_err_t_size() -> libc::c_uint; fn rust_uv_helper_sockaddr_in_size() -> libc::c_uint; + fn rust_uv_helper_sockaddr_in6_size() -> libc::c_uint; fn rust_uv_helper_uv_async_t_size() -> libc::c_uint; fn rust_uv_helper_uv_timer_t_size() -> libc::c_uint; } @@ -686,6 +693,17 @@ unsafe fn ip4_addr(ip: str, port: int) ret rustrt::rust_uv_ip4_addr(addr_vec_ptr, port as libc::c_int); } +unsafe fn ip6_addr(ip: str, port: int) +-> sockaddr_in6 { + let mut addr_vec = str::bytes(ip); + addr_vec += [0u8]; // add null terminator + let addr_vec_ptr = vec::unsafe::to_ptr(addr_vec); + let ip_back = str::from_bytes(addr_vec); + log(debug, #fmt("vec val: '%s' length: %u", + ip_back, vec::len(addr_vec))); + ret rustrt::rust_uv_ip6_addr(addr_vec_ptr, + port as libc::c_int); +} unsafe fn timer_init(loop_ptr: *libc::c_void, timer_ptr: *uv_timer_t) -> libc::c_int { @@ -1366,6 +1384,21 @@ mod test { log(debug, output); assert foreign_handle_size as uint == rust_handle_size; } + #[test] + #[ignore(cfg(target_os = "freebsd"))] + fn test_uv_ll_struct_size_sockaddr_in6() { + let native_handle_size = + rustrt::rust_uv_helper_sockaddr_in6_size(); + let rust_handle_size = sys::size_of::(); + let output = #fmt("sockaddr_in -- native: %u rust: %u", + native_handle_size as uint, rust_handle_size); + log(debug, output); + // FIXME .. rust appears to pack structs to the nearest byte..? + // .. can't get the uv::ll::sockaddr_in6 to == 28 :/ + // .. so the type always appears to be 32 in size.. which is + // good, i guess.. better too big than too little + assert (4u+native_handle_size as uint) == rust_handle_size; + } #[test] #[ignore(cfg(target_os = "freebsd"))] From e1c7b30fec2277f591f4bd47b5100a262afdf131 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 17 Jun 2012 20:36:36 -0700 Subject: [PATCH 21/45] std: adding uv::ll::ip4_name and refactored net::ip to use it replaces net::ip's previously, hand-rolled impl for ipv4 addr parsing.. we're relying on libuv, now --- src/libstd/net_ip.rs | 52 +++++++++++++++++++------------------------ src/libstd/net_tcp.rs | 20 ++++++++++++----- src/libstd/uv_ll.rs | 18 +++++++++++++++ 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 64cded848d1ab..106f1baa8c5b7 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -5,6 +5,11 @@ Types/fns concerning Internet Protocol (IP), versions 4 & 6 import vec; import uint; +import sockaddr_in = uv::ll::sockaddr_in; +import sockaddr_in6 = uv::ll::sockaddr_in6; +import uv_ip4_addr = uv::ll::ip4_addr; +import uv_ip4_name = uv::ll::ip4_name; + export ip_addr, parse_addr_err; export format_addr; export v4; @@ -12,7 +17,7 @@ export v4; #[doc = "An IP address"] enum ip_addr { #[doc="An IPv4 address"] - ipv4(u8, u8, u8, u8), + ipv4(sockaddr_in), ipv6(u16,u16,u16,u16,u16,u16,u16,u16) } @@ -32,8 +37,14 @@ Convert a `ip_addr` to a str "] fn format_addr(ip: ip_addr) -> str { alt ip { - ipv4(a, b, c, d) { - #fmt["%u.%u.%u.%u", a as uint, b as uint, c as uint, d as uint] + ipv4(addr) { + unsafe { + let result = uv_ip4_name(&addr); + if result == "" { + fail "failed to convert inner sockaddr_in address to str" + } + result + } } ipv6(_, _, _, _, _, _, _, _) { fail "FIXME (#2651) impl parsing of ipv6 addr"; @@ -59,30 +70,19 @@ j Fails if the string is not a valid IPv4 address "] fn parse_addr(ip: str) -> ip_addr { alt try_parse_addr(ip) { - result::ok(addr) { addr } + // FIXME: more copies brought to light to due the implicit + // copy compiler warning.. what can be done? out pointers, + // ala c#? + result::ok(addr) { copy(addr) } result::err(err_data) { fail err_data.err_msg } } } fn try_parse_addr(ip: str) -> result::result { - let parts = vec::map(str::split_char(ip, '.'), {|s| - alt uint::from_str(s) { - some(n) if n <= 255u { n } - _ { 256u } - } - }); - if vec::len(parts) != 4u { - result::err({err_msg: #fmt("'%s' doesn't have 4 parts", - ip)}) - } - else if vec::contains(parts, 256u) { - result::err({err_msg: #fmt("invalid octal in provided addr '%s'", - ip)}) - } - else { - result::ok(ipv4(parts[0] as u8, parts[1] as u8, - parts[2] as u8, parts[3] as u8)) + unsafe { + // need to figure out how to establish a parse failure.. + result::ok(ipv4(uv_ip4_addr(ip, 22))) } } } @@ -90,14 +90,8 @@ j Fails if the string is not a valid IPv4 address #[cfg(test)] mod test { #[test] - fn test_format_ip() { - assert (format_addr(ipv4(127u8, 0u8, 0u8, 1u8)) + fn test_ipv4_parse_and_format_ip() { + assert (format_addr(v4::parse_addr("127.0.0.1")) == "127.0.0.1") } - - #[test] - fn test_parse_ip() { - assert (v4::parse_addr("127.0.0.1") == - ipv4(127u8, 0u8, 0u8, 1u8)); - } } \ No newline at end of file diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 6718e3729f74a..7c3349efae4bf 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -126,7 +126,7 @@ that can be used to send and receive data to/from the remote host. In the event of failure, a `net::tcp::tcp_connect_err_data` instance will be returned "] -fn connect(input_ip: ip::ip_addr, port: uint, +fn connect(-input_ip: ip::ip_addr, port: uint, iotask: iotask) -> result::result unsafe { let result_po = comm::port::(); @@ -551,7 +551,7 @@ a `result` instance containing empty data of type `()` on a successful/normal shutdown, and a `tcp_listen_err_data` enum in the event of listen exiting because of an error "] -fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, +fn listen(-host_ip: ip::ip_addr, port: uint, backlog: uint, iotask: iotask, on_establish_cb: fn~(comm::chan>), +new_connect_cb: fn~(tcp_new_connection, @@ -568,7 +568,7 @@ fn listen(host_ip: ip::ip_addr, port: uint, backlog: uint, } } -fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, +fn listen_common(-host_ip: ip::ip_addr, port: uint, backlog: uint, iotask: iotask, on_establish_cb: fn~(comm::chan>), -on_connect_cb: fn~(*uv::ll::uv_tcp_t)) @@ -589,8 +589,15 @@ fn listen_common(host_ip: ip::ip_addr, port: uint, backlog: uint, let server_data_ptr = ptr::addr_of(server_data); let setup_result = comm::listen {|setup_ch| + // FIXME this is to address a compiler warning about + // an implicit copy.. it seems that double nested + // will defeat a move sigil, as is done to the host_ip + // arg above.. this same pattern works w/o complaint in + // tcp::connect (because the iotask::interact cb isn't + // nested within a comm::listen block) + let loc_ip = copy(host_ip); iotask::interact(iotask) {|loop_ptr| - let tcp_addr = ipv4_ip_addr_to_sockaddr_in(host_ip, + let tcp_addr = ipv4_ip_addr_to_sockaddr_in(loc_ip, port); alt uv::ll::tcp_init(loop_ptr, server_stream_ptr) { 0i32 { @@ -1201,9 +1208,10 @@ type tcp_buffered_socket_data = { fn ipv4_ip_addr_to_sockaddr_in(input_ip: ip::ip_addr, port: uint) -> uv::ll::sockaddr_in unsafe { // FIXME (#2656): ipv6 + let addr_str = ip::format_addr(input_ip); alt input_ip { - ip::ipv4(_,_,_,_) { - uv::ll::ip4_addr(ip::format_addr(input_ip), port as int) + ip::ipv4(addr) { + uv::ll::ip4_addr(addr_str, port as int) } ip::ipv6(_,_,_,_,_,_,_,_) { fail "FIXME (#2656) ipv6 not yet supported"; diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 42dd5b93ea95b..fb8ba36acd34f 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -704,6 +704,24 @@ unsafe fn ip6_addr(ip: str, port: int) ret rustrt::rust_uv_ip6_addr(addr_vec_ptr, port as libc::c_int); } +unsafe fn ip4_name(src: &sockaddr_in) -> str { + // ipv4 addr max size: 15 + 1 trailing null byte + let dst: [u8] = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8]; + let size = 16 as libc::size_t; + vec::as_buf(dst) {|dst_buf| + let result = rustrt::rust_uv_ip4_name(src as *sockaddr_in, + dst_buf, size); + alt result { + 0i32 { + str::unsafe::from_buf(dst_buf) + } + _ { + "" + } + } + } +} unsafe fn timer_init(loop_ptr: *libc::c_void, timer_ptr: *uv_timer_t) -> libc::c_int { From 01ab1b1a6a1d1c5948cf13d4c80a9a1ed0deee15 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 17 Jun 2012 20:37:24 -0700 Subject: [PATCH 22/45] std: getting uv_ip6_* utils working in uv::ll .. stub out some brokeness in net::tcp as a result of ipv6 coming online --- src/libstd/net_tcp.rs | 4 +--- src/libstd/uv_ll.rs | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 7c3349efae4bf..12ef64bab3961 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -1213,9 +1213,7 @@ fn ipv4_ip_addr_to_sockaddr_in(input_ip: ip::ip_addr, ip::ipv4(addr) { uv::ll::ip4_addr(addr_str, port as int) } - ip::ipv6(_,_,_,_,_,_,_,_) { - fail "FIXME (#2656) ipv6 not yet supported"; - } + _ { fail "only works w/ ipv4";} } } diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index fb8ba36acd34f..7976bdf6479e4 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -710,7 +710,27 @@ unsafe fn ip4_name(src: &sockaddr_in) -> str { 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8]; let size = 16 as libc::size_t; vec::as_buf(dst) {|dst_buf| - let result = rustrt::rust_uv_ip4_name(src as *sockaddr_in, + rustrt::rust_uv_ip4_name(src as *sockaddr_in, + dst_buf, size); + // FIXME: seems that checking the result of uv_ip4_name + // doesn't work too well.. + // libuv will actually map a malformed input ip to INADDR_NONE, + // which is going to be 255.255.255.255 on most + // platforms. + str::unsafe::from_buf(dst_buf); + } +} +unsafe fn ip6_name(src: &sockaddr_in6) -> str { + // ipv6 addr max size: 45 + 1 trailing null byte + let dst: [u8] = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8]; + let size = 46 as libc::size_t; + vec::as_buf(dst) {|dst_buf| + let result = rustrt::rust_uv_ip6_name(src as *sockaddr_in6, dst_buf, size); alt result { 0i32 { From 37f58e9834b851fd9e149279e9c45cb2e901e46e Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sun, 17 Jun 2012 20:42:48 -0700 Subject: [PATCH 23/45] std: adding net::ip::v6 utils and rudimentary tests, huzzah! (see caveats) libuv's own ip vetting code appears to in a somewhat woeful state, for both ipv4 and ipv6 (there are some notes in the tests for net_ip, as well as stuff added in uv_ll). They are aware of this and welcome patches. I have rudimentary code in place that can verify whether the provided str ip was, in fact, validly parsed by libuv, making a few assumptions: * for ipv4, we assume that the platform's INADDR_NONE val is 0xffffffff , I should write a helper to return this value from the platform's libc headers instead of hard-coding it in rust. * for ipv6, we assume that the library will always return '::' for malformed inputs.. as is the case in 64bit ubuntu. I need to verify this on other platforms.. but at least the debugging output is in place, so if expectations don't line up, it'll be straightforward to address --- src/libstd/net_ip.rs | 115 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 8 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 106f1baa8c5b7..655742b2e2c75 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -9,6 +9,8 @@ import sockaddr_in = uv::ll::sockaddr_in; import sockaddr_in6 = uv::ll::sockaddr_in6; import uv_ip4_addr = uv::ll::ip4_addr; import uv_ip4_name = uv::ll::ip4_name; +import uv_ip6_addr = uv::ll::ip6_addr; +import uv_ip6_name = uv::ll::ip6_name; export ip_addr, parse_addr_err; export format_addr; @@ -18,7 +20,7 @@ export v4; enum ip_addr { #[doc="An IPv4 address"] ipv4(sockaddr_in), - ipv6(u16,u16,u16,u16,u16,u16,u16,u16) + ipv6(sockaddr_in6) } #[doc=" @@ -46,8 +48,14 @@ fn format_addr(ip: ip_addr) -> str { result } } - ipv6(_, _, _, _, _, _, _, _) { - fail "FIXME (#2651) impl parsing of ipv6 addr"; + ipv6(addr) { + unsafe { + let result = uv_ip6_name(&addr); + if result == "" { + fail "failed to convert inner sockaddr_in address to str" + } + result + } } } } @@ -58,7 +66,7 @@ mod v4 { # Failure -j Fails if the string is not a valid IPv4 address + Fails if the string is not a valid IPv4 address # Arguments @@ -82,16 +90,107 @@ j Fails if the string is not a valid IPv4 address fn try_parse_addr(ip: str) -> result::result { unsafe { // need to figure out how to establish a parse failure.. - result::ok(ipv4(uv_ip4_addr(ip, 22))) + let new_addr = uv_ip4_addr(ip, 22); + let reformatted_name = uv_ip4_name(&new_addr); + log(debug, #fmt("try_parse_addr: input ip: %s reparsed ip: %s", + ip, reformatted_name)); + // here we're going to + let inaddr_none_val = "255.255.255.255"; + if ip != inaddr_none_val && reformatted_name == inaddr_none_val { + result::err({err_msg:#fmt("failed to parse '%s'", + ip)}) + } + else { + result::ok(ipv4(new_addr)) + } } } } +mod v6 { + #[doc = " + Convert a str to `ip_addr` + + # Failure + + Fails if the string is not a valid IPv6 address -#[cfg(test)] + # Arguments + + * ip - an ipv6 string. See RFC2460 for spec. + + # Returns + + * an `ip_addr` of the `ipv6` variant + "] + fn parse_addr(ip: str) -> ip_addr { + alt try_parse_addr(ip) { + // FIXME: more copies brought to light to due the implicit + // copy compiler warning.. what can be done? out pointers, + // ala c#? + result::ok(addr) { copy(addr) } + result::err(err_data) { + fail err_data.err_msg + } + } + } + fn try_parse_addr(ip: str) -> result::result { + unsafe { + // need to figure out how to establish a parse failure.. + let new_addr = uv_ip6_addr(ip, 22); + let reparsed_name = uv_ip6_name(&new_addr); + log(debug, #fmt("v6::try_parse_addr ip: '%s' reparsed '%s'", + ip, reparsed_name)); + // '::' appears to be uv_ip6_name() returns for bogus + // parses.. + if ip != "::" && reparsed_name == "::" { + result::err({err_msg:#fmt("failed to parse '%s'", + ip)}) + } + else { + result::ok(ipv6(new_addr)) + } + } + } +} + +//#[cfg(test)] mod test { #[test] fn test_ipv4_parse_and_format_ip() { - assert (format_addr(v4::parse_addr("127.0.0.1")) - == "127.0.0.1") + let localhost_str = "127.0.0.1"; + assert (format_addr(v4::parse_addr(localhost_str)) + == localhost_str) + } + #[test] + fn test_ipv6_parse_and_format_ip() { + let localhost_str = "::1"; + let format_result = format_addr(v6::parse_addr(localhost_str)); + log(debug, #fmt("results: expected: '%s' actual: '%s'", + localhost_str, format_result)); + assert format_result == localhost_str; + } + #[test] + fn test_ipv4_bad_parse() { + alt v4::try_parse_addr("b4df00d") { + result::err(err_info) { + log(debug, #fmt("got error as expected %?", err_info)); + assert true; + } + result::ok(addr) { + fail #fmt("Expected failure, but got addr %?", addr); + } + } + } + #[test] + fn test_ipv6_bad_parse() { + alt v6::try_parse_addr("::,~2234k;") { + result::err(err_info) { + log(debug, #fmt("got error as expected %?", err_info)); + assert true; + } + result::ok(addr) { + fail #fmt("Expected failure, but got addr %?", addr); + } + } } } \ No newline at end of file From 88f9f045dcf077bc01d5e28fdeb96b654ddffafe Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 20 Jun 2012 07:01:43 -0700 Subject: [PATCH 24/45] rt: more sizeof helpers + misc consts for uv_getaddrinfo --- src/rt/rust_uv.cpp | 30 ++++++++++++++++++++++++++++++ src/rt/rustrt.def.in | 7 +++++++ 2 files changed, 37 insertions(+) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 7e719a5f45005..4d3de40f95e17 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -312,6 +312,30 @@ extern "C" size_t rust_uv_helper_uv_timer_t_size() { return sizeof(uv_timer_t); } +extern "C" size_t +rust_uv_helper_addr_in_size() { + return sizeof(sockaddr_in6); +} +extern "C" size_t +rust_uv_helper_uv_getaddrinfo_t_size() { + return sizeof(uv_getaddrinfo_t); +} +extern "C" size_t +rust_uv_helper_addrinfo_size() { + return sizeof(addrinfo); +} +extern "C" unsigned long int +rust_uv_helper_get_INADDR_NONE() { + return INADDR_NONE; +} +extern "C" unsigned long int +rust_uv_helper_get_AF_INET() { + return AF_INET; +} +extern "C" unsigned long int +rust_uv_helper_get_AF_INET6() { + return AF_INET6; +} extern "C" uv_stream_t* rust_uv_get_stream_handle_from_connect_req(uv_connect_t* connect) { @@ -480,3 +504,9 @@ extern "C" void rust_uv_current_kernel_free(void* mem) { current_kernel_free(mem); } + +extern "C" int +rust_uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* handle, uv_getaddrinfo_cb cb, + const char* node, const char* service, const struct addrinfo* hints) { + return uv_getaddrinfo(loop, handle, cb, node, service, hints); +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index b8086531ac7d5..523de3e88ca4d 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -130,6 +130,12 @@ rust_uv_helper_uv_write_t_size rust_uv_helper_uv_err_t_size rust_uv_helper_sockaddr_in_size rust_uv_helper_sockaddr_in6_size +rust_uv_helper_addr_in_size +rust_uv_helper_addrinfo_size +rust_uv_helper_uv_getaddrinfo_t_size +rust_uv_helper_get_INADDR_NONE +rust_uv_helper_get_AF_INET +rust_uv_helper_get_AF_INET6 rust_uv_helper_uv_async_t_size rust_uv_helper_uv_timer_t_size rust_uv_get_stream_handle_from_connect_req @@ -146,6 +152,7 @@ rust_uv_get_len_from_buf rust_uv_get_kernel_global_chan_ptr rust_uv_current_kernel_malloc rust_uv_current_kernel_free +rust_uv_getaddr_info rust_dbg_lock_create rust_dbg_lock_destroy rust_dbg_lock_lock From 75a1295c659efe87b0c05ea5d6f25015388d365e Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 20 Jun 2012 07:02:16 -0700 Subject: [PATCH 25/45] std: mapped addrinfo, addr_in and uv_getaddrinfo_t as rust records --- src/libstd/uv_ll.rs | 80 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 7976bdf6479e4..1050d587336cf 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -229,6 +229,25 @@ type sockaddr_in6 = { a2: *u8, a3: *u8 }; +// unix size: 28 +// unix size: 28 .. FIXME: stuck with 32 becuse of rust padding structs? +type addr_in = { + a0: *u8, a1: *u8, + a2: *u8, a3: *u8 +}; + +// unix size: 48 +type addrinfo = { + a00: *u8, a01: *u8, a02: *u8, a03: *u8, + a04: *u8, a05: *u8 +}; + +// unix size: 72 +type uv_getaddrinfo_t = { + a00: *u8, a01: *u8, a02: *u8, a03: *u8, a04: *u8, a05: *u8, + a06: *u8, a07: *u8, a08: *u8 +}; + mod uv_ll_struct_stubgen { fn gen_stub_uv_tcp_t() -> uv_tcp_t { ret gen_stub_os(); @@ -474,10 +493,18 @@ mod uv_ll_struct_stubgen { a12: 0 as *u8 }; } + fn gen_stub_uv_getaddrinfo_t() -> uv_getaddrinfo_t { + { + a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, a03: 0 as *u8, + a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, a07: 0 as *u8, + a08: 0 as *u8 + } + } } #[nolink] native mod rustrt { + // libuv public API fn rust_uv_loop_new() -> *libc::c_void; fn rust_uv_loop_delete(lp: *libc::c_void); fn rust_uv_loop_refcount(loop_ptr: *libc::c_void) -> libc::c_int; @@ -533,6 +560,14 @@ native mod rustrt { repeat: libc::c_uint) -> libc::c_int; fn rust_uv_timer_stop(handle: *uv_timer_t) -> libc::c_int; + fn rust_uv_getaddrinfo(loop_ptr: *libc::c_void, + handle: *uv_getaddrinfo_t, cb: *u8, + node_name_ptr: *u8, + service_name_ptr: *u8, + // should probably only pass ptr::null() + hints: *addrinfo) + -> libc::c_int; + // data accessors/helpers for rust-mapped uv structs fn rust_uv_malloc_buf_base_of(sug_size: libc::size_t) -> *u8; fn rust_uv_free_base_of_buf(++buf: uv_buf_t); @@ -567,6 +602,9 @@ native mod rustrt { fn rust_uv_helper_sockaddr_in6_size() -> libc::c_uint; fn rust_uv_helper_uv_async_t_size() -> libc::c_uint; fn rust_uv_helper_uv_timer_t_size() -> libc::c_uint; + fn rust_uv_helper_uv_getaddrinfo_t_size() -> libc::c_uint; + fn rust_uv_helper_addrinfo_size() -> libc::c_uint; + fn rust_uv_helper_addr_in_size() -> libc::c_uint; } unsafe fn loop_new() -> *libc::c_void { @@ -717,7 +755,7 @@ unsafe fn ip4_name(src: &sockaddr_in) -> str { // libuv will actually map a malformed input ip to INADDR_NONE, // which is going to be 255.255.255.255 on most // platforms. - str::unsafe::from_buf(dst_buf); + str::unsafe::from_buf(dst_buf) } } unsafe fn ip6_name(src: &sockaddr_in6) -> str { @@ -772,6 +810,9 @@ unsafe fn async_t() -> uv_async_t { unsafe fn timer_t() -> uv_timer_t { ret uv_ll_struct_stubgen::gen_stub_uv_timer_t(); } +unsafe fn getaddrinfo_t() -> uv_getaddrinfo_t { + ret uv_ll_struct_stubgen::gen_stub_uv_getaddrinfo_t(); +} // data access helpers unsafe fn get_loop_for_uv_handle(handle: *T) @@ -1431,12 +1472,24 @@ mod test { let output = #fmt("sockaddr_in -- native: %u rust: %u", native_handle_size as uint, rust_handle_size); log(debug, output); - // FIXME .. rust appears to pack structs to the nearest byte..? + // FIXME .. rust appears to pad structs to the nearest byte..? // .. can't get the uv::ll::sockaddr_in6 to == 28 :/ // .. so the type always appears to be 32 in size.. which is // good, i guess.. better too big than too little assert (4u+native_handle_size as uint) == rust_handle_size; } + #[test] + #[ignore(cfg(target_os = "freebsd"))] + fn test_uv_ll_struct_size_addr_in() { + let native_handle_size = + rustrt::rust_uv_helper_addr_in_size(); + let rust_handle_size = sys::size_of::(); + let output = #fmt("addr_in -- native: %u rust: %u", + native_handle_size as uint, rust_handle_size); + log(debug, output); + // FIXME .. see note above about struct padding + assert (4u+native_handle_size as uint) == rust_handle_size; + } #[test] #[ignore(cfg(target_os = "freebsd"))] @@ -1461,4 +1514,27 @@ mod test { log(debug, output); assert foreign_handle_size as uint == rust_handle_size; } + + #[test] + #[ignore(cfg(target_os = "freebsd"))] + fn test_uv_ll_struct_size_uv_getaddrinfo_t() { + let native_handle_size = + rustrt::rust_uv_helper_uv_getaddrinfo_t_size(); + let rust_handle_size = sys::size_of::(); + let output = #fmt("uv_getaddrinfo_t -- native: %u rust: %u", + native_handle_size as uint, rust_handle_size); + log(debug, output); + assert native_handle_size as uint == rust_handle_size; + } + #[test] + #[ignore(cfg(target_os = "freebsd"))] + fn test_uv_ll_struct_size_addrinfo() { + let native_handle_size = + rustrt::rust_uv_helper_addrinfo_size(); + let rust_handle_size = sys::size_of::(); + let output = #fmt("addrinfo -- native: %u rust: %u", + native_handle_size as uint, rust_handle_size); + log(debug, output); + assert native_handle_size as uint == rust_handle_size; + } } From 475361e8f3702448f91fc9bb422bc9a1769fac95 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 22 Jun 2012 13:55:54 -0700 Subject: [PATCH 26/45] rt: more helper functions to get uv_getaddrinfo going --- src/rt/rust_uv.cpp | 17 +++++++++++++++++ src/rt/rustrt.def.in | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 4d3de40f95e17..4b9fe5e0047f3 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -510,3 +510,20 @@ rust_uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* handle, uv_getaddrinfo_cb const char* node, const char* service, const struct addrinfo* hints) { return uv_getaddrinfo(loop, handle, cb, node, service, hints); } +extern "C" bool +rust_uv_is_ipv4_addrinfo(addrinfo* input) { + // if it aint AF_INET, it's AF_INET6 + return input->ai_family == AF_INET; +} +extern "C" addrinfo* +rust_uv_get_next_addrinfo(addrinfo* input) { + return input->ai_next; +} +extern "C" sockaddr_in* +rust_uv_addrinfo_as_sockaddr_in(addrinfo* input) { + return (sockaddr_in*)input->ai_addr; +} +extern "C" sockaddr_in6* +rust_uv_addrinfo_as_sockaddr_in6(addrinfo* input) { + return (sockaddr_in6*)input->ai_addr; +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 523de3e88ca4d..b7102045114dc 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -123,6 +123,10 @@ rust_uv_read_start rust_uv_read_stop rust_uv_malloc_buf_base_of rust_uv_free_base_of_buf +rust_uv_is_ipv4_addrinfo +rust_uv_get_next_addrinfo +rust_uv_addrinfo_as_sockaddr_in +rust_uv_addrinfo_as_sockaddr_in6 rust_uv_helper_uv_tcp_t_size rust_uv_helper_uv_connect_t_size rust_uv_helper_uv_buf_t_size From e3d7764e7cb2262ffa597558881db87cea449376 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 22 Jun 2012 14:00:16 -0700 Subject: [PATCH 27/45] std: wire-up low-level bindings to libuv's uv_getaddrinfo API and friends --- src/libstd/uv_ll.rs | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 1050d587336cf..e645050828ba8 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -561,14 +561,18 @@ native mod rustrt { fn rust_uv_timer_stop(handle: *uv_timer_t) -> libc::c_int; fn rust_uv_getaddrinfo(loop_ptr: *libc::c_void, - handle: *uv_getaddrinfo_t, cb: *u8, + handle: *uv_getaddrinfo_t, + cb: *u8, node_name_ptr: *u8, service_name_ptr: *u8, // should probably only pass ptr::null() - hints: *addrinfo) - -> libc::c_int; + hints: *addrinfo) -> libc::c_int; // data accessors/helpers for rust-mapped uv structs + fn rust_uv_is_ipv4_addrinfo(input: *addrinfo) -> bool; + fn rust_uv_get_next_addrinfo(input: *addrinfo) -> *addrinfo; + fn rust_uv_addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in; + fn rust_uv_addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6; fn rust_uv_malloc_buf_base_of(sug_size: libc::size_t) -> *u8; fn rust_uv_free_base_of_buf(++buf: uv_buf_t); fn rust_uv_get_stream_handle_from_connect_req( @@ -793,6 +797,19 @@ unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint, unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> libc::c_int { ret rustrt::rust_uv_timer_stop(timer_ptr); } +unsafe fn getaddrinfo(loop_ptr: *libc::c_void, + handle: *uv_getaddrinfo_t, + cb: *u8, + node_name_ptr: *u8, + service_name_ptr: *u8, + hints: *addrinfo) -> libc::c_int { + rustrt::rust_uv_getaddrinfo(loop_ptr, + handle, + cb, + node_name_ptr, + service_name_ptr, + hints) +} // libuv struct initializers unsafe fn tcp_t() -> uv_tcp_t { @@ -888,6 +905,19 @@ type uv_err_data = { err_msg: str }; +unsafe fn is_ipv4_addrinfo(input: *addrinfo) -> bool { + rustrt::rust_uv_is_ipv4_addrinfo(input) +} +unsafe fn get_next_addrinfo(input: *addrinfo) -> *addrinfo { + rustrt::rust_uv_get_next_addrinfo(input) +} +unsafe fn addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in { + rustrt::rust_uv_addrinfo_as_sockaddr_in(input) +} +unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 { + rustrt::rust_uv_addrinfo_as_sockaddr_in6(input) +} + #[cfg(test)] mod test { enum tcp_read_data { From d3baed6de2dc933a53d93bd604cdf31080a148c8 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 22 Jun 2012 15:31:56 -0700 Subject: [PATCH 28/45] std: roughcut impl of net::ip::get_addr() still needs tests --- src/libstd/net_ip.rs | 99 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 655742b2e2c75..d0eda904e836a 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -4,17 +4,28 @@ Types/fns concerning Internet Protocol (IP), versions 4 & 6 import vec; import uint; +import iotask = uv::iotask::iotask; +import interact = uv::iotask::interact; +import comm::methods; import sockaddr_in = uv::ll::sockaddr_in; import sockaddr_in6 = uv::ll::sockaddr_in6; +import addrinfo = uv::ll::addrinfo; +import uv_getaddrinfo_t = uv::ll::uv_getaddrinfo_t; import uv_ip4_addr = uv::ll::ip4_addr; import uv_ip4_name = uv::ll::ip4_name; import uv_ip6_addr = uv::ll::ip6_addr; import uv_ip6_name = uv::ll::ip6_name; +import uv_getaddrinfo = uv::ll::getaddrinfo; +import create_uv_getaddrinfo_t = uv::ll::getaddrinfo_t; +import set_data_for_uv_handle = uv::ll::set_data_for_uv_handle; +import get_data_for_uv_handle = uv::ll::get_data_for_uv_handle; +import ll = uv::ll; export ip_addr, parse_addr_err; export format_addr; -export v4; +export v4, v6; +export get_addr; #[doc = "An IP address"] enum ip_addr { @@ -60,6 +71,92 @@ fn format_addr(ip: ip_addr) -> str { } } +type get_addr_data = { + output_ch: comm::chan> +}; + +crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, + res: *addrinfo) unsafe { + let handle_data = get_data_for_uv_handle(handle) as + *get_addr_data; + if status == 0i32 { + if res != (ptr::null::()) { + let mut out_vec = []; + let mut curr_addr = res; + loop { + if ll::is_ipv4_addrinfo(curr_addr) { + out_vec += + [ipv4(copy(( + *ll::addrinfo_as_sockaddr_in(curr_addr))))]; + } + else { + out_vec += + [ipv6(copy(( + *ll::addrinfo_as_sockaddr_in6(curr_addr))))]; + } + + let next_addr = ll::get_next_addrinfo(curr_addr); + if next_addr == ptr::null::() as *addrinfo { + break; + } + else { + curr_addr = next_addr + } + } + (*handle_data).output_ch.send(result::ok(out_vec)); + } + else { + (*handle_data).output_ch.send( + result::err(get_addr_unknown_error)); + } + } + else { + (*handle_data).output_ch.send( + result::err(get_addr_unknown_error)); + } +} + +#[doc=" +"] +enum ip_get_addr_err { + get_addr_unknown_error +} + +#[doc=" +"] +fn get_addr(++node: str, iotask: iotask) + -> result::result<[ip_addr], ip_get_addr_err> unsafe { + comm::listen {|output_ch| + str::unpack_slice(node) {|node_ptr, len| + log(debug, #fmt("sliace len %?", len)); + let handle = create_uv_getaddrinfo_t(); + let handle_ptr = ptr::addr_of(handle); + let handle_data: get_addr_data = { + output_ch: output_ch + }; + let handle_data_ptr = ptr::addr_of(handle_data); + interact(iotask) {|loop_ptr| + let result = uv_getaddrinfo( + loop_ptr, + handle_ptr, + get_addr_cb, + node_ptr, + ptr::null(), + ptr::null()); + alt result { + 0i32 { + set_data_for_uv_handle(handle_ptr, handle_data_ptr); + } + _ { + output_ch.send(result::err(get_addr_unknown_error)); + } + } + }; + output_ch.recv() + } + } +} + mod v4 { #[doc = " Convert a str to `ip_addr` From de31f78073ec15d78861b1c61f0d8a7981f3dc7f Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 22 Jun 2012 15:45:09 -0700 Subject: [PATCH 29/45] fix typo in rustrt.def.in --- src/rt/rustrt.def.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index b7102045114dc..2cdcddb647f86 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -156,7 +156,7 @@ rust_uv_get_len_from_buf rust_uv_get_kernel_global_chan_ptr rust_uv_current_kernel_malloc rust_uv_current_kernel_free -rust_uv_getaddr_info +rust_uv_getaddrinfo rust_dbg_lock_create rust_dbg_lock_destroy rust_dbg_lock_lock From 28490716d837af8c8db905f1dd37d3cf083247da Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 22 Jun 2012 21:33:11 -0700 Subject: [PATCH 30/45] WIP set aside unshift --- src/libstd/net_tcp.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 12ef64bab3961..f1436e7c83e1a 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -771,7 +771,9 @@ impl tcp_socket_buf of io::reader for @tcp_socket_buf { self.read_bytes(1u)[0] as int } fn unread_byte(amt: int) { - vec::unshift((*self).buf, amt as u8); + // FIXME: stubbing this out pending the + // return of vec::unshift + //vec::unshift((*self).buf, amt as u8); } fn eof() -> bool { false // noop From aeeb8b4ebfe477512f7d5f45ab4bbec855f03a0c Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 25 Jun 2012 08:01:19 -0700 Subject: [PATCH 31/45] rt: adding uv_freeaddrinfo binding and tweek signature for uv_getaddrinfo --- src/rt/rust_uv.cpp | 10 ++++++++-- src/rt/rustrt.def.in | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 4b9fe5e0047f3..a461e7d8c1c91 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -506,10 +506,16 @@ rust_uv_current_kernel_free(void* mem) { } extern "C" int -rust_uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* handle, uv_getaddrinfo_cb cb, - const char* node, const char* service, const struct addrinfo* hints) { +rust_uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* handle, + uv_getaddrinfo_cb cb, + char* node, char* service, + addrinfo* hints) { return uv_getaddrinfo(loop, handle, cb, node, service, hints); } +extern "C" void +rust_uv_freeaddrinfo(addrinfo* res) { + uv_freeaddrinfo(res); +} extern "C" bool rust_uv_is_ipv4_addrinfo(addrinfo* input) { // if it aint AF_INET, it's AF_INET6 diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 2cdcddb647f86..c454f4d496ad9 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -157,6 +157,7 @@ rust_uv_get_kernel_global_chan_ptr rust_uv_current_kernel_malloc rust_uv_current_kernel_free rust_uv_getaddrinfo +rust_uv_freeaddrinfo rust_dbg_lock_create rust_dbg_lock_destroy rust_dbg_lock_lock From 21ee11af57201f91d682b19308aa50cb533ae347 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 25 Jun 2012 08:02:34 -0700 Subject: [PATCH 32/45] std: net::ip::get_addr is working w/ happy path test. needs more. --- src/libstd/net_ip.rs | 85 ++++++++++++++++++++++++++++++++----------- src/libstd/net_tcp.rs | 16 ++++---- src/libstd/uv_ll.rs | 8 +++- 3 files changed, 77 insertions(+), 32 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index d0eda904e836a..9f19a3dcba8c1 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -17,9 +17,10 @@ import uv_ip4_name = uv::ll::ip4_name; import uv_ip6_addr = uv::ll::ip6_addr; import uv_ip6_name = uv::ll::ip6_name; import uv_getaddrinfo = uv::ll::getaddrinfo; +import uv_freeaddrinfo = uv::ll::freeaddrinfo; import create_uv_getaddrinfo_t = uv::ll::getaddrinfo_t; -import set_data_for_uv_handle = uv::ll::set_data_for_uv_handle; -import get_data_for_uv_handle = uv::ll::get_data_for_uv_handle; +import set_data_for_req = uv::ll::set_data_for_req; +import get_data_for_req = uv::ll::get_data_for_req; import ll = uv::ll; export ip_addr, parse_addr_err; @@ -77,43 +78,65 @@ type get_addr_data = { crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, res: *addrinfo) unsafe { - let handle_data = get_data_for_uv_handle(handle) as + log(debug, "in get_addr_cb"); + let handle_data = get_data_for_req(handle) as *get_addr_data; if status == 0i32 { if res != (ptr::null::()) { let mut out_vec = []; + let mut addr_strings = []; + log(debug, #fmt("initial addrinfo: %?", res)); let mut curr_addr = res; loop { - if ll::is_ipv4_addrinfo(curr_addr) { - out_vec += - [ipv4(copy(( - *ll::addrinfo_as_sockaddr_in(curr_addr))))]; + let new_ip_addr = if ll::is_ipv4_addrinfo(curr_addr) { + ipv4(copy(( + *ll::addrinfo_as_sockaddr_in(curr_addr)))) } else { - out_vec += - [ipv6(copy(( - *ll::addrinfo_as_sockaddr_in6(curr_addr))))]; + ipv6(copy(( + *ll::addrinfo_as_sockaddr_in6(curr_addr)))) + }; + // we're doing this check to avoid adding multiple + // ip_addrs to the out_vec that are duplicates.. on + // 64bit unbuntu a call to uv_getaddrinfo against + // localhost seems to return three addrinfos, all + // distinct (by ptr addr), that are all ipv4 + // addresses and all point to 127.0.0.1 + let addr_str = format_addr(new_ip_addr); + if !vec::contains(addr_strings, addr_str) { + addr_strings += [addr_str]; + out_vec += [new_ip_addr]; } let next_addr = ll::get_next_addrinfo(curr_addr); if next_addr == ptr::null::() as *addrinfo { + log(debug, "null next_addr encountered. no mas"); break; } else { - curr_addr = next_addr + curr_addr = next_addr; + log(debug, #fmt("next_addr addrinfo: %?", curr_addr)); } } + log(debug, #fmt("successful process addrinfo result, len: %?", + vec::len(out_vec))); (*handle_data).output_ch.send(result::ok(out_vec)); } else { + log(debug, "addrinfo pointer is NULL"); (*handle_data).output_ch.send( result::err(get_addr_unknown_error)); } } else { + log(debug, "status != 0 error in get_addr_cb"); (*handle_data).output_ch.send( result::err(get_addr_unknown_error)); } + if res != (ptr::null::()) { + uv_freeaddrinfo(res); + } + log(debug, "leaving get_addr_cb"); } #[doc=" @@ -128,7 +151,7 @@ fn get_addr(++node: str, iotask: iotask) -> result::result<[ip_addr], ip_get_addr_err> unsafe { comm::listen {|output_ch| str::unpack_slice(node) {|node_ptr, len| - log(debug, #fmt("sliace len %?", len)); + log(debug, #fmt("slice len %?", len)); let handle = create_uv_getaddrinfo_t(); let handle_ptr = ptr::addr_of(handle); let handle_data: get_addr_data = { @@ -145,7 +168,7 @@ fn get_addr(++node: str, iotask: iotask) ptr::null()); alt result { 0i32 { - set_data_for_uv_handle(handle_ptr, handle_data_ptr); + set_data_for_req(handle_ptr, handle_data_ptr); } _ { output_ch.send(result::err(get_addr_unknown_error)); @@ -175,9 +198,6 @@ mod v4 { "] fn parse_addr(ip: str) -> ip_addr { alt try_parse_addr(ip) { - // FIXME: more copies brought to light to due the implicit - // copy compiler warning.. what can be done? out pointers, - // ala c#? result::ok(addr) { copy(addr) } result::err(err_data) { fail err_data.err_msg @@ -198,7 +218,7 @@ mod v4 { ip)}) } else { - result::ok(ipv4(new_addr)) + result::ok(ipv4(copy(new_addr))) } } } @@ -221,9 +241,6 @@ mod v6 { "] fn parse_addr(ip: str) -> ip_addr { alt try_parse_addr(ip) { - // FIXME: more copies brought to light to due the implicit - // copy compiler warning.. what can be done? out pointers, - // ala c#? result::ok(addr) { copy(addr) } result::err(err_data) { fail err_data.err_msg @@ -250,7 +267,7 @@ mod v6 { } } -//#[cfg(test)] +#[cfg(test)] mod test { #[test] fn test_ipv4_parse_and_format_ip() { @@ -290,4 +307,30 @@ mod test { } } } + #[test] + fn test_get_addr() { + let localhost_name = "localhost"; + let iotask = uv::global_loop::get(); + let ga_result = get_addr(localhost_name, iotask); + if result::is_err(ga_result) { + fail "got err result from net::ip::get_addr();" + } + // note really sure how to realiably test/assert + // this.. mostly just wanting to see it work, atm. + let results = result::unwrap(ga_result); + log(debug, #fmt("test_get_addr: Number of results for %s: %?", + localhost_name, vec::len(results))); + for vec::each(results) {|r| + let ipv_prefix = alt r { + ipv4(_) { + "IPv4" + } + ipv6(_) { + "IPv6" + } + }; + log(debug, #fmt("test_get_addr: result %s: '%s'", + ipv_prefix, format_addr(r))); + } + } } \ No newline at end of file diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index f1436e7c83e1a..d4fd650933907 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -418,7 +418,7 @@ net::tcp::listen(remote_ip, remote_port, backlog) let cont_ch = comm::chan(cont_po); task::spawn {|| let accept_result = net::tcp::accept(new_conn); - if accept_result.is_failure() { + if accept_result.is_err() { comm::send(cont_ch, result::get_err(accept_result)); // fail? } @@ -754,7 +754,7 @@ impl tcp_socket_buf of io::reader for @tcp_socket_buf { } else { let read_result = read((*self).sock, 0u); - if read_result.is_failure() { + if read_result.is_err() { let err_data = read_result.get_err(); log(debug, #fmt("ERROR sock_buf as io::reader.read err %? %?", err_data.err_name, err_data.err_msg)); @@ -771,9 +771,7 @@ impl tcp_socket_buf of io::reader for @tcp_socket_buf { self.read_bytes(1u)[0] as int } fn unread_byte(amt: int) { - // FIXME: stubbing this out pending the - // return of vec::unshift - //vec::unshift((*self).buf, amt as u8); + vec::unshift((*self).buf, amt as u8); } fn eof() -> bool { false // noop @@ -798,7 +796,7 @@ impl tcp_socket_buf of io::writer for @tcp_socket_buf { }; let write_buf_vec_ptr = ptr::addr_of(write_buf_vec); let w_result = write_common_impl(socket_data_ptr, write_buf_vec_ptr); - if w_result.is_failure() { + if w_result.is_err() { let err_data = w_result.get_err(); log(debug, #fmt("ERROR sock_buf as io::writer.writer err: %? %?", err_data.err_name, err_data.err_msg)); @@ -1321,7 +1319,7 @@ mod test { client_ch, hl_loop) }; - assert actual_resp_result.is_success(); + assert actual_resp_result.is_ok(); let actual_resp = actual_resp_result.get(); let actual_req = comm::recv(server_result_po); log(debug, #fmt("REQ: expected: '%s' actual: '%s'", @@ -1453,7 +1451,7 @@ mod test { // client let server_addr = ip::v4::parse_addr(server_ip); let conn_result = connect(server_addr, server_port, iotask); - if result::is_failure(conn_result) { + if result::is_err(conn_result) { assert false; } let sock_buf = @socket_buf(result::unwrap(conn_result)); @@ -1589,7 +1587,7 @@ mod test { new_conn, kill_ch); }); // err check on listen_result - if result::is_failure(listen_result) { + if result::is_err(listen_result) { result::get_err(listen_result) } else { diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index e645050828ba8..09f8c61d45d48 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -567,6 +567,7 @@ native mod rustrt { service_name_ptr: *u8, // should probably only pass ptr::null() hints: *addrinfo) -> libc::c_int; + fn rust_uv_freeaddrinfo(res: *addrinfo); // data accessors/helpers for rust-mapped uv structs fn rust_uv_is_ipv4_addrinfo(input: *addrinfo) -> bool; @@ -755,7 +756,7 @@ unsafe fn ip4_name(src: &sockaddr_in) -> str { rustrt::rust_uv_ip4_name(src as *sockaddr_in, dst_buf, size); // FIXME: seems that checking the result of uv_ip4_name - // doesn't work too well.. + // doesn't work too well.. // libuv will actually map a malformed input ip to INADDR_NONE, // which is going to be 255.255.255.255 on most // platforms. @@ -810,6 +811,9 @@ unsafe fn getaddrinfo(loop_ptr: *libc::c_void, service_name_ptr, hints) } +unsafe fn freeaddrinfo(res: *addrinfo) { + rustrt::rust_uv_freeaddrinfo(res); +} // libuv struct initializers unsafe fn tcp_t() -> uv_tcp_t { @@ -1544,7 +1548,7 @@ mod test { log(debug, output); assert foreign_handle_size as uint == rust_handle_size; } - + #[test] #[ignore(cfg(target_os = "freebsd"))] fn test_uv_ll_struct_size_uv_getaddrinfo_t() { From 5c322948022d9ff026aeb05c1f32185ebcfa779b Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 06:41:18 -0700 Subject: [PATCH 33/45] rt: whitespace cleanup in rust_uv --- src/rt/rust_uv.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index a461e7d8c1c91..e47b3585b9cf9 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -326,15 +326,15 @@ rust_uv_helper_addrinfo_size() { } extern "C" unsigned long int rust_uv_helper_get_INADDR_NONE() { - return INADDR_NONE; + return INADDR_NONE; } extern "C" unsigned long int rust_uv_helper_get_AF_INET() { - return AF_INET; + return AF_INET; } extern "C" unsigned long int rust_uv_helper_get_AF_INET6() { - return AF_INET6; + return AF_INET6; } extern "C" uv_stream_t* @@ -479,11 +479,11 @@ rust_uv_ip6_addr(const char* ip, int port) { } extern "C" int rust_uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { - return uv_ip4_name(src, dst, size); + return uv_ip4_name(src, dst, size); } extern "C" int rust_uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { - return uv_ip6_name(src, dst, size); + return uv_ip6_name(src, dst, size); } extern "C" uintptr_t* @@ -507,29 +507,29 @@ rust_uv_current_kernel_free(void* mem) { extern "C" int rust_uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_getaddrinfo_cb cb, - char* node, char* service, - addrinfo* hints) { - return uv_getaddrinfo(loop, handle, cb, node, service, hints); + uv_getaddrinfo_cb cb, + char* node, char* service, + addrinfo* hints) { + return uv_getaddrinfo(loop, handle, cb, node, service, hints); } extern "C" void rust_uv_freeaddrinfo(addrinfo* res) { - uv_freeaddrinfo(res); + uv_freeaddrinfo(res); } extern "C" bool rust_uv_is_ipv4_addrinfo(addrinfo* input) { - // if it aint AF_INET, it's AF_INET6 - return input->ai_family == AF_INET; + // if it aint AF_INET, it's AF_INET6 + return input->ai_family == AF_INET; } extern "C" addrinfo* rust_uv_get_next_addrinfo(addrinfo* input) { - return input->ai_next; + return input->ai_next; } extern "C" sockaddr_in* rust_uv_addrinfo_as_sockaddr_in(addrinfo* input) { - return (sockaddr_in*)input->ai_addr; + return (sockaddr_in*)input->ai_addr; } extern "C" sockaddr_in6* rust_uv_addrinfo_as_sockaddr_in6(addrinfo* input) { - return (sockaddr_in6*)input->ai_addr; + return (sockaddr_in6*)input->ai_addr; } From cb15e788c866294cd1fa57df128df3d00318538d Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 06:53:32 -0700 Subject: [PATCH 34/45] std: whitespace/comment clean --- src/libstd/net_ip.rs | 12 ------------ src/libstd/net_tcp.rs | 11 +++-------- src/libstd/uv_ll.rs | 20 +++++++++++--------- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 9f19a3dcba8c1..0e13a2c590c40 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -84,7 +84,6 @@ crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, if status == 0i32 { if res != (ptr::null::()) { let mut out_vec = []; - let mut addr_strings = []; log(debug, #fmt("initial addrinfo: %?", res)); let mut curr_addr = res; loop { @@ -96,17 +95,6 @@ crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, ipv6(copy(( *ll::addrinfo_as_sockaddr_in6(curr_addr)))) }; - // we're doing this check to avoid adding multiple - // ip_addrs to the out_vec that are duplicates.. on - // 64bit unbuntu a call to uv_getaddrinfo against - // localhost seems to return three addrinfos, all - // distinct (by ptr addr), that are all ipv4 - // addresses and all point to 127.0.0.1 - let addr_str = format_addr(new_ip_addr); - if !vec::contains(addr_strings, addr_str) { - addr_strings += [addr_str]; - out_vec += [new_ip_addr]; - } let next_addr = ll::get_next_addrinfo(curr_addr); if next_addr == ptr::null::() as *addrinfo { diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index d4fd650933907..da8c55c3d9580 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -7,7 +7,8 @@ import uv::iotask; import uv::iotask::iotask; import comm::methods; import future_spawn = future::spawn; -// FIXME: should be able to replace w/ result::{result, extensions}; +// FIXME #1935 +// should be able to, but can't atm, replace w/ result::{result, extensions}; import result::*; import libc::size_t; import str::extensions; @@ -589,7 +590,7 @@ fn listen_common(-host_ip: ip::ip_addr, port: uint, backlog: uint, let server_data_ptr = ptr::addr_of(server_data); let setup_result = comm::listen {|setup_ch| - // FIXME this is to address a compiler warning about + // this is to address a compiler warning about // an implicit copy.. it seems that double nested // will defeat a move sigil, as is done to the host_ip // arg above.. this same pattern works w/o complaint in @@ -1239,9 +1240,6 @@ mod test { impl_gl_tcp_ipv4_server_address_in_use(); } #[test] - // FIXME: this probably needs to be ignored on windows. - // ... need to verify (someday we'll have 64bit windows! :) - //#[ignore(cfg(target_os = "win32"))] fn test_gl_tcp_server_access_denied() unsafe { impl_gl_tcp_ipv4_server_access_denied(); } @@ -1270,9 +1268,6 @@ mod test { } #[test] #[ignore(cfg(target_os = "linux"))] - // FIXME: this probably needs to be ignored on windows. - // ... need to verify - //#[ignore(cfg(target_os = "win32"))] fn test_gl_tcp_server_access_denied() unsafe { impl_gl_tcp_ipv4_server_access_denied(); } diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 09f8c61d45d48..35fa5d4e57ee2 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -223,14 +223,15 @@ type sockaddr_in = { mut sin_zero: (u8, u8, u8, u8, u8, u8, u8, u8) }; -// unix size: 28 .. FIXME: stuck with 32 becuse of rust padding structs? +// unix size: 28 .. FIXME #1645 +// stuck with 32 becuse of rust padding structs? type sockaddr_in6 = { a0: *u8, a1: *u8, a2: *u8, a3: *u8 }; -// unix size: 28 -// unix size: 28 .. FIXME: stuck with 32 becuse of rust padding structs? +// unix size: 28 .. FIXME #1645 +// stuck with 32 becuse of rust padding structs? type addr_in = { a0: *u8, a1: *u8, a2: *u8, a3: *u8 @@ -755,11 +756,12 @@ unsafe fn ip4_name(src: &sockaddr_in) -> str { vec::as_buf(dst) {|dst_buf| rustrt::rust_uv_ip4_name(src as *sockaddr_in, dst_buf, size); - // FIXME: seems that checking the result of uv_ip4_name + // seems that checking the result of uv_ip4_name // doesn't work too well.. - // libuv will actually map a malformed input ip to INADDR_NONE, - // which is going to be 255.255.255.255 on most - // platforms. + // you're stuck looking at the value of dst_buf + // to see if it is the string representation of + // INADDR_NONE (0xffffffff or 255.255.255.255 on + // many platforms) str::unsafe::from_buf(dst_buf) } } @@ -1506,7 +1508,7 @@ mod test { let output = #fmt("sockaddr_in -- native: %u rust: %u", native_handle_size as uint, rust_handle_size); log(debug, output); - // FIXME .. rust appears to pad structs to the nearest byte..? + // FIXME #1645 .. rust appears to pad structs to the nearest byte..? // .. can't get the uv::ll::sockaddr_in6 to == 28 :/ // .. so the type always appears to be 32 in size.. which is // good, i guess.. better too big than too little @@ -1521,7 +1523,7 @@ mod test { let output = #fmt("addr_in -- native: %u rust: %u", native_handle_size as uint, rust_handle_size); log(debug, output); - // FIXME .. see note above about struct padding + // FIXME #1645 .. see note above about struct padding assert (4u+native_handle_size as uint) == rust_handle_size; } From cdf8fd07576f35fa3271d873e902ffec4dee3961 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 09:05:02 -0700 Subject: [PATCH 35/45] rt: get rid of unused helpers for AF_INET and add bool-based ones, instead --- src/rt/rust_uv.cpp | 15 +++++---------- src/rt/rustrt.def.in | 3 +-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index e47b3585b9cf9..f681c6bdd9966 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -324,18 +324,10 @@ extern "C" size_t rust_uv_helper_addrinfo_size() { return sizeof(addrinfo); } -extern "C" unsigned long int +extern "C" unsigned int rust_uv_helper_get_INADDR_NONE() { return INADDR_NONE; } -extern "C" unsigned long int -rust_uv_helper_get_AF_INET() { - return AF_INET; -} -extern "C" unsigned long int -rust_uv_helper_get_AF_INET6() { - return AF_INET6; -} extern "C" uv_stream_t* rust_uv_get_stream_handle_from_connect_req(uv_connect_t* connect) { @@ -518,9 +510,12 @@ rust_uv_freeaddrinfo(addrinfo* res) { } extern "C" bool rust_uv_is_ipv4_addrinfo(addrinfo* input) { - // if it aint AF_INET, it's AF_INET6 return input->ai_family == AF_INET; } +extern "C" bool +rust_uv_is_ipv6_addrinfo(addrinfo* input) { + return input->ai_family == AF_INET6; +} extern "C" addrinfo* rust_uv_get_next_addrinfo(addrinfo* input) { return input->ai_next; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index c454f4d496ad9..2fed7b3568570 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -124,6 +124,7 @@ rust_uv_read_stop rust_uv_malloc_buf_base_of rust_uv_free_base_of_buf rust_uv_is_ipv4_addrinfo +rust_uv_is_ipv6_addrinfo rust_uv_get_next_addrinfo rust_uv_addrinfo_as_sockaddr_in rust_uv_addrinfo_as_sockaddr_in6 @@ -138,8 +139,6 @@ rust_uv_helper_addr_in_size rust_uv_helper_addrinfo_size rust_uv_helper_uv_getaddrinfo_t_size rust_uv_helper_get_INADDR_NONE -rust_uv_helper_get_AF_INET -rust_uv_helper_get_AF_INET6 rust_uv_helper_uv_async_t_size rust_uv_helper_uv_timer_t_size rust_uv_get_stream_handle_from_connect_req From 96c36588c734dd5abd808bcc13fb83b8dafce294 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 09:05:33 -0700 Subject: [PATCH 36/45] std: add uv::ll::is_ipv6_addrinfo and get_INADDR_NONE --- src/libstd/uv_ll.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 35fa5d4e57ee2..e0668ebd44f87 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -571,7 +571,9 @@ native mod rustrt { fn rust_uv_freeaddrinfo(res: *addrinfo); // data accessors/helpers for rust-mapped uv structs + fn rust_uv_helper_get_INADDR_NONE() -> u32; fn rust_uv_is_ipv4_addrinfo(input: *addrinfo) -> bool; + fn rust_uv_is_ipv6_addrinfo(input: *addrinfo) -> bool; fn rust_uv_get_next_addrinfo(input: *addrinfo) -> *addrinfo; fn rust_uv_addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in; fn rust_uv_addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6; @@ -914,6 +916,12 @@ type uv_err_data = { unsafe fn is_ipv4_addrinfo(input: *addrinfo) -> bool { rustrt::rust_uv_is_ipv4_addrinfo(input) } +unsafe fn is_ipv6_addrinfo(input: *addrinfo) -> bool { + rustrt::rust_uv_is_ipv6_addrinfo(input) +} +unsafe fn get_INADDR_NONE() -> u32 { + rustrt::rust_uv_helper_get_INADDR_NONE() +} unsafe fn get_next_addrinfo(input: *addrinfo) -> *addrinfo { rustrt::rust_uv_get_next_addrinfo(input) } From d5ffb7fb6584049d84a864c916ec913743a1b1ad Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 09:07:24 -0700 Subject: [PATCH 37/45] std: beef up ipv4 validation a bit now the best of what we had prior to libuv integration (proper validation of an ipv4 string), along with libuv support (initial ipv6 support) libuv has even weaker facilities for validating an input ipv6 (but still more than what we had), so eventually the "right" answer would be to roll a proper ipv6 address string parser in rust --- src/libstd/net_ip.rs | 62 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 0e13a2c590c40..77940468cfaa1 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -91,10 +91,18 @@ crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, ipv4(copy(( *ll::addrinfo_as_sockaddr_in(curr_addr)))) } - else { + else if ll::is_ipv6_addrinfo(curr_addr) { ipv6(copy(( *ll::addrinfo_as_sockaddr_in6(curr_addr)))) + } + else { + log(debug, "curr_addr is not of family AF_INET or "+ + "AF_INET6. Error."); + (*handle_data).output_ch.send( + result::err(get_addr_unknown_error)); + break; }; + out_vec += [new_ip_addr]; let next_addr = ll::get_next_addrinfo(curr_addr); if next_addr == ptr::null::() as *addrinfo { @@ -192,18 +200,58 @@ mod v4 { } } } + // the simple, old style numberic representation of + // ipv4 + type ipv4_rep = { a: u8, b: u8, c: u8, d:u8 }; + impl x for ipv4_rep { + // this is pretty dastardly, i know + unsafe fn as_u32() -> u32 { + *((ptr::addr_of(self)) as *u32) + } + } + fn parse_to_ipv4_rep(ip: str) -> result::result { + let parts = vec::map(str::split_char(ip, '.'), {|s| + alt uint::from_str(s) { + some(n) if n <= 255u { n } + _ { 256u } + } + }); + if vec::len(parts) != 4u { + result::err(#fmt("'%s' doesn't have 4 parts", ip)) + } + else if vec::contains(parts, 256u) { + result::err(#fmt("invalid octal in addr '%s'", ip)) + } + else { + result::ok({a: parts[0] as u8, b: parts[1] as u8, + c: parts[2] as u8, d: parts[3] as u8}) + } + } fn try_parse_addr(ip: str) -> result::result { unsafe { - // need to figure out how to establish a parse failure.. + let INADDR_NONE = ll::get_INADDR_NONE(); + let ip_rep_result = parse_to_ipv4_rep(ip); + if result::is_err(ip_rep_result) { + let err_str = result::get_err(ip_rep_result); + ret result::err({err_msg: err_str}) + } + // ipv4_rep.as_u32 is unsafe :/ + let input_is_inaddr_none = + result::get(ip_rep_result).as_u32() == INADDR_NONE; + let new_addr = uv_ip4_addr(ip, 22); let reformatted_name = uv_ip4_name(&new_addr); log(debug, #fmt("try_parse_addr: input ip: %s reparsed ip: %s", ip, reformatted_name)); - // here we're going to - let inaddr_none_val = "255.255.255.255"; - if ip != inaddr_none_val && reformatted_name == inaddr_none_val { - result::err({err_msg:#fmt("failed to parse '%s'", - ip)}) + let ref_ip_rep_result = parse_to_ipv4_rep(reformatted_name); + if result::is_err(ref_ip_rep_result) { + let err_str = result::get_err(ref_ip_rep_result); + ret result::err({err_msg: err_str}) + } + if result::get(ref_ip_rep_result).as_u32() == INADDR_NONE && + !input_is_inaddr_none { + ret result::err( + {err_msg: "uv_ip4_name produced invalid result."}) } else { result::ok(ipv4(copy(new_addr))) From 757f74b8ea470d6954c6f1166d229a9afed3c6a0 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 11:29:57 -0700 Subject: [PATCH 38/45] std: add test for net::ip::get_addr failure --- src/libstd/net_ip.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 77940468cfaa1..95a8e953a5e3e 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -368,5 +368,15 @@ mod test { log(debug, #fmt("test_get_addr: result %s: '%s'", ipv_prefix, format_addr(r))); } + // at least one result.. this is going to vary from system + // to system, based on stuff like the contents of /etc/hosts + assert vec::len(results) > 0; + } + #[test] + fn test_get_addr_bad_input() { + let localhost_name = "sjkl234m,./sdf"; + let iotask = uv::global_loop::get(); + let ga_result = get_addr(localhost_name, iotask); + assert result::is_err(ga_result); } } \ No newline at end of file From b60e3e9b5b533b60a56c80022e761132acb89c03 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 12:47:44 -0700 Subject: [PATCH 39/45] std: addressing #2656 (ipv6 support in net::tcp) .. there are some additional FIXME nags in net_tcp (L 1012) about blocking because libuv is holding unsafe ptrs to task local data. the proposed fix going is not really feasible w/ the current design, IMO, but i'll leave it there in case someone really wants to make the case without creating more hassle than it's worth. --- src/libstd/net_ip.rs | 4 +-- src/libstd/net_tcp.rs | 68 +++++++++++++++++++++++++++---------------- src/libstd/uv_ll.rs | 23 +++++++++++++++ src/rt/rust_uv.cpp | 33 +++++++++++---------- src/rt/rustrt.def.in | 2 ++ 5 files changed, 88 insertions(+), 42 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 95a8e953a5e3e..6087def662446 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -230,7 +230,7 @@ mod v4 { fn try_parse_addr(ip: str) -> result::result { unsafe { let INADDR_NONE = ll::get_INADDR_NONE(); - let ip_rep_result = parse_to_ipv4_rep(ip); + let ip_rep_result = parse_to_ipv4_rep(ip); if result::is_err(ip_rep_result) { let err_str = result::get_err(ip_rep_result); ret result::err({err_msg: err_str}) @@ -243,7 +243,7 @@ mod v4 { let reformatted_name = uv_ip4_name(&new_addr); log(debug, #fmt("try_parse_addr: input ip: %s reparsed ip: %s", ip, reformatted_name)); - let ref_ip_rep_result = parse_to_ipv4_rep(reformatted_name); + let ref_ip_rep_result = parse_to_ipv4_rep(reformatted_name); if result::is_err(ref_ip_rep_result) { let err_str = result::get_err(ref_ip_rep_result); ret result::err({err_msg: err_str}) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index da8c55c3d9580..585307b82661b 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -164,16 +164,35 @@ fn connect(-input_ip: ip::ip_addr, port: uint, alt input_ip { ipv4 { log(debug, "dealing w/ ipv4 connection.."); - let tcp_addr = ipv4_ip_addr_to_sockaddr_in(input_ip, - port); - let tcp_addr_ptr = ptr::addr_of(tcp_addr); let connect_req_ptr = ptr::addr_of((*socket_data_ptr).connect_req); - alt uv::ll::tcp_connect( - connect_req_ptr, - stream_handle_ptr, - tcp_addr_ptr, - tcp_connect_on_connect_cb) { + let addr_str = ip::format_addr(input_ip); + let connect_result = alt input_ip { + ip::ipv4(addr) { + // have to "recreate" the sockaddr_in/6 + // since the ip_addr discards the port + // info.. should probably add an additional + // rust type that actually is closer to + // what the libuv API expects (ip str + port num) + log(debug, #fmt("addr: %?", addr)); + let in_addr = uv::ll::ip4_addr(addr_str, port as int); + uv::ll::tcp_connect( + connect_req_ptr, + stream_handle_ptr, + ptr::addr_of(in_addr), + tcp_connect_on_connect_cb) + } + ip::ipv6(addr) { + log(debug, #fmt("addr: %?", addr)); + let in_addr = uv::ll::ip6_addr(addr_str, port as int); + uv::ll::tcp_connect6( + connect_req_ptr, + stream_handle_ptr, + ptr::addr_of(in_addr), + tcp_connect_on_connect_cb) + } + }; + alt connect_result { 0i32 { log(debug, "tcp_connect successful"); // reusable data that we'll have for the @@ -598,15 +617,27 @@ fn listen_common(-host_ip: ip::ip_addr, port: uint, backlog: uint, // nested within a comm::listen block) let loc_ip = copy(host_ip); iotask::interact(iotask) {|loop_ptr| - let tcp_addr = ipv4_ip_addr_to_sockaddr_in(loc_ip, - port); alt uv::ll::tcp_init(loop_ptr, server_stream_ptr) { 0i32 { uv::ll::set_data_for_uv_handle( server_stream_ptr, server_data_ptr); - alt uv::ll::tcp_bind(server_stream_ptr, - ptr::addr_of(tcp_addr)) { + let addr_str = ip::format_addr(loc_ip); + let bind_result = alt loc_ip { + ip::ipv4(addr) { + log(debug, #fmt("addr: %?", addr)); + let in_addr = uv::ll::ip4_addr(addr_str, port as int); + uv::ll::tcp_bind(server_stream_ptr, + ptr::addr_of(in_addr)) + } + ip::ipv6(addr) { + log(debug, #fmt("addr: %?", addr)); + let in_addr = uv::ll::ip6_addr(addr_str, port as int); + uv::ll::tcp_bind6(server_stream_ptr, + ptr::addr_of(in_addr)) + } + }; + alt bind_result { 0i32 { alt uv::ll::listen(server_stream_ptr, backlog as libc::c_int, @@ -1205,19 +1236,6 @@ type tcp_buffered_socket_data = { mut buf: [u8] }; -// convert rust ip_addr to libuv's native representation -fn ipv4_ip_addr_to_sockaddr_in(input_ip: ip::ip_addr, - port: uint) -> uv::ll::sockaddr_in unsafe { - // FIXME (#2656): ipv6 - let addr_str = ip::format_addr(input_ip); - alt input_ip { - ip::ipv4(addr) { - uv::ll::ip4_addr(addr_str, port as int) - } - _ { fail "only works w/ ipv4";} - } -} - //#[cfg(test)] mod test { // FIXME don't run on fbsd or linux 32 bit (#2064) diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index e0668ebd44f87..7921a84175a51 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -542,6 +542,14 @@ native mod rustrt { // FIXME ref #2064 fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, ++addr: *sockaddr_in) -> libc::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) -> libc::c_int; + // FIXME ref #2064 + fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, + ++addr: *sockaddr_in6) -> libc::c_int; fn rust_uv_listen(stream: *libc::c_void, backlog: libc::c_int, cb: *u8) -> libc::c_int; fn rust_uv_accept(server: *libc::c_void, client: *libc::c_void) @@ -651,11 +659,26 @@ unsafe fn tcp_connect(connect_ptr: *uv_connect_t, after_connect_cb, addr_ptr); } // FIXME ref #2064 +unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, + tcp_handle_ptr: *uv_tcp_t, + addr_ptr: *sockaddr_in6, + ++after_connect_cb: *u8) +-> libc::c_int { + ret rustrt::rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, + after_connect_cb, addr_ptr); +} +// FIXME ref #2064 unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> libc::c_int { ret rustrt::rust_uv_tcp_bind(tcp_server_ptr, addr_ptr); } +// FIXME ref #2064 +unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, + addr_ptr: *sockaddr_in6) -> libc::c_int { + ret rustrt::rust_uv_tcp_bind6(tcp_server_ptr, + addr_ptr); +} unsafe fn listen(stream: *T, backlog: libc::c_int, cb: *u8) -> libc::c_int { diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index f681c6bdd9966..e47af4e10a342 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -238,32 +238,36 @@ rust_uv_tcp_connect(uv_connect_t* connect_ptr, uv_tcp_t* tcp_ptr, uv_connect_cb cb, sockaddr_in* addr_ptr) { - rust_task* task = rust_get_current_task(); - LOG(task, stdlib, "inside rust_uv_tcp_connect"); // FIXME ref #2064 sockaddr_in addr = *addr_ptr; - LOG(task, stdlib, "before tcp_connect .. port: %d", - addr.sin_port); - LOG(task, stdlib, "before tcp_connect.. tcp stream:" \ - "%lu cb ptr: %lu", - (unsigned long int)tcp_ptr, (unsigned long int)cb); int result = uv_tcp_connect(connect_ptr, tcp_ptr, addr, cb); - LOG(task, stdlib, "leaving rust_uv_tcp_connect.." \ - "and result: %d", - result); return result; } extern "C" int rust_uv_tcp_bind(uv_tcp_t* tcp_server, sockaddr_in* addr_ptr) { // FIXME ref #2064 - rust_task* task = rust_get_current_task(); sockaddr_in addr = *addr_ptr; - LOG(task, stdlib, "before uv_tcp_bind .. tcp_server:" \ - "%lu port: %d", - (unsigned long int)tcp_server, addr.sin_port); return uv_tcp_bind(tcp_server, addr); } +extern "C" int +rust_uv_tcp_connect6(uv_connect_t* connect_ptr, + uv_tcp_t* tcp_ptr, + uv_connect_cb cb, + sockaddr_in6* addr_ptr) { + // FIXME ref #2064 + sockaddr_in6 addr = *addr_ptr; + int result = uv_tcp_connect6(connect_ptr, tcp_ptr, addr, cb); + return result; +} + +extern "C" int +rust_uv_tcp_bind6 +(uv_tcp_t* tcp_server, sockaddr_in6* addr_ptr) { + // FIXME ref #2064 + sockaddr_in6 addr = *addr_ptr; + return uv_tcp_bind6(tcp_server, addr); +} extern "C" int rust_uv_listen(uv_stream_t* stream, int backlog, @@ -328,7 +332,6 @@ extern "C" unsigned int rust_uv_helper_get_INADDR_NONE() { return INADDR_NONE; } - extern "C" uv_stream_t* rust_uv_get_stream_handle_from_connect_req(uv_connect_t* connect) { return connect->handle; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 2fed7b3568570..a218782dcbe63 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -116,6 +116,8 @@ rust_uv_ip6_addr rust_uv_ip6_name rust_uv_tcp_connect rust_uv_tcp_bind +rust_uv_tcp_connect6 +rust_uv_tcp_bind6 rust_uv_listen rust_uv_accept rust_uv_write From 95c41f2348cad339147f096acaef6a94304f72ec Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 14:39:47 -0700 Subject: [PATCH 40/45] std: fix errors from recent rebase and vec expr/type syntax update --- src/libstd/net_ip.rs | 8 ++++---- src/libstd/net_tcp.rs | 44 +++++++++++++++++++++---------------------- src/libstd/uv_ll.rs | 18 +++++++++--------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 6087def662446..3efca378bc885 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -73,7 +73,7 @@ fn format_addr(ip: ip_addr) -> str { } type get_addr_data = { - output_ch: comm::chan> + output_ch: comm::chan> }; crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, @@ -83,7 +83,7 @@ crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, *get_addr_data; if status == 0i32 { if res != (ptr::null::()) { - let mut out_vec = []; + let mut out_vec = []/~; log(debug, #fmt("initial addrinfo: %?", res)); let mut curr_addr = res; loop { @@ -102,7 +102,7 @@ crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, result::err(get_addr_unknown_error)); break; }; - out_vec += [new_ip_addr]; + out_vec += [new_ip_addr]/~; let next_addr = ll::get_next_addrinfo(curr_addr); if next_addr == ptr::null::() as *addrinfo { @@ -144,7 +144,7 @@ enum ip_get_addr_err { #[doc=" "] fn get_addr(++node: str, iotask: iotask) - -> result::result<[ip_addr], ip_get_addr_err> unsafe { + -> result::result<[ip_addr]/~, ip_get_addr_err> unsafe { comm::listen {|output_ch| str::unpack_slice(node) {|node_ptr, len| log(debug, #fmt("slice len %?", len)); diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 585307b82661b..c0aa3394e7703 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -45,7 +45,7 @@ class tcp_socket { new(socket_data: @tcp_socket_data) { self.socket_data = socket_data; } drop { unsafe { - tear_down_socket_data(socket_data) + tear_down_socket_data(self.socket_data) } } } @@ -56,8 +56,9 @@ A buffered wrapper for `net::tcp::tcp_socket` It is created with a call to `net::tcp::socket_buf()` and has impls that satisfy both the `io::reader` and `io::writer` ifaces. "] -resource tcp_socket_buf(data: @tcp_buffered_socket_data) { - log(debug, #fmt("dtor for tcp_socket_buf.. %?", data)); +class tcp_socket_buf { + let data: @tcp_buffered_socket_data; + new(data: @tcp_buffered_socket_data) { self.data = data; } } #[doc=" @@ -305,7 +306,7 @@ fn write_future(sock: tcp_socket, raw_write_data: [u8]/~) let socket_data_ptr = ptr::addr_of(*(sock.socket_data)); future_spawn {|| let data_copy = copy(raw_write_data); - write_common_impl(socket_data_ptr, data_copy); + write_common_impl(socket_data_ptr, data_copy) } } @@ -337,10 +338,10 @@ Stop reading from an open TCP connection; used with `read_start` * `sock` - a `net::tcp::tcp_socket` that you wish to stop reading on "] fn read_stop(sock: tcp_socket, - -read_port: comm::port>) -> + -read_port: comm::port>) -> result::result<(), tcp_err_data> unsafe { log(debug, #fmt("taking the read_port out of commission %?", read_port)); - let socket_data = ptr::addr_of(**sock); + let socket_data = ptr::addr_of(*sock.socket_data); read_stop_common_impl(socket_data) } @@ -735,7 +736,7 @@ or `io::writer` A buffered wrapper that you can cast as an `io::reader` or `io::writer` "] fn socket_buf(-sock: tcp_socket) -> tcp_socket_buf { - tcp_socket_buf(@{ sock: sock, mut buf: [] }) + tcp_socket_buf(@{ sock: sock, mut buf: []/~ }) } #[doc=" @@ -747,7 +748,7 @@ impl tcp_socket for tcp_socket { read_start(self) } fn read_stop(-read_port: - comm::port>) -> + comm::port>) -> result::result<(), tcp_err_data> { read_stop(self, read_port) } @@ -773,28 +774,28 @@ impl tcp_socket for tcp_socket { Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` "] impl tcp_socket_buf of io::reader for @tcp_socket_buf { - fn read_bytes(amt: uint) -> [u8] { + fn read_bytes(amt: uint) -> [u8]/~ { let has_amt_available = - vec::len((*self).buf) >= amt; + vec::len((*(self.data)).buf) >= amt; if has_amt_available { // no arbitrary-length shift in vec::? - let mut ret_buf = []; + let mut ret_buf = []/~; while vec::len(ret_buf) < amt { - ret_buf += [vec::shift((*self).buf)]; + ret_buf += [vec::shift((*(self.data)).buf)]/~; } ret_buf } else { - let read_result = read((*self).sock, 0u); + let read_result = read((*(self.data)).sock, 0u); if read_result.is_err() { let err_data = read_result.get_err(); log(debug, #fmt("ERROR sock_buf as io::reader.read err %? %?", err_data.err_name, err_data.err_msg)); - [] + []/~ } else { let new_chunk = result::unwrap(read_result); - (*self).buf += new_chunk; + (*(self.data)).buf += new_chunk; self.read_bytes(amt) } } @@ -803,7 +804,7 @@ impl tcp_socket_buf of io::reader for @tcp_socket_buf { self.read_bytes(1u)[0] as int } fn unread_byte(amt: int) { - vec::unshift((*self).buf, amt as u8); + vec::unshift((*(self.data)).buf, amt as u8); } fn eof() -> bool { false // noop @@ -822,12 +823,9 @@ Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` "] impl tcp_socket_buf of io::writer for @tcp_socket_buf { fn write(data: [const u8]/&) unsafe { - let socket_data_ptr = ptr::addr_of(**((*self).sock)); - let write_buf_vec = vec::unpack_const_slice(data) {|ptr, len| - [ uv::ll::buf_init(ptr as *u8, len) ] - }; - let write_buf_vec_ptr = ptr::addr_of(write_buf_vec); - let w_result = write_common_impl(socket_data_ptr, write_buf_vec_ptr); + let socket_data_ptr = ptr::addr_of(*((*(self.data)).sock).socket_data); + let w_result = write_common_impl(socket_data_ptr, + vec::slice(data, 0, vec::len(data))); if w_result.is_err() { let err_data = w_result.get_err(); log(debug, #fmt("ERROR sock_buf as io::writer.writer err: %? %?", @@ -1233,7 +1231,7 @@ type tcp_socket_data = { type tcp_buffered_socket_data = { sock: tcp_socket, - mut buf: [u8] + mut buf: [u8]/~ }; //#[cfg(test)] diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 7921a84175a51..5f75523e2b64c 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -765,7 +765,7 @@ unsafe fn ip4_addr(ip: str, port: int) unsafe fn ip6_addr(ip: str, port: int) -> sockaddr_in6 { let mut addr_vec = str::bytes(ip); - addr_vec += [0u8]; // add null terminator + addr_vec += [0u8]/~; // add null terminator let addr_vec_ptr = vec::unsafe::to_ptr(addr_vec); let ip_back = str::from_bytes(addr_vec); log(debug, #fmt("vec val: '%s' length: %u", @@ -775,8 +775,8 @@ unsafe fn ip6_addr(ip: str, port: int) } unsafe fn ip4_name(src: &sockaddr_in) -> str { // ipv4 addr max size: 15 + 1 trailing null byte - let dst: [u8] = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8]; + let dst: [u8]/~ = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8]/~; let size = 16 as libc::size_t; vec::as_buf(dst) {|dst_buf| rustrt::rust_uv_ip4_name(src as *sockaddr_in, @@ -792,12 +792,12 @@ unsafe fn ip4_name(src: &sockaddr_in) -> str { } unsafe fn ip6_name(src: &sockaddr_in6) -> str { // ipv6 addr max size: 45 + 1 trailing null byte - let dst: [u8] = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8]; + let dst: [u8]/~ = [0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, + 0u8,0u8,0u8,0u8,0u8,0u8]/~; let size = 46 as libc::size_t; vec::as_buf(dst) {|dst_buf| let result = rustrt::rust_uv_ip6_name(src as *sockaddr_in6, From 2ce9281c9db3d739c02b88195fb50a90f7260fbd Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 26 Jun 2012 16:13:50 -0700 Subject: [PATCH 41/45] rename net::ip tests en masse --- src/libstd/net_ip.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 3efca378bc885..ca0c69cb7244f 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -306,13 +306,13 @@ mod v6 { #[cfg(test)] mod test { #[test] - fn test_ipv4_parse_and_format_ip() { + fn test_ip_ipv4_parse_and_format_ip() { let localhost_str = "127.0.0.1"; assert (format_addr(v4::parse_addr(localhost_str)) == localhost_str) } #[test] - fn test_ipv6_parse_and_format_ip() { + fn test_ip_ipv6_parse_and_format_ip() { let localhost_str = "::1"; let format_result = format_addr(v6::parse_addr(localhost_str)); log(debug, #fmt("results: expected: '%s' actual: '%s'", @@ -320,7 +320,7 @@ mod test { assert format_result == localhost_str; } #[test] - fn test_ipv4_bad_parse() { + fn test_ip_ipv4_bad_parse() { alt v4::try_parse_addr("b4df00d") { result::err(err_info) { log(debug, #fmt("got error as expected %?", err_info)); @@ -332,7 +332,7 @@ mod test { } } #[test] - fn test_ipv6_bad_parse() { + fn test_ip_ipv6_bad_parse() { alt v6::try_parse_addr("::,~2234k;") { result::err(err_info) { log(debug, #fmt("got error as expected %?", err_info)); @@ -344,7 +344,7 @@ mod test { } } #[test] - fn test_get_addr() { + fn test_ip_get_addr() { let localhost_name = "localhost"; let iotask = uv::global_loop::get(); let ga_result = get_addr(localhost_name, iotask); @@ -373,7 +373,7 @@ mod test { assert vec::len(results) > 0; } #[test] - fn test_get_addr_bad_input() { + fn test_ip_get_addr_bad_input() { let localhost_name = "sjkl234m,./sdf"; let iotask = uv::global_loop::get(); let ga_result = get_addr(localhost_name, iotask); From 9fa68d372d6d389caf86e0cabccd768a8372c8d5 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 27 Jun 2012 15:28:03 -0700 Subject: [PATCH 42/45] std/rt: cleanup and adding sockaddr_in6 mapping for win32 --- src/libstd/net_ip.rs | 1 + src/libstd/net_tcp.rs | 3 ++- src/libstd/uv_ll.rs | 37 ++++++++++++++++++++----------------- src/rt/rust_uv.cpp | 12 +++++++----- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index ca0c69cb7244f..3bd95a718a4cd 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -332,6 +332,7 @@ mod test { } } #[test] + #[ignore(target_os="win32")] fn test_ip_ipv6_bad_parse() { alt v6::try_parse_addr("::,~2234k;") { result::err(err_info) { diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index c0aa3394e7703..feec985b236dc 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -823,7 +823,8 @@ Implementation of `io::reader` iface for a buffered `net::tcp::tcp_socket` "] impl tcp_socket_buf of io::writer for @tcp_socket_buf { fn write(data: [const u8]/&) unsafe { - let socket_data_ptr = ptr::addr_of(*((*(self.data)).sock).socket_data); + let socket_data_ptr = + ptr::addr_of(*((*(self.data)).sock).socket_data); let w_result = write_common_impl(socket_data_ptr, vec::slice(data, 0, vec::len(data))); if w_result.is_err() { diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 5f75523e2b64c..0d6043be36bfc 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -225,10 +225,18 @@ type sockaddr_in = { // unix size: 28 .. FIXME #1645 // stuck with 32 becuse of rust padding structs? +#[cfg(unix)] type sockaddr_in6 = { a0: *u8, a1: *u8, a2: *u8, a3: *u8 }; +#[cfg(windows)] +type sockaddr_in6 = { + a0: *u8, a1: *u8, + a2: *u8, a3: *u8, + a4: *u8, a5: *u8, + a6: *u8, a7: *u8 +}; // unix size: 28 .. FIXME #1645 // stuck with 32 becuse of rust padding structs? @@ -753,25 +761,17 @@ unsafe fn buf_init(++input: *u8, len: uint) -> uv_buf_t { } unsafe fn ip4_addr(ip: str, port: int) -> sockaddr_in { - let mut addr_vec = str::bytes(ip); - vec::push(addr_vec, 0u8); // add null terminator - let addr_vec_ptr = vec::unsafe::to_ptr(addr_vec); - let ip_back = str::from_bytes(addr_vec); - log(debug, #fmt("vec val: '%s' length: %u", - ip_back, vec::len(addr_vec))); - ret rustrt::rust_uv_ip4_addr(addr_vec_ptr, - port as libc::c_int); + str::as_c_str(ip) {|ip_buf| + rustrt::rust_uv_ip4_addr(ip_buf as *u8, + port as libc::c_int) + } } unsafe fn ip6_addr(ip: str, port: int) -> sockaddr_in6 { - let mut addr_vec = str::bytes(ip); - addr_vec += [0u8]/~; // add null terminator - let addr_vec_ptr = vec::unsafe::to_ptr(addr_vec); - let ip_back = str::from_bytes(addr_vec); - log(debug, #fmt("vec val: '%s' length: %u", - ip_back, vec::len(addr_vec))); - ret rustrt::rust_uv_ip6_addr(addr_vec_ptr, + str::as_c_str(ip) {|ip_buf| + rustrt::rust_uv_ip6_addr(ip_buf as *u8, port as libc::c_int); + } } unsafe fn ip4_name(src: &sockaddr_in) -> str { // ipv4 addr max size: 15 + 1 trailing null byte @@ -800,7 +800,10 @@ unsafe fn ip6_name(src: &sockaddr_in6) -> str { 0u8,0u8,0u8,0u8,0u8,0u8]/~; let size = 46 as libc::size_t; vec::as_buf(dst) {|dst_buf| - let result = rustrt::rust_uv_ip6_name(src as *sockaddr_in6, + let src_unsafe_ptr = src as *sockaddr_in6; + log(debug, #fmt("val of src *sockaddr_in6: %? sockaddr_in6: %?", + src_unsafe_ptr, src)); + let result = rustrt::rust_uv_ip6_name(src_unsafe_ptr, dst_buf, size); alt result { 0i32 { @@ -1536,7 +1539,7 @@ mod test { let native_handle_size = rustrt::rust_uv_helper_sockaddr_in6_size(); let rust_handle_size = sys::size_of::(); - let output = #fmt("sockaddr_in -- native: %u rust: %u", + let output = #fmt("sockaddr_in6 -- native: %u rust: %u", native_handle_size as uint, rust_handle_size); log(debug, output); // FIXME #1645 .. rust appears to pad structs to the nearest byte..? diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index e47af4e10a342..9124172af1a1b 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -459,7 +459,7 @@ extern "C" struct sockaddr_in rust_uv_ip4_addr(const char* ip, int port) { rust_task* task = rust_get_current_task(); LOG(task, stdlib, "before creating addr_ptr.. ip %s" \ - "port %d", ip, port); + " port %d\n", ip, port); struct sockaddr_in addr = uv_ip4_addr(ip, port); LOG(task, stdlib, "after creating .. port: %d", addr.sin_port); return addr; @@ -468,9 +468,8 @@ extern "C" struct sockaddr_in6 rust_uv_ip6_addr(const char* ip, int port) { rust_task* task = rust_get_current_task(); LOG(task, stdlib, "before creating addr_ptr.. ip %s" \ - "port %d", ip, port); - struct sockaddr_in6 addr = uv_ip6_addr(ip, port); - return addr; + " port %d\n", ip, port); + return uv_ip6_addr(ip, port); } extern "C" int rust_uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { @@ -478,7 +477,10 @@ rust_uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { } extern "C" int rust_uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { - return uv_ip6_name(src, dst, size); + int result = uv_ip6_name(src, dst, size); + printf("rust_uv_ip6_name: src ptr: %lu dst result: '%s'\n", + (unsigned long int)src, dst); + return result; } extern "C" uintptr_t* From d3d810a4d4bcfa5c0f3e9391771ed14f09fe2cb0 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 27 Jun 2012 15:45:46 -0700 Subject: [PATCH 43/45] std: cleanups, post-rebase --- src/libstd/net_tcp.rs | 1 + src/libstd/uv_ll.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index feec985b236dc..76d5ccd3fcc46 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -6,6 +6,7 @@ import ip = net_ip; import uv::iotask; import uv::iotask::iotask; import comm::methods; +import future::future; import future_spawn = future::spawn; // FIXME #1935 // should be able to, but can't atm, replace w/ result::{result, extensions}; diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 0d6043be36bfc..a58ffca1dd104 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -770,7 +770,7 @@ unsafe fn ip6_addr(ip: str, port: int) -> sockaddr_in6 { str::as_c_str(ip) {|ip_buf| rustrt::rust_uv_ip6_addr(ip_buf as *u8, - port as libc::c_int); + port as libc::c_int) } } unsafe fn ip4_name(src: &sockaddr_in) -> str { From fd6f455241d0f3b4954696f78573c18d86bf9041 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 27 Jun 2012 15:59:04 -0700 Subject: [PATCH 44/45] std: adding some basic docs for net::ip::get_addr --- src/libstd/net_ip.rs | 139 +++++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 63 deletions(-) diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 3bd95a718a4cd..70003a224828d 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -72,76 +72,26 @@ fn format_addr(ip: ip_addr) -> str { } } -type get_addr_data = { - output_ch: comm::chan> -}; - -crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, - res: *addrinfo) unsafe { - log(debug, "in get_addr_cb"); - let handle_data = get_data_for_req(handle) as - *get_addr_data; - if status == 0i32 { - if res != (ptr::null::()) { - let mut out_vec = []/~; - log(debug, #fmt("initial addrinfo: %?", res)); - let mut curr_addr = res; - loop { - let new_ip_addr = if ll::is_ipv4_addrinfo(curr_addr) { - ipv4(copy(( - *ll::addrinfo_as_sockaddr_in(curr_addr)))) - } - else if ll::is_ipv6_addrinfo(curr_addr) { - ipv6(copy(( - *ll::addrinfo_as_sockaddr_in6(curr_addr)))) - } - else { - log(debug, "curr_addr is not of family AF_INET or "+ - "AF_INET6. Error."); - (*handle_data).output_ch.send( - result::err(get_addr_unknown_error)); - break; - }; - out_vec += [new_ip_addr]/~; - - let next_addr = ll::get_next_addrinfo(curr_addr); - if next_addr == ptr::null::() as *addrinfo { - log(debug, "null next_addr encountered. no mas"); - break; - } - else { - curr_addr = next_addr; - log(debug, #fmt("next_addr addrinfo: %?", curr_addr)); - } - } - log(debug, #fmt("successful process addrinfo result, len: %?", - vec::len(out_vec))); - (*handle_data).output_ch.send(result::ok(out_vec)); - } - else { - log(debug, "addrinfo pointer is NULL"); - (*handle_data).output_ch.send( - result::err(get_addr_unknown_error)); - } - } - else { - log(debug, "status != 0 error in get_addr_cb"); - (*handle_data).output_ch.send( - result::err(get_addr_unknown_error)); - } - if res != (ptr::null::()) { - uv_freeaddrinfo(res); - } - log(debug, "leaving get_addr_cb"); -} - #[doc=" +Represents errors returned from `net::ip::get_addr()` "] enum ip_get_addr_err { get_addr_unknown_error } #[doc=" +Attempts name resolution on the provided `node` string + +# Arguments + +* `node` - a string representing some host address +* `iotask` - a `uv::iotask` used to interact with the underlying event loop + +# Returns + +A `result<[ip_addr]/~, ip_get_addr_err>` instance that will contain +a vector of `ip_addr` results, in the case of success, or an error +object in the case of failure "] fn get_addr(++node: str, iotask: iotask) -> result::result<[ip_addr]/~, ip_get_addr_err> unsafe { @@ -303,6 +253,69 @@ mod v6 { } } +type get_addr_data = { + output_ch: comm::chan> +}; + +crust fn get_addr_cb(handle: *uv_getaddrinfo_t, status: libc::c_int, + res: *addrinfo) unsafe { + log(debug, "in get_addr_cb"); + let handle_data = get_data_for_req(handle) as + *get_addr_data; + if status == 0i32 { + if res != (ptr::null::()) { + let mut out_vec = []/~; + log(debug, #fmt("initial addrinfo: %?", res)); + let mut curr_addr = res; + loop { + let new_ip_addr = if ll::is_ipv4_addrinfo(curr_addr) { + ipv4(copy(( + *ll::addrinfo_as_sockaddr_in(curr_addr)))) + } + else if ll::is_ipv6_addrinfo(curr_addr) { + ipv6(copy(( + *ll::addrinfo_as_sockaddr_in6(curr_addr)))) + } + else { + log(debug, "curr_addr is not of family AF_INET or "+ + "AF_INET6. Error."); + (*handle_data).output_ch.send( + result::err(get_addr_unknown_error)); + break; + }; + out_vec += [new_ip_addr]/~; + + let next_addr = ll::get_next_addrinfo(curr_addr); + if next_addr == ptr::null::() as *addrinfo { + log(debug, "null next_addr encountered. no mas"); + break; + } + else { + curr_addr = next_addr; + log(debug, #fmt("next_addr addrinfo: %?", curr_addr)); + } + } + log(debug, #fmt("successful process addrinfo result, len: %?", + vec::len(out_vec))); + (*handle_data).output_ch.send(result::ok(out_vec)); + } + else { + log(debug, "addrinfo pointer is NULL"); + (*handle_data).output_ch.send( + result::err(get_addr_unknown_error)); + } + } + else { + log(debug, "status != 0 error in get_addr_cb"); + (*handle_data).output_ch.send( + result::err(get_addr_unknown_error)); + } + if res != (ptr::null::()) { + uv_freeaddrinfo(res); + } + log(debug, "leaving get_addr_cb"); +} + #[cfg(test)] mod test { #[test] From 12d388e3481d2363e062f4c3ba081e4ba0ac5788 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 29 Jun 2012 07:06:32 -0700 Subject: [PATCH 45/45] std: uv::ll fixes for 32bit linux --- src/libstd/uv_ll.rs | 65 +++++++++++++++++++++++++++++++++++++-------- src/rt/rust_uv.cpp | 2 -- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index a58ffca1dd104..4c0f3835f32e7 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -225,12 +225,12 @@ type sockaddr_in = { // unix size: 28 .. FIXME #1645 // stuck with 32 becuse of rust padding structs? -#[cfg(unix)] +#[cfg(target_arch="x86_64")] type sockaddr_in6 = { a0: *u8, a1: *u8, a2: *u8, a3: *u8 }; -#[cfg(windows)] +#[cfg(target_arch="x86")] type sockaddr_in6 = { a0: *u8, a1: *u8, a2: *u8, a3: *u8, @@ -240,16 +240,59 @@ type sockaddr_in6 = { // unix size: 28 .. FIXME #1645 // stuck with 32 becuse of rust padding structs? -type addr_in = { - a0: *u8, a1: *u8, - a2: *u8, a3: *u8 -}; +type addr_in = addr_in_impl::addr_in; +#[cfg(unix)] +mod addr_in_impl { + #[cfg(target_arch="x86_64")] + type addr_in = { + a0: *u8, a1: *u8, + a2: *u8, a3: *u8 + }; + #[cfg(target_arch="x86")] + type addr_in = { + a0: *u8, a1: *u8, + a2: *u8, a3: *u8, + a4: *u8, a5: *u8, + a6: *u8, a7: *u8, + }; +} +#[cfg(windows)] +mod addr_in_impl { + type addr_in = { + a0: *u8, a1: *u8, + a2: *u8, a3: *u8 + }; +} -// unix size: 48 -type addrinfo = { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8 -}; +// unix size: 48, 32bit: 32 +type addrinfo = addrinfo_impl::addrinfo; +#[cfg(target_os="linux")] +mod addrinfo_impl { + #[cfg(target_arch="x86_64")] + type addrinfo = { + a00: *u8, a01: *u8, a02: *u8, a03: *u8, + a04: *u8, a05: *u8 + }; + #[cfg(target_arch="x86")] + type addrinfo = { + a00: *u8, a01: *u8, a02: *u8, a03: *u8, + a04: *u8, a05: *u8, a06: *u8, a07: *u8 + }; +} +#[cfg(target_os="macos")] +mod addrinfo_impl { + type addrinfo = { + a00: *u8, a01: *u8, a02: *u8, a03: *u8, + a04: *u8, a05: *u8 + }; +} +#[cfg(windows)] +mod addrinfo_impl { + type addrinfo = { + a00: *u8, a01: *u8, a02: *u8, a03: *u8, + a04: *u8, a05: *u8 + }; +} // unix size: 72 type uv_getaddrinfo_t = { diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 9124172af1a1b..706e8ff43807f 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -478,8 +478,6 @@ rust_uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { extern "C" int rust_uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { int result = uv_ip6_name(src, dst, size); - printf("rust_uv_ip6_name: src ptr: %lu dst result: '%s'\n", - (unsigned long int)src, dst); return result; }