Reuse multicast socket address.
[mctap.git] / src / mctap.c
CommitLineData
3415540f
FT
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
b5038e15
FT
7#include <arpa/inet.h>
8#include <errno.h>
9
10#include "utils.h"
3415540f
FT
11
12static void usage(FILE *out)
13{
b5038e15
FT
14 fprintf(out, "usage: mctap [-h] MCASTGROUP PORT\n");
15}
16
17static char *formataddress(struct sockaddr *arg, socklen_t arglen)
18{
19 struct sockaddr_in *ipv4;
20 struct sockaddr_in6 *ipv6;
21 static char *ret = NULL;
22 char buf[1024];
23
24 if(ret != NULL)
25 free(ret);
26 ret = NULL;
27 switch(arg->sa_family)
28 {
29 case AF_UNIX:
30 ret = strdup("Unix socket");
31 break;
32 case AF_INET:
33 ipv4 = (struct sockaddr_in *)arg;
34 if(inet_ntop(AF_INET, &ipv4->sin_addr, buf, sizeof(buf)) == NULL)
35 return(NULL);
36 ret = sprintf2("%s:%i", buf, (int)ntohs(ipv4->sin_port));
37 break;
38 case AF_INET6:
39 ipv6 = (struct sockaddr_in6 *)arg;
40 if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL)
41 return(NULL);
42 ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port));
43 break;
44 default:
45 errno = EPFNOSUPPORT;
46 break;
47 }
48 return(ret);
49}
50
51static int mkmcastsk4(struct in_addr group, int port)
52{
53 int fd;
aeddd223 54 int soval;
b5038e15
FT
55 struct sockaddr_in nm;
56 struct ip_mreqn mreq;
57
58 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
aeddd223
FT
59 soval = 1;
60 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &soval, sizeof(soval)))
61 return(-1);
b5038e15
FT
62 memset(&nm, 0, sizeof(nm));
63 nm.sin_family = AF_INET;
64 nm.sin_port = htons(port);
65 if(bind(fd, (struct sockaddr *)&nm, sizeof(nm)))
66 return(-1);
67 memset(&mreq, 0, sizeof(mreq));
68 mreq.imr_multiaddr = group;
aeddd223 69 if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
b5038e15
FT
70 return(-1);
71 return(fd);
72}
73
74static void test(int fd)
75{
76 char buf[65536];
77 int ret;
78 struct sockaddr_storage nm;
79 socklen_t nmlen;
80
81 while(1) {
82 nmlen = sizeof(nm);
83 ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&nm, &nmlen);
84 if(ret < 0) {
85 fprintf(stderr, "mctap: recvfrom: %s\n", strerror(ret));
86 exit(1);
87 }
88 printf("%s %i:\n", formataddress((struct sockaddr *)&nm, nmlen), ret);
89 }
3415540f
FT
90}
91
92int main(int argc, char **argv)
93{
94 int c;
b5038e15
FT
95 int sock;
96 struct in_addr group;
97 int port;
3415540f 98
b5038e15 99 while((c = getopt(argc, argv, "h")) >= 0) {
3415540f
FT
100 switch(c) {
101 case 'h':
102 usage(stdout);
103 return(0);
104 default:
105 usage(stderr);
106 exit(1);
107 }
108 }
b5038e15
FT
109 if(argc - optind < 2) {
110 usage(stderr);
111 exit(1);
112 }
113 if(!inet_aton(argv[optind], &group)) {
114 fprintf(stderr, "mctap: invalid group address: %s\n", argv[optind]);
115 exit(1);
116 }
117 port = atoi(argv[optind + 1]);
118 if((sock = mkmcastsk4(group, port)) < 0) {
119 fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno));
120 exit(1);
121 }
3415540f 122
b5038e15 123 test(sock);
3415540f
FT
124 return(0);
125}