📄 qnativesocketengine_unix.cpp
字号:
case EINVAL: setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); break; case EADDRNOTAVAIL: setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString); break; default: break; }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData());#endif return false; }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", address.toString().toLatin1().constData(), port);#endif socketState = QAbstractSocket::BoundState; return true;}bool QNativeSocketEnginePrivate::nativeListen(int backlog){ if (qt_socket_listen(socketDescriptor, backlog) < 0) { switch (errno) { case EADDRINUSE: setError(QAbstractSocket::AddressInUseError, PortInuseErrorString); break; default: break; }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", backlog, socketErrorString.toLatin1().constData());#endif return false; }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);#endif socketState = QAbstractSocket::ListeningState; return true;}int QNativeSocketEnginePrivate::nativeAccept(){ int acceptedDescriptor = qt_socket_accept(socketDescriptor, 0, 0);#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);#endif // Ensure that the socket is closed on exec*() ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); return acceptedDescriptor;}qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const{ /* Apparently, there is not consistency among different operating systems on how to use FIONREAD. FreeBSD, Linux and Solaris all expect the 3rd argument to ioctl() to be an int, which is normally 32-bit even on 64-bit machines. IRIX, on the other hand, expects a size_t, which is 64-bit on 64-bit machines. So, the solution is to use size_t initialized to zero to make sure all bits are set to zero, preventing underflow with the FreeBSD/Linux/Solaris ioctls. */ size_t nbytes = 0; // gives shorter than true amounts on Unix domain sockets. qint64 available = 0; if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) available = (qint64) *((int *) &nbytes);#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available);#endif return available;}bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const{ // Create a sockaddr struct and reset its port number.#if !defined(QT_NO_IPV6) struct sockaddr_storage storage; sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<sockaddr_in6 *>(&storage); storagePtrIPv6->sin6_port = 0;#else struct sockaddr storage;#endif sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage); storagePtr->sa_family = 0; sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage); storagePtrIPv4->sin_port = 0; QT_SOCKLEN_T storageSize = sizeof(storage); // 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. ssize_t readBytes; do { char c; readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, storagePtr, &storageSize); } while (readBytes == -1 && errno == EINTR); // If there's no error, or if our buffer was too small, there must be a // pending datagram. bool result = (readBytes != -1) || errno == EMSGSIZE;#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s", result ? "true" : "false");#endif return result;}qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const{ QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192); ssize_t recvResult = -1; 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); if (recvResult == -1 && errno == EINTR) continue; if (recvResult != (ssize_t) udpMessagePeekBuffer.size()) break; udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2); }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %i", recvResult);#endif return qint64(recvResult);}qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port){#if !defined(QT_NO_IPV6) struct sockaddr_storage aa;#else struct sockaddr_in aa;#endif memset(&aa, 0, sizeof(aa)); QT_SOCKLEN_T sz; sz = sizeof(aa); ssize_t recvFromResult = 0; do { char c; recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, 0, (struct sockaddr *)&aa, &sz); } while (recvFromResult == -1 && errno == EINTR); if (recvFromResult == -1) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); } else if (port || address) { qt_socket_getPortAndAddress((struct sockaddr *) &aa, port, address); }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", data, qt_prettyDebug(data, qMin(recvFromResult, ssize_t(16)), recvFromResult).data(), maxSize, address ? address->toString().toLatin1().constData() : "(nil)", port ? *port : 0, (qint64) recvFromResult);#endif return qint64(maxSize ? recvFromResult : recvFromResult == -1 ? -1 : 0);}qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port){ struct sockaddr_in sockAddrIPv4; struct sockaddr *sockAddrPtr = 0; QT_SOCKLEN_T sockAddrSize = 0;#if !defined(QT_NO_IPV6) struct sockaddr_in6 sockAddrIPv6; if (host.protocol() == QAbstractSocket::IPv6Protocol) { memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); sockAddrIPv6.sin6_family = AF_INET6; sockAddrIPv6.sin6_port = htons(port); Q_IPV6ADDR tmp = host.toIPv6Address(); memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp)); sockAddrSize = sizeof(sockAddrIPv6); sockAddrPtr = (struct sockaddr *)&sockAddrIPv6; } else#endif if (host.protocol() == QAbstractSocket::IPv4Protocol) { memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4)); sockAddrIPv4.sin_family = AF_INET; sockAddrIPv4.sin_port = htons(port); sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address()); sockAddrSize = sizeof(sockAddrIPv4); sockAddrPtr = (struct sockaddr *)&sockAddrIPv4; } // ignore the SIGPIPE signal qt_ignore_sigpipe(); ssize_t sentBytes; do { sentBytes = ::sendto(socketDescriptor, data, len, 0, sockAddrPtr, sockAddrSize); } while (sentBytes == -1 && errno == EINTR); if (sentBytes < 0) { switch (errno) { case EMSGSIZE: setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); break; default: setError(QAbstractSocket::NetworkError, SendDatagramErrorString); } }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(), port, (qint64) sentBytes);#endif return qint64(sentBytes);}bool QNativeSocketEnginePrivate::fetchConnectionParameters(){ localPort = 0; localAddress.clear(); peerPort = 0; peerAddress.clear(); if (socketDescriptor == -1) return false;#if !defined(QT_NO_IPV6) struct sockaddr_storage sa;#else struct sockaddr_in sa;#endif struct sockaddr *sockAddrPtr = (struct sockaddr *) &sa; QT_SOCKLEN_T sockAddrSize = sizeof(sa); // Determine local address memset(&sa, 0, sizeof(sa)); if (::getsockname(socketDescriptor, sockAddrPtr, &sockAddrSize) == 0) { qt_socket_getPortAndAddress(sockAddrPtr, &localPort, &localAddress); // Determine protocol family switch (sockAddrPtr->sa_family) { case AF_INET: socketProtocol = QAbstractSocket::IPv4Protocol; break;#if !defined (QT_NO_IPV6) case AF_INET6: socketProtocol = QAbstractSocket::IPv6Protocol; break;#endif default: socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; break; } } else if (errno == EBADF) { setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString); return false; } // Determine the remote address if (!::getpeername(socketDescriptor, sockAddrPtr, &sockAddrSize)) qt_socket_getPortAndAddress(sockAddrPtr, &peerPort, &peerAddress); // Determine the socket type (UDP/TCP) int value = 0; QT_SOCKOPTLEN_T valueSize = sizeof(int); if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) { if (value == SOCK_STREAM) socketType = QAbstractSocket::TcpSocket; else if (value == SOCK_DGRAM) socketType = QAbstractSocket::UdpSocket; else socketType = QAbstractSocket::UnknownSocketType; }#if defined (QNATIVESOCKETENGINE_DEBUG) QString socketProtocolStr = "UnknownProtocol"; if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; QString socketTypeStr = "UnknownSocketType"; if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," " peer == %s:%i, socket == %s - %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), socketProtocolStr.toLatin1().constData());#endif return true;}void QNativeSocketEnginePrivate::nativeClose(){#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEngine::nativeClose()");#endif ::close(socketDescriptor);}qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len){ Q_Q(QNativeSocketEngine); // ignore the SIGPIPE signal qt_ignore_sigpipe(); // loop while ::write() returns -1 and errno == EINTR, in case // of an interrupting signal. ssize_t writtenBytes; do { writtenBytes = ::write(socketDescriptor, data, len); } while (writtenBytes < 0 && errno == EINTR); if (writtenBytes < 0) { switch (errno) { case EPIPE: case ECONNRESET: writtenBytes = -1; setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); q->close(); break; case EAGAIN: writtenBytes = 0; break; case EMSGSIZE: setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); break; default: break; } }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", data, qt_prettyDebug(data, qMin((int) len, 16), (int) len).data(), len, (int) writtenBytes);#endif return qint64(writtenBytes);}/**/qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize){ Q_Q(QNativeSocketEngine); if (!q->isValid()) { qWarning("QNativeSocketEngine::unbufferedRead: Invalid socket"); return -1; } ssize_t r = 0; do { r = ::read(socketDescriptor, data, maxSize); } while (r == -1 && errno == EINTR); if (r < 0) { r = -1; switch (errno) {#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN case EWOULDBLOCK:#endif case EAGAIN: // No data was available for reading r = -2; break; case EBADF: case EINVAL: case EIO: setError(QAbstractSocket::NetworkError, ReadErrorString); break; case ECONNRESET: r = 0; break; default: break; } }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i", data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), maxSize, r);#endif return qint64(r);}int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const{ fd_set fds; FD_ZERO(&fds); FD_SET(socketDescriptor, &fds); struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; if (selectForRead) return select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); else return select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);}int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const{ fd_set fdread; FD_ZERO(&fdread); if (checkRead) FD_SET(socketDescriptor, &fdread); fd_set fdwrite; FD_ZERO(&fdwrite); if (checkWrite) FD_SET(socketDescriptor, &fdwrite); struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); if (ret <= 0) return ret; *selectForRead = FD_ISSET(socketDescriptor, &fdread); *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -