From dd66edaacb31b0c4e4c7b68204ae4e760c1bc2d4 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Thu, 29 Sep 2011 09:32:27 -0600 Subject: [PATCH] add multicaster --- packages/multicaster/multicaster.mk | 16 +++ packages/multicaster/src/Makefile | 12 ++ packages/multicaster/src/multicaster-client.c | 109 ++++++++++++++++++ packages/multicaster/src/multicaster-server.c | 71 ++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 packages/multicaster/multicaster.mk create mode 100644 packages/multicaster/src/Makefile create mode 100644 packages/multicaster/src/multicaster-client.c create mode 100644 packages/multicaster/src/multicaster-server.c diff --git a/packages/multicaster/multicaster.mk b/packages/multicaster/multicaster.mk new file mode 100644 index 0000000..ce8e15c --- /dev/null +++ b/packages/multicaster/multicaster.mk @@ -0,0 +1,16 @@ +MULTICASTER_PKGDIR = $(TARGET)/multicaster + +multicaster-install: multicaster-build + mkdir -p $(MULTICASTER_PKGDIR) + + mkdir -p $(MULTICASTER_PKGDIR)/bin/ + $(MAKE) -C packages/multicaster/src install DESTDIR=$(CURDIR)/$(MULTICASTER_PKGDIR) + +multicaster-clean: + rm -rf $(MULTICASTER_PKGDIR) + $(MAKE) -C packages/multicaster/src clean + +multicaster-build: + $(MAKE) -C packages/multicaster/src build + +PACKAGES += multicaster diff --git a/packages/multicaster/src/Makefile b/packages/multicaster/src/Makefile new file mode 100644 index 0000000..629b3dc --- /dev/null +++ b/packages/multicaster/src/Makefile @@ -0,0 +1,12 @@ +CFLAGS = -Wall -Werror +LDFLAGS = -static +TARGETS = multicaster-server multicaster-client + +all: build +build: $(TARGETS) + +install: $(TARGETS) + install -m 0755 $(TARGETS) $(DESTDIR)/bin + +clean: + rm -f *.o $(TARGETS) \ No newline at end of file diff --git a/packages/multicaster/src/multicaster-client.c b/packages/multicaster/src/multicaster-client.c new file mode 100644 index 0000000..6c00f66 --- /dev/null +++ b/packages/multicaster/src/multicaster-client.c @@ -0,0 +1,109 @@ +/* multicast_client.c + * Adopted from tmouse's client/server example code + * found at http://cboard.cprogramming.com/showthread.php?t=67469 + */ + +#include +#include +#include +#include /* for printf() and fprintf() */ +#include /* for atoi() and exit() */ +#include /* for memset() */ +#include /* for timestamps */ +#include + +void DieWithError(const char* errorMessage) +{ + fprintf(stderr, "%s\n", errorMessage); + exit(10); +} + +int main(int argc, char* argv[]) +{ + int sock; /* Socket */ + char* multicastIP; /* Arg: IP Multicast Address */ + char* multicastPort; /* Arg: Port */ + struct addrinfo * multicastAddr = {0}; /* Multicast Address */ + struct addrinfo * localAddr; /* Local address to bind to */ + struct addrinfo hints = { 0 }; /* Hints for name lookup */ + + if ( argc != 3 ) + { + fprintf(stderr,"Usage: %s \n", argv[0]); + exit(10); + } + + multicastIP = argv[1]; /* First arg: Multicast IP address */ + multicastPort = argv[2]; /* Second arg: Multicast port */ + + /* Resolve the multicast group address */ + hints.ai_family = PF_INET6; + hints.ai_flags = AI_NUMERICHOST; + if ( getaddrinfo(multicastIP, NULL, &hints, &multicastAddr) != 0 ) DieWithError("getaddrinfo() failed"); + + /* Get a local address with the same family as our multicast group */ + hints.ai_family = multicastAddr->ai_family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; /* Return an address we can bind to */ + if ( getaddrinfo(NULL, multicastPort, &hints, &localAddr) != 0 ) + { + DieWithError("getaddrinfo() failed"); + } + + /* Create socket for receiving datagrams */ + if ( (sock = socket(localAddr->ai_family, localAddr->ai_socktype, 0)) == -1 ) + { + DieWithError("socket() failed"); + } + + const int trueValue = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &trueValue, sizeof(trueValue)); +#ifdef __APPLE__ + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const void *) &trueValue, sizeof(trueValue)); +#endif + + /* Bind to the multicast port */ + if ( bind(sock, localAddr->ai_addr, localAddr->ai_addrlen) != 0 ) + { + DieWithError("bind() failed"); + } + + /* Join the multicast group. */ + if ((multicastAddr->ai_family == PF_INET6)&&(multicastAddr->ai_addrlen == sizeof(struct sockaddr_in6))) + { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(multicastAddr->ai_addr); + struct ipv6_mreq multicastRequest; /* Multicast address join structure */ + + /* Specify the multicast group */ + memcpy(&multicastRequest.ipv6mr_multiaddr, &((struct sockaddr_in6*)(multicastAddr->ai_addr))->sin6_addr, sizeof(multicastRequest.ipv6mr_multiaddr)); + + printf("scope_id: %d\n", addr->sin6_scope_id); + + /* Accept multicast from any interface */ + multicastRequest.ipv6mr_interface = addr->sin6_scope_id; + + /* Join the multicast address */ + if ( setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*) &multicastRequest, sizeof(multicastRequest)) != 0 ) DieWithError("setsockopt(IPV6_JOIN_GROUP) failed"); + } + else DieWithError("Not IPv6"); + + freeaddrinfo(localAddr); + freeaddrinfo(multicastAddr); + + for (;;) /* Run forever */ + { + char recvString[500]; /* Buffer for received string */ + int recvStringLen; /* Length of received string */ + + /* Receive a single datagram from the server */ + if ((recvStringLen = recvfrom(sock, recvString, sizeof(recvString) - 1, 0, NULL, 0)) < 0) DieWithError("recvfrom() failed"); + recvString[recvStringLen] = '\0'; + + /* Print the received string */ + printf("Received string [%s]\n", recvString); + } + + /* NOT REACHED */ + close(sock); + exit(EXIT_SUCCESS); +} diff --git a/packages/multicaster/src/multicaster-server.c b/packages/multicaster/src/multicaster-server.c new file mode 100644 index 0000000..5812d14 --- /dev/null +++ b/packages/multicaster/src/multicaster-server.c @@ -0,0 +1,71 @@ +/* multicast_server.c + * Adapted from tmouse's IPv6 client/server example code + * found at http://cboard.cprogramming.com/showthread.php?t=67469 + */ + +#include /* for fprintf() */ +#include +#include +#include +#include /* for atoi() and exit() */ +#include +#include + +static void DieWithError(const char* errorMessage) +{ + fprintf(stderr, "%s\n", errorMessage); + exit(10); +} + +int main(int argc, char *argv[]) +{ + int sock; /* Socket */ + char* multicastIP; /* Arg: IP Multicast address */ + char* multicastPort; /* Arg: Server port */ + char* sendString; /* Arg: String to multicast */ + size_t sendStringLen; /* Length of string to multicast */ + struct addrinfo * multicastAddr; /* Multicast address */ + struct addrinfo hints = { 0 }; /* Hints for name lookup */ + + if ( argc != 4 ) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(10); + } + + multicastIP = argv[1]; /* First arg: multicast IP address */ + multicastPort = argv[2]; /* Second arg: multicast port */ + sendString = argv[3]; /* Third arg: String to multicast */ + sendStringLen = strlen(sendString); /* Find length of sendString */ + + /* Resolve destination address for multicast datagrams */ + hints.ai_family = PF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(multicastIP, multicastPort, &hints, &multicastAddr) != 0) DieWithError("getaddrinfo() failed"); + + /* Create socket for sending multicast datagrams */ + if ((sock = socket(multicastAddr->ai_family, multicastAddr->ai_socktype, 0)) == -1) DieWithError("socket() failed"); + + //int scope_id = if_nametoindex("eth0"); + //if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char *) &scope_id, sizeof(scope_id)) != 0) DieWithError("setsockopt(MULTICAST_IF) failed"); + + for (;;) /* Run forever */ + { + int sendLen = sendto(sock, sendString, sendStringLen, 0, multicastAddr->ai_addr, multicastAddr->ai_addrlen); + if (sendLen == sendStringLen ) + { + printf("Sent [%s] (%i bytes) to %s, port %s\n", sendString, sendLen, multicastIP, multicastPort); + } + else + { + DieWithError("sendto() sent a different number of bytes than expected"); + } + sleep(1); /* Multicast sendString in datagram to clients every second */ + } + + /* NOT REACHED */ + freeaddrinfo(multicastAddr); + close(sock); + return 0; +}