xref: /openbsd/regress/sys/netinet/mcast/mcsend.c (revision 9f2a3839)
1 /*	$OpenBSD: mcsend.c,v 1.2 2019/09/05 02:44:36 bluhm Exp $	*/
2 /*
3  * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/socket.h>
19 
20 #include <arpa/inet.h>
21 #include <netinet/in.h>
22 
23 #include <err.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 void __dead usage(void);
30 
31 void __dead
usage(void)32 usage(void)
33 {
34 	fprintf(stderr,
35 "mcsend [-f file] [-g group] [-i ifaddr] [-m message] [-p port]\n"
36 "    -f file         print message to log file, default stdout\n"
37 "    -g group        multicast group, default 224.0.0.123\n"
38 "    -i ifaddr       multicast interface address\n"
39 "    -m message      message in payload, maximum 255 characters, default foo\n"
40 "    -l loop         disable or enable loopback, 0 or 1\n"
41 "    -p port         destination port number, default 12345\n"
42 "    -t ttl          set multicast ttl\n");
43 	exit(2);
44 }
45 
46 int
main(int argc,char * argv[])47 main(int argc, char *argv[])
48 {
49 	struct sockaddr_in sin;
50 	FILE *log;
51 	const char *errstr, *file, *group, *ifaddr, *msg;
52 	size_t len;
53 	ssize_t n;
54 	int ch, s, loop, port, ttl;
55 
56 	log = stdout;
57 	file = NULL;
58 	group = "224.0.1.123";
59 	ifaddr = NULL;
60 	loop = -1;
61 	msg = "foo";
62 	port = 12345;
63 	ttl = -1;
64 	while ((ch = getopt(argc, argv, "f:g:i:l:m:p:t:")) != -1) {
65 		switch (ch) {
66 		case 'f':
67 			file = optarg;
68 			break;
69 		case 'g':
70 			group = optarg;
71 			break;
72 		case 'i':
73 			ifaddr = optarg;
74 			break;
75 		case 'l':
76 			loop = strtonum(optarg, 0, 1, &errstr);
77 			if (errstr != NULL)
78 				errx(1, "loop is %s: %s", errstr, optarg);
79 			break;
80 		case 'm':
81 			msg = optarg;
82 			break;
83 		case 'p':
84 			port = strtonum(optarg, 1, 0xffff, &errstr);
85 			if (errstr != NULL)
86 				errx(1, "port is %s: %s", errstr, optarg);
87 			break;
88 		case 't':
89 			ttl = strtonum(optarg, 0, 255, &errstr);
90 			if (errstr != NULL)
91 				errx(1, "ttl is %s: %s", errstr, optarg);
92 			break;
93 		default:
94 			usage();
95 		}
96 	}
97 	argc -= optind;
98 	argv += optind;
99 	if (argc)
100 		usage();
101 
102 	if (file != NULL) {
103 		log = fopen(file, "w");
104 		if (log == NULL)
105 			err(1, "fopen %s", file);
106 	}
107 
108 	s = socket(AF_INET, SOCK_DGRAM, 0);
109 	if (s == -1)
110 		err(1, "socket");
111 	if (ifaddr != NULL) {
112 		struct in_addr addr;
113 
114 		if (inet_pton(AF_INET, ifaddr, &addr) == -1)
115 			err(1, "inet_pton %s", ifaddr);
116 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr,
117 		    sizeof(addr)) == -1)
118 			err(1, "setsockopt IP_MULTICAST_IF %s", ifaddr);
119 	}
120 	if (loop != -1) {
121 		unsigned char value = loop;
122 
123 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &value,
124 		    sizeof(value)) == -1)
125 			err(1, "setsockopt loop %d", loop);
126 	}
127 	if (ttl != -1) {
128 		unsigned char value = ttl;
129 
130 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &value,
131 		    sizeof(value)) == -1)
132 			err(1, "setsockopt ttl %d", ttl);
133 	}
134 
135 	memset(&sin, 0, sizeof(sin));
136 	sin.sin_len = sizeof(sin);
137 	sin.sin_family = AF_INET;
138 	sin.sin_port = htons(port);
139 	if (inet_pton(AF_INET, group, &sin.sin_addr) == -1)
140 		err(1, "inet_pton %s", group);
141 	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
142 		err(1, "connect %s:%d", group, port);
143 
144 	len = strlen(msg);
145 	if (len >= 255)
146 		err(1, "message too long %zu", len);
147 	n = send(s, msg, len, 0);
148 	if (n == -1)
149 		err(1, "send");
150 	if ((size_t)n != len)
151 		errx(1, "send %zd", n);
152 	fprintf(log, ">>> %s\n", msg);
153 	fflush(log);
154 
155 	return 0;
156 }
157