+#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "log.h"
-#include "markpool.h"
#include "udpstream.h"
#include "util.h"
-UDPStream::UDPStream(const sockaddr_in6 &dst, MarkPool *mark_pool)
- : dst(dst),
- mark_pool(mark_pool),
- fwmark(0)
+#ifndef SO_MAX_PACING_RATE
+#define SO_MAX_PACING_RATE 47
+#endif
+
+UDPStream::UDPStream(const sockaddr_in6 &dst, uint32_t pacing_rate, int ttl, int multicast_iface_index)
+ : dst(dst)
{
sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
return;
}
- if (mark_pool != NULL) {
- fwmark = mark_pool->get_mark();
- if (setsockopt(sock, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark)) == -1) {
- if (fwmark != 0) {
- log_perror("setsockopt(SO_MARK)");
- }
+ if (setsockopt(sock, SOL_SOCKET, SO_MAX_PACING_RATE, &pacing_rate, sizeof(pacing_rate)) == -1) {
+ if (pacing_rate != ~0U) {
+ 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)");
+ }
+ }
+
+ if (multicast_iface_index != -1) {
+ ip_mreqn mr;
+ memset(&mr, 0, sizeof(mr));
+ mr.imr_ifindex = multicast_iface_index;
+ if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mr, sizeof(mr)) == -1) {
+ log_perror("setsockopt(IP_MULTICAST_IF)");
+ }
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface_index, sizeof(multicast_iface_index)) == -1) {
+ log_perror("setsockopt(IPV6_MULTICAST_IF)");
}
}
}
if (sock != -1) {
safe_close(sock);
}
- if (mark_pool != NULL) {
- mark_pool->release_mark(fwmark);
- }
}
void UDPStream::send(const char *data, size_t bytes)