-
Notifications
You must be signed in to change notification settings - Fork 242
FreeBSD fix for dual-stack and IPv6 QoS #3664
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,7 +129,7 @@ void CSocket::Init ( const quint16 iNewPortNumber, const quint16 iNewQosNumber, | |
| } | ||
| #endif | ||
|
|
||
| #if !defined( Q_OS_DARWIN ) && !defined( Q_OS_WIN ) | ||
| #if !defined( Q_OS_BSD4 ) && !defined( Q_OS_WIN ) | ||
| // set the QoS for IPv4 as well, as this is a dual-protocol socket | ||
| if ( setsockopt ( UdpSocket, IPPROTO_IP, IP_TOS, (const char*) &tos, sizeof ( tos ) ) == -1 ) | ||
| { | ||
|
|
@@ -272,44 +272,55 @@ CSocket::~CSocket() | |
| #endif | ||
| } | ||
|
|
||
| #if defined( Q_OS_DARWIN ) | ||
| // sendto_ipv4_with_tos - helper function for macOS to set TOS when sending IPv4 over IPv6 socket | ||
| #if defined( Q_OS_BSD4 ) | ||
|
ann0see marked this conversation as resolved.
|
||
| // sendto_ipv4_with_tos - helper function for macOS and FreeBSD to set TOS when sending IPv4 over IPv6 socket | ||
| static ssize_t sendto_ipv4_with_tos ( int fd, const void* buf, size_t len, int flags, const struct sockaddr* dest, socklen_t destlen, int tos ) | ||
| { | ||
| // For a description of 'struct cmsghdr' and the 'CMSG_xxx' macros, see 'man 3 cmsg' on a Linux machine. | ||
| // The macOS man pages are less descriptive, but the API is the same, being based on the BSD socket interface. | ||
|
|
||
| # if defined( Q_OS_FREEBSD ) | ||
| using tos_cmsg_type = unsigned char; | ||
| # else | ||
| using tos_cmsg_type = int; | ||
| # endif | ||
|
|
||
| // The cmsg buffer is only set up once (tos doesn't change) so can be static | ||
| static union | ||
| { | ||
| unsigned char cbuf[CMSG_SPACE ( sizeof ( int ) )]; | ||
| struct cmsghdr h; | ||
| unsigned char cbuf[CMSG_SPACE ( sizeof ( tos_cmsg_type ) )]; | ||
| struct cmsghdr align; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Why) is the naming change needed? here probably stands for header?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably no reason. Name was chosen by ChatGPT, but h is good enough really.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And lots and lots of networking code everywhere uses this approach. (OK, it's very old networking code...)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -> back to h |
||
| } u; | ||
| static socklen_t clen = 0; | ||
| static size_t clen = 0; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. size_t is more generic. Is this guaranteed to be sound?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ChatGPT recommended it for maximum portability, but I didn't test both with and without.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not use size_t if something specific exists and it compiles. |
||
|
|
||
| if ( clen == 0 ) | ||
| { | ||
| // set up the cmsg buffer | ||
| memset ( u.cbuf, 0, sizeof ( u.cbuf ) ); | ||
| memset ( &u, 0, sizeof ( u ) ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. &u is just to make it more concise?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's to make it clear it's the address of both the cbuf and header. |
||
|
|
||
| struct cmsghdr* cmsg = reinterpret_cast<struct cmsghdr*> ( u.cbuf ); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, this is C pointer magic -- but isn't the union overlaying struct cmsghdr* cmsg = &u.align;or am I misunderstanding it completely?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that's an excellent point. The magic was provided by ChatGPT when I asked it why the original function worked on macOS but not FreeBSD. I didn't study it in detail at the time, but I think you're right, and prefer your suggestion. I'm happy to change it and test, but no time today. |
||
| cmsg->cmsg_level = IPPROTO_IP; | ||
| cmsg->cmsg_type = IP_TOS; | ||
| cmsg->cmsg_len = CMSG_LEN ( sizeof ( tos_cmsg_type ) ); | ||
|
|
||
| u.h.cmsg_level = IPPROTO_IP; | ||
| u.h.cmsg_type = IP_TOS; | ||
| u.h.cmsg_len = CMSG_LEN ( sizeof ( int ) ); | ||
| memcpy ( CMSG_DATA ( &u.h ), &tos, sizeof ( int ) ); | ||
| clen = (socklen_t) u.h.cmsg_len; | ||
| tos_cmsg_type v = static_cast<tos_cmsg_type> ( tos & 0xFF ); | ||
| memcpy ( CMSG_DATA ( cmsg ), &v, sizeof ( v ) ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. v doesn't say much. As far as I understand this, you extract a bit from tos? It should be made more clear what that is.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's throw-away -- it needs to be an instance variable (so
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll revisit tomorrow, tidy up and test again. |
||
| clen = CMSG_SPACE ( sizeof ( tos_cmsg_type ) ); | ||
| } | ||
|
|
||
| struct iovec iov; | ||
| memset ( &iov, 0, sizeof ( iov ) ); | ||
| iov.iov_base = const_cast<void*> ( buf ); | ||
| iov.iov_len = len; | ||
|
|
||
| struct msghdr msg; | ||
| memset ( &msg, 0, sizeof ( msg ) ); | ||
|
|
||
| msg.msg_name = const_cast<sockaddr*> ( dest ); | ||
| msg.msg_namelen = destlen; | ||
| msg.msg_iov = &iov; | ||
| msg.msg_iovlen = 1; | ||
| msg.msg_control = (void*) u.cbuf; | ||
| msg.msg_control = u.cbuf; | ||
| msg.msg_controllen = clen; | ||
|
|
||
| return sendmsg ( fd, &msg, flags ); | ||
|
|
@@ -355,8 +366,8 @@ void CSocket::SendPacket ( const CVector<uint8_t>& vecbySendBuf, const CHostAddr | |
| addr[2] = htonl ( 0xFFFF ); | ||
| addr[3] = htonl ( HostAddr.InetAddr.toIPv4Address() ); | ||
|
|
||
| #if defined( Q_OS_DARWIN ) | ||
| // In macOS we need to set TOS explicitly when sending IPv4 over IPv6 socket | ||
| #if defined( Q_OS_BSD4 ) | ||
| // In macOS and FreeBSD we need to set TOS explicitly when sending IPv4 over IPv6 socket | ||
| status = sendto_ipv4_with_tos ( UdpSocket, | ||
| (const char*) &( (CVector<uint8_t>) vecbySendBuf )[0], | ||
| iVecSizeOut, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need a guidance note on where these are defined and how - specifically for Jamulus - they should be used. (Not part of this PR, obviously.)