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
This commit is contained in:
Jeff Olson 2012-06-17 20:36:36 -07:00 committed by Brian Anderson
parent c027292846
commit 30f26ddbc9
3 changed files with 55 additions and 35 deletions

View File

@ -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<ip_addr,parse_addr_err> {
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));
}
}

View File

@ -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<tcp_socket, tcp_connect_err_data> unsafe {
let result_po = comm::port::<conn_attempt>();
@ -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<option<tcp_err_data>>),
+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<option<tcp_err_data>>),
-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";

View File

@ -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 {