diff options
-rw-r--r-- | src/network/socket/qnativesocketengine.cpp | 28 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_p.h | 13 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 119 |
3 files changed, 160 insertions, 0 deletions
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index a169ca0..d4092b6 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -647,6 +647,34 @@ int QNativeSocketEngine::accept() } /*! + \since 4.8 +*/ +bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface) +{ + Q_D(QNativeSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false); + Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false); + return d->nativeJoinMulticastGroup(groupAddress, sourceAddress, interface); +} + +/*! + \since 4.8 +*/ +bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface) +{ + Q_D(QNativeSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::leaveMulticastGroup(), false); + Q_CHECK_STATE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false); + return d->nativeLeaveMulticastGroup(groupAddress, sourceAddress, interface); +} + +/*! 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 eca16f6..7ec1166 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -123,6 +123,13 @@ public: int accept(); void close(); + bool joinMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface); + bool leaveMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface); + qint64 bytesAvailable() const; qint64 read(char *data, qint64 maxlen); @@ -237,6 +244,12 @@ public: bool nativeBind(const QHostAddress &address, quint16 port); bool nativeListen(int backlog); int nativeAccept(); + bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface); + bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface); qint64 nativeBytesAvailable() const; bool nativeHasPendingDatagrams() const; diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index a9f6921..f10c692 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -247,6 +247,9 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co case QNativeSocketEngine::KeepAliveOption: n = SO_KEEPALIVE; break; + case QNativeSocketEngine::MulticastLoopback: + n = IP_MULTICAST_LOOP; + break; } int v = -1; @@ -330,6 +333,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt case QNativeSocketEngine::KeepAliveOption: n = SO_KEEPALIVE; break; + case QNativeSocketEngine::MulticastLoopback: + n = IP_MULTICAST_LOOP; + break; } return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0; @@ -579,6 +585,119 @@ int QNativeSocketEnginePrivate::nativeAccept() return acceptedDescriptor; } +static bool doMulticast(QNativeSocketEnginePrivate *d, + int howAsm6, + int howAsm4, + int howSsm4, + const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface) +{ + int sockOpt = 0; + void *sockArg; + int sockArgSize; + + ip_mreq asm4; + ip_mreq_source ssm4; +#ifndef QT_NO_IPV6 + ipv6_mreq asm6; + + if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { + sockOpt = howAsm6; + sockArg = &asm6; + sockArgSize = sizeof(asm6); + memset(&asm6, 0, sizeof(asm6)); + Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); + memcpy(&asm6.ipv6mr_multiaddr, &ip6, sizeof(ip6)); + Q_UNUSED(sourceAddress); // ### not possible to specify a single source when using IPv6? + asm6.ipv6mr_interface = interface.index(); + } else +#endif + if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { + if (!sourceAddress.isNull()) { + sockOpt = howSsm4; + sockArg = &ssm4; + sockArgSize = sizeof(ssm4); + memset(&ssm4, 0, sizeof(ssm4)); + ssm4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address()); + ssm4.imr_sourceaddr.s_addr = htonl(sourceAddress.toIPv4Address()); + } else { + sockOpt = howAsm4; + sockArg = &asm4; + sockArgSize = sizeof(asm4); + memset(&asm4, 0, sizeof(asm4)); + asm4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address()); + } + + if (interface.isValid()) { + QList<QNetworkAddressEntry> addressEntries = interface.addressEntries(); + if (!addressEntries.isEmpty()) { + QHostAddress firstIP = addressEntries.first().ip(); + asm4.imr_interface.s_addr = htonl(firstIP.toIPv4Address()); + } else { + d->setError(QAbstractSocket::NetworkError, + QNativeSocketEnginePrivate::NetworkUnreachableErrorString); + return false; + } + } else { + asm4.imr_interface.s_addr = INADDR_ANY; + } + } else { + // unreachable + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString); + return false; + } + + int res = setsockopt(d->socketDescriptor, IPPROTO_IP, sockOpt, sockArg, sockArgSize); + if (res == -1) { + switch (errno) { + case ENOPROTOOPT: + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::OperationUnsupportedErrorString); + break; + default: + break; + } + return false; + } + return true; +} + +bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface) +{ + return doMulticast(this, +#ifndef QT_NO_IPV6 + IPV6_JOIN_GROUP, +#else + 0, +#endif + IP_ADD_MEMBERSHIP, + IP_ADD_SOURCE_MEMBERSHIP, + groupAddress, + sourceAddress, + interface); +} + +bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QHostAddress &sourceAddress, + const QNetworkInterface &interface) +{ + return doMulticast(this, +#ifndef QT_NO_IPV6 + IPV6_LEAVE_GROUP, +#else + 0, +#endif + IP_DROP_MEMBERSHIP, + IP_DROP_SOURCE_MEMBERSHIP, + groupAddress, + sourceAddress, + interface); +} + qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const { int nbytes = 0; |