dpc / mioco.pre-0.9

Scalable, coroutine-based, asynchronous IO handling library for Rust programming language. (aka MIO COroutines).
Mozilla Public License 2.0
457 stars 30 forks source link

`TcpListener::from_listener` not working as expected #116

Closed troplin closed 8 years ago

troplin commented 8 years ago

I'm trying to set IPV6_V6ONLY sockopt. Not sure if I'm using everything as intended...

[package]
name = "mioco_test"
version = "0.1.0"

[dependencies]
mioco = "0.3.1"
env_logger = "*"
log = "*"
net2 = "0.2.22"
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate mioco;
extern crate net2;

use mioco::tcp;
use std::{net,str};

const DEFAULT_LISTEN_ADDR : &'static str = "::";
fn listend_addr() -> net::IpAddr {
    str::FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
}

fn main() {
    env_logger::init().unwrap();
    info!("Starting...");

    mioco::start(move ||{
        let addr = listend_addr();
        let builder = net2::TcpBuilder::new_v6().unwrap();
        builder.only_v6(true).unwrap();
        let addr = net::SocketAddr::new(addr.clone(), 45678);
        builder.bind(&addr).unwrap();
        let listener = builder.to_tcp_listener().unwrap();
        let listener = tcp::TcpListener::from_listener(listener, &addr).unwrap();
        info!("Listening on {:?}", listener.local_addr());

        let _ = listener.accept().unwrap();
        Ok(())
    });
    info!("Stopped.");
}
$ RUST_LOG=mioco_test=debug cargo run
     Running `target/debug/mioco_test`
INFO:mioco_test: Starting...
INFO:mioco_test: Listening on Ok(V6([::]:45678))
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 22, message: "Invalid argument" } }', ../src/libcore/result.rs:746
note: Run with `RUST_BACKTRACE=1` for a backtrace.
INFO:mioco_test: Stopped.
dpc commented 8 years ago

Thanks for reporting.

strace ./target/debug/mioco_test says:

socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 15
ioctl(15, FIOCLEX)                      = 0
setsockopt(15, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
bind(15, {sa_family=AF_INET6, sin6_port=htons(45678), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
fcntl(15, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
accept4(15, 0x7effc95feaf0, 0x7effc95feaec, SOCK_CLOEXEC) = -1 EINVAL (Invalid argument)

So it looks like mioco is working OK, and you're using it OK, but the problem is with IPv6. Are you sure :: should work and your local networking setup is OK? Does it work with loopback (::1)?

If this is a Linux box, can you provide me with outputs of ip -6 ad ls?

dpc commented 8 years ago

I completely removed mioco from the picture and I'm getting same results:

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate net2;

use std::{net,str};

const DEFAULT_LISTEN_ADDR : &'static str = "::1";
fn listend_addr() -> net::IpAddr {
    str::FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
}

fn main() {
    env_logger::init().unwrap();
    info!("Starting...");

    let addr = listend_addr();
    let builder = net2::TcpBuilder::new_v6().unwrap();
    builder.only_v6(true).unwrap();
    let addr = net::SocketAddr::new(addr.clone(), 0);
    builder.bind(&addr).unwrap();
    let listener = builder.to_tcp_listener().unwrap();
    info!("Listening on {:?}", listener.local_addr());

    let _ = listener.accept().unwrap();
    info!("Stopped.");
}
dpc commented 8 years ago

I've reported a bug in net2 crate - hopefully someone there can help.

If you're OK with it, since it does not seem mioco related, I'll close the issue here.

troplin commented 8 years ago

If I use listen() instead of to_tcp_listener() it works, I'm feeling a bit stupid now.

I didn't use listen() in the first place because TcpListener::from_listener() takes the address as second argument. This made me believe that I need to pass a TcpListener that is not yet bound (i.e. bind() not called). My original code did not include a call to bind().

So, back to mioco topic, why does from_listener() take an address as argument if the socket has to be bound already?

dpc commented 8 years ago

No worries. I'd say it's an API/documentation problem if you were mislead.

About the from_listener. Mioco is very tightly built on top of mio. The API exposed by tcp module is directly corresponding to mio::tcp.

http://rustdoc.s3-website-us-east-1.amazonaws.com/mio/master/mio/tcp/struct.TcpListener.html#method.from_listener

So mio has it's own type that builts on std::net, and mioco does the same.

I know it can be confusing, but the software is young and should probably improve documentation.

dpc commented 8 years ago

I'm not sure how to immediately improve anything so I'm closing.