Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zmq_udp: need ability to specify bind address separately from multicast address for multi-homed hosts #2212

Closed
Bklyn opened this issue Nov 15, 2016 · 8 comments

Comments

@Bklyn
Copy link
Contributor

Bklyn commented Nov 15, 2016

The ZMP_RADIO and ZMP_DISH socket types look like great addition to ZMQ. Thanks!

When receiving multicast data on multi-homed hosts, some users will require the ability to select which interface is used for a given multicast stream, as the data may not transit on the default interface.

I'd suggest a syntax perhaps like udp://mcaddr[@bindaddr]:port (where [] indicates the @bindaddr is optional not that it appears in square brackets)

So, in other words, this code on lines 114-116 from udp_socket.cpp would need to change:

    109     //  If a should bind and not a multicast, the dest address
    110     //  is actually the bind address
    111     if (bind_ && !is_mutlicast)
    112         bind_address = dest_address;
    113     else {
    114         bind_address.sin_family = AF_INET;
    115         bind_address.sin_port = htons (port);
    116         bind_address.sin_addr.s_addr = htons (INADDR_ANY);
    117     }

Also, I believe all of these htons should be htonl (all from udp_socket.cpp):

83:        dest_address.sin_addr.s_addr = htons (INADDR_ANY);
103:    iface.s_addr = htons (INADDR_ANY);
116:        bind_address.sin_addr.s_addr = htons (INADDR_ANY);

When configuring many hosts it is also useful to be able to specify the bind address by its interface name or using address/mask (i.e. 192.168.2.0/24). These would require the use of additional OS-specific APIs (i.e. getifaddrs(3)), but this is very powerful and will make configuration much more manageable.

@bluca
Copy link
Member

bluca commented Nov 15, 2016

Looks like a good idea, just a note: TCP sockets already support passing an address to bind to with the format: tcp://127.0.0.1:5564;127.0.0.1:5562 with the first tuple being the source and the second the destination.

This sounds similar, right? What about using the same format for consistency?

@Bklyn
Copy link
Contributor Author

Bklyn commented Nov 15, 2016

I was not aware of that syntax. Consistency makes perfect sense.

I think ultimately the code in tcp_address::resolve_interface and its delegate resolve_nic_name should be refactored into a separate class so they can be re-used in udp_address. Then any additional magic like ADDR/MASK syntax can be the province of (I think) resolve_nic_name.

@Bklyn
Copy link
Contributor Author

Bklyn commented Jun 7, 2017

I started refactoring code to move shared logic of address parsing and representation into a base ip_address class and letting tcp_address and udp_address inherit from or re-use it, but the interfaces of these two classes are quite different. Its a bit of a mess!

@simias
Copy link
Contributor

simias commented May 3, 2018

Oh, looks like we had the same idea one year apart. The factored parsing code got merged in #3070 and #3075 ports the UDP API to the shared code. Once it's merged adding bind address specification is going to be trivial.

I agree that the semicolon syntax makes the most sense, especially since that's what PGM does:

zmq_connect(socket, "pgm://192.168.1.1;239.192.1.1:5555");

I was wondering however if we should make it mandatory for multicast binding (a breaking change, but not critical since it's DRAFT) or have udp://mcast_addr:port implicitly be equivalent to udp://*;mcast_addr:port. I personally prefer the most explicit approach since it's not immediately obvious that an IP is multicast, so for instance if you consider:

socket_a.bind("udp://223.0.0.1:5555");
socket_b.bind("udp://224.0.0.1:5555");

These two calls look similar but the first one binds the local interface "223.0.0.1" on port 5555 while the second binds INADDR_ANY on port 5555 while subscribing to the multicast network 224.0.0.1. I think this overloaded syntax is a bit awkward. Meanwhile this should be clear:

socket_a.bind("udp://223.0.0.1:5555");
socket_b.bind("udp://*;224.0.0.1:5555");

@bluca
Copy link
Member

bluca commented May 3, 2018

I would suggest to do the same as the other multicast transport do w.r.t. default binding, so that there are the least surprises

@simias
Copy link
Contributor

simias commented May 3, 2018

Agreed, I need to figure out what PGM does.

@simias
Copy link
Contributor

simias commented May 3, 2018

So, regarding pgm:

  • epgm://239.192.1.1:5555 is valid and binds ANY

  • epgm://*;239.192.1.1:5555 is rejected

I guess the current "implicit multicast" format should be kept then, although as a counterpoint I could say that PGM so there's no really room for confusion, UDP has no such limitation.

@bluca
Copy link
Member

bluca commented May 3, 2018

Let's keep them in sync for now - it's still in draft stage so we can eventually change if there are complaints

simias added a commit to simias/libzmq that referenced this issue May 4, 2018
…dress

for multicast

Solution: augment the UDP URL syntax to accept an interface specifier with a
syntax similar to the PGM urls.

Fixes zeromq#2212
@simias simias mentioned this issue May 4, 2018
simias added a commit to simias/libzmq that referenced this issue May 4, 2018
…dress

for multicast

Solution: augment the UDP URL syntax to accept an interface specifier with a
syntax similar to the PGM urls.

Fixes zeromq#2212
@bluca bluca closed this as completed in 746d4a0 May 4, 2018
MohammadAlTurany pushed a commit to FairRootGroup/libzmq that referenced this issue Jan 28, 2019
…dress

for multicast

Solution: augment the UDP URL syntax to accept an interface specifier with a
syntax similar to the PGM urls.

Fixes zeromq#2212
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants