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-igmp_querier.c 24f08c3bdfSopenharmony_ci * 25f08c3bdfSopenharmony_ci * Description: 26f08c3bdfSopenharmony_ci * This utiltity sends IGMP queries. 27f08c3bdfSopenharmony_ci * (General Query, Multicast Address Specific Query 28f08c3bdfSopenharmony_ci * or Multicast Address and Source Specific Query) 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * Author: 31f08c3bdfSopenharmony_ci * Mitsuru Chinen <mitch@jp.ibm.com> 32f08c3bdfSopenharmony_ci * 33f08c3bdfSopenharmony_ci * History: 34f08c3bdfSopenharmony_ci * Apr 24 2006 - Created (Mitsuru Chinen) 35f08c3bdfSopenharmony_ci *---------------------------------------------------------------------------*/ 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_ci/* 38f08c3bdfSopenharmony_ci * Header Files 39f08c3bdfSopenharmony_ci */ 40f08c3bdfSopenharmony_ci#include <stdio.h> 41f08c3bdfSopenharmony_ci#include <stdlib.h> 42f08c3bdfSopenharmony_ci#include <string.h> 43f08c3bdfSopenharmony_ci#include <errno.h> 44f08c3bdfSopenharmony_ci#include <netdb.h> 45f08c3bdfSopenharmony_ci#include <signal.h> 46f08c3bdfSopenharmony_ci#include <time.h> 47f08c3bdfSopenharmony_ci#include <unistd.h> 48f08c3bdfSopenharmony_ci#include <arpa/inet.h> 49f08c3bdfSopenharmony_ci#include <net/if.h> 50f08c3bdfSopenharmony_ci#include <netinet/in.h> 51f08c3bdfSopenharmony_ci#include <netinet/igmp.h> 52f08c3bdfSopenharmony_ci#include <sys/ioctl.h> 53f08c3bdfSopenharmony_ci#include <sys/socket.h> 54f08c3bdfSopenharmony_ci#include <sys/types.h> 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci#include "ns-mcast.h" 57f08c3bdfSopenharmony_ci#include "ns-traffic.h" 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci/* 60f08c3bdfSopenharmony_ci * Structure Definitions 61f08c3bdfSopenharmony_ci */ 62f08c3bdfSopenharmony_cistruct igmp_info { 63f08c3bdfSopenharmony_ci uint32_t ifindex; 64f08c3bdfSopenharmony_ci struct igmpv3_query *query; 65f08c3bdfSopenharmony_ci double timeout; 66f08c3bdfSopenharmony_ci struct timespec interval; 67f08c3bdfSopenharmony_ci}; 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci/* 70f08c3bdfSopenharmony_ci * Gloval variables 71f08c3bdfSopenharmony_ci */ 72f08c3bdfSopenharmony_cichar *program_name; /* program name */ 73f08c3bdfSopenharmony_cistruct sigaction handler; /* Behavior for a signal */ 74f08c3bdfSopenharmony_ciint catch_sighup; /* When catch the SIGHUP, set to non-zero */ 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci/* 77f08c3bdfSopenharmony_ci * Function: usage() 78f08c3bdfSopenharmony_ci * 79f08c3bdfSopenharmony_ci * Descripton: 80f08c3bdfSopenharmony_ci * Print the usage of this program. Then, terminate this program with 81f08c3bdfSopenharmony_ci * the specified exit value. 82f08c3bdfSopenharmony_ci * 83f08c3bdfSopenharmony_ci * Argument: 84f08c3bdfSopenharmony_ci * exit_value: exit value 85f08c3bdfSopenharmony_ci * 86f08c3bdfSopenharmony_ci * Return value: 87f08c3bdfSopenharmony_ci * This function does not return. 88f08c3bdfSopenharmony_ci */ 89f08c3bdfSopenharmony_civoid usage(char *program_name, int exit_value) 90f08c3bdfSopenharmony_ci{ 91f08c3bdfSopenharmony_ci FILE *stream = stdout; /* stream where the usage is output */ 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci if (exit_value == EXIT_FAILURE) 94f08c3bdfSopenharmony_ci stream = stderr; 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci fprintf(stream, "%s [OPTION]\n" 97f08c3bdfSopenharmony_ci "\t-I ifname\tname of listening interface\n" 98f08c3bdfSopenharmony_ci "\t-m addr\tmulticast address\n" 99f08c3bdfSopenharmony_ci "\t-s addrs\tcomma separated array of Source Addresses\n" 100f08c3bdfSopenharmony_ci "\t-r value\tMax Resp Code\n" 101f08c3bdfSopenharmony_ci "\t-i value\tinterval [nanosec]\n" 102f08c3bdfSopenharmony_ci "\t-t value\ttimeout [sec]\n" 103f08c3bdfSopenharmony_ci "\t-o\t\tsend only one query\n" 104f08c3bdfSopenharmony_ci "\t-b\t\twork in the background\n" 105f08c3bdfSopenharmony_ci "\t-d\t\tdisplay debug informations\n" 106f08c3bdfSopenharmony_ci "\t-h\t\tdisplay this usage\n", program_name); 107f08c3bdfSopenharmony_ci exit(exit_value); 108f08c3bdfSopenharmony_ci} 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci/* 111f08c3bdfSopenharmony_ci * Function: set_signal_flag() 112f08c3bdfSopenharmony_ci * 113f08c3bdfSopenharmony_ci * Description: 114f08c3bdfSopenharmony_ci * This function sets global variables accordig to signal 115f08c3bdfSopenharmony_ci * 116f08c3bdfSopenharmony_ci * Argument: 117f08c3bdfSopenharmony_ci * type: type of signal 118f08c3bdfSopenharmony_ci * 119f08c3bdfSopenharmony_ci * Return value: 120f08c3bdfSopenharmony_ci * None 121f08c3bdfSopenharmony_ci */ 122f08c3bdfSopenharmony_civoid set_signal_flag(int type) 123f08c3bdfSopenharmony_ci{ 124f08c3bdfSopenharmony_ci if (debug) 125f08c3bdfSopenharmony_ci fprintf(stderr, "Catch signal. type is %d\n", type); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci switch (type) { 128f08c3bdfSopenharmony_ci case SIGHUP: 129f08c3bdfSopenharmony_ci catch_sighup = 1; 130f08c3bdfSopenharmony_ci handler.sa_handler = SIG_IGN; 131f08c3bdfSopenharmony_ci if (sigaction(type, &handler, NULL) < 0) 132f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 133f08c3bdfSopenharmony_ci break; 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci default: 136f08c3bdfSopenharmony_ci fprintf(stderr, "Unexpected signal (%d) is caught\n", type); 137f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 138f08c3bdfSopenharmony_ci } 139f08c3bdfSopenharmony_ci} 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci/* 142f08c3bdfSopenharmony_ci * Function: create_query() 143f08c3bdfSopenharmony_ci * 144f08c3bdfSopenharmony_ci * Description: 145f08c3bdfSopenharmony_ci * This function create a igmpv3 query information. 146f08c3bdfSopenharmony_ci * This function allocates memory to store the information. 147f08c3bdfSopenharmony_ci * 148f08c3bdfSopenharmony_ci * Argument: 149f08c3bdfSopenharmony_ci * code: Max Resp Code 150f08c3bdfSopenharmony_ci * maddr: multicast address 151f08c3bdfSopenharmony_ci * saddrs: comma separated array of the source addresses 152f08c3bdfSopenharmony_ci * 153f08c3bdfSopenharmony_ci * Return value: 154f08c3bdfSopenharmony_ci * pointer to allocated igmpv3_query structure 155f08c3bdfSopenharmony_ci */ 156f08c3bdfSopenharmony_cistruct igmpv3_query *create_query(uint8_t code, char *maddr, char *saddrs) 157f08c3bdfSopenharmony_ci{ 158f08c3bdfSopenharmony_ci struct igmpv3_query *query; /* pointer to igmpv3_query structure */ 159f08c3bdfSopenharmony_ci uint16_t numsrc; /* number of source address */ 160f08c3bdfSopenharmony_ci size_t query_size; /* size of igmpv3_query */ 161f08c3bdfSopenharmony_ci struct in_addr ip; 162f08c3bdfSopenharmony_ci uint32_t idx; 163f08c3bdfSopenharmony_ci char *sp, *ep; 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_ci /* calculate the number of source address */ 166f08c3bdfSopenharmony_ci if (saddrs == NULL) { 167f08c3bdfSopenharmony_ci numsrc = 0; 168f08c3bdfSopenharmony_ci } else { 169f08c3bdfSopenharmony_ci numsrc = 1; 170f08c3bdfSopenharmony_ci for (sp = saddrs; *sp != '\0'; sp++) 171f08c3bdfSopenharmony_ci if (*sp == ',') 172f08c3bdfSopenharmony_ci numsrc++; 173f08c3bdfSopenharmony_ci } 174f08c3bdfSopenharmony_ci if (debug) 175f08c3bdfSopenharmony_ci fprintf(stderr, "number of source address is %u\n", numsrc); 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_ci /* allocate memory for igmpv3_query structure */ 178f08c3bdfSopenharmony_ci query_size = MY_IGMPV3_QUERY_SIZE(numsrc); 179f08c3bdfSopenharmony_ci query = (struct igmpv3_query *)calloc(1, query_size); 180f08c3bdfSopenharmony_ci if (query == NULL) 181f08c3bdfSopenharmony_ci fatal_error("calloc()"); 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci /* substitute paramaters */ 184f08c3bdfSopenharmony_ci query->type = IGMP_HOST_MEMBERSHIP_QUERY; 185f08c3bdfSopenharmony_ci query->code = code; 186f08c3bdfSopenharmony_ci query->csum = 0; /* Calculate later */ 187f08c3bdfSopenharmony_ci query->resv = 0; 188f08c3bdfSopenharmony_ci query->suppress = 0; 189f08c3bdfSopenharmony_ci query->qrv = 0; 190f08c3bdfSopenharmony_ci query->qqic = 0; 191f08c3bdfSopenharmony_ci query->nsrcs = htons(numsrc); 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci /* substitute multicast address */ 194f08c3bdfSopenharmony_ci if (maddr == NULL) { 195f08c3bdfSopenharmony_ci query->group = htonl(INADDR_ANY); 196f08c3bdfSopenharmony_ci } else { 197f08c3bdfSopenharmony_ci if (inet_pton(AF_INET, maddr, &ip) <= 0) { 198f08c3bdfSopenharmony_ci fprintf(stderr, 199f08c3bdfSopenharmony_ci "multicast address is something wrong\n"); 200f08c3bdfSopenharmony_ci return NULL; 201f08c3bdfSopenharmony_ci } 202f08c3bdfSopenharmony_ci query->group = ip.s_addr; 203f08c3bdfSopenharmony_ci } 204f08c3bdfSopenharmony_ci 205f08c3bdfSopenharmony_ci /* substitute source addresses */ 206f08c3bdfSopenharmony_ci sp = saddrs; 207f08c3bdfSopenharmony_ci for (idx = 0; idx < numsrc; idx++) { 208f08c3bdfSopenharmony_ci ep = strchr(sp, ','); 209f08c3bdfSopenharmony_ci if (ep != NULL) 210f08c3bdfSopenharmony_ci *ep = '\0'; 211f08c3bdfSopenharmony_ci if (debug) 212f08c3bdfSopenharmony_ci fprintf(stderr, "source address[%u]: %s\n", idx, sp); 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci if (inet_pton(AF_INET, sp, &ip) <= 0) { 215f08c3bdfSopenharmony_ci fprintf(stderr, 216f08c3bdfSopenharmony_ci "source address list is something wrong\n"); 217f08c3bdfSopenharmony_ci return NULL; 218f08c3bdfSopenharmony_ci } 219f08c3bdfSopenharmony_ci query->srcs[idx] = ip.s_addr; 220f08c3bdfSopenharmony_ci sp = ep + 1; 221f08c3bdfSopenharmony_ci } 222f08c3bdfSopenharmony_ci 223f08c3bdfSopenharmony_ci /* Calculate checksum */ 224f08c3bdfSopenharmony_ci query->csum = calc_checksum((u_int16_t *) query, query_size); 225f08c3bdfSopenharmony_ci 226f08c3bdfSopenharmony_ci return query; 227f08c3bdfSopenharmony_ci} 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_ci/* 230f08c3bdfSopenharmony_ci * Function: parse_options() 231f08c3bdfSopenharmony_ci * 232f08c3bdfSopenharmony_ci * Description: 233f08c3bdfSopenharmony_ci * This function parse the options 234f08c3bdfSopenharmony_ci * 235f08c3bdfSopenharmony_ci * Argument: 236f08c3bdfSopenharmony_ci * argc: the number of argument 237f08c3bdfSopenharmony_ci * argv: arguments 238f08c3bdfSopenharmony_ci * info_p: pointer to data of querier information 239f08c3bdfSopenharmony_ci * bg_p: pointer to the flag of working in backgrond 240f08c3bdfSopenharmony_ci * 241f08c3bdfSopenharmony_ci * Return value: 242f08c3bdfSopenharmony_ci * None 243f08c3bdfSopenharmony_ci */ 244f08c3bdfSopenharmony_civoid parse_options(int argc, char *argv[], struct igmp_info *info_p, int *bg_p) 245f08c3bdfSopenharmony_ci{ 246f08c3bdfSopenharmony_ci int optc; /* option */ 247f08c3bdfSopenharmony_ci unsigned long opt_ul; /* option value in unsigned long */ 248f08c3bdfSopenharmony_ci double opt_d; /* option value in double */ 249f08c3bdfSopenharmony_ci uint8_t max_resp; /* Max Resp Code */ 250f08c3bdfSopenharmony_ci char *maddr; /* multicast address */ 251f08c3bdfSopenharmony_ci char *saddrs; /* comma separated array of source addresses */ 252f08c3bdfSopenharmony_ci 253f08c3bdfSopenharmony_ci max_resp = IGMP_MAX_HOST_REPORT_DELAY; 254f08c3bdfSopenharmony_ci maddr = NULL; 255f08c3bdfSopenharmony_ci saddrs = NULL; 256f08c3bdfSopenharmony_ci 257f08c3bdfSopenharmony_ci while ((optc = getopt(argc, argv, "I:m:s:r:t:i:obdh")) != EOF) { 258f08c3bdfSopenharmony_ci switch (optc) { 259f08c3bdfSopenharmony_ci case 'I': 260f08c3bdfSopenharmony_ci info_p->ifindex = if_nametoindex(optarg); 261f08c3bdfSopenharmony_ci if (info_p->ifindex == 0) { 262f08c3bdfSopenharmony_ci fprintf(stderr, 263f08c3bdfSopenharmony_ci "specified interface is incorrect\n"); 264f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 265f08c3bdfSopenharmony_ci } 266f08c3bdfSopenharmony_ci break; 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci case 'm': 269f08c3bdfSopenharmony_ci maddr = strdup(optarg); 270f08c3bdfSopenharmony_ci if (maddr == NULL) 271f08c3bdfSopenharmony_ci fatal_error("strdup()"); 272f08c3bdfSopenharmony_ci break; 273f08c3bdfSopenharmony_ci 274f08c3bdfSopenharmony_ci case 's': 275f08c3bdfSopenharmony_ci saddrs = strdup(optarg); 276f08c3bdfSopenharmony_ci if (saddrs == NULL) 277f08c3bdfSopenharmony_ci fatal_error("strdup()"); 278f08c3bdfSopenharmony_ci break; 279f08c3bdfSopenharmony_ci 280f08c3bdfSopenharmony_ci case 'r': 281f08c3bdfSopenharmony_ci opt_ul = strtoul(optarg, NULL, 0); 282f08c3bdfSopenharmony_ci if (opt_ul > 255) { 283f08c3bdfSopenharmony_ci fprintf(stderr, 284f08c3bdfSopenharmony_ci "Max Resp Code should be less then 256\n"); 285f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 286f08c3bdfSopenharmony_ci } 287f08c3bdfSopenharmony_ci max_resp = opt_ul; 288f08c3bdfSopenharmony_ci break; 289f08c3bdfSopenharmony_ci 290f08c3bdfSopenharmony_ci case 't': 291f08c3bdfSopenharmony_ci opt_d = strtod(optarg, NULL); 292f08c3bdfSopenharmony_ci if (opt_d < 0.0) { 293f08c3bdfSopenharmony_ci fprintf(stderr, 294f08c3bdfSopenharmony_ci "Timeout should be positive value\n"); 295f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 296f08c3bdfSopenharmony_ci } 297f08c3bdfSopenharmony_ci info_p->timeout = opt_d; 298f08c3bdfSopenharmony_ci break; 299f08c3bdfSopenharmony_ci 300f08c3bdfSopenharmony_ci case 'i': 301f08c3bdfSopenharmony_ci if (strtotimespec(optarg, &info_p->interval)) { 302f08c3bdfSopenharmony_ci fprintf(stderr, 303f08c3bdfSopenharmony_ci "Interval is something wrong\n"); 304f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 305f08c3bdfSopenharmony_ci } 306f08c3bdfSopenharmony_ci break; 307f08c3bdfSopenharmony_ci 308f08c3bdfSopenharmony_ci case 'o': 309f08c3bdfSopenharmony_ci info_p->timeout = -1.0; 310f08c3bdfSopenharmony_ci break; 311f08c3bdfSopenharmony_ci 312f08c3bdfSopenharmony_ci case 'b': 313f08c3bdfSopenharmony_ci *bg_p = 1; 314f08c3bdfSopenharmony_ci break; 315f08c3bdfSopenharmony_ci 316f08c3bdfSopenharmony_ci case 'd': 317f08c3bdfSopenharmony_ci debug = 1; 318f08c3bdfSopenharmony_ci break; 319f08c3bdfSopenharmony_ci 320f08c3bdfSopenharmony_ci case 'h': 321f08c3bdfSopenharmony_ci usage(program_name, EXIT_SUCCESS); 322f08c3bdfSopenharmony_ci break; 323f08c3bdfSopenharmony_ci 324f08c3bdfSopenharmony_ci default: 325f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 326f08c3bdfSopenharmony_ci } 327f08c3bdfSopenharmony_ci } 328f08c3bdfSopenharmony_ci 329f08c3bdfSopenharmony_ci if (info_p->ifindex == 0) { 330f08c3bdfSopenharmony_ci fprintf(stderr, "specified interface seems incorrect\n"); 331f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 332f08c3bdfSopenharmony_ci } 333f08c3bdfSopenharmony_ci 334f08c3bdfSopenharmony_ci if ((info_p->query = create_query(max_resp, maddr, saddrs)) == NULL) 335f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 336f08c3bdfSopenharmony_ci 337f08c3bdfSopenharmony_ci free(maddr); 338f08c3bdfSopenharmony_ci free(saddrs); 339f08c3bdfSopenharmony_ci} 340f08c3bdfSopenharmony_ci 341f08c3bdfSopenharmony_ci/* 342f08c3bdfSopenharmony_ci * Function: create_socket() 343f08c3bdfSopenharmony_ci * 344f08c3bdfSopenharmony_ci * Description: 345f08c3bdfSopenharmony_ci * This function creates a socket to send 346f08c3bdfSopenharmony_ci * 347f08c3bdfSopenharmony_ci * Argument: 348f08c3bdfSopenharmony_ci * info_p: pointer to data of igmp query information 349f08c3bdfSopenharmony_ci * 350f08c3bdfSopenharmony_ci * Return value: 351f08c3bdfSopenharmony_ci * file descriptor referencing the socket 352f08c3bdfSopenharmony_ci */ 353f08c3bdfSopenharmony_ciint create_socket(struct igmp_info *info_p) 354f08c3bdfSopenharmony_ci{ 355f08c3bdfSopenharmony_ci int sd; /* socket file descriptor */ 356f08c3bdfSopenharmony_ci int on; 357f08c3bdfSopenharmony_ci unsigned char opt[4] = { 0x94, 0x04, 0x00, 0x00 }; /* Router Alert */ 358f08c3bdfSopenharmony_ci struct ip_mreqn mcast_req, *req_p = &mcast_req; 359f08c3bdfSopenharmony_ci 360f08c3bdfSopenharmony_ci /* Create a socket */ 361f08c3bdfSopenharmony_ci sd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); 362f08c3bdfSopenharmony_ci if (sd < 0) 363f08c3bdfSopenharmony_ci fatal_error("socket()"); 364f08c3bdfSopenharmony_ci 365f08c3bdfSopenharmony_ci /* Enable to reuse the socket */ 366f08c3bdfSopenharmony_ci on = 1; 367f08c3bdfSopenharmony_ci if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))) 368f08c3bdfSopenharmony_ci fatal_error("setsockopt(): enable to reuse the socket"); 369f08c3bdfSopenharmony_ci 370f08c3bdfSopenharmony_ci /* Add router alert option */ 371f08c3bdfSopenharmony_ci if (setsockopt(sd, IPPROTO_IP, IP_OPTIONS, opt, sizeof(opt))) 372f08c3bdfSopenharmony_ci fatal_error("setsockopt(): socket options"); 373f08c3bdfSopenharmony_ci 374f08c3bdfSopenharmony_ci /* Specify the interface for outgoing datagrams */ 375f08c3bdfSopenharmony_ci req_p->imr_multiaddr.s_addr = info_p->query->group; 376f08c3bdfSopenharmony_ci req_p->imr_address.s_addr = htonl(INADDR_ANY); 377f08c3bdfSopenharmony_ci req_p->imr_ifindex = info_p->ifindex; 378f08c3bdfSopenharmony_ci if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, 379f08c3bdfSopenharmony_ci req_p, sizeof(struct ip_mreqn))) { 380f08c3bdfSopenharmony_ci fatal_error("setsockopt(): specify the interface"); 381f08c3bdfSopenharmony_ci } 382f08c3bdfSopenharmony_ci 383f08c3bdfSopenharmony_ci return sd; 384f08c3bdfSopenharmony_ci} 385f08c3bdfSopenharmony_ci 386f08c3bdfSopenharmony_ci/* 387f08c3bdfSopenharmony_ci * Function: send_query() 388f08c3bdfSopenharmony_ci * 389f08c3bdfSopenharmony_ci * Description: 390f08c3bdfSopenharmony_ci * This function sends IGMP query 391f08c3bdfSopenharmony_ci * 392f08c3bdfSopenharmony_ci * Argument: 393f08c3bdfSopenharmony_ci * info_p: pointer to data of igmp query information 394f08c3bdfSopenharmony_ci * 395f08c3bdfSopenharmony_ci * Return value: 396f08c3bdfSopenharmony_ci * None 397f08c3bdfSopenharmony_ci */ 398f08c3bdfSopenharmony_civoid send_query(struct igmp_info *info_p) 399f08c3bdfSopenharmony_ci{ 400f08c3bdfSopenharmony_ci int sd; 401f08c3bdfSopenharmony_ci int retval; 402f08c3bdfSopenharmony_ci double start_time; 403f08c3bdfSopenharmony_ci struct sockaddr_in to; 404f08c3bdfSopenharmony_ci size_t query_size; 405f08c3bdfSopenharmony_ci 406f08c3bdfSopenharmony_ci /* Set singal hander for SIGHUP */ 407f08c3bdfSopenharmony_ci handler.sa_handler = set_signal_flag; 408f08c3bdfSopenharmony_ci handler.sa_flags = 0; 409f08c3bdfSopenharmony_ci if (sigfillset(&handler.sa_mask) < 0) 410f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 411f08c3bdfSopenharmony_ci if (sigaction(SIGHUP, &handler, NULL) < 0) 412f08c3bdfSopenharmony_ci fatal_error("sigaction()"); 413f08c3bdfSopenharmony_ci 414f08c3bdfSopenharmony_ci /* Specify multicast address to send */ 415f08c3bdfSopenharmony_ci to.sin_family = AF_INET; 416f08c3bdfSopenharmony_ci to.sin_port = IPPROTO_IGMP; 417f08c3bdfSopenharmony_ci if (info_p->query->group == htonl(INADDR_ANY)) 418f08c3bdfSopenharmony_ci to.sin_addr.s_addr = IGMP_ALL_HOSTS; 419f08c3bdfSopenharmony_ci else 420f08c3bdfSopenharmony_ci to.sin_addr.s_addr = info_p->query->group; 421f08c3bdfSopenharmony_ci 422f08c3bdfSopenharmony_ci /* Create a socket */ 423f08c3bdfSopenharmony_ci sd = create_socket(info_p); 424f08c3bdfSopenharmony_ci 425f08c3bdfSopenharmony_ci /* loop for sending queries */ 426f08c3bdfSopenharmony_ci start_time = time(NULL); 427f08c3bdfSopenharmony_ci query_size = MY_IGMPV3_QUERY_SIZE(ntohs(info_p->query->nsrcs)); 428f08c3bdfSopenharmony_ci if (debug) 429f08c3bdfSopenharmony_ci fprintf(stderr, "query size is %zu\n", query_size); 430f08c3bdfSopenharmony_ci 431f08c3bdfSopenharmony_ci for (;;) { 432f08c3bdfSopenharmony_ci retval = sendto(sd, info_p->query, query_size, 0, 433f08c3bdfSopenharmony_ci (struct sockaddr *)&to, 434f08c3bdfSopenharmony_ci sizeof(struct sockaddr_in)); 435f08c3bdfSopenharmony_ci if (retval != query_size) { 436f08c3bdfSopenharmony_ci if (errno == ENOBUFS) { 437f08c3bdfSopenharmony_ci sleep(1); 438f08c3bdfSopenharmony_ci continue; 439f08c3bdfSopenharmony_ci } 440f08c3bdfSopenharmony_ci 441f08c3bdfSopenharmony_ci if (catch_sighup) 442f08c3bdfSopenharmony_ci break; 443f08c3bdfSopenharmony_ci else 444f08c3bdfSopenharmony_ci fatal_error("sendto()"); 445f08c3bdfSopenharmony_ci } 446f08c3bdfSopenharmony_ci 447f08c3bdfSopenharmony_ci /* Check timeout: 448f08c3bdfSopenharmony_ci If timeout value is negative only send one datagram */ 449f08c3bdfSopenharmony_ci if (info_p->timeout) 450f08c3bdfSopenharmony_ci if (info_p->timeout < difftime(time(NULL), start_time)) 451f08c3bdfSopenharmony_ci break; 452f08c3bdfSopenharmony_ci 453f08c3bdfSopenharmony_ci /* Wait in specified interval */ 454f08c3bdfSopenharmony_ci nanosleep(&info_p->interval, NULL); 455f08c3bdfSopenharmony_ci 456f08c3bdfSopenharmony_ci /* catch SIGHUP */ 457f08c3bdfSopenharmony_ci if (catch_sighup) 458f08c3bdfSopenharmony_ci break; 459f08c3bdfSopenharmony_ci 460f08c3bdfSopenharmony_ci } 461f08c3bdfSopenharmony_ci 462f08c3bdfSopenharmony_ci close(sd); 463f08c3bdfSopenharmony_ci} 464f08c3bdfSopenharmony_ci 465f08c3bdfSopenharmony_ci/* 466f08c3bdfSopenharmony_ci * 467f08c3bdfSopenharmony_ci * Function: main() 468f08c3bdfSopenharmony_ci * 469f08c3bdfSopenharmony_ci */ 470f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 471f08c3bdfSopenharmony_ci{ 472f08c3bdfSopenharmony_ci struct igmp_info mcast_rcv; 473f08c3bdfSopenharmony_ci int background = 0; 474f08c3bdfSopenharmony_ci 475f08c3bdfSopenharmony_ci debug = 0; 476f08c3bdfSopenharmony_ci program_name = strdup(argv[0]); 477f08c3bdfSopenharmony_ci 478f08c3bdfSopenharmony_ci memset(&mcast_rcv, '\0', sizeof(struct igmp_info)); 479f08c3bdfSopenharmony_ci parse_options(argc, argv, &mcast_rcv, &background); 480f08c3bdfSopenharmony_ci 481f08c3bdfSopenharmony_ci if (background) /* Work in the background */ 482f08c3bdfSopenharmony_ci if (daemon(0, 0) < 0) 483f08c3bdfSopenharmony_ci fatal_error("daemon()"); 484f08c3bdfSopenharmony_ci 485f08c3bdfSopenharmony_ci send_query(&mcast_rcv); 486f08c3bdfSopenharmony_ci 487f08c3bdfSopenharmony_ci exit(EXIT_SUCCESS); 488f08c3bdfSopenharmony_ci} 489