• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/omcproxy/src/client.c

  1 /*
  2  * Author: Steven Barth <steven at midlink.org>
  3  *
  4  * Copyright 2015 Deutsche Telekom AG
  5  *
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  *
 10  *  http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing permissions and
 16  * limitations under the License.
 17  *
 18  */
 19 
 20 #include <errno.h>
 21 #include <string.h>
 22 #include <unistd.h>
 23 #include <alloca.h>
 24 
 25 #include <arpa/inet.h>
 26 #include <netinet/in.h>
 27 #include <linux/mroute6.h>
 28 #include <libubox/list.h>
 29 #include <libubox/avl.h>
 30 
 31 #include "client.h"
 32 
 33 
 34 // Add / update / remove a client entry for a multicast group
 35 int client_set(struct client *client, const struct in6_addr *group,
 36                 bool include, const struct in6_addr sources[], size_t cnt)
 37 {
 38         int family = (IN6_IS_ADDR_V4MAPPED(group)) ? AF_INET : AF_INET6;
 39         int sol = (family == AF_INET) ? SOL_IP : SOL_IPV6;
 40         char addrbuf[INET6_ADDRSTRLEN];
 41         size_t len = sizeof(struct group_filter) + cnt * sizeof(struct sockaddr_storage);
 42         struct {
 43                 struct group_filter f;
 44                 struct sockaddr_storage s[];
 45         } *filter = alloca(len);
 46         struct sockaddr_in *in_addr = (struct sockaddr_in*)&filter->f.gf_group;
 47         struct sockaddr_in6 *in6_addr = (struct sockaddr_in6*)&filter->f.gf_group;
 48 
 49         inet_ntop(AF_INET6, group, addrbuf, sizeof(addrbuf));
 50         L_DEBUG("%s: %s on %d => %s (+%d sources)", __FUNCTION__, addrbuf,
 51                         client->ifindex, (include) ? "include" : "exclude", (int)cnt);
 52 
 53         // Construct MSFILTER for outgoing IGMP / MLD
 54         memset(filter, 0, len);
 55         filter->f.gf_interface = client->ifindex;
 56         filter->f.gf_fmode = include ? MCAST_INCLUDE : MCAST_EXCLUDE;
 57         filter->f.gf_group.ss_family = family;
 58         filter->f.gf_numsrc = cnt;
 59 
 60         if (family == AF_INET)
 61                 client_unmap(&in_addr->sin_addr, group);
 62         else
 63                 in6_addr->sin6_addr = *group;
 64 
 65         for (size_t i = 0; i < cnt; ++i) {
 66                 filter->f.gf_slist[i].ss_family = family;
 67 
 68                 in_addr = (struct sockaddr_in*)&filter->f.gf_slist[i];
 69                 in6_addr = (struct sockaddr_in6*)&filter->f.gf_slist[i];
 70 
 71                 if (family == AF_INET)
 72                         client_unmap(&in_addr->sin_addr, &sources[i]);
 73                 else
 74                         in6_addr->sin6_addr = sources[i];
 75         }
 76 
 77         int fd = (family == AF_INET) ? client->igmp_fd : client->mld_fd;
 78         setsockopt(fd, sol, MCAST_LEAVE_GROUP, filter, sizeof(struct group_req));
 79         if (!include || cnt > 0) {
 80                 if (setsockopt(fd, sol, MCAST_JOIN_GROUP, filter, sizeof(struct group_req))
 81                                 && family == AF_INET && errno == ENOBUFS) {
 82                         L_WARN("proxy: kernel denied joining multicast group. check igmp_max_memberships?");
 83                         return -errno;
 84                 }
 85 
 86                 if (setsockopt(fd, sol, MCAST_MSFILTER, filter, len))
 87                         return -errno;
 88         }
 89         return 0;
 90 }
 91 
 92 // Initialize client-instance
 93 int client_init(struct client *client, int ifindex)
 94 {
 95         client->igmp_fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 96         if (client->igmp_fd < 0)
 97                 return -errno;
 98 
 99         client->mld_fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
100         if (client->mld_fd < 0)
101                 return -errno;
102 
103         client->ifindex = ifindex;
104         return 0;
105 }
106 
107 // Cleanup client-instance
108 void client_deinit(struct client *client)
109 {
110         if (client->ifindex) {
111                 close(client->igmp_fd);
112                 close(client->mld_fd);
113                 client->igmp_fd = -1;
114                 client->mld_fd = -1;
115                 client->ifindex = 0;
116         }
117 }
118 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt