1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "log.h"
#include "udpstream.h"
#include "util.h"
#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 | SOCK_CLOEXEC, IPPROTO_UDP);
if (sock == -1) {
// Oops. Ignore this output, then.
log_perror("socket");
return;
}
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)");
}
}
}
UDPStream::~UDPStream()
{
if (sock != -1) {
safe_close(sock);
}
}
void UDPStream::send(const char *data, size_t bytes)
{
if (sock == -1) {
return;
}
ssize_t err = sendto(sock, data, bytes, 0, reinterpret_cast<sockaddr *>(&dst), sizeof(dst));
if (err == -1) {
log_perror("sendto");
}
}
|