1f08c3bdfSopenharmony_ci/******************************************************************************/ 2f08c3bdfSopenharmony_ci/* */ 3f08c3bdfSopenharmony_ci/* Copyright (c) International Business Machines Corp., 2006 */ 4f08c3bdfSopenharmony_ci/* */ 5f08c3bdfSopenharmony_ci/* This program is free software; you can redistribute it and/or modify */ 6f08c3bdfSopenharmony_ci/* it under the terms of the GNU General Public License as published by */ 7f08c3bdfSopenharmony_ci/* the Free Software Foundation; either version 2 of the License, or */ 8f08c3bdfSopenharmony_ci/* (at your option) any later version. */ 9f08c3bdfSopenharmony_ci/* */ 10f08c3bdfSopenharmony_ci/* This program is distributed in the hope that it will be useful, */ 11f08c3bdfSopenharmony_ci/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12f08c3bdfSopenharmony_ci/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13f08c3bdfSopenharmony_ci/* the GNU General Public License for more details. */ 14f08c3bdfSopenharmony_ci/* */ 15f08c3bdfSopenharmony_ci/* You should have received a copy of the GNU General Public License */ 16f08c3bdfSopenharmony_ci/* along with this program; if not, write to the Free Software */ 17f08c3bdfSopenharmony_ci/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18f08c3bdfSopenharmony_ci/* */ 19f08c3bdfSopenharmony_ci/******************************************************************************/ 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_ci/* 22f08c3bdfSopenharmony_ci * File: 23f08c3bdfSopenharmony_ci * ns-mcast_join.c 24f08c3bdfSopenharmony_ci * 25f08c3bdfSopenharmony_ci * Description: 26f08c3bdfSopenharmony_ci * This is an assistant tool to join multicast groups 27f08c3bdfSopenharmony_ci * 28f08c3bdfSopenharmony_ci * Author: 29f08c3bdfSopenharmony_ci * Mitsuru Chinen <mitch@jp.ibm.com> 30f08c3bdfSopenharmony_ci * 31f08c3bdfSopenharmony_ci * History: 32f08c3bdfSopenharmony_ci * May 1 2006 - Created (Mitsuru Chinen) 33f08c3bdfSopenharmony_ci *---------------------------------------------------------------------------*/ 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci/* 36f08c3bdfSopenharmony_ci * Header Files 37f08c3bdfSopenharmony_ci */ 38f08c3bdfSopenharmony_ci#include <netinet/in.h> 39f08c3bdfSopenharmony_ci#include <stdio.h> 40f08c3bdfSopenharmony_ci#include <stdlib.h> 41f08c3bdfSopenharmony_ci#include <string.h> 42f08c3bdfSopenharmony_ci#include <errno.h> 43f08c3bdfSopenharmony_ci#include <netdb.h> 44f08c3bdfSopenharmony_ci#include <signal.h> 45f08c3bdfSopenharmony_ci#include <time.h> 46f08c3bdfSopenharmony_ci#include <unistd.h> 47f08c3bdfSopenharmony_ci#include <net/if.h> 48f08c3bdfSopenharmony_ci#include <sys/ioctl.h> 49f08c3bdfSopenharmony_ci#include <sys/socket.h> 50f08c3bdfSopenharmony_ci#include <sys/types.h> 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci#include "ns-mcast.h" 53f08c3bdfSopenharmony_ci#include "ns-traffic.h" 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci#define ADDR_STR_MAXSIZE 80 56f08c3bdfSopenharmony_ci#define OPEN_SOCK_MIN 6 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci/* 59f08c3bdfSopenharmony_ci * Gloval variables 60f08c3bdfSopenharmony_ci */ 61f08c3bdfSopenharmony_cichar *program_name; /* program name */ 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_cistruct sigaction handler; /* Behavior for a signal */ 64f08c3bdfSopenharmony_civolatile int catch_sighup; /* When catch the SIGHUP, set to non-zero */ 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_cisa_family_t family; /* protocol family */ 67f08c3bdfSopenharmony_ciint level; /* protocol levels */ 68f08c3bdfSopenharmony_ciuint32_t ifindex; /* interface index where listening multicast */ 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_cisize_t num_group; /* Number of the groups */ 71f08c3bdfSopenharmony_cichar *mcast_prefix; /* Prefix of the multicast address */ 72f08c3bdfSopenharmony_ciuint32_t fmode; /* filter mode */ 73f08c3bdfSopenharmony_cichar *saddrs; /* comma separated array of source addresses */ 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_ciint is_multi_socket; /* If non-zero, multi-socket mode */ 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_cisize_t join_leave_times; /* If non-zero, join-leave mode */ 78f08c3bdfSopenharmony_ci /* the value is times of join/leave */ 79f08c3bdfSopenharmony_cichar *mcast_addr; /* multicast address to join/leave */ 80f08c3bdfSopenharmony_cistruct timespec interval; /* interval for join-leave mode */ 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_ci/* 83f08c3bdfSopenharmony_ci * Function: usage() 84f08c3bdfSopenharmony_ci * 85f08c3bdfSopenharmony_ci * Descripton: 86f08c3bdfSopenharmony_ci * Print the usage of this program. Then, terminate this program with 87f08c3bdfSopenharmony_ci * the specified exit value. 88f08c3bdfSopenharmony_ci * 89f08c3bdfSopenharmony_ci * Argument: 90f08c3bdfSopenharmony_ci * exit_value: exit value 91f08c3bdfSopenharmony_ci * 92f08c3bdfSopenharmony_ci * Return value: 93f08c3bdfSopenharmony_ci * This function does not return. 94f08c3bdfSopenharmony_ci */ 95f08c3bdfSopenharmony_civoid usage(char *program_name, int exit_value) 96f08c3bdfSopenharmony_ci{ 97f08c3bdfSopenharmony_ci FILE *stream = stdout; /* stream where the usage is output */ 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci if (exit_value == EXIT_FAILURE) 100f08c3bdfSopenharmony_ci stream = stderr; 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci fprintf(stream, "%s [OPTION]\n" 103f08c3bdfSopenharmony_ci "\t-f num\tprotocol family\n" 104f08c3bdfSopenharmony_ci "\t\t 4 : IPv4\n" 105f08c3bdfSopenharmony_ci "\t\t 6 : IPv6\n" 106f08c3bdfSopenharmony_ci "\t-I ifname\tname of listening interface\n" 107f08c3bdfSopenharmony_ci "\t-a addr\tmulticast address for join-leave mode\n" 108f08c3bdfSopenharmony_ci "\t-F mode\tfilter mode\n" 109f08c3bdfSopenharmony_ci "\t\t include : include mode\n" 110f08c3bdfSopenharmony_ci "\t\t exclude : exclude mode\n" 111f08c3bdfSopenharmony_ci "\t-s addrs\tcomma separated array of Source Addresses\n" 112f08c3bdfSopenharmony_ci "\t-d\t\tdisplay debug informations\n" 113f08c3bdfSopenharmony_ci "\t-h\t\tdisplay this usage\n" 114f08c3bdfSopenharmony_ci "\n" 115f08c3bdfSopenharmony_ci "\t[multiple join mode]\n" 116f08c3bdfSopenharmony_ci "\t -n num\tnumber of multicast address\n" 117f08c3bdfSopenharmony_ci "\t -p prefix\tprefix of the multicast address\n" 118f08c3bdfSopenharmony_ci "\t -m\t\tmultiple socket mode\n" 119f08c3bdfSopenharmony_ci "\t\t 4 : a.b(.x.y) - x y is defined automatically\n" 120f08c3bdfSopenharmony_ci "\t\t 6 : {prefix}::z - z is defined automatically\n" 121f08c3bdfSopenharmony_ci "\n" 122f08c3bdfSopenharmony_ci "\t[join-leave mode]\n" 123f08c3bdfSopenharmony_ci "\t -l times of join/leave\n" 124f08c3bdfSopenharmony_ci "\t -i nsec\tinterval for join-leave mode\n", program_name); 125f08c3bdfSopenharmony_ci exit(exit_value); 126f08c3bdfSopenharmony_ci} 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci/* 129f08c3bdfSopenharmony_ci * Function: set_signal_flag() 130f08c3bdfSopenharmony_ci * 131f08c3bdfSopenharmony_ci * Description: 132f08c3bdfSopenharmony_ci * This function sets global variables accordig to signal 133f08c3bdfSopenharmony_ci * 134f08c3bdfSopenharmony_ci * Argument: 135f08c3bdfSopenharmony_ci * type: type of signal 136f08c3bdfSopenharmony_ci * 137f08c3bdfSopenharmony_ci * Return value: 138f08c3bdfSopenharmony_ci * None 139f08c3bdfSopenharmony_ci */ 140f08c3bdfSopenharmony_civoid set_signal_flag(int type) 141f08c3bdfSopenharmony_ci{ 142f08c3bdfSopenharmony_ci if (debug) 143f08c3bdfSopenharmony_ci fprintf(stderr, "Catch signal. type is %d\n", type); 144f08c3bdfSopenharmony_ci 145f08c3bdfSopenharmony_ci switch (type) { 146f08c3bdfSopenharmony_ci case SIGHUP: 147f08c3bdfSopenharmony_ci catch_sighup = 1; 148f08c3bdfSopenharmony_ci handler.sa_handler = SIG_IGN; 149f08c3bdfSopenharmony_ci if (sigaction(type, &handler, NULL) < 0) 150f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 151f08c3bdfSopenharmony_ci break; 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci default: 154f08c3bdfSopenharmony_ci fprintf(stderr, "Unexpected signal (%d) is caught\n", type); 155f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 156f08c3bdfSopenharmony_ci } 157f08c3bdfSopenharmony_ci} 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci/* 160f08c3bdfSopenharmony_ci * Function: parse_options() 161f08c3bdfSopenharmony_ci * 162f08c3bdfSopenharmony_ci * Description: 163f08c3bdfSopenharmony_ci * This function parse the options 164f08c3bdfSopenharmony_ci * 165f08c3bdfSopenharmony_ci * Argument: 166f08c3bdfSopenharmony_ci * argc: the number of argument 167f08c3bdfSopenharmony_ci * argv: arguments 168f08c3bdfSopenharmony_ci * 169f08c3bdfSopenharmony_ci * Return value: 170f08c3bdfSopenharmony_ci * None 171f08c3bdfSopenharmony_ci */ 172f08c3bdfSopenharmony_civoid parse_options(int argc, char *argv[]) 173f08c3bdfSopenharmony_ci{ 174f08c3bdfSopenharmony_ci int optc; /* option */ 175f08c3bdfSopenharmony_ci unsigned long opt_ul; /* option value in unsigned long */ 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_ci while ((optc = getopt(argc, argv, "f:I:p:F:s:n:ml:i:a:dh")) != EOF) { 178f08c3bdfSopenharmony_ci switch (optc) { 179f08c3bdfSopenharmony_ci case 'f': 180f08c3bdfSopenharmony_ci if (optarg[0] == '4') { 181f08c3bdfSopenharmony_ci family = PF_INET; /* IPv4 */ 182f08c3bdfSopenharmony_ci level = IPPROTO_IP; 183f08c3bdfSopenharmony_ci } else if (optarg[0] == '6') { 184f08c3bdfSopenharmony_ci family = PF_INET6; /* IPv6 */ 185f08c3bdfSopenharmony_ci level = IPPROTO_IPV6; 186f08c3bdfSopenharmony_ci } else { 187f08c3bdfSopenharmony_ci fprintf(stderr, 188f08c3bdfSopenharmony_ci "protocol family should be 4 or 6.\n"); 189f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 190f08c3bdfSopenharmony_ci } 191f08c3bdfSopenharmony_ci break; 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci case 'I': 194f08c3bdfSopenharmony_ci ifindex = if_nametoindex(optarg); 195f08c3bdfSopenharmony_ci if (ifindex == 0) { 196f08c3bdfSopenharmony_ci fprintf(stderr, 197f08c3bdfSopenharmony_ci "specified interface is incorrect\n"); 198f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 199f08c3bdfSopenharmony_ci } 200f08c3bdfSopenharmony_ci break; 201f08c3bdfSopenharmony_ci 202f08c3bdfSopenharmony_ci case 'p': 203f08c3bdfSopenharmony_ci mcast_prefix = strdup(optarg); 204f08c3bdfSopenharmony_ci break; 205f08c3bdfSopenharmony_ci 206f08c3bdfSopenharmony_ci case 'F': 207f08c3bdfSopenharmony_ci if (strncmp(optarg, "exclude", 8) == 0) 208f08c3bdfSopenharmony_ci fmode = MCAST_EXCLUDE; 209f08c3bdfSopenharmony_ci else if (strncmp(optarg, "include", 8) == 0) 210f08c3bdfSopenharmony_ci fmode = MCAST_INCLUDE; 211f08c3bdfSopenharmony_ci else { 212f08c3bdfSopenharmony_ci fprintf(stderr, 213f08c3bdfSopenharmony_ci "specified filter mode is incorrect\n"); 214f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 215f08c3bdfSopenharmony_ci } 216f08c3bdfSopenharmony_ci break; 217f08c3bdfSopenharmony_ci 218f08c3bdfSopenharmony_ci case 'l': 219f08c3bdfSopenharmony_ci join_leave_times = strtoul(optarg, NULL, 0); 220f08c3bdfSopenharmony_ci break; 221f08c3bdfSopenharmony_ci 222f08c3bdfSopenharmony_ci case 'i': 223f08c3bdfSopenharmony_ci if (strtotimespec(optarg, &interval)) { 224f08c3bdfSopenharmony_ci fprintf(stderr, 225f08c3bdfSopenharmony_ci "Interval is something wrong\n"); 226f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 227f08c3bdfSopenharmony_ci } 228f08c3bdfSopenharmony_ci break; 229f08c3bdfSopenharmony_ci 230f08c3bdfSopenharmony_ci case 'a': 231f08c3bdfSopenharmony_ci mcast_addr = strdup(optarg); 232f08c3bdfSopenharmony_ci break; 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_ci case 's': 235f08c3bdfSopenharmony_ci saddrs = strdup(optarg); 236f08c3bdfSopenharmony_ci if (saddrs == NULL) 237f08c3bdfSopenharmony_ci fatal_error("strdup()"); 238f08c3bdfSopenharmony_ci break; 239f08c3bdfSopenharmony_ci 240f08c3bdfSopenharmony_ci case 'n': 241f08c3bdfSopenharmony_ci opt_ul = strtoul(optarg, NULL, 0); 242f08c3bdfSopenharmony_ci if (opt_ul > 255 * 254) { 243f08c3bdfSopenharmony_ci fprintf(stderr, 244f08c3bdfSopenharmony_ci "The number of group shoud be less than %u\n", 245f08c3bdfSopenharmony_ci 255 * 254); 246f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 247f08c3bdfSopenharmony_ci } 248f08c3bdfSopenharmony_ci num_group = opt_ul; 249f08c3bdfSopenharmony_ci break; 250f08c3bdfSopenharmony_ci 251f08c3bdfSopenharmony_ci case 'm': 252f08c3bdfSopenharmony_ci is_multi_socket = 1; 253f08c3bdfSopenharmony_ci break; 254f08c3bdfSopenharmony_ci 255f08c3bdfSopenharmony_ci case 'd': 256f08c3bdfSopenharmony_ci debug = 1; 257f08c3bdfSopenharmony_ci break; 258f08c3bdfSopenharmony_ci 259f08c3bdfSopenharmony_ci case 'h': 260f08c3bdfSopenharmony_ci usage(program_name, EXIT_SUCCESS); 261f08c3bdfSopenharmony_ci break; 262f08c3bdfSopenharmony_ci 263f08c3bdfSopenharmony_ci default: 264f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 265f08c3bdfSopenharmony_ci } 266f08c3bdfSopenharmony_ci } 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci if (ifindex == 0) { 269f08c3bdfSopenharmony_ci fprintf(stderr, "specified interface seems incorrect\n"); 270f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 271f08c3bdfSopenharmony_ci } 272f08c3bdfSopenharmony_ci 273f08c3bdfSopenharmony_ci if (saddrs) { 274f08c3bdfSopenharmony_ci if (fmode != MCAST_EXCLUDE && fmode != MCAST_INCLUDE) { 275f08c3bdfSopenharmony_ci fprintf(stderr, "filter mode is wrong\n"); 276f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 277f08c3bdfSopenharmony_ci } 278f08c3bdfSopenharmony_ci } 279f08c3bdfSopenharmony_ci} 280f08c3bdfSopenharmony_ci 281f08c3bdfSopenharmony_ci/* 282f08c3bdfSopenharmony_ci * Function: join_group() 283f08c3bdfSopenharmony_ci * 284f08c3bdfSopenharmony_ci * Description: 285f08c3bdfSopenharmony_ci * This function make sockets to join the groups 286f08c3bdfSopenharmony_ci * 287f08c3bdfSopenharmony_ci * Return value: 288f08c3bdfSopenharmony_ci * None 289f08c3bdfSopenharmony_ci */ 290f08c3bdfSopenharmony_civoid join_group(void) 291f08c3bdfSopenharmony_ci{ 292f08c3bdfSopenharmony_ci int sd; /* socket file descriptor */ 293f08c3bdfSopenharmony_ci int *sock_array; /* socket descriptor array */ 294f08c3bdfSopenharmony_ci size_t num_sock; /* number of the socket */ 295f08c3bdfSopenharmony_ci char maddr[ADDR_STR_MAXSIZE]; /* multicast address in string */ 296f08c3bdfSopenharmony_ci int idx; 297f08c3bdfSopenharmony_ci struct addrinfo *maddr_info; 298f08c3bdfSopenharmony_ci struct group_req *grp_info; 299f08c3bdfSopenharmony_ci struct group_filter *gsf; 300f08c3bdfSopenharmony_ci 301f08c3bdfSopenharmony_ci if (!is_multi_socket) 302f08c3bdfSopenharmony_ci num_sock = 1; 303f08c3bdfSopenharmony_ci else 304f08c3bdfSopenharmony_ci num_sock = num_group; 305f08c3bdfSopenharmony_ci 306f08c3bdfSopenharmony_ci /* Allocate socket array */ 307f08c3bdfSopenharmony_ci sock_array = calloc(num_sock, sizeof(int)); 308f08c3bdfSopenharmony_ci if (sock_array == NULL) 309f08c3bdfSopenharmony_ci fatal_error("calloc()"); 310f08c3bdfSopenharmony_ci 311f08c3bdfSopenharmony_ci for (idx = 0; idx < num_sock; idx++) { 312f08c3bdfSopenharmony_ci sock_array[idx] = socket(family, SOCK_DGRAM, IPPROTO_UDP); 313f08c3bdfSopenharmony_ci 314f08c3bdfSopenharmony_ci if (sock_array[idx] < 0) { 315f08c3bdfSopenharmony_ci if (idx < OPEN_SOCK_MIN) 316f08c3bdfSopenharmony_ci fatal_error("socket()"); 317f08c3bdfSopenharmony_ci else { 318f08c3bdfSopenharmony_ci int j; /* Closed some sockets for daemon() */ 319f08c3bdfSopenharmony_ci for (j = 0; j < OPEN_SOCK_MIN; j++) 320f08c3bdfSopenharmony_ci close(sock_array[idx - 1 - j]); 321f08c3bdfSopenharmony_ci num_group = idx - j - 1; 322f08c3bdfSopenharmony_ci break; 323f08c3bdfSopenharmony_ci } 324f08c3bdfSopenharmony_ci } 325f08c3bdfSopenharmony_ci 326f08c3bdfSopenharmony_ci if (!is_multi_socket) 327f08c3bdfSopenharmony_ci maximize_sockbuf(sock_array[idx]); 328f08c3bdfSopenharmony_ci } 329f08c3bdfSopenharmony_ci 330f08c3bdfSopenharmony_ci sd = sock_array[0]; 331f08c3bdfSopenharmony_ci if (mcast_addr) { 332f08c3bdfSopenharmony_ci strncpy(maddr, mcast_addr, ADDR_STR_MAXSIZE); 333f08c3bdfSopenharmony_ci if (debug) 334f08c3bdfSopenharmony_ci fprintf(stderr, "multicast address is %s\n", maddr); 335f08c3bdfSopenharmony_ci } 336f08c3bdfSopenharmony_ci 337f08c3bdfSopenharmony_ci for (idx = 0; idx < num_group; idx++) { 338f08c3bdfSopenharmony_ci if (is_multi_socket) 339f08c3bdfSopenharmony_ci sd = sock_array[idx]; 340f08c3bdfSopenharmony_ci 341f08c3bdfSopenharmony_ci if (debug) 342f08c3bdfSopenharmony_ci fprintf(stderr, "socket: %d\n", sd); 343f08c3bdfSopenharmony_ci 344f08c3bdfSopenharmony_ci if (mcast_prefix) { 345f08c3bdfSopenharmony_ci switch (family) { 346f08c3bdfSopenharmony_ci case PF_INET: 347f08c3bdfSopenharmony_ci { 348f08c3bdfSopenharmony_ci unsigned int x, y; 349f08c3bdfSopenharmony_ci x = idx / 254; 350f08c3bdfSopenharmony_ci y = idx % 254 + 1; 351f08c3bdfSopenharmony_ci sprintf(maddr, "%s.%d.%d", mcast_prefix, 352f08c3bdfSopenharmony_ci x, y); 353f08c3bdfSopenharmony_ci } 354f08c3bdfSopenharmony_ci break; 355f08c3bdfSopenharmony_ci 356f08c3bdfSopenharmony_ci case PF_INET6: 357f08c3bdfSopenharmony_ci sprintf(maddr, "%s:%x", mcast_prefix, idx + 1); 358f08c3bdfSopenharmony_ci break; 359f08c3bdfSopenharmony_ci } 360f08c3bdfSopenharmony_ci 361f08c3bdfSopenharmony_ci if (debug) 362f08c3bdfSopenharmony_ci fprintf(stderr, "multicast address is %s\n", 363f08c3bdfSopenharmony_ci maddr); 364f08c3bdfSopenharmony_ci } 365f08c3bdfSopenharmony_ci 366f08c3bdfSopenharmony_ci maddr_info = get_maddrinfo(family, maddr, NULL); 367f08c3bdfSopenharmony_ci 368f08c3bdfSopenharmony_ci grp_info = create_group_info(ifindex, maddr_info); 369f08c3bdfSopenharmony_ci if (setsockopt(sd, level, MCAST_JOIN_GROUP, grp_info, 370f08c3bdfSopenharmony_ci sizeof(struct group_req)) == -1) { 371f08c3bdfSopenharmony_ci if (idx == 0) 372f08c3bdfSopenharmony_ci fatal_error("setsockopt(): Join no group"); 373f08c3bdfSopenharmony_ci else { 374f08c3bdfSopenharmony_ci num_group--; 375f08c3bdfSopenharmony_ci free(grp_info); 376f08c3bdfSopenharmony_ci freeaddrinfo(maddr_info); 377f08c3bdfSopenharmony_ci break; 378f08c3bdfSopenharmony_ci } 379f08c3bdfSopenharmony_ci free(grp_info); 380f08c3bdfSopenharmony_ci } 381f08c3bdfSopenharmony_ci 382f08c3bdfSopenharmony_ci if (saddrs) { 383f08c3bdfSopenharmony_ci gsf = 384f08c3bdfSopenharmony_ci create_source_filter(ifindex, maddr_info, fmode, 385f08c3bdfSopenharmony_ci saddrs); 386f08c3bdfSopenharmony_ci if (setsockopt 387f08c3bdfSopenharmony_ci (sd, level, MCAST_MSFILTER, gsf, 388f08c3bdfSopenharmony_ci GROUP_FILTER_SIZE(gsf->gf_numsrc)) == -1) { 389f08c3bdfSopenharmony_ci if (idx == 0) 390f08c3bdfSopenharmony_ci fatal_error 391f08c3bdfSopenharmony_ci ("setsockopt(): Add no group filter"); 392f08c3bdfSopenharmony_ci else { 393f08c3bdfSopenharmony_ci num_group--; 394f08c3bdfSopenharmony_ci free(gsf); 395f08c3bdfSopenharmony_ci freeaddrinfo(maddr_info); 396f08c3bdfSopenharmony_ci break; 397f08c3bdfSopenharmony_ci } 398f08c3bdfSopenharmony_ci free(gsf); 399f08c3bdfSopenharmony_ci } 400f08c3bdfSopenharmony_ci } 401f08c3bdfSopenharmony_ci 402f08c3bdfSopenharmony_ci freeaddrinfo(maddr_info); 403f08c3bdfSopenharmony_ci } 404f08c3bdfSopenharmony_ci 405f08c3bdfSopenharmony_ci fprintf(stdout, "%zu groups\n", num_group); 406f08c3bdfSopenharmony_ci fflush(stdout); 407f08c3bdfSopenharmony_ci 408f08c3bdfSopenharmony_ci /* Become a daemon for the next step in shell script */ 409f08c3bdfSopenharmony_ci if (daemon(0, 0) < 0) 410f08c3bdfSopenharmony_ci fatal_error("daemon()"); 411f08c3bdfSopenharmony_ci 412f08c3bdfSopenharmony_ci /* Waiting for SIGHUP */ 413f08c3bdfSopenharmony_ci handler.sa_handler = set_signal_flag; 414f08c3bdfSopenharmony_ci handler.sa_flags = 0; 415f08c3bdfSopenharmony_ci if (sigfillset(&handler.sa_mask) < 0) 416f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 417f08c3bdfSopenharmony_ci if (sigaction(SIGHUP, &handler, NULL) < 0) 418f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 419f08c3bdfSopenharmony_ci 420f08c3bdfSopenharmony_ci for (;;) 421f08c3bdfSopenharmony_ci if (catch_sighup) 422f08c3bdfSopenharmony_ci break; 423f08c3bdfSopenharmony_ci} 424f08c3bdfSopenharmony_ci 425f08c3bdfSopenharmony_ci/* 426f08c3bdfSopenharmony_ci * Function: join_leave_group() 427f08c3bdfSopenharmony_ci * 428f08c3bdfSopenharmony_ci * Description: 429f08c3bdfSopenharmony_ci * This function make sockets to join the groups then leave it 430f08c3bdfSopenharmony_ci * 431f08c3bdfSopenharmony_ci * Return value: 432f08c3bdfSopenharmony_ci * None 433f08c3bdfSopenharmony_ci */ 434f08c3bdfSopenharmony_civoid join_leave_group(void) 435f08c3bdfSopenharmony_ci{ 436f08c3bdfSopenharmony_ci int sd; /* socket file descriptor */ 437f08c3bdfSopenharmony_ci struct addrinfo *maddr_info; 438f08c3bdfSopenharmony_ci struct group_req *grp_info; 439f08c3bdfSopenharmony_ci struct group_filter *gsf; 440f08c3bdfSopenharmony_ci size_t cnt; 441f08c3bdfSopenharmony_ci 442f08c3bdfSopenharmony_ci sd = socket(family, SOCK_DGRAM, IPPROTO_UDP); 443f08c3bdfSopenharmony_ci if (sd < 0) 444f08c3bdfSopenharmony_ci fatal_error("socket()"); 445f08c3bdfSopenharmony_ci 446f08c3bdfSopenharmony_ci maddr_info = get_maddrinfo(family, mcast_addr, NULL); 447f08c3bdfSopenharmony_ci grp_info = create_group_info(ifindex, maddr_info); 448f08c3bdfSopenharmony_ci if (saddrs) 449f08c3bdfSopenharmony_ci gsf = create_source_filter(ifindex, maddr_info, fmode, saddrs); 450f08c3bdfSopenharmony_ci else 451f08c3bdfSopenharmony_ci gsf = NULL; 452f08c3bdfSopenharmony_ci 453f08c3bdfSopenharmony_ci /* Waiting for SIGHUP */ 454f08c3bdfSopenharmony_ci handler.sa_handler = set_signal_flag; 455f08c3bdfSopenharmony_ci handler.sa_flags = 0; 456f08c3bdfSopenharmony_ci if (sigfillset(&handler.sa_mask) < 0) 457f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 458f08c3bdfSopenharmony_ci if (sigaction(SIGHUP, &handler, NULL) < 0) 459f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 460f08c3bdfSopenharmony_ci 461f08c3bdfSopenharmony_ci for (cnt = 0; cnt < join_leave_times; cnt++) { 462f08c3bdfSopenharmony_ci /* Join */ 463f08c3bdfSopenharmony_ci if (setsockopt(sd, level, MCAST_JOIN_GROUP, grp_info, 464f08c3bdfSopenharmony_ci sizeof(struct group_req)) == -1) 465f08c3bdfSopenharmony_ci fatal_error("setsockopt(): Failed to join a group"); 466f08c3bdfSopenharmony_ci 467f08c3bdfSopenharmony_ci if (gsf) 468f08c3bdfSopenharmony_ci if (setsockopt(sd, level, MCAST_MSFILTER, gsf, 469f08c3bdfSopenharmony_ci GROUP_FILTER_SIZE(gsf->gf_numsrc)) == -1) 470f08c3bdfSopenharmony_ci fatal_error 471f08c3bdfSopenharmony_ci ("setsockopt(): Failed to add a group filter"); 472f08c3bdfSopenharmony_ci 473f08c3bdfSopenharmony_ci nanosleep(&interval, NULL); 474f08c3bdfSopenharmony_ci 475f08c3bdfSopenharmony_ci /* Leave */ 476f08c3bdfSopenharmony_ci if (setsockopt(sd, level, MCAST_LEAVE_GROUP, grp_info, 477f08c3bdfSopenharmony_ci sizeof(struct group_req)) == -1) 478f08c3bdfSopenharmony_ci fatal_error("setsockopt(): Failed to leave a group"); 479f08c3bdfSopenharmony_ci 480f08c3bdfSopenharmony_ci nanosleep(&interval, NULL); 481f08c3bdfSopenharmony_ci 482f08c3bdfSopenharmony_ci if (catch_sighup) 483f08c3bdfSopenharmony_ci break; 484f08c3bdfSopenharmony_ci } 485f08c3bdfSopenharmony_ci 486f08c3bdfSopenharmony_ci free(grp_info); 487f08c3bdfSopenharmony_ci if (gsf) 488f08c3bdfSopenharmony_ci free(gsf); 489f08c3bdfSopenharmony_ci freeaddrinfo(maddr_info); 490f08c3bdfSopenharmony_ci} 491f08c3bdfSopenharmony_ci 492f08c3bdfSopenharmony_ci/* 493f08c3bdfSopenharmony_ci * 494f08c3bdfSopenharmony_ci * Function: main() 495f08c3bdfSopenharmony_ci * 496f08c3bdfSopenharmony_ci */ 497f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 498f08c3bdfSopenharmony_ci{ 499f08c3bdfSopenharmony_ci debug = 0; 500f08c3bdfSopenharmony_ci program_name = strdup(argv[0]); 501f08c3bdfSopenharmony_ci 502f08c3bdfSopenharmony_ci parse_options(argc, argv); 503f08c3bdfSopenharmony_ci 504f08c3bdfSopenharmony_ci if (!join_leave_times) { 505f08c3bdfSopenharmony_ci if (mcast_prefix == NULL && mcast_addr == NULL) { 506f08c3bdfSopenharmony_ci fprintf(stderr, "multicast address is not specified\n"); 507f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 508f08c3bdfSopenharmony_ci } 509f08c3bdfSopenharmony_ci join_group(); 510f08c3bdfSopenharmony_ci } else { 511f08c3bdfSopenharmony_ci if (mcast_addr == NULL) { 512f08c3bdfSopenharmony_ci fprintf(stderr, "multicast address is not specified\n"); 513f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 514f08c3bdfSopenharmony_ci } 515f08c3bdfSopenharmony_ci join_leave_group(); 516f08c3bdfSopenharmony_ci } 517f08c3bdfSopenharmony_ci 518f08c3bdfSopenharmony_ci exit(EXIT_SUCCESS); 519f08c3bdfSopenharmony_ci} 520