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