Multicast test code.
[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     struct sockaddr_in nm;
55     struct ip_mreqn mreq;
56     
57     fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
58     memset(&nm, 0, sizeof(nm));
59     nm.sin_family = AF_INET;
60     nm.sin_port = htons(port);
61     if(bind(fd, (struct sockaddr *)&nm, sizeof(nm)))
62         return(-1);
63     memset(&mreq, 0, sizeof(mreq));
64     mreq.imr_multiaddr = group;
65     if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
66         return(-1);
67     return(fd);
68 }
69
70 static void test(int fd)
71 {
72     char buf[65536];
73     int ret;
74     struct sockaddr_storage nm;
75     socklen_t nmlen;
76     
77     while(1) {
78         nmlen = sizeof(nm);
79         ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&nm, &nmlen);
80         if(ret < 0) {
81             fprintf(stderr, "mctap: recvfrom: %s\n", strerror(ret));
82             exit(1);
83         }
84         printf("%s %i:\n", formataddress((struct sockaddr *)&nm, nmlen), ret);
85     }
86 }
87
88 int main(int argc, char **argv)
89 {
90     int c;
91     int sock;
92     struct in_addr group;
93     int port;
94     
95     while((c = getopt(argc, argv, "h")) >= 0) {
96         switch(c) {
97         case 'h':
98             usage(stdout);
99             return(0);
100         default:
101             usage(stderr);
102             exit(1);
103         }
104     }
105     if(argc - optind < 2) {
106         usage(stderr);
107         exit(1);
108     }
109     if(!inet_aton(argv[optind], &group)) {
110         fprintf(stderr, "mctap: invalid group address: %s\n", argv[optind]);
111         exit(1);
112     }
113     port = atoi(argv[optind + 1]);
114     if((sock = mkmcastsk4(group, port)) < 0) {
115         fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno));
116         exit(1);
117     }
118     
119     test(sock);
120     return(0);
121 }