📄 qnativesocketengine_unix.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtNetwork module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************///#define QNATIVESOCKETENGINE_DEBUG#include "qplatformdefs.h"#include "qnativesocketengine_p.h"#include "qiodevice.h"#include "qhostaddress.h"#include "qvarlengtharray.h"#include <time.h>#include <errno.h>#include <fcntl.h>#ifndef QT_NO_IPV6IFNAME#include <net/if.h>#endif#ifndef QT_NO_IPV6IFNAME#include <net/if.h>#endif#ifdef QT_LSB#include <arpa/inet.h>#endif//#define QNATIVESOCKETENGINE_DEBUG#if defined QNATIVESOCKETENGINE_DEBUG#include <qstring.h>#include <ctype.h>/* Returns a human readable representation of the first \a len characters in \a data.*/static QByteArray qt_prettyDebug(const char *data, int len, int maxSize){ if (!data) return "(null)"; QByteArray out; for (int i = 0; i < len; ++i) { char c = data[i]; if (isprint(c)) { out += c; } else switch (c) { case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: QString tmp; tmp.sprintf("\\%o", c); out += tmp.toLatin1(); } } if (len < maxSize) out += "..."; return out;}#endif// Almost always the same. If not, specify in qplatformdefs.h.#if !defined(QT_SOCKOPTLEN_T)# define QT_SOCKOPTLEN_T QT_SOCKLEN_T#endif// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDEDstatic inline int qt_socket_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen){ return ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen)); }#if defined(accept)# undef accept#endif// UnixWare 7 redefines listen -> _listenstatic inline int qt_socket_listen(int s, int backlog){ return ::listen(s, backlog); }#if defined(listen)# undef listen#endif// UnixWare 7 redefines socket -> _socketstatic inline int qt_socket_socket(int domain, int type, int protocol){ return ::socket(domain, type, protocol); }#if defined(socket)# undef socket#endifstatic void qt_ignore_sigpipe(){ // Set to ignore SIGPIPE once only. static QBasicAtomic atom = Q_ATOMIC_INIT(0); if (atom.testAndSet(0, 1)) { struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; ::sigaction(SIGPIPE, &noaction, 0); }}/* Extracts the port and address from a sockaddr, and stores them in \a port and \a addr if they are non-null.*/static inline void qt_socket_getPortAndAddress(struct sockaddr *sa, quint16 *port, QHostAddress *addr){#if !defined(QT_NO_IPV6) if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; Q_IPV6ADDR tmp; memcpy(&tmp, &sa6->sin6_addr.s6_addr, sizeof(tmp)); if (addr) { QHostAddress tmpAddress; tmpAddress.setAddress(tmp); *addr = tmpAddress;#ifndef QT_NO_IPV6IFNAME char scopeid[IFNAMSIZ]; if (::if_indextoname(sa6->sin6_scope_id, scopeid) > 0) { addr->setScopeId(QLatin1String(scopeid)); } else#endif addr->setScopeId(QString::number(sa6->sin6_scope_id)); } if (port) *port = ntohs(sa6->sin6_port); return; }#endif struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; if (port) *port = ntohs(sa4->sin_port); if (addr) { QHostAddress tmpAddress; tmpAddress.setAddress(ntohl(sa4->sin_addr.s_addr)); *addr = tmpAddress; }}/*! \internal Creates and returns a new socket descriptor of type \a socketType and \a socketProtocol. Returns -1 on failure.*/bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol socketProtocol){#ifndef QT_NO_IPV6 int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET;#else Q_UNUSED(socketProtocol); int protocol = AF_INET;#endif int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; int socket = qt_socket_socket(protocol, type, 0); if (socket <= 0) { switch (errno) { case EPROTONOSUPPORT: case EAFNOSUPPORT: case EINVAL: setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); break; case ENFILE: case EMFILE: case ENOBUFS: case ENOMEM: setError(QAbstractSocket::SocketResourceError, ResourceErrorString); break; case EACCES: setError(QAbstractSocket::SocketAccessError, AccessErrorString); break; default: break; } return false; } // Ensure that the socket is closed on exec*(). ::fcntl(socket, F_SETFD, FD_CLOEXEC); socketDescriptor = socket; return true;}/* Returns the value of the socket option \a opt.*/int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const{ Q_Q(const QNativeSocketEngine); if (!q->isValid()) return -1; int n = -1; switch (opt) { case QNativeSocketEngine::ReceiveBufferSocketOption: n = SO_RCVBUF; break; case QNativeSocketEngine::SendBufferSocketOption: n = SO_SNDBUF; break; case QNativeSocketEngine::NonBlockingSocketOption: break; case QNativeSocketEngine::BroadcastSocketOption: break; case QNativeSocketEngine::AddressReusable: n = SO_REUSEADDR; break; case QNativeSocketEngine::BindExclusively: return true; case QNativeSocketEngine::ReceiveOutOfBandData: n = SO_OOBINLINE; break; } int v = -1; QT_SOCKOPTLEN_T len = sizeof(v); if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1) return v; return -1;}/* Sets the socket option \a opt to \a v.*/bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v){ Q_Q(QNativeSocketEngine); if (!q->isValid()) return false; int n = 0; switch (opt) { case QNativeSocketEngine::ReceiveBufferSocketOption: n = SO_RCVBUF; break; case QNativeSocketEngine::SendBufferSocketOption: n = SO_SNDBUF; break; case QNativeSocketEngine::BroadcastSocketOption: n = SO_BROADCAST; break; case QNativeSocketEngine::NonBlockingSocketOption: { // Make the socket nonblocking. int flags = ::fcntl(socketDescriptor, F_GETFL, 0); if (flags == -1) {#ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_GETFL) failed");#endif return false; } if (::fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {#ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_SETFL) failed");#endif return false; } return true; } case QNativeSocketEngine::AddressReusable:#ifdef SO_REUSEPORT n = SO_REUSEPORT;#else n = SO_REUSEADDR;#endif break; case QNativeSocketEngine::BindExclusively: return true; case QNativeSocketEngine::ReceiveOutOfBandData: n = SO_OOBINLINE; break; } return ::setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0;}bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, 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 (addr.protocol() == QAbstractSocket::IPv6Protocol) { memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); sockAddrIPv6.sin6_family = AF_INET6; sockAddrIPv6.sin6_port = htons(port);#ifndef QT_NO_IPV6IFNAME sockAddrIPv6.sin6_scope_id = ::if_nametoindex(addr.scopeId().toLatin1().data());#else sockAddrIPv6.sin6_scope_id = addr.scopeId().toInt();#endif Q_IPV6ADDR ip6 = addr.toIPv6Address(); memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6)); sockAddrSize = sizeof(sockAddrIPv6); sockAddrPtr = (struct sockaddr *) &sockAddrIPv6; } else#if 0 {}#endif#endif if (addr.protocol() == QAbstractSocket::IPv4Protocol) { memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4)); sockAddrIPv4.sin_family = AF_INET; sockAddrIPv4.sin_port = htons(port); sockAddrIPv4.sin_addr.s_addr = htonl(addr.toIPv4Address()); sockAddrSize = sizeof(sockAddrIPv4); sockAddrPtr = (struct sockaddr *) &sockAddrIPv4; } else { // unreachable } int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize); if (connectResult == -1) { switch (errno) { case EISCONN: socketState = QAbstractSocket::ConnectedState; break; case ECONNREFUSED: case EINVAL: setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); socketState = QAbstractSocket::UnconnectedState; break; case ETIMEDOUT: setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); break; case EHOSTUNREACH: setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); socketState = QAbstractSocket::UnconnectedState; break; case ENETUNREACH: setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); socketState = QAbstractSocket::UnconnectedState; break; case EADDRINUSE: setError(QAbstractSocket::NetworkError, AddressInuseErrorString); break; case EINPROGRESS: case EALREADY: setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString); socketState = QAbstractSocket::ConnectingState; break; case EAGAIN: setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString); setError(QAbstractSocket::SocketResourceError, ResourceErrorString); break; case EACCES: case EPERM: setError(QAbstractSocket::SocketAccessError, AccessErrorString); socketState = QAbstractSocket::UnconnectedState; break; case EAFNOSUPPORT: case EBADF: case EFAULT: case ENOTSOCK: socketState = QAbstractSocket::UnconnectedState; default: break; } if (socketState != QAbstractSocket::ConnectedState) {#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", addr.toString().toLatin1().constData(), port, socketState == QAbstractSocket::ConnectingState ? "Connection in progress" : socketErrorString.toLatin1().constData());#endif return false; } }#if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", addr.toString().toLatin1().constData(), port);#endif socketState = QAbstractSocket::ConnectedState; return true;}bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, 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 (address.protocol() == QAbstractSocket::IPv6Protocol) { memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); sockAddrIPv6.sin6_family = AF_INET6; sockAddrIPv6.sin6_port = htons(port);#ifndef QT_NO_IPV6IFNAME sockAddrIPv6.sin6_scope_id = ::if_nametoindex(address.scopeId().toLatin1().data());#else sockAddrIPv6.sin6_scope_id = address.scopeId().toInt();#endif Q_IPV6ADDR tmp = address.toIPv6Address(); memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp)); sockAddrSize = sizeof(sockAddrIPv6); sockAddrPtr = (struct sockaddr *) &sockAddrIPv6; } else#endif if (address.protocol() == QAbstractSocket::IPv4Protocol) { memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4)); sockAddrIPv4.sin_family = AF_INET; sockAddrIPv4.sin_port = htons(port); sockAddrIPv4.sin_addr.s_addr = htonl(address.toIPv4Address()); sockAddrSize = sizeof(sockAddrIPv4); sockAddrPtr = (struct sockaddr *) &sockAddrIPv4; } else { // unreachable } int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize); if (bindResult < 0) { switch(errno) { case EADDRINUSE: setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); break; case EACCES: setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -