Merge branch 'vendor/DIFFUTILS'
[dragonfly.git] / test / udp / mcastconn / mcastconn.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3
4 #include <arpa/inet.h>
5 #include <netinet/in.h>
6
7 #include <err.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 static void
15 usage(const char *cmd)
16 {
17         fprintf(stderr, "%s -m addr -p port -i addr "
18             "-r remote_ip4 -P remote_port\n", cmd);
19         exit(1);
20 }
21
22 static int
23 create_sock(const struct sockaddr_in *in, const struct in_addr *iface)
24 {
25         struct ip_mreq mreq;
26         int s, on;
27
28         s = socket(AF_INET, SOCK_DGRAM, 0);
29         if (s < 0)
30                 err(2, "socket failed");
31
32         on = 1;
33         if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0)
34                 err(2, "setsockopt SO_REUSEPORT failed");
35
36         if (bind(s, (const struct sockaddr *)in, sizeof(*in)) < 0)
37                 err(2, "bind failed");
38
39         memset(&mreq, 0, sizeof(mreq));
40         mreq.imr_multiaddr = in->sin_addr;
41         mreq.imr_interface = *iface;
42         if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
43             &mreq, sizeof(mreq)) < 0)
44                 err(2, "setsockopt IP_ADD_MEMBERSHIP failed");
45
46         return s;
47 }
48
49 int
50 main(int argc, char *argv[])
51 {
52         struct sockaddr_in in, remote_in;
53         struct in_addr iface;
54         int s1, s2, opt, n;
55         uint8_t buf[18];
56
57         memset(&in, 0, sizeof(in));
58         in.sin_family = AF_INET;
59
60         memset(&remote_in, 0, sizeof(remote_in));
61         remote_in.sin_family = AF_INET;
62
63         memset(&iface, 0, sizeof(iface));
64
65         while ((opt = getopt(argc, argv, "P:i:m:p:r:")) != -1) {
66                 switch (opt) {
67                 case 'P':
68                         remote_in.sin_port = strtol(optarg, NULL, 10);
69                         remote_in.sin_port = htons(remote_in.sin_port);
70                         break;
71
72                 case 'i':
73                         if (inet_pton(AF_INET, optarg, &iface) <= 0)
74                                 usage(argv[0]);
75                         break;
76
77                 case 'm':
78                         if (inet_pton(AF_INET, optarg, &in.sin_addr) <= 0)
79                                 usage(argv[0]);
80                         break;
81
82                 case 'p':
83                         in.sin_port = strtol(optarg, NULL, 10);
84                         in.sin_port = htons(in.sin_port);
85                         break;
86
87                 case 'r':
88                         if (inet_pton(AF_INET, optarg,
89                             &remote_in.sin_addr) <= 0)
90                                 usage(argv[0]);
91                         break;
92
93                 default:
94                         usage(argv[0]);
95                 }
96         }
97
98         if (in.sin_addr.s_addr == INADDR_ANY || in.sin_port == 0 ||
99             iface.s_addr == INADDR_ANY ||
100             remote_in.sin_addr.s_addr == INADDR_ANY ||
101             remote_in.sin_port == 0)
102                 usage(argv[0]);
103
104         s1 = create_sock(&in, &iface);
105         s2 = create_sock(&in, &iface);
106
107         if (connect(s2, (const struct sockaddr *)&remote_in,
108             sizeof(remote_in)) < 0)
109                 err(2, "connect failed");
110
111         n = read(s1, buf, sizeof(buf));
112         if (n < 0)
113                 err(2, "read 1 failed");
114         fprintf(stderr, "read 1 got %d\n", n);
115
116         n = read(s2, buf, sizeof(buf));
117         if (n < 0)
118                 err(2, "read 2 failed");
119         fprintf(stderr, "read 2 got %d\n", n);
120
121         exit(0);
122 }