xref: /openbsd-src/regress/sys/netinet/mcast/mcsend.c (revision 9f2a3839487c3a27e4af1fda972880605dcf2d7f)
1*9f2a3839Sbluhm /*	$OpenBSD: mcsend.c,v 1.2 2019/09/05 02:44:36 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 
20a631866dSbluhm #include <arpa/inet.h>
21a631866dSbluhm #include <netinet/in.h>
22a631866dSbluhm 
23a631866dSbluhm #include <err.h>
24a631866dSbluhm #include <stdlib.h>
25a631866dSbluhm #include <stdio.h>
26a631866dSbluhm #include <string.h>
27a631866dSbluhm #include <unistd.h>
28a631866dSbluhm 
29a631866dSbluhm void __dead usage(void);
30a631866dSbluhm 
31a631866dSbluhm void __dead
usage(void)32a631866dSbluhm usage(void)
33a631866dSbluhm {
34a631866dSbluhm 	fprintf(stderr,
35a631866dSbluhm "mcsend [-f file] [-g group] [-i ifaddr] [-m message] [-p port]\n"
36a631866dSbluhm "    -f file         print message to log file, default stdout\n"
37a631866dSbluhm "    -g group        multicast group, default 224.0.0.123\n"
38a631866dSbluhm "    -i ifaddr       multicast interface address\n"
39a631866dSbluhm "    -m message      message in payload, maximum 255 characters, default foo\n"
40a631866dSbluhm "    -l loop         disable or enable loopback, 0 or 1\n"
41a631866dSbluhm "    -p port         destination port number, default 12345\n"
42a631866dSbluhm "    -t ttl          set multicast ttl\n");
43a631866dSbluhm 	exit(2);
44a631866dSbluhm }
45a631866dSbluhm 
46a631866dSbluhm int
main(int argc,char * argv[])47a631866dSbluhm main(int argc, char *argv[])
48a631866dSbluhm {
49a631866dSbluhm 	struct sockaddr_in sin;
50a631866dSbluhm 	FILE *log;
51a631866dSbluhm 	const char *errstr, *file, *group, *ifaddr, *msg;
52a631866dSbluhm 	size_t len;
53a631866dSbluhm 	ssize_t n;
54a631866dSbluhm 	int ch, s, loop, port, ttl;
55a631866dSbluhm 
56a631866dSbluhm 	log = stdout;
57a631866dSbluhm 	file = NULL;
58*9f2a3839Sbluhm 	group = "224.0.1.123";
59a631866dSbluhm 	ifaddr = NULL;
60a631866dSbluhm 	loop = -1;
61a631866dSbluhm 	msg = "foo";
62a631866dSbluhm 	port = 12345;
63a631866dSbluhm 	ttl = -1;
64a631866dSbluhm 	while ((ch = getopt(argc, argv, "f:g:i:l:m:p:t:")) != -1) {
65a631866dSbluhm 		switch (ch) {
66a631866dSbluhm 		case 'f':
67a631866dSbluhm 			file = optarg;
68a631866dSbluhm 			break;
69a631866dSbluhm 		case 'g':
70a631866dSbluhm 			group = optarg;
71a631866dSbluhm 			break;
72a631866dSbluhm 		case 'i':
73a631866dSbluhm 			ifaddr = optarg;
74a631866dSbluhm 			break;
75a631866dSbluhm 		case 'l':
76a631866dSbluhm 			loop = strtonum(optarg, 0, 1, &errstr);
77a631866dSbluhm 			if (errstr != NULL)
78a631866dSbluhm 				errx(1, "loop is %s: %s", errstr, optarg);
79a631866dSbluhm 			break;
80a631866dSbluhm 		case 'm':
81a631866dSbluhm 			msg = optarg;
82a631866dSbluhm 			break;
83a631866dSbluhm 		case 'p':
84a631866dSbluhm 			port = strtonum(optarg, 1, 0xffff, &errstr);
85a631866dSbluhm 			if (errstr != NULL)
86a631866dSbluhm 				errx(1, "port is %s: %s", errstr, optarg);
87a631866dSbluhm 			break;
88a631866dSbluhm 		case 't':
89a631866dSbluhm 			ttl = strtonum(optarg, 0, 255, &errstr);
90a631866dSbluhm 			if (errstr != NULL)
91a631866dSbluhm 				errx(1, "ttl is %s: %s", errstr, optarg);
92a631866dSbluhm 			break;
93a631866dSbluhm 		default:
94a631866dSbluhm 			usage();
95a631866dSbluhm 		}
96a631866dSbluhm 	}
97a631866dSbluhm 	argc -= optind;
98a631866dSbluhm 	argv += optind;
99a631866dSbluhm 	if (argc)
100a631866dSbluhm 		usage();
101a631866dSbluhm 
102a631866dSbluhm 	if (file != NULL) {
103a631866dSbluhm 		log = fopen(file, "w");
104a631866dSbluhm 		if (log == NULL)
105a631866dSbluhm 			err(1, "fopen %s", file);
106a631866dSbluhm 	}
107a631866dSbluhm 
108a631866dSbluhm 	s = socket(AF_INET, SOCK_DGRAM, 0);
109a631866dSbluhm 	if (s == -1)
110a631866dSbluhm 		err(1, "socket");
111a631866dSbluhm 	if (ifaddr != NULL) {
112*9f2a3839Sbluhm 		struct in_addr addr;
113*9f2a3839Sbluhm 
114a631866dSbluhm 		if (inet_pton(AF_INET, ifaddr, &addr) == -1)
115a631866dSbluhm 			err(1, "inet_pton %s", ifaddr);
116a631866dSbluhm 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr,
117a631866dSbluhm 		    sizeof(addr)) == -1)
118a631866dSbluhm 			err(1, "setsockopt IP_MULTICAST_IF %s", ifaddr);
119a631866dSbluhm 	}
120a631866dSbluhm 	if (loop != -1) {
121a631866dSbluhm 		unsigned char value = loop;
122a631866dSbluhm 
123a631866dSbluhm 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &value,
124a631866dSbluhm 		    sizeof(value)) == -1)
125a631866dSbluhm 			err(1, "setsockopt loop %d", loop);
126a631866dSbluhm 	}
127a631866dSbluhm 	if (ttl != -1) {
128a631866dSbluhm 		unsigned char value = ttl;
129a631866dSbluhm 
130a631866dSbluhm 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &value,
131a631866dSbluhm 		    sizeof(value)) == -1)
132a631866dSbluhm 			err(1, "setsockopt ttl %d", ttl);
133a631866dSbluhm 	}
134a631866dSbluhm 
135*9f2a3839Sbluhm 	memset(&sin, 0, sizeof(sin));
136a631866dSbluhm 	sin.sin_len = sizeof(sin);
137a631866dSbluhm 	sin.sin_family = AF_INET;
138a631866dSbluhm 	sin.sin_port = htons(port);
139a631866dSbluhm 	if (inet_pton(AF_INET, group, &sin.sin_addr) == -1)
140a631866dSbluhm 		err(1, "inet_pton %s", group);
141a631866dSbluhm 	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
142a631866dSbluhm 		err(1, "connect %s:%d", group, port);
143a631866dSbluhm 
144a631866dSbluhm 	len = strlen(msg);
145a631866dSbluhm 	if (len >= 255)
146a631866dSbluhm 		err(1, "message too long %zu", len);
147a631866dSbluhm 	n = send(s, msg, len, 0);
148a631866dSbluhm 	if (n == -1)
149a631866dSbluhm 		err(1, "send");
150a631866dSbluhm 	if ((size_t)n != len)
151a631866dSbluhm 		errx(1, "send %zd", n);
152a631866dSbluhm 	fprintf(log, ">>> %s\n", msg);
153a631866dSbluhm 	fflush(log);
154a631866dSbluhm 
155a631866dSbluhm 	return 0;
156a631866dSbluhm }
157