summaryrefslogtreecommitdiff
path: root/mcastseed/src/msock.c
diff options
context:
space:
mode:
authorLudovic Pouzenc <ludovic@pouzenc.fr>2016-06-17 11:31:16 +0200
committerLudovic Pouzenc <ludovic@pouzenc.fr>2016-06-17 11:31:16 +0200
commitfbb8c27761964f3ee87f859bfbb57db75849cd1a (patch)
tree6ec5ed2a72e5e2205614ec96678c62aee3c869c4 /mcastseed/src/msock.c
downloadeficast-fbb8c27761964f3ee87f859bfbb57db75849cd1a.tar.gz
eficast-fbb8c27761964f3ee87f859bfbb57db75849cd1a.tar.bz2
eficast-fbb8c27761964f3ee87f859bfbb57db75849cd1a.zip
Initial import : make-boot-image.sh operationnal. Dumb mcastseed.
Diffstat (limited to 'mcastseed/src/msock.c')
-rw-r--r--mcastseed/src/msock.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/mcastseed/src/msock.c b/mcastseed/src/msock.c
new file mode 100644
index 0000000..8274710
--- /dev/null
+++ b/mcastseed/src/msock.c
@@ -0,0 +1,371 @@
+/*
+ msock.c - multicast socket creation routines
+
+ (C) 2016 Christian Beier <dontmind@sdf.org>
+
+*/
+
+#ifndef __MINGW32__
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "msock.h"
+
+SOCKET mcast_send_socket(char* multicastIP, char* multicastPort, int multicastTTL, struct addrinfo **multicastAddr) {
+
+ SOCKET sock;
+ struct addrinfo hints = { 0 }; /* Hints for name lookup */
+
+
+#ifdef WIN32
+ WSADATA trash;
+ if(WSAStartup(MAKEWORD(2,0),&trash)!=0)
+ DieWithError("Couldn't init Windows Sockets\n");
+#endif
+
+
+ /*
+ Resolve destination address for multicast datagrams
+ */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ int status;
+ if ((status = getaddrinfo(multicastIP, multicastPort, &hints, multicastAddr)) != 0 )
+ {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
+ return -1;
+ }
+
+
+
+ /*
+ Create socket for sending multicast datagrams
+ */
+ if ( (sock = socket((*multicastAddr)->ai_family, (*multicastAddr)->ai_socktype, 0)) < 0 ) {
+ perror("socket() failed");
+ freeaddrinfo(*multicastAddr);
+ return -1;
+ }
+
+ /*
+ Set TTL of multicast packet
+ */
+ if ( setsockopt(sock,
+ (*multicastAddr)->ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
+ (*multicastAddr)->ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL,
+ (char*) &multicastTTL, sizeof(multicastTTL)) != 0 ) {
+ perror("setsockopt() failed");
+ freeaddrinfo(*multicastAddr);
+ return -1;
+ }
+
+
+ /*
+ set the sending interface
+ */
+ if((*multicastAddr)->ai_family == PF_INET) {
+ in_addr_t iface = INADDR_ANY; /* well, yeah, any */
+ if(setsockopt (sock,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (char*)&iface, sizeof(iface)) != 0) {
+ perror("interface setsockopt() sending interface");
+ freeaddrinfo(*multicastAddr);
+ return -1;
+ }
+
+ }
+ if((*multicastAddr)->ai_family == PF_INET6) {
+ unsigned int ifindex = 0; /* 0 means 'default interface'*/
+ if(setsockopt (sock,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ (char*)&ifindex, sizeof(ifindex)) != 0) {
+ perror("interface setsockopt() sending interface");
+ freeaddrinfo(*multicastAddr);
+ return -1;
+ }
+
+ }
+
+
+ return sock;
+
+}
+
+
+
+SOCKET mcast_recv_socket(char* multicastIP, char* multicastPort, int multicastRecvBufSize) {
+
+ SOCKET sock;
+ struct addrinfo hints = { 0 }; /* Hints for name lookup */
+ struct addrinfo* localAddr = 0; /* Local address to bind to */
+ struct addrinfo* multicastAddr = 0; /* Multicast Address */
+ int yes=1;
+
+#ifdef WIN32
+ WSADATA trash;
+ if(WSAStartup(MAKEWORD(2,0),&trash)!=0)
+ DieWithError("Couldn't init Windows Sockets\n");
+#endif
+
+
+ /* Resolve the multicast group address */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ int status;
+ if ((status = getaddrinfo(multicastIP, NULL, &hints, &multicastAddr)) != 0) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
+ goto error;
+ }
+
+
+ /*
+ Get a local address with the same family (IPv4 or IPv6) as our multicast group
+ This is for receiving on a certain port.
+ */
+ 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 ) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
+ goto error;
+ }
+
+
+ /* Create socket for receiving datagrams */
+ if ( (sock = socket(localAddr->ai_family, localAddr->ai_socktype, 0)) < 0 ) {
+ perror("socket() failed");
+ goto error;
+ }
+
+
+
+ /*
+ * Enable SO_REUSEADDR to allow multiple instances of this
+ * application to receive copies of the multicast datagrams.
+ */
+ if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(int)) == -1) {
+ perror("setsockopt");
+ goto error;
+ }
+
+ /* Bind the local address to the multicast port */
+ if ( bind(sock, localAddr->ai_addr, localAddr->ai_addrlen) != 0 ) {
+ perror("bind() failed");
+ goto error;
+ }
+
+ /* get/set socket receive buffer */
+ int optval=0;
+ socklen_t optval_len = sizeof(optval);
+ int dfltrcvbuf;
+ if(getsockopt(sock, SOL_SOCKET, SO_RCVBUF,(char*)&optval, &optval_len) !=0) {
+ perror("getsockopt");
+ goto error;
+ }
+ dfltrcvbuf = optval;
+ optval = multicastRecvBufSize;
+ if(setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&optval,sizeof(optval)) != 0) {
+ perror("setsockopt");
+ goto error;
+ }
+ if(getsockopt(sock, SOL_SOCKET, SO_RCVBUF,(char*)&optval, &optval_len) != 0) {
+ perror("getsockopt");
+ goto error;
+ }
+ printf("tried to set socket receive buffer from %d to %d, got %d\n",
+ dfltrcvbuf, multicastRecvBufSize, optval);
+
+
+
+
+ /* Join the multicast group. We do this seperately depending on whether we
+ * are using IPv4 or IPv6.
+ */
+ if ( multicastAddr->ai_family == PF_INET &&
+ multicastAddr->ai_addrlen == sizeof(struct sockaddr_in) ) /* IPv4 */
+ {
+ struct ip_mreq multicastRequest; /* Multicast address join structure */
+
+ /* Specify the multicast group */
+ memcpy(&multicastRequest.imr_multiaddr,
+ &((struct sockaddr_in*)(multicastAddr->ai_addr))->sin_addr,
+ sizeof(multicastRequest.imr_multiaddr));
+
+ /* Accept multicast from any interface */
+ multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ /* Join the multicast address */
+ if ( setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &multicastRequest, sizeof(multicastRequest)) != 0 ) {
+ perror("setsockopt() failed");
+ goto error;
+ }
+ }
+ else if ( multicastAddr->ai_family == PF_INET6 &&
+ multicastAddr->ai_addrlen == sizeof(struct sockaddr_in6) ) /* IPv6 */
+ {
+ 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));
+
+ /* Accept multicast from any interface */
+ multicastRequest.ipv6mr_interface = 0;
+
+ /* Join the multicast address */
+ if ( setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*) &multicastRequest, sizeof(multicastRequest)) != 0 ) {
+ perror("setsockopt() failed");
+ goto error;
+ }
+ }
+ else {
+ perror("Neither IPv4 or IPv6");
+ goto error;
+ }
+
+
+
+ if(localAddr)
+ freeaddrinfo(localAddr);
+ if(multicastAddr)
+ freeaddrinfo(multicastAddr);
+
+ return sock;
+
+ error:
+ if(localAddr)
+ freeaddrinfo(localAddr);
+ if(multicastAddr)
+ freeaddrinfo(multicastAddr);
+
+ return -1;
+}
+
+SOCKET ucast_client_socket(char* serverIP, char* serverPort) {
+
+ SOCKET sock;
+ struct addrinfo *serverAddr;
+ struct addrinfo hints = { 0 }; /* Hints for name lookup */
+
+
+#ifdef WIN32
+ WSADATA trash;
+ if(WSAStartup(MAKEWORD(2,0),&trash)!=0)
+ DieWithError("Couldn't init Windows Sockets\n");
+#endif
+
+
+ /*
+ Resolve destination address
+ */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ int status;
+ if ((status = getaddrinfo(serverIP, serverPort, &hints, &serverAddr)) != 0 )
+ {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
+ return -1;
+ }
+
+ /*
+ Create socket
+ */
+ if ( (sock = socket(serverAddr->ai_family, serverAddr->ai_socktype, 0)) < 0 ) {
+ perror("socket() failed");
+ freeaddrinfo(serverAddr);
+ return -1;
+ }
+
+ /*
+ Connect it to the remote server
+ */
+ if ( connect(sock, serverAddr->ai_addr, serverAddr->ai_addrlen) < 0 ) {
+ perror("connect() failed");
+ close(sock);
+ freeaddrinfo(serverAddr);
+ return -1;
+ }
+
+ freeaddrinfo(serverAddr);
+ return sock;
+}
+
+SOCKET ucast_server_socket(char* serverPort, int maxPendingConnections) {
+
+ SOCKET sock;
+ struct addrinfo *serverAddr;
+ struct addrinfo hints = { 0 }; /* Hints for name lookup */
+
+
+#ifdef WIN32
+ WSADATA trash;
+ if(WSAStartup(MAKEWORD(2,0),&trash)!=0)
+ DieWithError("Couldn't init Windows Sockets\n");
+#endif
+
+
+ /*
+ Prepare an addrinfo struct for a local socket
+ */
+ hints.ai_family = PF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ int status;
+ if ((status = getaddrinfo(NULL, serverPort, &hints, &serverAddr)) != 0 )
+ {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
+ return -1;
+ }
+ /*
+ Create socket
+ */
+ if ( (sock = socket(serverAddr->ai_family, serverAddr->ai_socktype, serverAddr->ai_protocol)) < 0 ) {
+ perror("socket() failed");
+ freeaddrinfo(serverAddr);
+ return -1;
+ }
+
+ /*
+ Accepts also IPv4 traffic if the socket is INET6
+ */
+ if(serverAddr->ai_family == PF_INET6) {
+ unsigned int no = 0;
+ if(setsockopt (sock,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (char*)&no, sizeof(no)) != 0) {
+ perror("setsockopt() !IPV6_V6ONLY failed");
+ freeaddrinfo(serverAddr);
+ return -1;
+ }
+ }
+
+ /*
+ Bind socket to local address/port
+ */
+ if ( bind(sock, serverAddr->ai_addr, serverAddr->ai_addrlen) < 0 ) {
+ perror("bind() failed");
+ close(sock);
+ freeaddrinfo(serverAddr);
+ return -1;
+ }
+
+ freeaddrinfo(serverAddr);
+ /*
+ Start listening incoming connections
+ */
+ if ( listen(sock, maxPendingConnections) < 0 ) {
+ perror("listen() failed");
+ close(sock);
+ }
+
+ return sock;
+}