summaryrefslogtreecommitdiff
path: root/draft/mcastseed/src/sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'draft/mcastseed/src/sockets.c')
-rw-r--r--draft/mcastseed/src/sockets.c303
1 files changed, 303 insertions, 0 deletions
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 <ludovic@pouzenc.fr>
+ *
+ * Greatly inspired from msock.h written by Christian Beier <dontmind@sdf.org>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#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;
+}
+