From 604f3d64764270c052cfb43081ec522237bbdb75 Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Fri, 5 May 2017 11:28:51 +0200 Subject: Massive add for all draft stuff to keep it in sync --- draft/mcastseed/src/sockets.c | 303 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 draft/mcastseed/src/sockets.c (limited to 'draft/mcastseed/src/sockets.c') diff --git a/draft/mcastseed/src/sockets.c b/draft/mcastseed/src/sockets.c new file mode 100644 index 0000000..6aea016 --- /dev/null +++ b/draft/mcastseed/src/sockets.c @@ -0,0 +1,303 @@ +/* + * Copyright 2016 by Ludovic Pouzenc + * + * Greatly inspired from msock.h written by Christian Beier + */ +#include +#include +#include +#include "sockets.h" + +int mcast_recv_socket(char *mcast_ip, char *port, int wanted_so_rcvbuf) { + + int sock; + struct addrinfo hints = { 0 }; /* Hints for name lookup */ + struct addrinfo *ai_local = NULL; /* Local address to bind to */ + struct addrinfo *mcast_ai = NULL; /* Multicast Address */ + int yes=1; + int status, optval; + socklen_t optval_len; + int dfltrcvbuf; + + /* Resolve the multicast group address */ + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + if ((status = getaddrinfo(mcast_ip, NULL, &hints, &mcast_ai)) != 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 = mcast_ai->ai_family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; /* Return an address we can bind to */ + if ( getaddrinfo(NULL, port, &hints, &ai_local) != 0 ) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); + goto error; + } + + /* Create socket for receiving datagrams */ + if ( (sock = socket(ai_local->ai_family, ai_local->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, ai_local->ai_addr, ai_local->ai_addrlen) != 0 ) { + perror("bind() failed"); + goto error; + } + + /* get/set socket receive buffer */ + optval=0; + optval_len = sizeof(optval); + if(getsockopt(sock, SOL_SOCKET, SO_RCVBUF,(char*)&optval, &optval_len) !=0) { + perror("getsockopt"); + goto error; + } + dfltrcvbuf = optval; + optval = wanted_so_rcvbuf; + 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; + } + fprintf(stderr, "tried to set socket receive buffer from %d to %d, got %d\n", + dfltrcvbuf, wanted_so_rcvbuf, optval); + + + /* Join the multicast group. We do this seperately depending on whether we + * are using IPv4 or IPv6. + */ + if ( mcast_ai->ai_family == PF_INET && + mcast_ai->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*)(mcast_ai->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 ( mcast_ai->ai_family == PF_INET6 && + mcast_ai->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*)(mcast_ai->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(ai_local) + freeaddrinfo(ai_local); + if(mcast_ai) + freeaddrinfo(mcast_ai); + + return sock; + +error: + if(ai_local) + freeaddrinfo(ai_local); + if(mcast_ai) + freeaddrinfo(mcast_ai); + + return -1; +} + + +int mcast_send_socket(char* mcast_ip, char* port, int multicastTTL, struct addrinfo **mcast_ai) { + + int sock; + struct addrinfo hints = { 0 }; /* Hints for name lookup */ + int status; + + + /* Resolve destination address for multicast datagrams */ + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + if ((status = getaddrinfo(mcast_ip, port, &hints, mcast_ai)) != 0 ) + { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); + return -1; + } + + /* Create socket for sending multicast datagrams */ + if ( (sock = socket((*mcast_ai)->ai_family, (*mcast_ai)->ai_socktype, 0)) < 0 ) { + perror("socket() failed"); + freeaddrinfo(*mcast_ai); + return -1; + } + + /* Set TTL of multicast packet */ + if ( setsockopt(sock, + (*mcast_ai)->ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, + (*mcast_ai)->ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL, + (char*) &multicastTTL, sizeof(multicastTTL)) != 0 ) { + perror("setsockopt() failed"); + freeaddrinfo(*mcast_ai); + return -1; + } + + /* set the sending interface */ + if((*mcast_ai)->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(*mcast_ai); + return -1; + } + + } + if((*mcast_ai)->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(*mcast_ai); + return -1; + } + + } + + return sock; +} + + +int ucast_server_socket(char* port, int max_pending_conn) { + + int sock; + struct addrinfo *serverAddr; + struct addrinfo hints = { 0 }; /* Hints for name lookup */ + int status; + + + /* Prepare an addrinfo struct for a local socket */ + hints.ai_family = PF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((status = getaddrinfo(NULL, port, &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, max_pending_conn) < 0 ) { + perror("listen() failed"); + close(sock); + } + + return sock; +} + +int ucast_client_socket(char* server_ip, char* port) { + + int sock; + struct addrinfo *serverAddr; + struct addrinfo hints = { 0 }; /* Hints for name lookup */ + int status; + + /* Resolve destination address */ + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + if ((status = getaddrinfo(server_ip, port, &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; +} + -- cgit v1.2.3