Multicast test code.
[mctap.git] / src / mctap.c
index 061edd5..b021d88 100644 (file)
@@ -4,17 +4,95 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "utils.h"
 
 static void usage(FILE *out)
 {
-    fprintf(out, "usage: mctap [-h]\n");
+    fprintf(out, "usage: mctap [-h] MCASTGROUP PORT\n");
+}
+
+static char *formataddress(struct sockaddr *arg, socklen_t arglen)
+{
+    struct sockaddr_in *ipv4;
+    struct sockaddr_in6 *ipv6;
+    static char *ret = NULL;
+    char buf[1024];
+    
+    if(ret != NULL)
+       free(ret);
+    ret = NULL;
+    switch(arg->sa_family)
+    {
+    case AF_UNIX:
+       ret = strdup("Unix socket");
+       break;
+    case AF_INET:
+       ipv4 = (struct sockaddr_in *)arg;
+       if(inet_ntop(AF_INET, &ipv4->sin_addr, buf, sizeof(buf)) == NULL)
+           return(NULL);
+       ret = sprintf2("%s:%i", buf, (int)ntohs(ipv4->sin_port));
+       break;
+    case AF_INET6:
+       ipv6 = (struct sockaddr_in6 *)arg;
+       if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL)
+           return(NULL);
+       ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port));
+       break;
+    default:
+       errno = EPFNOSUPPORT;
+       break;
+    }
+    return(ret);
+}
+
+static int mkmcastsk4(struct in_addr group, int port)
+{
+    int fd;
+    struct sockaddr_in nm;
+    struct ip_mreqn mreq;
+    
+    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    memset(&nm, 0, sizeof(nm));
+    nm.sin_family = AF_INET;
+    nm.sin_port = htons(port);
+    if(bind(fd, (struct sockaddr *)&nm, sizeof(nm)))
+       return(-1);
+    memset(&mreq, 0, sizeof(mreq));
+    mreq.imr_multiaddr = group;
+    if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
+       return(-1);
+    return(fd);
+}
+
+static void test(int fd)
+{
+    char buf[65536];
+    int ret;
+    struct sockaddr_storage nm;
+    socklen_t nmlen;
+    
+    while(1) {
+       nmlen = sizeof(nm);
+       ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&nm, &nmlen);
+       if(ret < 0) {
+           fprintf(stderr, "mctap: recvfrom: %s\n", strerror(ret));
+           exit(1);
+       }
+       printf("%s %i:\n", formataddress((struct sockaddr *)&nm, nmlen), ret);
+    }
 }
 
 int main(int argc, char **argv)
 {
     int c;
+    int sock;
+    struct in_addr group;
+    int port;
     
-    while((c = getopt(argc, argv, "-h")) >= 0) {
+    while((c = getopt(argc, argv, "h")) >= 0) {
        switch(c) {
        case 'h':
            usage(stdout);
@@ -24,6 +102,20 @@ int main(int argc, char **argv)
            exit(1);
        }
     }
+    if(argc - optind < 2) {
+       usage(stderr);
+       exit(1);
+    }
+    if(!inet_aton(argv[optind], &group)) {
+       fprintf(stderr, "mctap: invalid group address: %s\n", argv[optind]);
+       exit(1);
+    }
+    port = atoi(argv[optind + 1]);
+    if((sock = mkmcastsk4(group, port)) < 0) {
+       fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno));
+       exit(1);
+    }
     
+    test(sock);
     return(0);
 }