mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-10-29 11:23:23 +00:00
fix: add FreeBSD support for local address handling
- Add FreeBSD-specific packet info handling in ENet unix.c - Use IP_RECVDSTADDR/IP_SENDSRCADDR for FreeBSD instead of IP_PKTINFO - Enable IP_RECVDSTADDR socket option on video/audio sockets for FreeBSD - Remove incorrect IP_PKTINFO macro redefinition from misc.cpp - Add FreeBSD-specific send code in Sunshine's UDP streaming functions Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
This commit is contained in:
parent
6300ea0641
commit
69751d1943
63
patches/enet_freebsd.patch
Normal file
63
patches/enet_freebsd.patch
Normal file
@ -0,0 +1,63 @@
|
||||
diff --git a/unix.c b/unix.c
|
||||
index 1234567..abcdefg 100644
|
||||
--- a/unix.c
|
||||
+++ b/unix.c
|
||||
@@ -373,6 +373,14 @@ enet_socket_create (ENetSocketType type, int af)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#if defined(__FreeBSD__) && defined(IP_RECVDSTADDR)
|
||||
+ {
|
||||
+ // Enable IP_RECVDSTADDR for FreeBSD to receive destination address
|
||||
+ int on = 1;
|
||||
+ setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, (char *)&on, sizeof(on));
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
#ifdef IP_PKTINFO
|
||||
{
|
||||
// We turn this on for all sockets because it may be required for IPv4
|
||||
@@ -617,6 +625,21 @@ enet_socket_send (ENetSocket socket,
|
||||
// from this peer to ensure it correctly recognizes our responses as
|
||||
// coming from the expected host.
|
||||
if (localAddress != NULL) {
|
||||
+#if defined(__FreeBSD__) && defined(IP_SENDSRCADDR)
|
||||
+ if (localAddress->address.ss_family == AF_INET) {
|
||||
+ struct in_addr srcAddr = ((struct sockaddr_in*)&localAddress->address)->sin_addr;
|
||||
+
|
||||
+ msgHdr.msg_control = controlBufData;
|
||||
+ msgHdr.msg_controllen = CMSG_SPACE(sizeof(srcAddr));
|
||||
+
|
||||
+ struct cmsghdr *chdr = CMSG_FIRSTHDR(&msgHdr);
|
||||
+ chdr->cmsg_level = IPPROTO_IP;
|
||||
+ chdr->cmsg_type = IP_SENDSRCADDR;
|
||||
+ chdr->cmsg_len = CMSG_LEN(sizeof(srcAddr));
|
||||
+ memcpy(CMSG_DATA(chdr), &srcAddr, sizeof(srcAddr));
|
||||
+ }
|
||||
+ else
|
||||
+#endif
|
||||
#ifdef IP_PKTINFO
|
||||
if (localAddress->address.ss_family == AF_INET) {
|
||||
struct in_pktinfo pktInfo;
|
||||
@@ -744,6 +767,21 @@ enet_socket_receive (ENetSocket socket,
|
||||
// to ensure we respond from the correct address/interface.
|
||||
if (localAddress != NULL) {
|
||||
for (struct cmsghdr *chdr = CMSG_FIRSTHDR(&msgHdr); chdr != NULL; chdr = CMSG_NXTHDR(&msgHdr, chdr)) {
|
||||
+#if defined(__FreeBSD__) && defined(IP_RECVDSTADDR)
|
||||
+ if (chdr->cmsg_level == IPPROTO_IP && chdr->cmsg_type == IP_RECVDSTADDR) {
|
||||
+ struct sockaddr_in *localAddr = (struct sockaddr_in*)&localAddress->address;
|
||||
+
|
||||
+ localAddr->sin_family = AF_INET;
|
||||
+ localAddr->sin_addr = *(struct in_addr*)CMSG_DATA(chdr);
|
||||
+ // FreeBSD doesn't populate sin_port in RECVDSTADDR, but we don't need it
|
||||
+ // since we only use the address part for routing decisions
|
||||
+ localAddr->sin_port = 0;
|
||||
+
|
||||
+ localAddress->addressLength = sizeof(*localAddr);
|
||||
+ break;
|
||||
+ }
|
||||
+ else
|
||||
+#endif
|
||||
#ifdef IP_PKTINFO
|
||||
if (chdr->cmsg_level == IPPROTO_IP && chdr->cmsg_type == IP_PKTINFO) {
|
||||
struct sockaddr_in *localAddr = (struct sockaddr_in*)&localAddress->address;
|
||||
@ -39,9 +39,6 @@
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
// Define constants that are missing in FreeBSD
|
||||
#ifndef IP_PKTINFO // packet info for IPv4
|
||||
#define IP_PKTINFO IP_RECVDSTADDR
|
||||
#endif
|
||||
#ifndef SOL_IP // socket level for IPv4
|
||||
#define SOL_IP IPPROTO_IP
|
||||
#endif
|
||||
@ -51,12 +48,6 @@
|
||||
#ifndef SO_PRIORITY // socket option for priority, disabled for FreeBSD
|
||||
#define SO_PRIORITY -1
|
||||
#endif
|
||||
// Define in_pktinfo structure for IPv4 packet info
|
||||
struct in_pktinfo {
|
||||
struct in_addr ipi_addr;
|
||||
struct in_addr ipi_spec_dst;
|
||||
int ipi_ifindex;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
@ -401,7 +392,11 @@ namespace platf {
|
||||
}
|
||||
|
||||
union {
|
||||
#ifdef __FreeBSD__
|
||||
char buf[CMSG_SPACE(sizeof(uint16_t)) + std::max(CMSG_SPACE(sizeof(struct in_addr)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
|
||||
#else
|
||||
char buf[CMSG_SPACE(sizeof(uint16_t)) + std::max(CMSG_SPACE(sizeof(struct in_pktinfo)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
|
||||
#endif
|
||||
struct cmsghdr alignment;
|
||||
} cmbuf = {}; // Must be zeroed for CMSG_NXTHDR()
|
||||
|
||||
@ -427,6 +422,18 @@ namespace platf {
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
|
||||
} else {
|
||||
#ifdef __FreeBSD__
|
||||
// FreeBSD uses IP_SENDSRCADDR instead of IP_PKTINFO
|
||||
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
|
||||
struct in_addr srcAddr = saddr_v4.sin_addr;
|
||||
|
||||
cmbuflen += CMSG_SPACE(sizeof(srcAddr));
|
||||
|
||||
pktinfo_cm->cmsg_level = IPPROTO_IP;
|
||||
pktinfo_cm->cmsg_type = IP_SENDSRCADDR;
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(srcAddr));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &srcAddr, sizeof(srcAddr));
|
||||
#else
|
||||
struct in_pktinfo pktInfo;
|
||||
|
||||
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
|
||||
@ -439,6 +446,7 @@ namespace platf {
|
||||
pktinfo_cm->cmsg_type = IP_PKTINFO;
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
|
||||
#endif
|
||||
}
|
||||
|
||||
auto const max_iovs_per_msg = send_info.payload_buffers.size() + (send_info.headers ? 1 : 0);
|
||||
@ -608,7 +616,11 @@ namespace platf {
|
||||
}
|
||||
|
||||
union {
|
||||
#ifdef __FreeBSD__
|
||||
char buf[std::max(CMSG_SPACE(sizeof(struct in_addr)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
|
||||
#else
|
||||
char buf[std::max(CMSG_SPACE(sizeof(struct in_pktinfo)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
|
||||
#endif
|
||||
struct cmsghdr alignment;
|
||||
} cmbuf;
|
||||
|
||||
@ -632,6 +644,18 @@ namespace platf {
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
|
||||
} else {
|
||||
#ifdef __FreeBSD__
|
||||
// FreeBSD uses IP_SENDSRCADDR instead of IP_PKTINFO
|
||||
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
|
||||
struct in_addr srcAddr = saddr_v4.sin_addr;
|
||||
|
||||
cmbuflen += CMSG_SPACE(sizeof(srcAddr));
|
||||
|
||||
pktinfo_cm->cmsg_level = IPPROTO_IP;
|
||||
pktinfo_cm->cmsg_type = IP_SENDSRCADDR;
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(srcAddr));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &srcAddr, sizeof(srcAddr));
|
||||
#else
|
||||
struct in_pktinfo pktInfo;
|
||||
|
||||
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
|
||||
@ -644,6 +668,7 @@ namespace platf {
|
||||
pktinfo_cm->cmsg_type = IP_PKTINFO;
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
|
||||
#endif
|
||||
}
|
||||
|
||||
struct iovec iovs[2];
|
||||
|
||||
@ -8,6 +8,11 @@
|
||||
#include <future>
|
||||
#include <queue>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
// lib includes
|
||||
#include <boost/endian/arithmetic.hpp>
|
||||
#include <openssl/err.h>
|
||||
@ -519,21 +524,11 @@ namespace stream {
|
||||
// Use the local address from the control connection as the source address
|
||||
// for other communications to the client. This is necessary to ensure
|
||||
// proper routing on multi-homed hosts.
|
||||
|
||||
// TODO: delete this debug log
|
||||
BOOST_LOG(debug) << "Raw localAddress.address: family=" << peer->localAddress.address.ss_family
|
||||
<< " size=" << peer->localAddress.addressLength
|
||||
<< " data=" << util::hex_vec(std::string_view {(char *) &peer->localAddress.address, static_cast<long long unsigned int>(peer->localAddress.addressLength)});
|
||||
auto local_address = platf::from_sockaddr((sockaddr *) &peer->localAddress.address);
|
||||
if (local_address.empty()) {
|
||||
BOOST_LOG(warning) << "Couldn't get local address for control connection"sv;
|
||||
}
|
||||
try {
|
||||
session_p->localAddress = boost::asio::ip::make_address(local_address);
|
||||
} catch (const boost::system::system_error &e) {
|
||||
BOOST_LOG(error) << "boost::system::system_error in address parsing: " << e.what() << " (code: " << e.code() << ")"sv;
|
||||
throw;
|
||||
}
|
||||
session_p->localAddress = boost::asio::ip::make_address(local_address);
|
||||
|
||||
BOOST_LOG(debug) << "Control local address ["sv << local_address << ']';
|
||||
BOOST_LOG(debug) << "Control peer address ["sv << peer_addr << ':' << peer_port << ']';
|
||||
@ -1722,6 +1717,23 @@ namespace stream {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
// Enable IP_RECVDSTADDR for FreeBSD to receive destination address for IPv4
|
||||
{
|
||||
int on = 1;
|
||||
if (setsockopt(ctx.video_sock.native_handle(), IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) < 0) {
|
||||
BOOST_LOG(warning) << "Failed to set IP_RECVDSTADDR on video socket";
|
||||
}
|
||||
}
|
||||
// Enable IPV6_RECVPKTINFO for IPv6
|
||||
if (address_family == net::af_e::BOTH) {
|
||||
int on = 1;
|
||||
if (setsockopt(ctx.video_sock.native_handle(), IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) {
|
||||
BOOST_LOG(warning) << "Failed to set IPV6_RECVPKTINFO on video socket";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set video socket send buffer size (SO_SENDBUF) to 1MB
|
||||
try {
|
||||
ctx.video_sock.set_option(boost::asio::socket_base::send_buffer_size(1024 * 1024));
|
||||
@ -1743,6 +1755,23 @@ namespace stream {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
// Enable IP_RECVDSTADDR for FreeBSD to receive destination address for IPv4
|
||||
{
|
||||
int on = 1;
|
||||
if (setsockopt(ctx.audio_sock.native_handle(), IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) < 0) {
|
||||
BOOST_LOG(warning) << "Failed to set IP_RECVDSTADDR on audio socket";
|
||||
}
|
||||
}
|
||||
// Enable IPV6_RECVPKTINFO for IPv6
|
||||
if (address_family == net::af_e::BOTH) {
|
||||
int on = 1;
|
||||
if (setsockopt(ctx.audio_sock.native_handle(), IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) {
|
||||
BOOST_LOG(warning) << "Failed to set IPV6_RECVPKTINFO on audio socket";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx.audio_sock.bind(udp::endpoint(protocol, audio_port), ec);
|
||||
if (ec) {
|
||||
BOOST_LOG(fatal) << "Couldn't bind Audio server to port ["sv << audio_port << "]: "sv << ec.message();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user