8125c41e34e1f0aa6eab4265b2da1fc9fdda586f
[mctap.git] / src / mctap.c
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>
7 #include <arpa/inet.h>
8 #include <errno.h>
9
10 #include "utils.h"
11
12 static void usage(FILE *out)
13 {
14     fprintf(out, "usage: mctap [-h] MCASTGROUP PORT\n");
15 }
16
17 static 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
51 static int mkmcastsk4(struct in_addr group, int port)
52 {
53     int fd;
54     int soval;
55     struct sockaddr_in nm;
56     struct ip_mreqn mreq;
57     
58     fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
59     soval = 1;
60     if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &soval, sizeof(soval)))
61         return(-1);
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;
69     if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
70         return(-1);
71     soval = 1;
72     if(setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &soval, sizeof(soval)))
73         return(-1);
74     return(fd);
75 }
76
77 static void test(int fd)
78 {
79     char buf[65536];
80     int i, 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         for(i = 0; i < ret; i++) {
93             printf("%02x ", (unsigned char)buf[i]);
94             if(i % 20 == 0)
95                 putchar(10);
96         }
97     }
98 }
99
100 int main(int argc, char **argv)
101 {
102     int c;
103     int sock;
104     struct in_addr group;
105     int port;
106     
107     while((c = getopt(argc, argv, "h")) >= 0) {
108         switch(c) {
109         case 'h':
110             usage(stdout);
111             return(0);
112         default:
113             usage(stderr);
114             exit(1);
115         }
116     }
117     if(argc - optind < 2) {
118         usage(stderr);
119         exit(1);
120     }
121     if(!inet_aton(argv[optind], &group)) {
122         fprintf(stderr, "mctap: invalid group address: %s\n", argv[optind]);
123         exit(1);
124     }
125     port = atoi(argv[optind + 1]);
126     if((sock = mkmcastsk4(group, port)) < 0) {
127         fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno));
128         exit(1);
129     }
130     
131     test(sock);
132     return(0);
133 }