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;
}
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 {
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
// 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()) {
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;
}
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;
#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) {
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()
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);