Multicast test code.
authorFredrik Tolf <fredrik@dolda2000.com>
Sat, 9 Aug 2008 14:08:24 +0000 (16:08 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Sat, 9 Aug 2008 14:08:24 +0000 (16:08 +0200)
src/Makefile.am
src/mctap.c
src/utils.c [new file with mode: 0644]
src/utils.h [new file with mode: 0644]

index b8341da..7a6f135 100644 (file)
@@ -1,2 +1,2 @@
 bin_PROGRAMS=mctap
-mctap_SOURCES=mctap.c
+mctap_SOURCES=mctap.c utils.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);
 }
diff --git a/src/utils.c b/src/utils.c
new file mode 100644 (file)
index 0000000..d0219a0
--- /dev/null
@@ -0,0 +1,67 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "utils.h"
+
+void _sizebuf2(void **buf, size_t *sz, size_t wanted, size_t el)
+{
+    size_t n;
+    
+    n = *sz;
+    if(n == 0)
+       n = 1;
+    while(n < wanted)
+       n <<= 1;
+    if(n <= *sz)
+       return;
+    if(*buf != NULL)
+       *buf = srealloc(*buf, n * el);
+    else
+       *buf = smalloc(n * el);
+    *sz = n;
+}
+
+void _sizebuf(struct buffer *buf, size_t wanted, size_t el)
+{
+    size_t n;
+    
+    n = buf->s;
+    if(n == 0)
+       n = 1;
+    while(n < wanted)
+       n <<= 1;
+    if(n <= buf->s)
+       return;
+    if(buf->b != NULL)
+       buf->b = srealloc(buf->b, n * el);
+    else
+       buf->b = smalloc(n * el);
+    buf->s = n;
+}
+
+char *vsprintf2(char *format, va_list al)
+{
+    int ret;
+    char *buf;
+    va_list al2;
+    
+    va_copy(al2, al);
+    ret = vsnprintf(NULL, 0, format, al2);
+    va_end(al2);
+    buf = smalloc(ret + 1);
+    va_copy(al2, al);
+    vsnprintf(buf, ret + 1, format, al2);
+    va_end(al2);
+    return(buf);
+}
+
+char *sprintf2(char *format, ...)
+{
+    va_list args;
+    char *buf;
+    
+    va_start(args, format);
+    buf = vsprintf2(format, args);
+    va_end(args);
+    return(buf);
+}
diff --git a/src/utils.h b/src/utils.h
new file mode 100644 (file)
index 0000000..3a1c41a
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef _UTILS_H
+#define _UTILS_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#define smalloc(size) ({void *__result__; ((__result__ = malloc(size)) == NULL)?({exit(-1); (void *)0;}):__result__;})
+#define srealloc(ptr, size) ({void *__result__; ((__result__ = realloc((ptr), (size))) == NULL)?({exit(-1); (void *)0;}):__result__;})
+#define szmalloc(size) memset(smalloc(size), 0, size)
+#define sstrdup(str) ({char *__strbuf__ = (str); strcpy(smalloc(strlen(__strbuf__) + 1), __strbuf__);})
+#define omalloc(o) ((o) = szmalloc(sizeof(*(o))))
+
+#define bufinit(buf) memset(&(buf), 0, sizeof(buf))
+#define buffree(buf) do { if((buf).b != NULL) {free((buf).b);} } while(0)
+#define bufdupc(buf) memcpy(smalloc((buf).d * sizeof(*((buf).b))), (buf).b, (buf).d * sizeof(*((buf).b)))
+#define sizebuf(buf, wanted) (_sizebuf((struct buffer *)&(buf), (wanted), sizeof(*((buf).b))))
+#define sizebuf2(buf, wanted) (_sizebuf2((void **)&(buf), &(buf ## size), (wanted), sizeof(*(buf))))
+#define bufdel(buf, i) (memmove((buf).b + (i), (buf).b + (i) + 1, (--((buf).d) - (i)) * sizeof(*((buf).b))))
+#define bufadd(buf, new) \
+do { \
+    _sizebuf((struct buffer *)&(buf), (buf).d + 1, sizeof(*((buf).b))); \
+    (buf).b[(buf).d++] = (new); \
+} while(0)
+#define bufcat(buf, new, size) \
+do { \
+    size_t __bufcat_size__; \
+    __bufcat_size__ = (size); \
+    _sizebuf((struct buffer *)&(buf), (buf).d + __bufcat_size__, sizeof((buf).b)); \
+    memcpy((buf).b + (buf).d, (new), (__bufcat_size__) * sizeof(*((buf).b))); \
+    (buf).d += __bufcat_size__; \
+} while(0)
+#define bufcatnum(buf, num, type) \
+do { \
+    type __buf__; \
+    __buf__ = (num); \
+    bufcat((buf), &__buf__, sizeof(type)); \
+} while(0)
+#define bufcatuid(buf, uid) \
+do { \
+    uniqid_t __buf__; \
+    __buf__ = (uid); \
+    bufcat((buf), &__buf__, sizeof(__buf__)); \
+} while(0)
+#define bufcatstr(buf, str) \
+do { \
+    char *__buf__; \
+    __buf__ = (str); \
+    bufcat((buf), __buf__, strlen(__buf__) + 1); \
+} while(0)
+#define bufcatstr2(buf, str) \
+do { \
+    char *__buf__; \
+    __buf__ = (str); \
+    bufcat((buf), __buf__, strlen(__buf__)); \
+} while(0)
+#define bufcats(buf, d) bufcat((buf), &(d), sizeof(d))
+#define bufeat(buf, len) \
+do { \
+    size_t __bufeat_size__; \
+    __bufeat_size__ = (len); \
+    memmove((buf).b, (buf).b + __bufeat_size__, (buf).d -= __bufeat_size__); \
+} while(0)
+
+struct buffer {
+    void *b;
+    size_t s, d;
+};
+
+struct charbuf {
+    char *b;
+    size_t s, d;
+};
+
+struct charvbuf {
+    char **b;
+    size_t s, d;
+};
+
+struct ptrbuf {
+    void **b;
+    size_t s, d;
+};
+
+void _sizebuf(struct buffer *buf, size_t wanted, size_t el);
+void _sizebuf2(void **buf, size_t *sz, size_t wanted, size_t el);
+char *vsprintf2(char *format, va_list al);
+char *sprintf2(char *format, ...);
+
+#endif