#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;
+ int soval;
+ struct sockaddr_in nm;
+ struct ip_mreqn mreq;
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ soval = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &soval, sizeof(soval)))
+ return(-1);
+ 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, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
+ return(-1);
+ soval = 1;
+ if(setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &soval, sizeof(soval)))
+ return(-1);
+ return(fd);
+}
+
+static void test(int fd)
+{
+ char buf[65536];
+ int i, 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);
+ for(i = 0; i < ret; i++) {
+ printf("%02x ", (unsigned char)buf[i]);
+ if(i % 20 == 0)
+ putchar(10);
+ }
+ }
}
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);
}