diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/network/socket/qabstractsocketengine_p.h | 2 | ||||
-rw-r--r-- | src/network/socket/qhttpsocketengine.cpp | 13 | ||||
-rw-r--r-- | src/network/socket/qhttpsocketengine_p.h | 2 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine.cpp | 20 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_p.h | 4 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 111 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 63 | ||||
-rw-r--r-- | src/network/socket/qsocks5socketengine.cpp | 14 | ||||
-rw-r--r-- | src/network/socket/qsocks5socketengine_p.h | 2 | ||||
-rw-r--r-- | src/network/socket/qudpsocket.cpp | 46 | ||||
-rw-r--r-- | src/network/socket/qudpsocket.h | 3 |
11 files changed, 269 insertions, 11 deletions
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h index 616fdb2..ec5fbd3 100644 --- a/src/network/socket/qabstractsocketengine_p.h +++ b/src/network/socket/qabstractsocketengine_p.h @@ -125,6 +125,8 @@ public: const QNetworkInterface &iface) = 0; virtual bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) = 0; + virtual QNetworkInterface multicastInterface() const = 0; + virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0; virtual qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0, quint16 *port = 0) = 0; diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index e467df8..cb0e296 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -45,6 +45,7 @@ #include "qurl.h" #include "qhttp.h" #include "qelapsedtimer.h" +#include "qnetworkinterface.h" #if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP) #include <qdebug.h> @@ -255,6 +256,18 @@ bool QHttpSocketEngine::leaveMulticastGroup(const QHostAddress &, return false; } +QNetworkInterface QHttpSocketEngine::multicastInterface() const +{ + return QNetworkInterface(); +} + +bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &) +{ + setError(QAbstractSocket::UnsupportedSocketOperationError, + QLatin1String("Operation on socket is not supported")); + return false; +} + qint64 QHttpSocketEngine::readDatagram(char *, qint64, QHostAddress *, quint16 *) { diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index 1a6b4f6..b68b7117 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -106,6 +106,8 @@ public: const QNetworkInterface &interface); bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &interface); + QNetworkInterface multicastInterface() const; + bool setMulticastInterface(const QNetworkInterface &iface); qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0, quint16 *port = 0); diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index 7cb3a1b..df73b9c 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -98,6 +98,7 @@ #include <qabstracteventdispatcher.h> #include <qsocketnotifier.h> +#include <qnetworkinterface.h> #include "qnativesocketengine_p.h" #include <private/qthread_p.h> @@ -672,6 +673,25 @@ bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, return d->nativeLeaveMulticastGroup(groupAddress, iface); } +/*! \since 4.8 */ +QNetworkInterface QNativeSocketEngine::multicastInterface() const +{ + Q_D(const QNativeSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::multicastInterface(), QNetworkInterface()); + Q_CHECK_TYPE(QNativeSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface()); + return d->nativeMulticastInterface(); +} + + +/*! \since 4.8 */ +bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface) +{ + Q_D(QNativeSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setMulticastInterface(), false); + Q_CHECK_TYPE(QNativeSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false); + return d->nativeSetMulticastInterface(iface); +} + /*! Returns the number of bytes that are currently available for reading. On error, -1 is returned. diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index ce00747..9baacf0 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -128,6 +128,8 @@ public: const QNetworkInterface &iface); bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface); + QNetworkInterface multicastInterface() const; + bool setMulticastInterface(const QNetworkInterface &iface); qint64 bytesAvailable() const; @@ -247,6 +249,8 @@ public: const QNetworkInterface &iface); bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface); + QNetworkInterface nativeMulticastInterface() const; + bool nativeSetMulticastInterface(const QNetworkInterface &iface); qint64 nativeBytesAvailable() const; bool nativeHasPendingDatagrams() const; diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 737e35a..e7f6c7e 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -249,12 +249,28 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co n = SO_KEEPALIVE; break; case QNativeSocketEngine::MulticastTtlOption: - level = IPPROTO_IP; - n = IP_MULTICAST_TTL; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_HOPS; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_TTL; + } break; case QNativeSocketEngine::MulticastLoopbackOption: - level = IPPROTO_IP; - n = IP_MULTICAST_LOOP; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_LOOP; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_LOOP; + } break; } @@ -340,12 +356,28 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt n = SO_KEEPALIVE; break; case QNativeSocketEngine::MulticastTtlOption: - level = IPPROTO_IP; - n = IP_MULTICAST_TTL; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_HOPS; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_TTL; + } break; case QNativeSocketEngine::MulticastLoopbackOption: - level = IPPROTO_IP; - n = IP_MULTICAST_LOOP; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_LOOP; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_LOOP; + } break; } @@ -693,6 +725,69 @@ bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &g interface); } +QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const +{ +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + uint v; + QT_SOCKOPTLEN_T sizeofv = sizeof(v); + if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, &sizeofv) == -1) + return QNetworkInterface(); + return QNetworkInterface::interfaceFromIndex(v); + } +#endif + + struct in_addr v = { 0 }; + QT_SOCKOPTLEN_T sizeofv = sizeof(v); + if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1) + return QNetworkInterface(); + if (v.s_addr != 0 && sizeofv >= sizeof(v)) { + QHostAddress ipv4(ntohl(v.s_addr)); + QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces(); + for (int i = 0; i < ifaces.count(); ++i) { + const QNetworkInterface &iface = ifaces.at(i); + if (!(iface.flags() & QNetworkInterface::CanMulticast)) + continue; + QList<QNetworkAddressEntry> entries = iface.addressEntries(); + for (int j = 0; j < entries.count(); ++j) { + const QNetworkAddressEntry &entry = entries.at(j); + if (entry.ip() == ipv4) + return iface; + } + } + } + return QNetworkInterface(); +} + +bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) +{ +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + uint v = iface.isValid() ? iface.index() : 0; + return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, sizeof(v)) != -1); + } +#endif + + struct in_addr v; + if (iface.isValid()) { + QList<QNetworkAddressEntry> entries = iface.addressEntries(); + for (int i = 0; i < entries.count(); ++i) { + const QNetworkAddressEntry &entry = entries.at(i); + const QHostAddress &ip = entry.ip(); + if (ip.protocol() == QAbstractSocket::IPv4Protocol) { + v.s_addr = htonl(ip.toIPv4Address()); + int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)); + if (r != -1) + return true; + } + } + return false; + } + + v.s_addr = INADDR_ANY; + return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)) != -1); +} + qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const { int nbytes = 0; diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index a922b45..2ca1f41 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -853,6 +853,69 @@ bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &g iface); } +QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const +{ +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + uint v; + QT_SOCKOPTLEN_T sizeofv = sizeof(v); + if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, &sizeofv) == -1) + return QNetworkInterface(); + return QNetworkInterface::interfaceFromIndex(v); + } +#endif + + struct in_addr v = { 0 }; + QT_SOCKOPTLEN_T sizeofv = sizeof(v); + if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, &sizeofv) == -1) + return QNetworkInterface(); + if (v.s_addr != 0 && sizeofv >= sizeof(v)) { + QHostAddress ipv4(ntohl(v.s_addr)); + QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces(); + for (int i = 0; i < ifaces.count(); ++i) { + const QNetworkInterface &iface = ifaces.at(i); + if (!(iface.flags() & QNetworkInterface::CanMulticast)) + continue; + QList<QNetworkAddressEntry> entries = iface.addressEntries(); + for (int j = 0; j < entries.count(); ++j) { + const QNetworkAddressEntry &entry = entries.at(j); + if (entry.ip() == ipv4) + return iface; + } + } + } + return QNetworkInterface(); +} + +bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) +{ +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + uint v = iface.isValid() ? iface.index() : 0; + return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, sizeof(v)) != -1); + } +#endif + + struct in_addr v; + if (iface.isValid()) { + QList<QNetworkAddressEntry> entries = iface.addressEntries(); + for (int i = 0; i < entries.count(); ++i) { + const QNetworkAddressEntry &entry = entries.at(i); + const QHostAddress &ip = entry.ip(); + if (ip.protocol() == QAbstractSocket::IPv4Protocol) { + v.s_addr = htonl(ip.toIPv4Address()); + int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)); + if (r != -1) + return true; + } + } + return false; + } + + v.s_addr = INADDR_ANY; + return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)) != -1); +} + qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const { unsigned long nbytes = 0; diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index dcaf561..17cf5b1 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -56,6 +56,7 @@ #include "qurl.h" #include "qauthenticator.h" #include <qendian.h> +#include <qnetworkinterface.h> QT_BEGIN_NAMESPACE @@ -1560,6 +1561,19 @@ bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &, return false; } + +QNetworkInterface QSocks5SocketEngine::multicastInterface() const +{ + return QNetworkInterface(); +} + +bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &) +{ + setError(QAbstractSocket::UnsupportedSocketOperationError, + QLatin1String("Operation on socket is not supported")); + return false; +} + qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr, quint16 *port) { diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h index 298595a..06fcad2 100644 --- a/src/network/socket/qsocks5socketengine_p.h +++ b/src/network/socket/qsocks5socketengine_p.h @@ -96,6 +96,8 @@ public: const QNetworkInterface &interface); bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &interface); + QNetworkInterface multicastInterface() const; + bool setMulticastInterface(const QNetworkInterface &iface); qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0, quint16 *port = 0); diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index dffb5df..5d8f4c0 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -77,11 +77,12 @@ \snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0 - QUdpSocket also supports UDP multicast. Use the joinMulticastGroup() and - leaveMulticastGroup() to control group membership, and the + QUdpSocket also supports UDP multicast. Use joinMulticastGroup() and + leaveMulticastGroup() to control group membership, and QAbstractSocket::MulticastTtlOption and QAbstractSocket::MulticastLoopbackOption to set the TTL and loopback socket - options. + options. Use setMulticastInterface() to control the outgoing interface for + multicast datagrams, and multicastInterface() to query it. With QUdpSocket, you can also establish a virtual connection to a UDP server using connectToHost() and then use read() and write() @@ -405,6 +406,45 @@ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress, } /*! + \since 4.8 + + Returns the interface for the outgoing interface for multicast datagrams. + This corresponds to the IP_MULTICAST_IF socket option for IPv4 sockets and + the IPV6_MULTICAST_IF socket option for IPv6 sockets. If no interface has + been previously set, this function returns an invalid QNetworkInterface. + The socket must be in BoundState, otherwise an invalid QNetworkInterface is + returned. + + \sa setMulticastInterface() +*/ +QNetworkInterface QUdpSocket::multicastInterface() const +{ + Q_D(const QUdpSocket); + QT_CHECK_BOUND("QUdpSocket::multicastInterface()", QNetworkInterface()); + return d->socketEngine->multicastInterface(); +} + +/*! + \since 4.8 + + Sets the outgoing interface for multicast datagrams to the interface \a + iface. This corresponds to the IP_MULTICAST_IF socket option for IPv4 + sockets and the IPV6_MULTICAST_IF socket option for IPv6 sockets. The + socket must be in BoundState, otherwise this function does nothing. + + \sa multicastInterface(), joinMulticastGroup(), leaveMulticastGroup() +*/ +void QUdpSocket::setMulticastInterface(const QNetworkInterface &iface) +{ + Q_D(QUdpSocket); + if (!isValid()) { + qWarning("QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState"); + return; + } + d->socketEngine->setMulticastInterface(iface); +} + +/*! Returns true if at least one datagram is waiting to be read; otherwise returns false. diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h index 54f82c9..b277d3f 100644 --- a/src/network/socket/qudpsocket.h +++ b/src/network/socket/qudpsocket.h @@ -84,6 +84,9 @@ public: bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface); + QNetworkInterface multicastInterface() const; + void setMulticastInterface(const QNetworkInterface &iface); + bool hasPendingDatagrams() const; qint64 pendingDatagramSize() const; qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = 0, quint16 *port = 0); |