+ 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);
+ }