Use multicast loopbacking.
[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 70 return(-1);
af3fc4a5
FT
71 soval = 1;
72 if(setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &soval, sizeof(soval)))
73 return(-1);
b5038e15
FT
74 return(fd);
75}
76
77static void test(int fd)
78{
79 char buf[65536];
80 int ret;
81 struct sockaddr_storage nm;
82 socklen_t nmlen;
83
84 while(1) {
85 nmlen = sizeof(nm);
86 ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&nm, &nmlen);
87 if(ret < 0) {
88 fprintf(stderr, "mctap: recvfrom: %s\n", strerror(ret));
89 exit(1);
90 }
91 printf("%s %i:\n", formataddress((struct sockaddr *)&nm, nmlen), ret);
92 }
3415540f
FT
93}
94
95int main(int argc, char **argv)
96{
97 int c;
b5038e15
FT
98 int sock;
99 struct in_addr group;
100 int port;
3415540f 101
b5038e15 102 while((c = getopt(argc, argv, "h")) >= 0) {
3415540f
FT
103 switch(c) {
104 case 'h':
105 usage(stdout);
106 return(0);
107 default:
108 usage(stderr);
109 exit(1);
110 }
111 }
b5038e15
FT
112 if(argc - optind < 2) {
113 usage(stderr);
114 exit(1);
115 }
116 if(!inet_aton(argv[optind], &group)) {
117 fprintf(stderr, "mctap: invalid group address: %s\n", argv[optind]);
118 exit(1);
119 }
120 port = atoi(argv[optind + 1]);
121 if((sock = mkmcastsk4(group, port)) < 0) {
122 fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno));
123 exit(1);
124 }
3415540f 125
b5038e15 126 test(sock);
3415540f
FT
127 return(0);
128}