hhromic / libe131

libE131: a lightweight C/C++ library for the E1.31 (sACN) protocol
Apache License 2.0
76 stars 19 forks source link

Multicasting on a computer with multiple network adapters #7

Closed eshkrab closed 11 months ago

eshkrab commented 5 years ago

Hello! I need to multicast sACN to a device from a computer that's connected to two networks, wifi and ethernet, where the device is only on the wifi network. Both the device and the computer are using this library for sACN. There doesn't seem to be API to select with network interface to use, and I'm happy to implement whatever's necessary myself, but I was wondering if you possibly have any tips/ideas on how to go about doing that.

Thank you!

hhromic commented 5 years ago

hi @eshkrab ! I'm glad to see the library is being useful to you.

Regarding the issue you are seeing, indeed I didn't think of multicast interface selection in the API originally. This is a requested feature, even in my NodeJS port of the library, however I haven't had time to see it myself. If you are willing to create a PR to address this issue, I'm more than happy to review it and get it in shape to merge it. I highly appreciate the testing scenario you are proposing!

For a starting point, I would like to understand your exact problem:

  1. You have computer A (with two interfaces, wired and wireless) and device B (with one wireless interface).
  2. You join device B to a multicast group using the function e131_multicast_join() configured to some universe.
  3. From computer A you try to send packets to a multicast destination using the function e131_multicast_dest(), configured to the universe of B. Please note that the computer A doesn't need to join the multicast universe, sending to a multicast address should be enough.
  4. The packets from A don't reach device B because they are transmitted to the wired network instead of wireless.

Is this the case you are experiencing?

hhromic commented 5 years ago

Note: it might be necessary to implement a new function to set the the IP_MULTICAST_IF option in the outgoing datagram socket. In the same vein and for completeness, it might be necessary to add a new interface parameter to e131_multicast_join() for when setting the IP_ADD_MEMBERSHIP socket option. Ref: https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html

hhromic commented 5 years ago

Hello again, it turned out this was relatively simple to implement :)

Please check the multicast branch of this repository. Can you test it using your setup? To select an interface for multicast, you can use ip link in your system to find its index. For example:

$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp1s0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether ((anonymised)) brd ff:ff:ff:ff:ff:ff
3: enp2s0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether ((anonymised)) brd ff:ff:ff:ff:ff:ff

Then you can use the shown numeric index (on the left side) with the e131_multicast_join() (for a server sACN application) or the new e131_multicast_iface() (for a client sACN application). Check the updated examples for their usage.

An index of 0 means to use an interface chosen by the system (the old behaviour).

eshkrab commented 5 years ago

Hello!

Thank you so very much! I ended up implementing a similar function right before you posted this and I'm getting the same result from both. Currently, whichever function I use, the data is streamed correctly for a long while but then the device stops receiving it. Considering I still see the packets being streamed, I'd call this a wonderful success and I'm sure my new problem is rooted elsewhere.

Thanks again for the help and such quick implementation, and here's mine just for kicks:

int e131_bind_interface(int sockfd, const char *interface) {
  struct ifaddrs* pList = NULL;
  struct ifaddrs* pAdapter = NULL;
  struct ifaddrs* pAdapterFound = NULL;
  int bindresult = -1;

  int result = getifaddrs(&pList);

  if (result < 0)
    return -1;

  pAdapter = pList;
  printf(" Trying to bind to :%s\n", interface);
  printf("Interfaces\n");
  while (pAdapter) {
    if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) && (AF_INET == pAdapter->ifa_addr->sa_family)) {
    //if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL)) {
      printf("%s\n",pAdapter->ifa_name);
      if (strcmp(pAdapter->ifa_name, interface) == 0) {
        pAdapterFound = pAdapter;
        break;
      }
    }
    pAdapter = pAdapter->ifa_next;
  }

  if (pAdapterFound != NULL) {
    //assuming AF_INT
    e131_addr_t addr;
    bindresult = bind(sockfd, pAdapterFound->ifa_addr, sizeof(addr));
  }

  freeifaddrs(pList);
  return bindresult;
}
hhromic commented 5 years ago

Um that's weird to happen. Multicasting can be a bit tricky, specially over wireless. Some things to try:

Can you confirm you used my code in the multicast branch and that also fails after a while? Using bind is relevant for receiving sockets, not for sending. My code uses a sockopt instead.

hhromic commented 5 years ago

Hi @eshkrab , any updates on this issue? Did you try with the code I supplied in the multicast branch? I would like to check if we need more debugging or this can be merged. Thanks for your help testing!

eshkrab commented 5 years ago

Hey @hhromic,

I had to temporarily step away from that specific part of the project for a little bit but the problem only occurs when I use the router. Using a switch or direct connection works perfectly and I am definitely able to send packets over the right interface. The receiving device is embedded but works with multicasting from a different implementation (Touchdesigner).

I haven't tried a different router or unicasting yet and I'll get post when I get back to working on this but I'm pretty confident it's most likely a router issue and not the code.

hhromic commented 5 years ago

Thanks for the heads-up! I will test once more to ensure transmission is selectively directed to different interfaces and the same for receiving, then I will merge the code for future multi-interface users. Thanks for the help and hope this library is useful for you!

hhromic commented 11 months ago

I now implemented an API for this in cfa0da7be0f770dfa2c1f021bf657d653db58d61. Will be available in the next release.