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