jean-airoldie / libzmq-rs

A strict subset of ØMQ with an ergonomic API.
https://jean-airoldie.github.io/libzmq-rs/
Apache License 2.0
58 stars 4 forks source link

how to bind to a IPv4 socket #137

Open jeremyandrews opened 4 years ago

jeremyandrews commented 4 years ago

All attempts to bind to an address are creating an IPv6 socket instead of the desired IPv4 socket.

For example:

    let addr: TcpAddr = "0.0.0.0:1234".try_into().unwrap();
    let server = ServerBuilder::new().bind(&addr).build().unwrap();
    let bound = server.last_endpoint().unwrap();
    println!("{:?}", bound);

Results in the following output:

Tcp(TcpAddr { src: None, host: SocketAddr { interface: Ip(V6(::ffff:0.0.0.0)), port: Specified(1234) } })

Using my actual IP address instead of 0.0.0.0 has the same general problem:

Tcp(TcpAddr { src: None, host: SocketAddr { interface: Ip(V6(::ffff:10.10.200.150)), port: Specified(1234) } })

I saw some examples that specify the interface, for example:

    let addr: TcpAddr = "wlp0s20f3;10.10.200.150:1234".try_into().unwrap();
    let server = ServerBuilder::new().bind(&addr).build().unwrap();

But this results in a panic:

thread 'main' panicked at 'invalid endpoint : tcp://10.10.200.150:1234;wlp0s20f3', .cargo/registry/src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/core/raw.rs:93:17

The backtrace:

  12: std::panicking::begin_panic_fmt
             at src/libstd/panicking.rs:332
  13: libzmq::core::raw::bind
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/core/raw.rs:93
  14: libzmq::core::raw::RawSocket::bind
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/core/raw.rs:233
  15: libzmq::core::Socket::bind
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/core/mod.rs:283
  16: libzmq::core::SocketConfig::apply
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/core/mod.rs:570
  17: libzmq::socket::server::ServerConfig::apply
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/socket/server.rs:206
  18: libzmq::socket::server::ServerConfig::with_ctx
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/socket/server.rs:197
  19: libzmq::socket::server::ServerConfig::build
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/socket/server.rs:192
  20: libzmq::socket::server::ServerBuilder::build
             at src/github.com-1ecc6299db9ec823/libzmq-0.2.4/src/socket/server.rs:335

I assume I'm doing something wrong, any help would be greatly appreciated.

If helpful, the actual code where I'm trying to implement this can be viewed here: https://github.com/jeremyandrews/goose/blob/gaggle/src/manager.rs

And I'm running with the following command:

cargo run --example simple -- --manager --manager-bind-host "wlp0s20f3;10.10.200.150" --manager-bind-port 1234 --expect-workers 3 --host http://apache.fosciana/ -vv

I'm compiling on Linux in an Ubuntu-based distribution (PopOS). Here's my interfaces:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 28:7f:cf:74:1d:23 brd ff:ff:ff:ff:ff:ff
    inet 10.10.200.150/16 brd 10.10.255.255 scope global dynamic noprefixroute wlp0s20f3
       valid_lft 6743sec preferred_lft 6743sec
    inet6 fe80::1c3d:22e5:738d:2989/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
jeremyandrews commented 4 years ago

And netstat showing that indeed it's incorrectly creating an IPv6 socket:

$ netstat -an | grep 1234
tcp6       0      0 127.0.0.1:1234          :::*                    LISTEN     
jean-airoldie commented 4 years ago

Currently its not supported, but it should be straight forward to add, a PR would be most welcomed.

By default the context enables the IPv6 features which probably forces a v6 socket to be created even with a v4 address. So I'm assuming allowing the user to modify the following line would work:

https://github.com/jean-airoldie/libzmq-rs/blob/ea8eef6ce1502a464f5925640c60db6174365db9/libzmq/src/ctx.rs#L358

I think the best approach would be to add a new force_ipv4 (or a better name) method to the CtxBuilder to toggle this option.

jean-airoldie commented 4 years ago

Yeah pretty sure this would work, after reading the zmq API doc:

The ZMQ_IPV6 argument sets the IPv6 value for all sockets created in the context from this point onwards. A value of 1 means IPv6 is enabled, while 0 means the socket will use only IPv4. When IPv6 is enabled, a socket will connect to, or accept connections from, both IPv4 and IPv6 hosts.

(Taken from http://api.zeromq.org/master:zmq-ctx-set)

jeremyandrews commented 4 years ago

Ah, I see. So it is creating an IPv4 socket, it's just creating an IPv6 socket as well.

It seems my problem is different than I thought, then -- recv_msg() isn't returning anything even when a client connects to the socket (or I telnet to the socket), and thus hanging forever.

jean-airoldie commented 4 years ago

It seems my problem is different than I thought, then -- recv_msg() isn't returning anything even when a client connects to the socket (or I telnet to the socket), and thus hanging forever.

The Server does not receive a notification when a new client gets connected, only when it sends a new message.