bin_PROGRAMS=mctap
-mctap_SOURCES=mctap.c
+mctap_SOURCES=mctap.c utils.c
#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);
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);
}
--- /dev/null
+#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);
+}
--- /dev/null
+#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