Release Cubemap 1.4.3.
[cubemap] / udpstream.cpp
1 #include <string.h>
2 #include <sys/socket.h>
3 #include <sys/types.h>
4
5 #include "log.h"
6 #include "udpstream.h"
7 #include "util.h"
8
9 #ifndef SO_MAX_PACING_RATE
10 #define SO_MAX_PACING_RATE 47
11 #endif
12
13 UDPStream::UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate, int ttl, int multicast_iface_index)
14         : dst(dst)
15 {
16         sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
17         if (sock == -1) {
18                 // Oops. Ignore this output, then.
19                 log_perror("socket");
20                 return;
21         }
22
23         if (setsockopt(sock, SOL_SOCKET, SO_MAX_PACING_RATE, &pacing_rate, sizeof(pacing_rate)) == -1) {
24                 if (pacing_rate != ~0U) {
25                         log_perror("setsockopt(SO_MAX_PACING_RATE)");
26                 }
27         }
28
29         if (ttl != -1) {
30                 // Seemingly the IPv4 parameters are used for sending to IPv4,
31                 // even on an AF_INET6 socket, so we need to set both.
32                 if (setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
33                         log_perror("setsockopt(IP_TTL)");
34                 }
35                 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
36                         log_perror("setsockopt(IP_MULTICAST_TTL)");
37                 }
38                 if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
39                         log_perror("setsockopt(IPV6_UNICAST_HOPS)");
40                 }
41                 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
42                         log_perror("setsockopt(IPV6_MULTICAST_HOPS)");
43                 }
44         }
45
46         if (multicast_iface_index != -1) {
47                 ip_mreqn mr;
48                 memset(&mr, 0, sizeof(mr));
49                 mr.imr_ifindex = multicast_iface_index;
50                 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mr, sizeof(mr)) == -1) {
51                         log_perror("setsockopt(IP_MULTICAST_IF)");
52                 }
53                 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface_index, sizeof(multicast_iface_index)) == -1) {
54                         log_perror("setsockopt(IPV6_MULTICAST_IF)");
55                 }
56         }
57 }
58
59 UDPStream::~UDPStream()
60 {
61         if (sock != -1) {
62                 safe_close(sock);
63         }
64 }
65
66 void UDPStream::send(const char *data, size_t bytes)
67 {
68         if (sock == -1) {
69                 return;
70         }
71         ssize_t err = sendto(sock, data, bytes, 0, reinterpret_cast<sockaddr *>(&dst), sizeof(dst));
72         if (err == -1) {
73                 log_perror("sendto");
74         }
75 }