@@ -270,6 +270,50 @@ CSocket::~CSocket()
270270#endif
271271}
272272
273+ #if defined( Q_OS_DARWIN )
274+ // sendto_ipv4_with_tos - helper function for macOS to set TOS when sending IPv4 over IPv6 socket
275+ 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 )
276+ {
277+ // For a description of 'struct cmsghdr' and the 'CMSG_xxx' macros, see 'man 3 cmsg' on a Linux machine.
278+ // The macOS man pages are less descriptive, but the API is the same, being based on the BSD socket interface.
279+
280+ // The cmsg buffer is only set up once (tos doesn't change) so can be static
281+ static union
282+ {
283+ unsigned char cbuf[CMSG_SPACE ( sizeof ( int ) )];
284+ struct cmsghdr h;
285+ } u;
286+ static socklen_t clen = 0 ;
287+
288+ if ( clen == 0 )
289+ {
290+ // set up the cmsg buffer
291+ memset ( u.cbuf , 0 , sizeof ( u.cbuf ) );
292+
293+ u.h .cmsg_level = IPPROTO_IP;
294+ u.h .cmsg_type = IP_TOS;
295+ u.h .cmsg_len = CMSG_LEN ( sizeof ( int ) );
296+ memcpy ( CMSG_DATA ( &u.h ), &tos, sizeof ( int ) );
297+ clen = (socklen_t ) u.h .cmsg_len ;
298+ }
299+
300+ struct iovec iov;
301+ iov.iov_base = const_cast <void *> ( buf );
302+ iov.iov_len = len;
303+
304+ struct msghdr msg;
305+
306+ msg.msg_name = const_cast <sockaddr*> ( dest );
307+ msg.msg_namelen = destlen;
308+ msg.msg_iov = &iov;
309+ msg.msg_iovlen = 1 ;
310+ msg.msg_control = (void *) u.cbuf ;
311+ msg.msg_controllen = clen;
312+
313+ return sendmsg ( fd, &msg, flags );
314+ }
315+ #endif
316+
273317void CSocket::SendPacket ( const CVector<uint8_t >& vecbySendBuf, const CHostAddress& HostAddr )
274318{
275319 int status = 0 ;
@@ -309,12 +353,23 @@ void CSocket::SendPacket ( const CVector<uint8_t>& vecbySendBuf, const CHostAddr
309353 addr[2 ] = htonl ( 0xFFFF );
310354 addr[3 ] = htonl ( HostAddr.InetAddr .toIPv4Address () );
311355
356+ #if defined( Q_OS_DARWIN )
357+ // In macOS we need to set TOS explicitly when sending IPv4 over IPv6 socket
358+ status = sendto_ipv4_with_tos ( UdpSocket,
359+ (const char *) &( (CVector<uint8_t >) vecbySendBuf )[0 ],
360+ iVecSizeOut,
361+ 0 ,
362+ &UdpSocketAddr.sa ,
363+ sizeof ( UdpSocketAddr.sa6 ),
364+ (int ) iQosNumber );
365+ #else
312366 status = sendto ( UdpSocket,
313367 (const char *) &( (CVector<uint8_t >) vecbySendBuf )[0 ],
314368 iVecSizeOut,
315369 0 ,
316370 &UdpSocketAddr.sa ,
317371 sizeof ( UdpSocketAddr.sa6 ) );
372+ #endif
318373 }
319374 else
320375 {
0 commit comments