diff options
Diffstat (limited to '')
-rw-r--r-- | agents/virt/common/bcast.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/agents/virt/common/bcast.c b/agents/virt/common/bcast.c new file mode 100644 index 0000000..2b498b7 --- /dev/null +++ b/agents/virt/common/bcast.c @@ -0,0 +1,347 @@ +/* + * Author: Lon Hohberger <lhh at redhat.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> + +/* Local includes */ +#include "bcast.h" +#include "debug.h" + +LOGSYS_DECLARE_SUBSYS ("XVM", SYSLOGLEVEL); + +/** + Sets up a multicast receive socket + */ +int +ipv4_bcast_recv_sk(char *addr, int port) +{ + int sock, val; + struct sockaddr_in sin; + + /* Store broadcast address */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = PF_INET; + sin.sin_port = htons(port); + if (inet_pton(PF_INET, addr, + (void *)&sin.sin_addr.s_addr) < 0) { + log_printf(LOG_ERR, "Invalid broadcast address: %s\n", addr); + return -1; + } + + dbg_printf(4, "Setting up ipv4 broadcast receive (%s:%d)\n", addr, port); + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + log_printf(LOG_ERR, "socket: %s\n", strerror(errno)); + close(sock); + sock = -1; + return 1; + } + + val = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, 1, sizeof(val)) < 0) { + log_printf(LOG_ERR, "setsockopt: %s\n", strerror(errno)); + close(sock); + return 1; + } + + /* + * Bind broadcast address + */ + if (bind(sock, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in)) < 0) { + printf("bind failed: %s\n", strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + +/** + Set up multicast send socket + */ +int +ipv4_bcast_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt, + socklen_t tgt_len, int ttl) +{ + int val; + struct ip_mreq mreq; + struct sockaddr_in mcast; + struct sockaddr_in src; + int sock; + + if (tgt_len < sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + /* Store multicast address */ + mcast.sin_family = PF_INET; + mcast.sin_port = htons(port); + if (inet_pton(PF_INET, addr, + (void *)&mcast.sin_addr.s_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + mreq.imr_multiaddr.s_addr = mcast.sin_addr.s_addr; + + /* Store sending address */ + src.sin_family = PF_INET; + src.sin_port = htons(port); + if (inet_pton(PF_INET, send_addr, + (void *)&src.sin_addr.s_addr) < 0) { + printf("Invalid source address: %s\n", send_addr); + return -1; + } + mreq.imr_interface.s_addr = src.sin_addr.s_addr; + + + /************************* + * SET UP MULTICAST SEND * + *************************/ + dbg_printf(4, "Setting up ipv4 multicast send (%s:%d)\n", addr, port); + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group (pass 1)\n"); + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast membership to transmit " + "socket %s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group (pass 2)\n"); + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &src.sin_addr, + sizeof(src.sin_addr)) == -1) { + printf("Failed to bind multicast transmit socket to " + "%s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * set time to live to 2 hops. + */ + dbg_printf(4, "Setting TTL to %d for fd%d\n", ttl, sock); + val = ttl; + if (setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &val, + sizeof(val))) + printf("warning: setting TTL failed %s\n", strerror(errno)); + + memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in)); + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + + +/** + Sets up a multicast receive (ipv6) socket + */ +int +ipv6_recv_sk(char *addr, int port) +{ + int sock, val; + struct ipv6_mreq mreq; + struct sockaddr_in6 sin; + + memset(&mreq, 0, sizeof(mreq)); + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = PF_INET6; + sin.sin6_port = htons(port); + if (inet_pton(PF_INET6, addr, + (void *)&sin.sin6_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + memcpy(&mreq.ipv6mr_multiaddr, &sin.sin6_addr, + sizeof(struct in6_addr)); + + + /******************************** + * SET UP MULTICAST RECV SOCKET * + ********************************/ + dbg_printf(4, "Setting up ipv6 multicast receive (%s:%d)\n", addr, port); + sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + printf("socket: %s\n", strerror(errno)); + close(sock); + sock = -1; + return 1; + } + + /* + * When using Multicast, bind to the LOCAL address, not the MULTICAST + * address. + */ + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = PF_INET6; + sin.sin6_port = htons(port); + sin.sin6_addr = in6addr_any; + if (bind(sock, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in6)) < 0) { + printf("bind failed: %s\n", strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "Disabling IP Multicast loopback\n"); + val = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof(val)) != 0) { + printf("Failed to disable multicast loopback\n"); + close(sock); + return -1; + } + + /* + * Join multicast group + */ + dbg_printf(4, "Joining IP Multicast group\n"); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast to socket %s: %s\n", + addr, strerror(errno)); + close(sock); + return -1; + } + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} + + +/** + Set up ipv6 multicast send socket + */ +int +ipv6_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt, + socklen_t tgt_len, int ttl) +{ + int val; + struct ipv6_mreq mreq; + struct sockaddr_in6 mcast; + struct sockaddr_in6 src; + int sock; + + if (tgt_len < sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + memset(&mreq, 0, sizeof(mreq)); + + /* Store multicast address */ + mcast.sin6_family = PF_INET6; + mcast.sin6_port = htons(port); + if (inet_pton(PF_INET6, addr, + (void *)&mcast.sin6_addr) < 0) { + printf("Invalid multicast address: %s\n", addr); + return -1; + } + + memcpy(&mreq.ipv6mr_multiaddr, &mcast.sin6_addr, + sizeof(struct in6_addr)); + + /* Store sending address */ + src.sin6_family = PF_INET6; + src.sin6_port = htons(port); + if (inet_pton(PF_INET6, send_addr, + (void *)&src.sin6_addr) < 0) { + printf("Invalid source address: %s\n", send_addr); + return -1; + } + + /************************* + * SET UP MULTICAST SEND * + *************************/ + dbg_printf(4, "Setting up ipv6 multicast send (%s:%d)\n", addr, port); + sock = socket(PF_INET6, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + dbg_printf(4, "Disabling IP Multicast loopback\n"); + val = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof(val)) != 0) { + printf("Failed to disable multicast loopback\n"); + close(sock); + return -1; + } + + /* + * Join Multicast group. + */ + dbg_printf(4, "Joining IP Multicast group\n"); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == -1) { + printf("Failed to add multicast membership to transmit " + "socket %s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + + /* + * Join Multicast group (part 2) + */ + /* + if (setsockopt(sock, IPPROTO_IPV6, IP_MULTICAST_IF, &src.sin6_addr, + sizeof(src.sin6_addr)) == -1) { + printf("Failed to bind multicast transmit socket to " + "%s: %s\n", addr, strerror(errno)); + close(sock); + return -1; + } + */ + + /* + * set time to live to 2 hops. + */ + val = ttl; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, + sizeof(val))) + printf("warning: setting TTL failed %s\n", strerror(errno)); + + memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in6)); + + dbg_printf(4, "%s: success, fd = %d\n", __FUNCTION__, sock); + return sock; +} |