]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - udp_recv.c
Simplify client_open().
[paraslash.git] / udp_recv.c
index ccd769b0e6e1d36b996b87874f09190f5d2fbb7e..9ea35d8d53ed2db68a54bfd1bc5527866d4f3061 100644 (file)
@@ -221,24 +221,40 @@ static void *udp_recv_parse_config(int argc, char **argv)
  * Perform AF-independent joining of multicast receive addresses.
  *
  * \param fd   Bound socket descriptor.
+ * \param iface        The receiving multicast interface, or NULL for the default.
  *
  * \return Zero if okay, negative on error.
  */
-static int mcast_receiver_setup(int fd)
+static int mcast_receiver_setup(int fd, const char *iface)
 {
        struct sockaddr_storage ss;
        socklen_t sslen = sizeof(ss);
+       int id = iface == NULL ? 0 : if_nametoindex(iface);
 
        if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0)
                goto err;
 
+       if (iface != NULL && id == 0)
+               PARA_WARNING_LOG("could not resolve interface %s, using default", iface);
+
        switch (ss.ss_family) {
        case AF_INET:
                if (IN_MULTICAST(htonl(((struct sockaddr_in *)&ss)->sin_addr.s_addr))) {
+#ifdef HAVE_IP_MREQN
+                       struct ip_mreqn m4;
+
+                       m4.imr_address.s_addr   = INADDR_ANY;
+                       m4.imr_ifindex          = id;
+#else
                        struct ip_mreq m4;
 
-                       memset(&m4, 0, sizeof(m4));
-                       m4.imr_multiaddr = ((struct sockaddr_in *)&ss)->sin_addr;
+                       m4.imr_interface.s_addr = INADDR_ANY;
+                       if (id != 0)
+                               PARA_ERROR_LOG("Setting IPv4 receiver mcast interface not supported.");
+
+#endif
+                       m4.imr_multiaddr        = ((struct sockaddr_in *)&ss)->sin_addr;
+
                        if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &m4, sizeof(m4)) < 0)
                                break;
                }
@@ -249,6 +265,7 @@ static int mcast_receiver_setup(int fd)
 
                        memset(&m6, 0, sizeof(m6));
                        memcpy(&m6.ipv6mr_multiaddr, &((struct sockaddr_in6 *)&ss)->sin6_addr, 16);
+                       m6.ipv6mr_interface = id;
                        if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &m6, sizeof(m6)) < 0)
                                break;
                }
@@ -265,6 +282,7 @@ static int udp_recv_open(struct receiver_node *rn)
 {
        struct private_udp_recv_data *purd;
        struct udp_recv_args_info *c = rn->conf;
+       char  *iface = c->iface_given ? c->iface_arg : NULL;
        int ret;
 
        rn->buf = para_calloc(UDP_RECV_CHUNK_SIZE);
@@ -276,7 +294,7 @@ static int udp_recv_open(struct receiver_node *rn)
                goto err;
        purd->fd = ret;
 
-       ret = mcast_receiver_setup(purd->fd);
+       ret = mcast_receiver_setup(purd->fd, iface);
        if (ret < 0) {
                close(purd->fd);
                return ret;