diff options
Diffstat (limited to 'src/network/socket')
-rw-r--r-- | src/network/socket/qabstractsocket.cpp | 17 | ||||
-rw-r--r-- | src/network/socket/qabstractsocket_p.h | 1 | ||||
-rw-r--r-- | src/network/socket/qlocalserver.cpp | 40 | ||||
-rw-r--r-- | src/network/socket/qlocalserver.h | 2 | ||||
-rw-r--r-- | src/network/socket/qlocalserver_win.cpp | 2 | ||||
-rw-r--r-- | src/network/socket/qlocalsocket.cpp | 14 | ||||
-rw-r--r-- | src/network/socket/qlocalsocket_win.cpp | 4 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine.cpp | 3 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_p.h | 2 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 60 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 38 | ||||
-rw-r--r-- | src/network/socket/qnet_unix_p.h | 10 | ||||
-rw-r--r-- | src/network/socket/qtcpserver_p.h | 3 | ||||
-rw-r--r-- | src/network/socket/qudpsocket.cpp | 10 |
14 files changed, 159 insertions, 47 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 0f13b1d1b8..ec88851589 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -940,7 +940,9 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port) // DefaultProxy here will raise an error proxyInUse = QNetworkProxy(); } +#endif // !QT_NO_NETWORKPROXY +#if !defined(QT_NO_NETWORKPROXY) || defined(Q_OS_WINRT) /*! \internal @@ -982,7 +984,7 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host) emit q->stateChanged(state); } -#endif +#endif // !QT_NO_NETWORKPROXY || Q_OS_WINRT /*! \internal @@ -1114,10 +1116,6 @@ void QAbstractSocketPrivate::_q_connectToNextAddress() // (localhost address on BSD or any UDP connect), emit // connected() and return. if ( -#if defined(Q_OS_WINRT) && _MSC_VER >= 1900 - !qEnvironmentVariableIsEmpty("QT_WINRT_USE_THREAD_NETWORK_CONTEXT") ? - socketEngine->connectToHostByName(hostName, port) : -#endif socketEngine->connectToHost(host, port)) { //_q_testConnection(); fetchConnectionParameters(); @@ -1696,6 +1694,8 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, } #endif + // Sync up with error string, which open() shall clear. + d->socketError = UnknownSocketError; if (openMode & QIODevice::Unbuffered) d->isBuffered = false; else if (!d_func()->isBuffered) @@ -1704,6 +1704,7 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, QIODevice::open(openMode); d->readChannelCount = d->writeChannelCount = 0; +#ifndef Q_OS_WINRT d->state = HostLookupState; emit stateChanged(d->state); @@ -1741,6 +1742,10 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, (d->state == ConnectingState || d->state == HostLookupState) ? " (connection in progress)" : ""); #endif +#else // !Q_OS_WINRT + // On WinRT we should always connect by name. Lookup and proxy handling are done by the API. + d->startConnectingByName(hostName); +#endif } /*! \overload @@ -1926,6 +1931,8 @@ bool QAbstractSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState return false; } + // Sync up with error string, which open() shall clear. + d->socketError = UnknownSocketError; if (d->threadData->hasEventDispatcher()) d->socketEngine->setReceiver(d); diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 5411133ea9..3873b50864 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -153,6 +153,7 @@ public: QAbstractSocket::SocketType socketType; QAbstractSocket::SocketState state; + // Must be kept in sync with QIODevicePrivate::errorString. QAbstractSocket::SocketError socketError; QAbstractSocket::NetworkLayerProtocol preferredNetworkLayerProtocol; diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index 3fcec954e7..a9789b7d04 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -41,6 +41,10 @@ #include "qlocalserver_p.h" #include "qlocalsocket.h" +#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP) +#include <QtCore/qt_windows.h> +#endif + QT_BEGIN_NAMESPACE /*! @@ -181,6 +185,42 @@ QLocalServer::SocketOptions QLocalServer::socketOptions() const } /*! + \since 5.10 + Returns the native socket descriptor the server uses to listen + for incoming instructions, or -1 if the server is not listening. + + The type of the descriptor depends on the platform: + \list + \li On Windows, the returned value is a + \l{https://msdn.microsoft.com/en-us/library/windows/desktop/ms740522(v=vs.85).aspx} + {Winsock 2 Socket Handle}. + + \li With WinRT and on INTEGRITY, the returned value is the + QTcpServer socket descriptor and the type is defined by + \l{QTcpServer::socketDescriptor}{socketDescriptor}. + + \li On all other UNIX-like operating systems, the type is + a file descriptor representing a listening socket. + \endlist + + \sa listen() +*/ +qintptr QLocalServer::socketDescriptor() const +{ + Q_D(const QLocalServer); + if (!isListening()) + return -1; +#if defined(QT_LOCALSOCKET_TCP) + return d->tcpServer.socketDescriptor(); +#elif defined(Q_OS_WIN) + const auto handle = d->connectionEventNotifier->handle(); + return handle != INVALID_HANDLE_VALUE ? qintptr(handle) : -1; +#else + return d->socketNotifier->socket(); +#endif +} + +/*! Stop listening for incoming connections. Existing connections are not affected, but any new connections will be refused. diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index 9bd2990389..454ac30c9b 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -92,6 +92,8 @@ public: void setSocketOptions(SocketOptions options); SocketOptions socketOptions() const; + qintptr socketDescriptor() const; + protected: virtual void incomingConnection(quintptr socketDescriptor); diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp index 8cb3449343..ced923ced1 100644 --- a/src/network/socket/qlocalserver_win.cpp +++ b/src/network/socket/qlocalserver_win.cpp @@ -225,7 +225,7 @@ bool QLocalServerPrivate::addListener() void QLocalServerPrivate::setError(const QString &function) { int windowsError = GetLastError(); - errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError)); + errorString = QString::fromLatin1("%1: %2").arg(function, qt_error_string(windowsError)); error = QAbstractSocket::UnknownSocketError; } diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 090a9e98c6..6fec2fdbd2 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -126,6 +126,20 @@ QT_BEGIN_NAMESPACE The socket descriptor is not available when QLocalSocket is in UnconnectedState. + The type of the descriptor depends on the platform: + + \list + \li On Windows, the returned value is a + \l{https://msdn.microsoft.com/en-us/library/windows/desktop/ms740522(v=vs.85).aspx} + {Winsock 2 Socket Handle}. + + \li With WinRT and on INTEGRITY, the returned value is the + QTcpSocket socket descriptor and the type is defined by + \l{QTcpSocket::socketDescriptor}{socketDescriptor}. + + \li On all other UNIX-like operating systems, the type is + a file descriptor representing a socket. + \endlist \sa setSocketDescriptor() */ diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 312c934632..ae94cb9d51 100644 --- a/src/network/socket/qlocalsocket_win.cpp +++ b/src/network/socket/qlocalsocket_win.cpp @@ -183,10 +183,8 @@ void QLocalSocket::connectToServer(OpenMode openMode) } // we have a valid handle - if (setSocketDescriptor((qintptr)localSocket, ConnectedState, openMode)) { - d->handle = localSocket; + if (setSocketDescriptor((qintptr)localSocket, ConnectedState, openMode)) emit connected(); - } } // This is reading from the buffer diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index 3f7c0d94e1..03395a37f0 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -1162,6 +1162,7 @@ bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWri return ret > 0; } +#if 0 // currently unused /*! Returns the size of the operating system's socket receive buffer. Depending on the operating system, this size may be @@ -1220,7 +1221,7 @@ void QNativeSocketEngine::setSendBufferSize(qint64 size) Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), Q_VOID); setOption(SendBufferSocketOption, size); } - +#endif /*! Sets the option \a option to the value \a value. diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 08e72072ef..d488ce150c 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -166,11 +166,13 @@ public: qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE; qint64 bytesToWrite() const Q_DECL_OVERRIDE; +#if 0 // currently unused qint64 receiveBufferSize() const; void setReceiveBufferSize(qint64 bufferSize); qint64 sendBufferSize() const; void setSendBufferSize(qint64 bufferSize); +#endif int option(SocketOption option) const Q_DECL_OVERRIDE; bool setOption(SocketOption option, int value) Q_DECL_OVERRIDE; diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 3cf65b3553..cb0a521360 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -670,8 +670,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6)); mreq6.ipv6mr_interface = interface.index(); - } else - if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { + } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { level = IPPROTO_IP; sockOpt = how4; sockArg = &mreq4; @@ -830,18 +829,10 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const { - // Create a sockaddr struct and reset its port number. - qt_sockaddr storage; - QT_SOCKLEN_T storageSize = sizeof(storage); - memset(&storage, 0, storageSize); - - // Peek 0 bytes into the next message. The size of the message may - // well be 0, so we can't check recvfrom's return value. + // Peek 1 bytes into the next message. ssize_t readBytes; - do { - char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); - } while (readBytes == -1 && errno == EINTR); + char c; + EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK)); // If there's no error, or if our buffer was too small, there must be a // pending datagram. @@ -856,24 +847,57 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { - QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192); ssize_t recvResult = -1; +#ifdef Q_OS_LINUX + // Linux can return the actual datagram size if we use MSG_TRUNC + char c; + EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC)); +#elif defined(SO_NREAD) + // macOS can return the actual datagram size if we use SO_NREAD + int value; + socklen_t valuelen = sizeof(value); + recvResult = getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &value, &valuelen); + if (recvResult != -1) + recvResult = value; +#else + // We need to grow the buffer to fit the entire datagram. + // We start at 1500 bytes (the MTU for Ethernet V2), which should catch + // almost all uses (effective MTU for UDP under IPv4 is 1468), except + // for localhost datagrams and those reassembled by the IP layer. + char udpMessagePeekBuffer[1500]; + struct msghdr msg; + struct iovec vec; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + vec.iov_base = udpMessagePeekBuffer; + vec.iov_len = sizeof(udpMessagePeekBuffer); for (;;) { // the data written to udpMessagePeekBuffer is discarded, so // this function is still reentrant although it might not look // so. - recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(), - udpMessagePeekBuffer.size(), MSG_PEEK); + recvResult = ::recvmsg(socketDescriptor, &msg, MSG_PEEK); if (recvResult == -1 && errno == EINTR) continue; - if (recvResult != (ssize_t) udpMessagePeekBuffer.size()) + // was the result truncated? + if ((msg.msg_flags & MSG_TRUNC) == 0) break; - udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2); + // grow by 16 times + msg.msg_iovlen *= 16; + if (msg.msg_iov != &vec) + delete[] msg.msg_iov; + msg.msg_iov = new struct iovec[msg.msg_iovlen]; + std::fill_n(msg.msg_iov, msg.msg_iovlen, vec); } + if (msg.msg_iov != &vec) + delete[] msg.msg_iov; +#endif + #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %zd", recvResult); #endif diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index a1f7f36700..6a091209be 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -944,9 +944,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6)); mreq6.ipv6mr_interface = iface.index(); - } else - - if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { + } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { level = IPPROTO_IP; sockOpt = how4; sockArg = reinterpret_cast<char *>(&mreq4); @@ -1148,10 +1146,10 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const DWORD bufferCount = 5; WSABUF * buf = 0; for (;;) { - // the data written to udpMessagePeekBuffer is discarded, so - // this function is still reentrant although it might not look - // so. - static char udpMessagePeekBuffer[8192]; + // We start at 1500 bytes (the MTU for Ethernet V2), which should catch + // almost all uses (effective MTU for UDP under IPv4 is 1468), except + // for localhost datagrams and those reassembled by the IP layer. + char udpMessagePeekBuffer[1500]; buf = new WSABUF[bufferCount]; for (DWORD i=0; i<bufferCount; i++) { @@ -1321,6 +1319,9 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l setPortAndAddress(header.destinationPort, header.destinationAddress, &aa, &msg.namelen); + uint oldIfIndex = 0; + bool mustSetIpv6MulticastIf = false; + if (msg.namelen == sizeof(aa.a6)) { // sending IPv6 if (header.hopLimit != -1) { @@ -1332,7 +1333,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr) + WSA_CMSG_SPACE(sizeof(int))); } - if (header.ifindex != 0 || !header.senderAddress.isNull()) { + if (!header.senderAddress.isNull()) { struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr)); memset(data, 0, sizeof(*data)); msg.Control.len += WSA_CMSG_SPACE(sizeof(*data)); @@ -1345,6 +1346,21 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l memcpy(&data->ipi6_addr, &tmp, sizeof(tmp)); cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr) + WSA_CMSG_SPACE(sizeof(*data))); + } else if (header.ifindex != 0) { + // Unlike other operating systems, setting the interface index in the in6_pktinfo + // structure above and leaving the ipi6_addr set to :: will cause the packets to be + // sent with source address ::. So we have to use IPV6_MULTICAST_IF, which MSDN is + // quite clear that "This option does not change the default interface for receiving + // IPv6 multicast traffic." + QT_SOCKOPTLEN_T len = sizeof(oldIfIndex); + if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, + reinterpret_cast<char *>(&oldIfIndex), &len) == -1 + || ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, + reinterpret_cast<const char *>(&header.ifindex), sizeof(header.ifindex)) == -1) { + setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + return -1; + } + mustSetIpv6MulticastIf = true; } } else { // sending IPv4 @@ -1398,6 +1414,12 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l ret = qint64(bytesSent); } + if (mustSetIpv6MulticastIf) { + // undo what we did above + ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, + reinterpret_cast<char *>(&oldIfIndex), sizeof(oldIfIndex)); + } + #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, qt_prettyDebug(data, qMin<qint64>(len, 16), len).data(), len, diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index 73d7ec2e77..5359872f96 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -174,16 +174,6 @@ static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg) #endif } -// VxWorks' headers do not specify any const modifiers -static inline in_addr_t qt_safe_inet_addr(const char *cp) -{ -#ifdef Q_OS_VXWORKS - return ::inet_addr((char *) cp); -#else - return ::inet_addr(cp); -#endif -} - static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags) { #ifdef MSG_NOSIGNAL diff --git a/src/network/socket/qtcpserver_p.h b/src/network/socket/qtcpserver_p.h index 71dc4d985f..b7fae4c105 100644 --- a/src/network/socket/qtcpserver_p.h +++ b/src/network/socket/qtcpserver_p.h @@ -63,7 +63,8 @@ QT_BEGIN_NAMESPACE -class QTcpServerPrivate : public QObjectPrivate, public QAbstractSocketEngineReceiver +class Q_NETWORK_EXPORT QTcpServerPrivate : public QObjectPrivate, + public QAbstractSocketEngineReceiver { Q_DECLARE_PUBLIC(QTcpServer) public: diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 79629a07f2..85c4f4cbfd 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -185,6 +185,10 @@ QUdpSocket::~QUdpSocket() This function returns \c true if successful; otherwise it returns \c false and sets the socket error accordingly. + \note Joining IPv6 multicast groups without an interface selection is not + supported in all operating systems. Consider using the overload where the + interface is specified. + \sa leaveMulticastGroup() */ bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress) @@ -219,6 +223,9 @@ bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress, This function returns \c true if successful; otherwise it returns \c false and sets the socket error accordingly. + \note This function should be called with the same arguments as were passed + to joinMulticastGroup(). + \sa joinMulticastGroup() */ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress) @@ -233,6 +240,9 @@ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress) Leaves the multicast group specified by \a groupAddress on the interface \a iface. + \note This function should be called with the same arguments as were passed + to joinMulticastGroup(). + \sa joinMulticastGroup() */ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress, |