diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 422e7da8f2..4ee9764e42 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -20,8 +20,14 @@ #include "QtNetwork/qhostaddress.h" #include "QtNetwork/qnetworkinterface.h" #include "private/qabstractsocketengine_p.h" +#include "qplatformdefs.h" + #ifndef Q_OS_WIN -# include "qplatformdefs.h" +# include +#else +# include +# include +# include #endif QT_BEGIN_NAMESPACE @@ -35,12 +41,58 @@ namespace { namespace SetSALen { template void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len) { sa->sa_len = len; } + template void set(T *sa, typename std::enable_if<(&T::sin_len, true), QT_SOCKLEN_T>::type len) + { sa->sin_len = len; } template void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len) { sin6->sin6_len = len; } template void set(T *, ...) {} } + +inline QT_SOCKLEN_T setSockaddr(sockaddr_in *sin, const QHostAddress &addr, quint16 port = 0) +{ + *sin = {}; + SetSALen::set(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + sin->sin_addr.s_addr = htonl(addr.toIPv4Address()); + return sizeof(*sin); } +inline QT_SOCKLEN_T setSockaddr(sockaddr_in6 *sin6, const QHostAddress &addr, quint16 port = 0) +{ + *sin6 = {}; + SetSALen::set(sin6, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + memcpy(sin6->sin6_addr.s6_addr, addr.toIPv6Address().c, sizeof(sin6->sin6_addr)); +#if QT_CONFIG(networkinterface) + sin6->sin6_scope_id = QNetworkInterface::interfaceIndexFromName(addr.scopeId()); +#else + // it had better be a number then, if it is not empty + sin6->sin6_scope_id = addr.scopeId().toUInt(); +#endif + return sizeof(*sin6); +} + +inline QT_SOCKLEN_T setSockaddr(sockaddr *sa, const QHostAddress &addr, quint16 port = 0) +{ + switch (addr.protocol()) { + case QHostAddress::IPv4Protocol: + return setSockaddr(reinterpret_cast(sa), addr, port); + + case QHostAddress::IPv6Protocol: + case QHostAddress::AnyIPProtocol: + return setSockaddr(reinterpret_cast(sa), addr, port); + + case QHostAddress::UnknownNetworkLayerProtocol: + break; + } + *sa = {}; + sa->sa_family = AF_UNSPEC; + return 0; +} +} // unnamed namespace + class QNativeSocketEnginePrivate; #ifndef QT_NO_NETWORKINTERFACE class QNetworkInterface; diff --git a/src/network/socket/qnativesocketengine_p_p.h b/src/network/socket/qnativesocketengine_p_p.h index 013b62ad29..801b3b95ba 100644 --- a/src/network/socket/qnativesocketengine_p_p.h +++ b/src/network/socket/qnativesocketengine_p_p.h @@ -155,38 +155,29 @@ public: bool checkProxy(const QHostAddress &address); bool fetchConnectionParameters(); -#if QT_CONFIG(networkinterface) - static uint scopeIdFromString(const QString &scopeid) - { return QNetworkInterface::interfaceIndexFromName(scopeid); } -#endif - /*! \internal Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize. The address \a is converted to IPv6 if the current socket protocol is also IPv6. */ void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize) { - if (address.protocol() == QAbstractSocket::IPv6Protocol - || address.protocol() == QAbstractSocket::AnyIPProtocol - || socketProtocol == QAbstractSocket::IPv6Protocol - || socketProtocol == QAbstractSocket::AnyIPProtocol) { - memset(&aa->a6, 0, sizeof(sockaddr_in6)); - aa->a6.sin6_family = AF_INET6; -#if QT_CONFIG(networkinterface) - aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId()); -#endif - aa->a6.sin6_port = htons(port); - Q_IPV6ADDR tmp = address.toIPv6Address(); - memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp)); + switch (socketProtocol) { + case QHostAddress::IPv6Protocol: + case QHostAddress::AnyIPProtocol: + // force to IPv6 + setSockaddr(&aa->a6, address, port); *sockAddrSize = sizeof(sockaddr_in6); - SetSALen::set(&aa->a, sizeof(sockaddr_in6)); - } else { - memset(&aa->a, 0, sizeof(sockaddr_in)); - aa->a4.sin_family = AF_INET; - aa->a4.sin_port = htons(port); - aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address()); + return; + + case QHostAddress::IPv4Protocol: + // force to IPv4 + setSockaddr(&aa->a4, address, port); *sockAddrSize = sizeof(sockaddr_in); - SetSALen::set(&aa->a, sizeof(sockaddr_in)); + return; + + case QHostAddress::UnknownNetworkLayerProtocol: + // don't force + *sockAddrSize = setSockaddr(&aa->a, address, port); } }