📄 q3socketdevice_unix.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the Qt3Support 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.******************************************************************************/#include "qplatformdefs.h"// 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, 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#endif#include "q3socketdevice.h"#ifndef QT_NO_NETWORK#include "qwindowdefs.h"#include <errno.h>#include <sys/types.h>static inline void qt_socket_getportaddr( struct sockaddr *sa, Q_UINT16 *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) ); QHostAddress a( tmp ); *addr = a; *port = ntohs( sa6->sin6_port ); return; }#endif struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; QHostAddress a( ntohl( sa4->sin_addr.s_addr ) ); *port = ntohs( sa4->sin_port ); *addr = QHostAddress( ntohl( sa4->sin_addr.s_addr ) ); return;}//#define QSOCKETDEVICE_DEBUG// internalvoid Q3SocketDevice::init(){}Q3SocketDevice::Protocol Q3SocketDevice::getProtocol() const{ if ( isValid() ) {#if !defined (QT_NO_IPV6) struct sockaddr_storage sa;#else struct sockaddr sa;#endif memset( &sa, 0, sizeof(sa) ); QT_SOCKLEN_T sz = sizeof( sa );#if !defined (QT_NO_IPV6) struct sockaddr *sap = reinterpret_cast<struct sockaddr *>(&sa); if ( !::getsockname(fd, sap, &sz) ) { switch ( sap->sa_family ) { case AF_INET: return IPv4; case AF_INET6: return IPv6; default: return Unknown; } }#else if ( !::getsockname(fd, &sa, &sz) ) { switch ( sa.sa_family ) { case AF_INET: return IPv4; default: return Unknown; } }#endif } return Unknown;}/*! Creates a new socket identifier. Returns -1 if there is a failure to create the new identifier; error() explains why. \sa setSocket()*/int Q3SocketDevice::createNewSocket(){#if !defined(QT_NO_IPV6) int s = qt_socket_socket( protocol() == IPv6 ? AF_INET6 : AF_INET, t == Datagram ? SOCK_DGRAM : SOCK_STREAM, 0 );#else int s = qt_socket_socket( AF_INET, t==Datagram?SOCK_DGRAM:SOCK_STREAM, 0 );#endif if ( s < 0 ) { switch( errno ) { case EPROTONOSUPPORT: e = InternalError; // 0 is supposed to work for both types break; case ENFILE: e = NoFiles; // special case for this break; case EACCES: e = Inaccessible; break; case ENOBUFS: case ENOMEM: e = NoResources; break; case EINVAL: e = Impossible; break; default: e = UnknownError; break; } } else { return s; } return -1;}/*! \reimp Closes the socket and sets the socket identifier to -1 (invalid). (This function ignores errors; if there are any then a file descriptor leakage might result. As far as we know, the only error that can arise is EBADF, and that would of course not cause leakage. There may be OS-specific errors that we haven't come across, however.) \sa open()*/void Q3SocketDevice::close(){ if ( fd == -1 || !isOpen() ) // already closed return; resetStatus(); setOpenMode(NotOpen); ::close( fd );#if defined(QSOCKETDEVICE_DEBUG) qDebug( "Q3SocketDevice::close: Closed socket %x", fd );#endif fd = -1; fetchConnectionParameters(); QIODevice::close();}/*! Returns true if the socket is valid and in blocking mode; otherwise returns false. Note that this function does not set error(). \warning On Windows, this function always returns true since the ioctlsocket() function is broken. \sa setBlocking(), isValid()*/bool Q3SocketDevice::blocking() const{ if ( !isValid() ) return true; int s = fcntl(fd, F_GETFL, 0); return !(s >= 0 && ((s & O_NDELAY) != 0));}/*! Makes the socket blocking if \a enable is true or nonblocking if \a enable is false. Sockets are blocking by default, but we recommend using nonblocking socket operations, especially for GUI programs that need to be responsive. \warning On Windows, this function should be used with care since whenever you use a QSocketNotifier on Windows, the socket is immediately made nonblocking. \sa blocking(), isValid()*/void Q3SocketDevice::setBlocking( bool enable ){#if defined(QSOCKETDEVICE_DEBUG) qDebug( "Q3SocketDevice::setBlocking( %d )", enable );#endif if ( !isValid() ) return; int tmp = ::fcntl(fd, F_GETFL, 0); if ( tmp >= 0 ) tmp = ::fcntl( fd, F_SETFL, enable ? (tmp&~O_NDELAY) : (tmp|O_NDELAY) ); if ( tmp >= 0 ) return; if ( e ) return; switch( errno ) { case EACCES: case EBADF: e = Impossible; break; case EFAULT: case EAGAIN:#if EAGAIN != EWOULDBLOCK case EWOULDBLOCK:#endif case EDEADLK: case EINTR: case EINVAL: case EMFILE: case ENOLCK: case EPERM: default: e = UnknownError; }}/*! Returns the value of the socket option \a opt.*/int Q3SocketDevice::option( Option opt ) const{ if ( !isValid() ) return -1; int n = -1; int v = -1; switch ( opt ) { case Broadcast: n = SO_BROADCAST; break; case ReceiveBuffer: n = SO_RCVBUF; break; case ReuseAddress: n = SO_REUSEADDR; break; case SendBuffer: n = SO_SNDBUF; break; } if ( n != -1 ) { QT_SOCKOPTLEN_T len; len = sizeof(v); int r = ::getsockopt( fd, SOL_SOCKET, n, (char*)&v, &len ); if ( r >= 0 ) return v; if ( !e ) { Q3SocketDevice *that = (Q3SocketDevice*)this; // mutable function switch( errno ) { case EBADF: case ENOTSOCK: that->e = Impossible; break; case EFAULT: that->e = InternalError; break; default: that->e = UnknownError; break; } } return -1; } return v;}/*! Sets the socket option \a opt to \a v.*/void Q3SocketDevice::setOption( Option opt, int v ){ if ( !isValid() ) return; int n = -1; // for really, really bad compilers switch ( opt ) { case Broadcast: n = SO_BROADCAST; break; case ReceiveBuffer: n = SO_RCVBUF; break; case ReuseAddress: n = SO_REUSEADDR; break; case SendBuffer: n = SO_SNDBUF; break; default: return; } if ( ::setsockopt( fd, SOL_SOCKET, n, (char*)&v, sizeof(v)) < 0 && e == NoError ) { switch( errno ) { case EBADF: case ENOTSOCK: e = Impossible; break; case EFAULT: e = InternalError; break; default: e = UnknownError; break; } }}/*! Connects to the IP address and port specified by \a addr and \a port. Returns true if it establishes a connection; otherwise returns false. If it returns false, error() explains why. Note that error() commonly returns NoError for non-blocking sockets; this just means that you can call connect() again in a little while and it'll probably succeed.*/bool Q3SocketDevice::connect( const QHostAddress &addr, Q_UINT16 port ){ if ( !isValid() ) return false; pa = addr; pp = port; struct sockaddr_in a4; struct sockaddr *aa; QT_SOCKLEN_T aalen;#if !defined(QT_NO_IPV6) struct sockaddr_in6 a6; if ( addr.isIPv6Address() ) { memset( &a6, 0, sizeof(a6) ); a6.sin6_family = AF_INET6; a6.sin6_port = htons( port ); Q_IPV6ADDR ip6 = addr.toIPv6Address(); memcpy( &a6.sin6_addr.s6_addr, &ip6, sizeof(ip6) ); aalen = sizeof( a6 ); aa = (struct sockaddr *)&a6; } else#endif if ( addr.isIPv4Address() ) { memset( &a4, 0, sizeof(a4) ); a4.sin_family = AF_INET; a4.sin_port = htons( port ); a4.sin_addr.s_addr = htonl( addr.toIPv4Address() ); aalen = sizeof(a4); aa = (struct sockaddr *)&a4; } else { e = Impossible; return false; } int r = QT_SOCKET_CONNECT( fd, aa, aalen ); if ( r == 0 ) { fetchConnectionParameters(); return true; } if ( errno == EISCONN || errno == EALREADY || errno == EINPROGRESS ) { fetchConnectionParameters(); return true; } if ( e != NoError || errno == EAGAIN || errno == EWOULDBLOCK ) { return false; } switch( errno ) { case EBADF: case ENOTSOCK: e = Impossible; break; case EFAULT: case EAFNOSUPPORT: e = InternalError; break; case ECONNREFUSED: e = ConnectionRefused; break; case ETIMEDOUT: case ENETUNREACH: e = NetworkFailure; break; case EADDRINUSE: e = NoResources; break; case EACCES: case EPERM: e = Inaccessible; break; default: e = UnknownError; break; } return false;}/*! Assigns a name to an unnamed socket. The name is the host address \a address and the port number \a port. If the operation succeeds, bind() returns true; otherwise it returns false without changing what port() and address() return. bind() is used by servers for setting up incoming connections. Call bind() before listen().*/bool Q3SocketDevice::bind( const QHostAddress &address, Q_UINT16 port ){ if ( !isValid() ) return false; int r; struct sockaddr_in a4;#if !defined(QT_NO_IPV6) struct sockaddr_in6 a6; if ( address.isIPv6Address() ) { memset( &a6, 0, sizeof(a6) ); a6.sin6_family = AF_INET6; a6.sin6_port = htons( port ); Q_IPV6ADDR tmp = address.toIPv6Address(); memcpy( &a6.sin6_addr.s6_addr, &tmp, sizeof(tmp) ); r = QT_SOCKET_BIND( fd, (struct sockaddr *)&a6, sizeof(a6) ); } else#endif if ( address.isIPv4Address() ) { memset( &a4, 0, sizeof(a4) ); a4.sin_family = AF_INET; a4.sin_port = htons( port ); a4.sin_addr.s_addr = htonl( address.toIPv4Address() ); r = QT_SOCKET_BIND( fd, (struct sockaddr*)&a4, sizeof(a4) ); } else { e = Impossible; return false; } if ( r < 0 ) { switch( errno ) { case EINVAL: e = AlreadyBound; break; case EACCES: e = Inaccessible; break; case ENOMEM: e = NoResources; break; case EFAULT: // a was illegal case ENAMETOOLONG: // sz was wrong e = InternalError; break; case EBADF: // AF_UNIX only case ENOTSOCK: // AF_UNIX only case EROFS: // AF_UNIX only case ENOENT: // AF_UNIX only case ENOTDIR: // AF_UNIX only case ELOOP: // AF_UNIX only e = Impossible; break; default: e = UnknownError; break; } return false; } fetchConnectionParameters(); return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -