xref: /openbsd-src/regress/sys/netinet/mcast/mcrecv.c (revision 5a9255e7fde1eff660134511e5a28e2366fbe25a)
1*5a9255e7Sbluhm /*	$OpenBSD: mcrecv.c,v 1.3 2021/07/06 11:50:34 bluhm Exp $	*/
2a631866dSbluhm /*
3a631866dSbluhm  * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
4a631866dSbluhm  *
5a631866dSbluhm  * Permission to use, copy, modify, and distribute this software for any
6a631866dSbluhm  * purpose with or without fee is hereby granted, provided that the above
7a631866dSbluhm  * copyright notice and this permission notice appear in all copies.
8a631866dSbluhm  *
9a631866dSbluhm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10a631866dSbluhm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11a631866dSbluhm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12a631866dSbluhm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13a631866dSbluhm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14a631866dSbluhm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15a631866dSbluhm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16a631866dSbluhm  */
17a631866dSbluhm 
18a631866dSbluhm #include <sys/socket.h>
19a631866dSbluhm #include <sys/wait.h>
20a631866dSbluhm 
21a631866dSbluhm #include <arpa/inet.h>
22a631866dSbluhm #include <netinet/in.h>
23a631866dSbluhm 
24a631866dSbluhm #include <err.h>
25a631866dSbluhm #include <limits.h>
26a631866dSbluhm #include <signal.h>
27a631866dSbluhm #include <stdlib.h>
28a631866dSbluhm #include <stdio.h>
299f2a3839Sbluhm #include <string.h>
30a631866dSbluhm #include <unistd.h>
31a631866dSbluhm 
32a631866dSbluhm void __dead usage(void);
33a631866dSbluhm void sigexit(int);
34a631866dSbluhm 
35a631866dSbluhm void __dead
usage(void)36a631866dSbluhm usage(void)
37a631866dSbluhm {
38a631866dSbluhm 	fprintf(stderr,
39a631866dSbluhm "mcrecv [-f file] [-g group] [-i ifaddr] [-n timeout] [-p port] [-r timeout]\n"
40a631866dSbluhm "    [mcsend ...]\n"
41a631866dSbluhm "    -f file         print message to log file, default stdout\n"
42a631866dSbluhm "    -g group        multicast group, default 224.0.0.123\n"
43a631866dSbluhm "    -i ifaddr       multicast interface address\n"
44a631866dSbluhm "    -n timeout      expect not to receive any message until timeout\n"
45a631866dSbluhm "    -p port         destination port number, default 12345\n"
46a631866dSbluhm "    -r timeout      receive timeout in seconds\n"
47a631866dSbluhm "    mcsend ...      after setting up receive, fork and exec send command\n");
48a631866dSbluhm 	exit(2);
49a631866dSbluhm }
50a631866dSbluhm 
51a631866dSbluhm int
main(int argc,char * argv[])52a631866dSbluhm main(int argc, char *argv[])
53a631866dSbluhm {
54a631866dSbluhm 	struct sockaddr_in sin;
55a631866dSbluhm 	struct ip_mreq mreq;
56a631866dSbluhm 	FILE *log;
57a631866dSbluhm 	const char *errstr, *file, *group, *ifaddr;
58a631866dSbluhm 	char msg[256];
59a631866dSbluhm 	ssize_t n;
60a631866dSbluhm 	int ch, s, norecv, port, status;
61a631866dSbluhm 	unsigned int timeout;
62a631866dSbluhm 	pid_t pid;
63a631866dSbluhm 
64a631866dSbluhm 	log = stdout;
65a631866dSbluhm 	file = NULL;
669f2a3839Sbluhm 	group = "224.0.1.123";
67a631866dSbluhm 	ifaddr = "0.0.0.0";
68a631866dSbluhm 	norecv = 0;
69a631866dSbluhm 	port = 12345;
70a631866dSbluhm 	timeout = 0;
71a631866dSbluhm 	while ((ch = getopt(argc, argv, "f:g:i:n:p:r:")) != -1) {
72a631866dSbluhm 		switch (ch) {
73a631866dSbluhm 		case 'f':
74a631866dSbluhm 			file = optarg;
75a631866dSbluhm 			break;
76a631866dSbluhm 		case 'g':
77a631866dSbluhm 			group = optarg;
78a631866dSbluhm 			break;
79a631866dSbluhm 		case 'i':
80a631866dSbluhm 			ifaddr = optarg;
81a631866dSbluhm 			break;
82a631866dSbluhm 		case 'n':
83a631866dSbluhm 			norecv = 1;
84a631866dSbluhm 			timeout = strtonum(optarg, 1, INT_MAX, &errstr);
85a631866dSbluhm 			if (errstr != NULL)
86a631866dSbluhm 				errx(1, "no timeout is %s: %s", errstr, optarg);
87a631866dSbluhm 			break;
88a631866dSbluhm 		case 'p':
89a631866dSbluhm 			port = strtonum(optarg, 1, 0xffff, &errstr);
90a631866dSbluhm 			if (errstr != NULL)
91a631866dSbluhm 				errx(1, "port is %s: %s", errstr, optarg);
92a631866dSbluhm 			break;
93a631866dSbluhm 		case 'r':
94a631866dSbluhm 			timeout = strtonum(optarg, 1, INT_MAX, &errstr);
95a631866dSbluhm 			if (errstr != NULL)
96a631866dSbluhm 				errx(1, "timeout is %s: %s", errstr, optarg);
97a631866dSbluhm 			break;
98a631866dSbluhm 		default:
99a631866dSbluhm 			usage();
100a631866dSbluhm 		}
101a631866dSbluhm 	}
102a631866dSbluhm 	argc -= optind;
103a631866dSbluhm 	argv += optind;
104a631866dSbluhm 
105a631866dSbluhm 	if (file != NULL) {
106a631866dSbluhm 		log = fopen(file, "w");
107a631866dSbluhm 		if (log == NULL)
108a631866dSbluhm 			err(1, "fopen %s", file);
109a631866dSbluhm 	}
110a631866dSbluhm 
111a631866dSbluhm 	s = socket(AF_INET, SOCK_DGRAM, 0);
112a631866dSbluhm 	if (s == -1)
113a631866dSbluhm 		err(1, "socket");
114a631866dSbluhm 	if (inet_pton(AF_INET, group, &mreq.imr_multiaddr) == -1)
115a631866dSbluhm 		err(1, "inet_pton %s", group);
116a631866dSbluhm 	if (inet_pton(AF_INET, ifaddr, &mreq.imr_interface) == -1)
117a631866dSbluhm 		err(1, "inet_pton %s", ifaddr);
118a631866dSbluhm 	if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
119a631866dSbluhm 	    sizeof(mreq)) == -1)
120a631866dSbluhm 		err(1, "setsockopt IP_ADD_MEMBERSHIP %s %s", group, ifaddr);
121a631866dSbluhm 
1229f2a3839Sbluhm 	memset(&sin, 0, sizeof(sin));
123a631866dSbluhm 	sin.sin_len = sizeof(sin);
124a631866dSbluhm 	sin.sin_family = AF_INET;
125a631866dSbluhm 	sin.sin_port = htons(port);
126a631866dSbluhm 	if (inet_pton(AF_INET, group, &sin.sin_addr) == -1)
127a631866dSbluhm 		err(1, "inet_pton %s", group);
128a631866dSbluhm 	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
129a631866dSbluhm 		err(1, "bind %s:%d", group, port);
130a631866dSbluhm 
131a631866dSbluhm 	if (argc) {
132a631866dSbluhm 		pid = fork();
133a631866dSbluhm 		switch (pid) {
134a631866dSbluhm 		case -1:
135a631866dSbluhm 			err(1, "fork");
136a631866dSbluhm 		case 0:
137a631866dSbluhm 			execvp(argv[0], argv);
138a631866dSbluhm 			err(1, "exec %s", argv[0]);
139a631866dSbluhm 		}
140a631866dSbluhm 	}
141a631866dSbluhm 	if (timeout) {
142a631866dSbluhm 		if (norecv) {
143a631866dSbluhm 			if (signal(SIGALRM, sigexit) == SIG_ERR)
144a631866dSbluhm 				err(1, "signal SIGALRM");
145a631866dSbluhm 		}
146*5a9255e7Sbluhm 		alarm(timeout);
147a631866dSbluhm 	}
148a631866dSbluhm 	n = recv(s, msg, sizeof(msg) - 1, 0);
149a631866dSbluhm 	if (n == -1)
150a631866dSbluhm 		err(1, "recv");
151a631866dSbluhm 	msg[n] = '\0';
152a631866dSbluhm 	fprintf(log, "<<< %s\n", msg);
153a631866dSbluhm 	fflush(log);
154a631866dSbluhm 
155a631866dSbluhm 	if (norecv)
156a631866dSbluhm 		errx(1, "received %s", msg);
157a631866dSbluhm 
158a631866dSbluhm 	if (argc) {
159a631866dSbluhm 		if (waitpid(pid, &status, 0) == -1)
160a631866dSbluhm 			err(1, "waitpid %d", pid);
161a631866dSbluhm 		if (status)
162a631866dSbluhm 			errx(1, "%s %d", argv[0], status);
163a631866dSbluhm 	}
164a631866dSbluhm 
165a631866dSbluhm 	return 0;
166a631866dSbluhm }
167a631866dSbluhm 
168a631866dSbluhm void
sigexit(int sig)169a631866dSbluhm sigexit(int sig)
170a631866dSbluhm {
171a631866dSbluhm 	_exit(0);
172a631866dSbluhm }
173