Support setting TTL on outgoing UDP streams. Especially useful for multicast.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 26 Apr 2014 17:00:37 +0000 (19:00 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 26 Apr 2014 17:00:37 +0000 (19:00 +0200)
config.cpp
config.h
cubemap.config.sample
main.cpp
serverpool.cpp
serverpool.h
udpstream.cpp
udpstream.h

index f1b05c1..57bf10a 100644 (file)
@@ -290,6 +290,14 @@ bool parse_udpstream(const ConfigLine &line, Config *config)
                udpstream.pacing_rate = atoi(pacing_rate_it->second.c_str()) * 1024 / 8;
        }
 
+       // Parse the TTL. The same value is used for unicast and multicast.
+       map<string, string>::const_iterator ttl_it = line.parameters.find("ttl");
+       if (ttl_it == line.parameters.end()) {
+               udpstream.ttl = -1;
+       } else {
+               udpstream.ttl = atoi(ttl_it->second.c_str());
+       }
+
        config->udpstreams.push_back(udpstream);
        return true;
 }
index 6053148..d5b0411 100644 (file)
--- a/config.h
+++ b/config.h
@@ -21,6 +21,7 @@ struct UDPStreamConfig {
        sockaddr_in6 dst;
        std::string src;  // Can be empty.
        uint32_t pacing_rate;  // In bytes per second. Default is ~0U (no limit).
+       int ttl;  // Default is -1 (use operating system default).
 };
 
 struct AcceptorConfig {
index 9b3c22b..a68bfb8 100644 (file)
@@ -38,3 +38,4 @@ stream /test.flv.metacube src=http://gruessi.zrh.sesse.net:4013/test.flv encodin
 stream /udp.ts src=udp://@:1234 backlog_size=1048576 pacing_rate_kbit=2000
 udpstream [2001:67c:29f4::50]:5000 src=http://pannekake.samfundet.no:9094/frikanalen.ts.metacube
 udpstream 193.35.52.50:5001 src=http://pannekake.samfundet.no:9094/frikanalen.ts.metacube
+udpstream 233.252.0.1:5002 src=http://pannekake.samfundet.no:9094/frikanalen.ts.metacube ttl=32
index 5ba79f9..eaec887 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -201,7 +201,10 @@ void create_streams(const Config &config,
        // UDP streams.
        for (unsigned i = 0; i < config.udpstreams.size(); ++i) {
                const UDPStreamConfig &udpstream_config = config.udpstreams[i];
-               int stream_index = servers->add_udpstream(udpstream_config.dst, udpstream_config.pacing_rate);
+               int stream_index = servers->add_udpstream(
+                       udpstream_config.dst,
+                       udpstream_config.pacing_rate,
+                       udpstream_config.ttl);
 
                string src = udpstream_config.src;
                if (!src.empty()) {
index 70f8658..021cf1d 100644 (file)
@@ -121,9 +121,9 @@ int ServerPool::add_stream_from_serialized(const StreamProto &stream, const vect
        return num_http_streams++;
 }
        
-int ServerPool::add_udpstream(const sockaddr_in6 &dst, int pacing_rate)
+int ServerPool::add_udpstream(const sockaddr_in6 &dst, int pacing_rate, int ttl)
 {
-       udp_streams.push_back(new UDPStream(dst, pacing_rate));
+       udp_streams.push_back(new UDPStream(dst, pacing_rate, ttl));
        return num_http_streams + udp_streams.size() - 1;
 }
 
index 2c2c537..07d9a5d 100644 (file)
@@ -32,7 +32,7 @@ public:
        int add_stream(const std::string &url, size_t backlog_size, Stream::Encoding encoding);
        int add_stream_from_serialized(const StreamProto &stream, const std::vector<int> &data_fds);
        void delete_stream(const std::string &url);
-       int add_udpstream(const sockaddr_in6 &dst, int pacing_rate);
+       int add_udpstream(const sockaddr_in6 &dst, int pacing_rate, int ttl);
 
        // Returns the stream index for the given URL (e.g. /foo.ts). Returns -1 on failure.
        int lookup_stream_by_url(const std::string &url) const;
index 1e79494..74d6ef0 100644 (file)
@@ -9,8 +9,8 @@
 #define SO_MAX_PACING_RATE 47
 #endif
 
-UDPStream::UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate)
-       : dst(dst) 
+UDPStream::UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate, int ttl)
+       : dst(dst)
 {
        sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
        if (sock == -1) {
@@ -24,6 +24,23 @@ UDPStream::UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate)
                        log_perror("setsockopt(SO_MAX_PACING_RATE)");
                }
        }
+
+       if (ttl != -1) {
+               // Seemingly the IPv4 parameters are used for sending to IPv4,
+               // even on an AF_INET6 socket, so we need to set both.
+               if (setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
+                       log_perror("setsockopt(IP_TTL)");
+               }
+               if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
+                       log_perror("setsockopt(IP_MULTICAST_TTL)");
+               }
+               if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
+                       log_perror("setsockopt(IPV6_UNICAST_HOPS)");
+               }
+               if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
+                       log_perror("setsockopt(IPV6_MULTICAST_HOPS)");
+               }
+       }
 }
 
 UDPStream::~UDPStream()
index ebc8ebc..4a2de65 100644 (file)
@@ -16,7 +16,7 @@ class MarkPool;
 
 class UDPStream {
 public:
-       UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate);
+       UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate, int ttl);
        ~UDPStream();
 
        void send(const char *data, size_t bytes);