void Q3SocketPrivate::setSocketDevice( Q3Socket *q, Q3SocketDevice *device ) { delete socket; delete rsn; delete wsn; if ( device ) { socket = device; } else { socket = new Q3SocketDevice( Q3SocketDevice::Stream, ( addr.isIPv4Address() ? Q3SocketDevice::IPv4 : Q3SocketDevice::IPv6 ), 0 ); socket->setBlocking( false ); socket->setAddressReusable( true ); } rsn = new QSocketNotifier( socket->socket(), QSocketNotifier::Read, q, "read" ); wsn = new QSocketNotifier( socket->socket(), QSocketNotifier::Write, q, "write" ); QObject::connect( rsn, SIGNAL(activated(int)), q, SLOT(sn_read()) ); rsn->setEnabled( false ); QObject::connect( wsn, SIGNAL(activated(int)), q, SLOT(sn_write()) ); wsn->setEnabled( false ); }
/* The common bit of the constructors. */ void Q3ServerSocket::init( const QHostAddress & address, Q_UINT16 port, int backlog ) { d->s = new Q3SocketDevice( Q3SocketDevice::Stream, address.isIPv4Address() ? Q3SocketDevice::IPv4 : Q3SocketDevice::IPv6, 0 ); #if !defined(Q_OS_WIN32) // Under Unix, we want to be able to use the port, even if a socket on the // same address-port is in TIME_WAIT. Under Windows this is possible anyway // -- furthermore, the meaning of reusable is different: it means that you // can use the same address-port for multiple listening sockets. d->s->setAddressReusable( true ); #endif if ( d->s->bind( address, port ) && d->s->listen( backlog ) ) { d->n = new QSocketNotifier( d->s->socket(), QSocketNotifier::Read, this, "accepting new connections" ); connect( d->n, SIGNAL(activated(int)), this, SLOT(incomingConnection(int)) ); } else {
Q_LONG Q3SocketDevice::writeBlock( const char * data, Q_ULONG len, const QHostAddress & host, Q_UINT16 port ) { if ( t != Datagram ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Not datagram" ); #endif return -1; // for now - later we can do t/tcp } if ( data == 0 && len != 0 ) { #if defined(QT_CHECK_NULL) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Null pointer error" ); #endif return -1; } if ( !isValid() ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Invalid socket" ); #endif return -1; } if ( !isOpen() ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Device is not open" ); #endif return -1; } if ( !isWritable() ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Write operation not permitted" ); #endif return -1; } struct sockaddr_in a4; struct sockaddr *aa; QT_SOCKLEN_T slen; #if !defined(QT_NO_IPV6) struct sockaddr_in6 a6; if ( host.isIPv6Address() ) { memset( &a6, 0, sizeof(a6) ); a6.sin6_family = AF_INET6; a6.sin6_port = htons( port ); Q_IPV6ADDR tmp = host.toIPv6Address(); memcpy( &a6.sin6_addr.s6_addr, &tmp, sizeof(tmp) ); slen = sizeof( a6 ); aa = (struct sockaddr *)&a6; } else #endif if ( host.isIPv4Address() ) { memset( &a4, 0, sizeof(a4) ); a4.sin_family = AF_INET; a4.sin_port = htons( port ); a4.sin_addr.s_addr = htonl( host.toIPv4Address() ); slen = sizeof(a4); aa = (struct sockaddr *)&a4; } else { e = Impossible; return -1; } // we'd use MSG_DONTWAIT + MSG_NOSIGNAL if Stevens were right. // but apparently Stevens and most implementors disagree bool done = false; int r = 0; while ( !done ) { r = ::sendto( fd, data, len, 0, aa, slen); done = true; if ( r < 0 && e == NoError && errno != EAGAIN && errno != EWOULDBLOCK ) { switch( errno ) { case EINTR: // signal - call read() or whatever again done = false; break; case ENOSPC: case EPIPE: case EIO: case EISDIR: case EBADF: case EINVAL: case EFAULT: case ENOTCONN: case ENOTSOCK: e = Impossible; break; #if defined(ENONET) case ENONET: #endif case EHOSTUNREACH: case ENETDOWN: case ENETUNREACH: case ETIMEDOUT: e = NetworkFailure; break; default: e = UnknownError; break; } } } return r; }
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; }
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; }
Q_LONG Q3SocketDevice::writeBlock( const char * data, Q_ULONG len, const QHostAddress & host, quint16 port ) { if ( t != Datagram ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Not datagram" ); #endif return -1; // for now - later we can do t/tcp } if ( data == 0 && len != 0 ) { #if defined(QT_CHECK_NULL) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Null pointer error" ); #endif return -1; } if ( !isValid() ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Invalid socket" ); #endif return -1; } if ( !isOpen() ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Device is not open" ); #endif return -1; } if ( !isWritable() ) { #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG) qWarning( "Q3SocketDevice::sendBlock: Write operation not permitted" ); #endif return -1; } struct sockaddr_in a4; struct sockaddr *aa; SOCKLEN_T slen; #if !defined(QT_NO_IPV6) qt_sockaddr_in6 a6; if ( initialized >= 0x20 && host.isIPv6Address() ) { memset( &a6, 0, sizeof(a6) ); a6.sin6_family = AF_INET6; a6.sin6_port = htons( port ); Q_IPV6ADDR tmp = host.toIPv6Address(); memcpy( &a6.sin6_addr.qt_s6_addr, &tmp, sizeof(tmp) ); slen = sizeof( a6 ); aa = (struct sockaddr *)&a6; } else #endif if ( host.isIPv4Address() ) { memset( &a4, 0, sizeof(a4) ); a4.sin_family = AF_INET; a4.sin_port = htons( port ); a4.sin_addr.s_addr = htonl( host.toIPv4Address() ); slen = sizeof(a4); aa = (struct sockaddr *)&a4; } else { e = Impossible; return -1; } // we'd use MSG_DONTWAIT + MSG_NOSIGNAL if Stevens were right. // but apparently Stevens and most implementors disagree bool done = false; qint64 r = 0; while ( !done ) { r = ::sendto( fd, data, len, 0, aa, slen ); done = true; if ( r == SOCKET_ERROR && e == NoError ) {//&& e != EAGAIN ) { switch( WSAGetLastError() ) { case WSANOTINITIALISED: e = Impossible; break; case WSAENETDOWN: case WSAEACCES: case WSAENETRESET: case WSAESHUTDOWN: case WSAEHOSTUNREACH: case WSAECONNABORTED: case WSAECONNRESET: case WSAEADDRNOTAVAIL: case WSAENETUNREACH: case WSAETIMEDOUT: e = NetworkFailure; break; case WSAEINTR: done = false; break; case WSAEINPROGRESS: e = NoResources; // ### perhaps try it later? break; case WSAEFAULT: case WSAEOPNOTSUPP: case WSAEAFNOSUPPORT: e = InternalError; break; case WSAENOBUFS: case WSAEMSGSIZE: e = NoResources; break; case WSAENOTCONN: case WSAENOTSOCK: case WSAEINVAL: case WSAEDESTADDRREQ: e = Impossible; break; case WSAEWOULDBLOCK: r = 0; break; default: e = UnknownError; break; } } } return r; }
bool Q3SocketDevice::bind( const QHostAddress &address, quint16 port ) { if ( !isValid() ) return false; int r; struct sockaddr_in a4; #if !defined(QT_NO_IPV6) qt_sockaddr_in6 a6; if ( initialized >= 0x20 && 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.qt_s6_addr, &tmp, sizeof(tmp) ); r = ::bind( fd, (struct sockaddr *)&a6, sizeof(struct qt_sockaddr_storage) ); } 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 = ::bind( fd, (struct sockaddr*)&a4, sizeof(struct sockaddr_in) ); } else { e = Impossible; return false; } if ( r == SOCKET_ERROR ) { switch( WSAGetLastError() ) { case WSANOTINITIALISED: e = Impossible; break; case WSAENETDOWN: e = NetworkFailure; break; case WSAEACCES: e = Inaccessible; break; case WSAEADDRNOTAVAIL: e = Inaccessible; break; case WSAEFAULT: e = InternalError; break; case WSAEINPROGRESS: case WSAENOBUFS: e = NoResources; break; case WSAEADDRINUSE: case WSAEINVAL: e = AlreadyBound; break; case WSAENOTSOCK: e = Impossible; break; default: e = UnknownError; break; } return false; } fetchConnectionParameters(); return true; }
bool Q3SocketDevice::connect( const QHostAddress &addr, quint16 port ) { if ( !isValid() ) return false; pa = addr; pp = port; struct sockaddr_in a4; struct sockaddr *aa; SOCKLEN_T aalen; #if !defined(QT_NO_IPV6) qt_sockaddr_in6 a6; if ( initialized >= 0x20 && 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.qt_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 = ::connect( fd, aa, aalen ); if ( r == SOCKET_ERROR ) { switch( WSAGetLastError() ) { case WSANOTINITIALISED: e = Impossible; break; case WSAENETDOWN: e = NetworkFailure; break; case WSAEADDRINUSE: case WSAEINPROGRESS: case WSAENOBUFS: e = NoResources; break; case WSAEINTR: e = UnknownError; // ### ? break; case WSAEALREADY: // ### ? break; case WSAEADDRNOTAVAIL: e = ConnectionRefused; // ### ? break; case WSAEAFNOSUPPORT: case WSAEFAULT: e = InternalError; break; case WSAEINVAL: break; case WSAECONNREFUSED: e = ConnectionRefused; break; case WSAEISCONN: goto successful; case WSAENETUNREACH: case WSAETIMEDOUT: e = NetworkFailure; break; case WSAENOTSOCK: e = Impossible; break; case WSAEWOULDBLOCK: break; case WSAEACCES: e = Inaccessible; break; case 10107: // Workaround for a problem with the WinSock Proxy Server. See // also support/arc-12/25557 for details on the problem. goto successful; default: e = UnknownError; break; } return false; } successful: fetchConnectionParameters(); return true; }