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_receiver.c 24f08c3bdfSopenharmony_ci * 25f08c3bdfSopenharmony_ci * Description: 26f08c3bdfSopenharmony_ci * This is a multicast UDP datagram receiver 27f08c3bdfSopenharmony_ci * 28f08c3bdfSopenharmony_ci * Author: 29f08c3bdfSopenharmony_ci * Mitsuru Chinen <mitch@jp.ibm.com> 30f08c3bdfSopenharmony_ci * 31f08c3bdfSopenharmony_ci * History: 32f08c3bdfSopenharmony_ci * Apr 19 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/* 56f08c3bdfSopenharmony_ci * Structure Definitions 57f08c3bdfSopenharmony_ci */ 58f08c3bdfSopenharmony_cistruct mcast_rcv_info { 59f08c3bdfSopenharmony_ci struct addrinfo *mainfo; 60f08c3bdfSopenharmony_ci struct group_req *greq; 61f08c3bdfSopenharmony_ci struct group_filter *gsf; 62f08c3bdfSopenharmony_ci double timeout; 63f08c3bdfSopenharmony_ci}; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_ci/* 66f08c3bdfSopenharmony_ci * Gloval variables 67f08c3bdfSopenharmony_ci */ 68f08c3bdfSopenharmony_cichar *program_name; /* program name */ 69f08c3bdfSopenharmony_cistruct sigaction handler; /* Behavior for a signal */ 70f08c3bdfSopenharmony_ciint catch_sighup; /* When catch the SIGHUP, set to non-zero */ 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci/* 73f08c3bdfSopenharmony_ci * Function: usage() 74f08c3bdfSopenharmony_ci * 75f08c3bdfSopenharmony_ci * Descripton: 76f08c3bdfSopenharmony_ci * Print the usage of this program. Then, terminate this program with 77f08c3bdfSopenharmony_ci * the specified exit value. 78f08c3bdfSopenharmony_ci * 79f08c3bdfSopenharmony_ci * Argument: 80f08c3bdfSopenharmony_ci * exit_value: exit value 81f08c3bdfSopenharmony_ci * 82f08c3bdfSopenharmony_ci * Return value: 83f08c3bdfSopenharmony_ci * This function does not return. 84f08c3bdfSopenharmony_ci */ 85f08c3bdfSopenharmony_civoid usage(char *program_name, int exit_value) 86f08c3bdfSopenharmony_ci{ 87f08c3bdfSopenharmony_ci FILE *stream = stdout; /* stream where the usage is output */ 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci if (exit_value == EXIT_FAILURE) 90f08c3bdfSopenharmony_ci stream = stderr; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci fprintf(stream, "%s [OPTION]\n" 93f08c3bdfSopenharmony_ci "\t-f num\ttprotocol family\n" 94f08c3bdfSopenharmony_ci "\t\t 4 : IPv4\n" 95f08c3bdfSopenharmony_ci "\t\t 6 : IPv6\n" 96f08c3bdfSopenharmony_ci "\t-I ifname\tname of listening interface\n" 97f08c3bdfSopenharmony_ci "\t-m addr\tmulticast address\n" 98f08c3bdfSopenharmony_ci "\t-F mode\tfilter mode\n" 99f08c3bdfSopenharmony_ci "\t\t include : include mode\n" 100f08c3bdfSopenharmony_ci "\t\t exclude : exclude mode\n" 101f08c3bdfSopenharmony_ci "\t-s addrs\tcomma separated array of Source Addresses\n" 102f08c3bdfSopenharmony_ci "\t-p num\tport number\n" 103f08c3bdfSopenharmony_ci "\t-t value\ttimeout [sec]\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: parse_options() 143f08c3bdfSopenharmony_ci * 144f08c3bdfSopenharmony_ci * Description: 145f08c3bdfSopenharmony_ci * This function parse the options 146f08c3bdfSopenharmony_ci * 147f08c3bdfSopenharmony_ci * Argument: 148f08c3bdfSopenharmony_ci * argc: the number of argument 149f08c3bdfSopenharmony_ci * argv: arguments 150f08c3bdfSopenharmony_ci * info_p: pointer to data of multicast receiver information 151f08c3bdfSopenharmony_ci * bg_p: pointer to the flag of working in backgrond 152f08c3bdfSopenharmony_ci * 153f08c3bdfSopenharmony_ci * Return value: 154f08c3bdfSopenharmony_ci * None 155f08c3bdfSopenharmony_ci */ 156f08c3bdfSopenharmony_civoid 157f08c3bdfSopenharmony_ciparse_options(int argc, char *argv[], struct mcast_rcv_info *info_p, int *bg_p) 158f08c3bdfSopenharmony_ci{ 159f08c3bdfSopenharmony_ci int optc; /* option */ 160f08c3bdfSopenharmony_ci unsigned long opt_ul; /* option value in unsigned long */ 161f08c3bdfSopenharmony_ci double opt_d; /* option value in double */ 162f08c3bdfSopenharmony_ci uint32_t ifindex = 0; /* interface index where listening multicast */ 163f08c3bdfSopenharmony_ci sa_family_t family = AF_UNSPEC; /* protocol family */ 164f08c3bdfSopenharmony_ci char *maddr; /* multicast address */ 165f08c3bdfSopenharmony_ci uint32_t fmode = 0; /* filter mode */ 166f08c3bdfSopenharmony_ci char *saddrs; /* comma separated array of source addresses */ 167f08c3bdfSopenharmony_ci char *portnum; /* listen port number in character string */ 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_ci maddr = NULL; 170f08c3bdfSopenharmony_ci saddrs = NULL; 171f08c3bdfSopenharmony_ci portnum = NULL; 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci while ((optc = getopt(argc, argv, "f:I:m:F:s:p:t:bdh")) != EOF) { 174f08c3bdfSopenharmony_ci switch (optc) { 175f08c3bdfSopenharmony_ci case 'f': 176f08c3bdfSopenharmony_ci if (optarg[0] == '4') 177f08c3bdfSopenharmony_ci family = PF_INET; /* IPv4 */ 178f08c3bdfSopenharmony_ci else if (optarg[0] == '6') 179f08c3bdfSopenharmony_ci family = PF_INET6; /* IPv6 */ 180f08c3bdfSopenharmony_ci else { 181f08c3bdfSopenharmony_ci fprintf(stderr, 182f08c3bdfSopenharmony_ci "protocol family should be 4 or 6.\n"); 183f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 184f08c3bdfSopenharmony_ci } 185f08c3bdfSopenharmony_ci break; 186f08c3bdfSopenharmony_ci 187f08c3bdfSopenharmony_ci case 'I': 188f08c3bdfSopenharmony_ci ifindex = if_nametoindex(optarg); 189f08c3bdfSopenharmony_ci if (ifindex == 0) { 190f08c3bdfSopenharmony_ci fprintf(stderr, 191f08c3bdfSopenharmony_ci "specified interface is incorrect\n"); 192f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 193f08c3bdfSopenharmony_ci } 194f08c3bdfSopenharmony_ci break; 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci case 'm': 197f08c3bdfSopenharmony_ci maddr = strdup(optarg); 198f08c3bdfSopenharmony_ci if (maddr == NULL) 199f08c3bdfSopenharmony_ci fatal_error("strdup()"); 200f08c3bdfSopenharmony_ci break; 201f08c3bdfSopenharmony_ci 202f08c3bdfSopenharmony_ci case 'F': 203f08c3bdfSopenharmony_ci if (strncmp(optarg, "exclude", 8) == 0) 204f08c3bdfSopenharmony_ci fmode = MCAST_EXCLUDE; 205f08c3bdfSopenharmony_ci else if (strncmp(optarg, "include", 8) == 0) 206f08c3bdfSopenharmony_ci fmode = MCAST_INCLUDE; 207f08c3bdfSopenharmony_ci else { 208f08c3bdfSopenharmony_ci fprintf(stderr, 209f08c3bdfSopenharmony_ci "specified filter mode is incorrect\n"); 210f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 211f08c3bdfSopenharmony_ci } 212f08c3bdfSopenharmony_ci break; 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci case 's': 215f08c3bdfSopenharmony_ci saddrs = strdup(optarg); 216f08c3bdfSopenharmony_ci if (saddrs == NULL) 217f08c3bdfSopenharmony_ci fatal_error("strdup()"); 218f08c3bdfSopenharmony_ci break; 219f08c3bdfSopenharmony_ci 220f08c3bdfSopenharmony_ci case 'p': 221f08c3bdfSopenharmony_ci opt_ul = strtoul(optarg, NULL, 0); 222f08c3bdfSopenharmony_ci if (opt_ul < PORTNUMMIN || PORTNUMMAX < opt_ul) { 223f08c3bdfSopenharmony_ci fprintf(stderr, 224f08c3bdfSopenharmony_ci "The range of port is from %u to %u\n", 225f08c3bdfSopenharmony_ci PORTNUMMIN, PORTNUMMAX); 226f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 227f08c3bdfSopenharmony_ci } 228f08c3bdfSopenharmony_ci portnum = strdup(optarg); 229f08c3bdfSopenharmony_ci break; 230f08c3bdfSopenharmony_ci 231f08c3bdfSopenharmony_ci case 't': 232f08c3bdfSopenharmony_ci opt_d = strtod(optarg, NULL); 233f08c3bdfSopenharmony_ci if (opt_d < 0.0) { 234f08c3bdfSopenharmony_ci fprintf(stderr, 235f08c3bdfSopenharmony_ci "Timeout should be positive value\n"); 236f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 237f08c3bdfSopenharmony_ci } 238f08c3bdfSopenharmony_ci info_p->timeout = opt_d; 239f08c3bdfSopenharmony_ci break; 240f08c3bdfSopenharmony_ci 241f08c3bdfSopenharmony_ci case 'b': 242f08c3bdfSopenharmony_ci *bg_p = 1; 243f08c3bdfSopenharmony_ci break; 244f08c3bdfSopenharmony_ci 245f08c3bdfSopenharmony_ci case 'd': 246f08c3bdfSopenharmony_ci debug = 1; 247f08c3bdfSopenharmony_ci break; 248f08c3bdfSopenharmony_ci 249f08c3bdfSopenharmony_ci case 'h': 250f08c3bdfSopenharmony_ci usage(program_name, EXIT_SUCCESS); 251f08c3bdfSopenharmony_ci break; 252f08c3bdfSopenharmony_ci 253f08c3bdfSopenharmony_ci default: 254f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 255f08c3bdfSopenharmony_ci } 256f08c3bdfSopenharmony_ci } 257f08c3bdfSopenharmony_ci 258f08c3bdfSopenharmony_ci if (ifindex == 0) { 259f08c3bdfSopenharmony_ci fprintf(stderr, "specified interface seems incorrect\n"); 260f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 261f08c3bdfSopenharmony_ci } 262f08c3bdfSopenharmony_ci 263f08c3bdfSopenharmony_ci if (maddr == NULL) { 264f08c3bdfSopenharmony_ci fprintf(stderr, "multicast address is not specified\n"); 265f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 266f08c3bdfSopenharmony_ci } 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci if (portnum == NULL) { 269f08c3bdfSopenharmony_ci fprintf(stderr, "listening port number is not specified\n"); 270f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 271f08c3bdfSopenharmony_ci } 272f08c3bdfSopenharmony_ci 273f08c3bdfSopenharmony_ci info_p->mainfo = get_maddrinfo(family, maddr, portnum); 274f08c3bdfSopenharmony_ci info_p->greq = create_group_info(ifindex, info_p->mainfo); 275f08c3bdfSopenharmony_ci if (saddrs) { 276f08c3bdfSopenharmony_ci if (fmode != MCAST_EXCLUDE && fmode != MCAST_INCLUDE) { 277f08c3bdfSopenharmony_ci fprintf(stderr, "filter mode is wrong\n"); 278f08c3bdfSopenharmony_ci usage(program_name, EXIT_FAILURE); 279f08c3bdfSopenharmony_ci } 280f08c3bdfSopenharmony_ci info_p->gsf = 281f08c3bdfSopenharmony_ci create_source_filter(ifindex, info_p->mainfo, fmode, 282f08c3bdfSopenharmony_ci saddrs); 283f08c3bdfSopenharmony_ci } 284f08c3bdfSopenharmony_ci 285f08c3bdfSopenharmony_ci free(maddr); 286f08c3bdfSopenharmony_ci free(saddrs); 287f08c3bdfSopenharmony_ci free(portnum); 288f08c3bdfSopenharmony_ci} 289f08c3bdfSopenharmony_ci 290f08c3bdfSopenharmony_ci/* 291f08c3bdfSopenharmony_ci * Function: create_mcast_socket() 292f08c3bdfSopenharmony_ci * 293f08c3bdfSopenharmony_ci * Description: 294f08c3bdfSopenharmony_ci * This function creates a socket to receive multicast datagrams 295f08c3bdfSopenharmony_ci * 296f08c3bdfSopenharmony_ci * Argument: 297f08c3bdfSopenharmony_ci * info_p: pointer to data of multicast receiver information 298f08c3bdfSopenharmony_ci * 299f08c3bdfSopenharmony_ci * Return value: 300f08c3bdfSopenharmony_ci * file descriptor referencing the socket 301f08c3bdfSopenharmony_ci */ 302f08c3bdfSopenharmony_ciint create_mcast_socket(struct mcast_rcv_info *info_p) 303f08c3bdfSopenharmony_ci{ 304f08c3bdfSopenharmony_ci int sd; /* socket file descriptor */ 305f08c3bdfSopenharmony_ci int level; /* protocol levels */ 306f08c3bdfSopenharmony_ci int on; /* flag for setsockopt */ 307f08c3bdfSopenharmony_ci 308f08c3bdfSopenharmony_ci switch (info_p->mainfo->ai_family) { 309f08c3bdfSopenharmony_ci case PF_INET: 310f08c3bdfSopenharmony_ci level = IPPROTO_IP; 311f08c3bdfSopenharmony_ci break; 312f08c3bdfSopenharmony_ci case PF_INET6: 313f08c3bdfSopenharmony_ci level = IPPROTO_IPV6; 314f08c3bdfSopenharmony_ci break; 315f08c3bdfSopenharmony_ci default: 316f08c3bdfSopenharmony_ci level = 0; 317f08c3bdfSopenharmony_ci fprintf(stderr, "Unknown protocol level %d\n", level); 318f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 319f08c3bdfSopenharmony_ci break; 320f08c3bdfSopenharmony_ci } 321f08c3bdfSopenharmony_ci 322f08c3bdfSopenharmony_ci /* Create a socket */ 323f08c3bdfSopenharmony_ci sd = socket(info_p->mainfo->ai_family, info_p->mainfo->ai_socktype, 324f08c3bdfSopenharmony_ci info_p->mainfo->ai_protocol); 325f08c3bdfSopenharmony_ci if (sd < 0) 326f08c3bdfSopenharmony_ci fatal_error("socket()"); 327f08c3bdfSopenharmony_ci 328f08c3bdfSopenharmony_ci /* Bind to the multicast address */ 329f08c3bdfSopenharmony_ci if (bind(sd, info_p->mainfo->ai_addr, info_p->mainfo->ai_addrlen) < 0) 330f08c3bdfSopenharmony_ci fatal_error("bind()"); 331f08c3bdfSopenharmony_ci 332f08c3bdfSopenharmony_ci /* Enable to reuse the socket */ 333f08c3bdfSopenharmony_ci on = 1; 334f08c3bdfSopenharmony_ci if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))) 335f08c3bdfSopenharmony_ci fatal_error("setsockopt(): failed to set reuse the socket"); 336f08c3bdfSopenharmony_ci 337f08c3bdfSopenharmony_ci /* Join the multicast group */ 338f08c3bdfSopenharmony_ci if (setsockopt 339f08c3bdfSopenharmony_ci (sd, level, MCAST_JOIN_GROUP, info_p->greq, 340f08c3bdfSopenharmony_ci sizeof(struct group_req))) 341f08c3bdfSopenharmony_ci fatal_error("setsockopt(): failed to join the multicast group"); 342f08c3bdfSopenharmony_ci 343f08c3bdfSopenharmony_ci /* Apply the source filter */ 344f08c3bdfSopenharmony_ci if (info_p->gsf) { 345f08c3bdfSopenharmony_ci if (setsockopt 346f08c3bdfSopenharmony_ci (sd, level, MCAST_MSFILTER, info_p->gsf, 347f08c3bdfSopenharmony_ci GROUP_FILTER_SIZE(info_p->gsf->gf_numsrc))) 348f08c3bdfSopenharmony_ci fatal_error 349f08c3bdfSopenharmony_ci ("setsockopt(): failed to apply the source filter"); 350f08c3bdfSopenharmony_ci } 351f08c3bdfSopenharmony_ci 352f08c3bdfSopenharmony_ci return sd; 353f08c3bdfSopenharmony_ci} 354f08c3bdfSopenharmony_ci 355f08c3bdfSopenharmony_ci/* 356f08c3bdfSopenharmony_ci * Function: receive_mcast() 357f08c3bdfSopenharmony_ci * 358f08c3bdfSopenharmony_ci * Description: 359f08c3bdfSopenharmony_ci * This function receives multicast datagarms 360f08c3bdfSopenharmony_ci * 361f08c3bdfSopenharmony_ci * Argument: 362f08c3bdfSopenharmony_ci * info_p: pointer to data of multicast receiver information 363f08c3bdfSopenharmony_ci * 364f08c3bdfSopenharmony_ci * Return value: 365f08c3bdfSopenharmony_ci * None 366f08c3bdfSopenharmony_ci */ 367f08c3bdfSopenharmony_civoid receive_mcast(struct mcast_rcv_info *info_p) 368f08c3bdfSopenharmony_ci{ 369f08c3bdfSopenharmony_ci int sd; 370f08c3bdfSopenharmony_ci char *msgbuf; /* Pointer to the message */ 371f08c3bdfSopenharmony_ci size_t msgbuf_size; /* size of msgbuf */ 372f08c3bdfSopenharmony_ci ssize_t msglen; /* the length of message */ 373f08c3bdfSopenharmony_ci socklen_t optlen; /* size of the result parameter */ 374f08c3bdfSopenharmony_ci double start_time; /* start time when receiving datagrams */ 375f08c3bdfSopenharmony_ci 376f08c3bdfSopenharmony_ci /* Create a socket */ 377f08c3bdfSopenharmony_ci sd = create_mcast_socket(info_p); 378f08c3bdfSopenharmony_ci 379f08c3bdfSopenharmony_ci /* Allocate a buffer to store the message */ 380f08c3bdfSopenharmony_ci optlen = sizeof(msgbuf_size); 381f08c3bdfSopenharmony_ci if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &msgbuf_size, &optlen) < 0) { 382f08c3bdfSopenharmony_ci perror("getsockopt()"); 383f08c3bdfSopenharmony_ci close(sd); 384f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 385f08c3bdfSopenharmony_ci } 386f08c3bdfSopenharmony_ci msgbuf = malloc(msgbuf_size + 1); 387f08c3bdfSopenharmony_ci if (msgbuf == NULL) { 388f08c3bdfSopenharmony_ci fprintf(stderr, "malloc() is failed.\n"); 389f08c3bdfSopenharmony_ci close(sd); 390f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 391f08c3bdfSopenharmony_ci } 392f08c3bdfSopenharmony_ci 393f08c3bdfSopenharmony_ci /* Set singal hander for SIGHUP */ 394f08c3bdfSopenharmony_ci handler.sa_handler = set_signal_flag; 395f08c3bdfSopenharmony_ci handler.sa_flags = 0; 396f08c3bdfSopenharmony_ci if (sigfillset(&handler.sa_mask) < 0) 397f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 398f08c3bdfSopenharmony_ci if (sigaction(SIGHUP, &handler, NULL) < 0) 399f08c3bdfSopenharmony_ci fatal_error("sigfillset()"); 400f08c3bdfSopenharmony_ci 401f08c3bdfSopenharmony_ci /* Receive the message */ 402f08c3bdfSopenharmony_ci start_time = time(NULL); 403f08c3bdfSopenharmony_ci for (;;) { 404f08c3bdfSopenharmony_ci struct sockaddr_storage addr; 405f08c3bdfSopenharmony_ci socklen_t addrlen; 406f08c3bdfSopenharmony_ci 407f08c3bdfSopenharmony_ci addrlen = sizeof(addr); 408f08c3bdfSopenharmony_ci msglen = recvfrom(sd, msgbuf, msgbuf_size, MSG_DONTWAIT, 409f08c3bdfSopenharmony_ci (struct sockaddr *)&addr, &addrlen); 410f08c3bdfSopenharmony_ci if (msglen < 0) { 411f08c3bdfSopenharmony_ci if (errno != EAGAIN) 412f08c3bdfSopenharmony_ci fatal_error("recvfrom()"); 413f08c3bdfSopenharmony_ci } else if (debug) 414f08c3bdfSopenharmony_ci fprintf(stderr, "received %zd byte message\n", msglen); 415f08c3bdfSopenharmony_ci 416f08c3bdfSopenharmony_ci if (info_p->timeout) 417f08c3bdfSopenharmony_ci if (info_p->timeout < difftime(time(NULL), start_time)) 418f08c3bdfSopenharmony_ci break; 419f08c3bdfSopenharmony_ci 420f08c3bdfSopenharmony_ci if (catch_sighup) /* catch SIGHUP */ 421f08c3bdfSopenharmony_ci break; 422f08c3bdfSopenharmony_ci } 423f08c3bdfSopenharmony_ci 424f08c3bdfSopenharmony_ci close(sd); 425f08c3bdfSopenharmony_ci} 426f08c3bdfSopenharmony_ci 427f08c3bdfSopenharmony_ci/* 428f08c3bdfSopenharmony_ci * 429f08c3bdfSopenharmony_ci * Function: main() 430f08c3bdfSopenharmony_ci * 431f08c3bdfSopenharmony_ci */ 432f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 433f08c3bdfSopenharmony_ci{ 434f08c3bdfSopenharmony_ci struct mcast_rcv_info mcast_rcv; 435f08c3bdfSopenharmony_ci int background = 0; 436f08c3bdfSopenharmony_ci 437f08c3bdfSopenharmony_ci debug = 0; 438f08c3bdfSopenharmony_ci program_name = strdup(argv[0]); 439f08c3bdfSopenharmony_ci 440f08c3bdfSopenharmony_ci memset(&mcast_rcv, '\0', sizeof(struct mcast_rcv_info)); 441f08c3bdfSopenharmony_ci parse_options(argc, argv, &mcast_rcv, &background); 442f08c3bdfSopenharmony_ci 443f08c3bdfSopenharmony_ci if (background) /* Work in the background */ 444f08c3bdfSopenharmony_ci if (daemon(0, 0) < 0) 445f08c3bdfSopenharmony_ci fatal_error("daemon()"); 446f08c3bdfSopenharmony_ci 447f08c3bdfSopenharmony_ci receive_mcast(&mcast_rcv); 448f08c3bdfSopenharmony_ci 449f08c3bdfSopenharmony_ci exit(EXIT_SUCCESS); 450f08c3bdfSopenharmony_ci} 451