src/qt3support/network/q3socketdevice_unix.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qplatformdefs.h"
       
    43 
       
    44 // Almost always the same. If not, specify in qplatformdefs.h.
       
    45 #if !defined(QT_SOCKOPTLEN_T)
       
    46 # define QT_SOCKOPTLEN_T QT_SOCKLEN_T
       
    47 #endif
       
    48 
       
    49 // Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED
       
    50 static inline int qt_socket_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen)
       
    51 { return ::accept(s, addr, addrlen); }
       
    52 #if defined(accept)
       
    53 # undef accept
       
    54 #endif
       
    55 
       
    56 // UnixWare 7 redefines listen -> _listen
       
    57 static inline int qt_socket_listen(int s, int backlog)
       
    58 { return ::listen(s, backlog); }
       
    59 #if defined(listen)
       
    60 # undef listen
       
    61 #endif
       
    62 
       
    63 // UnixWare 7 redefines socket -> _socket
       
    64 static inline int qt_socket_socket(int domain, int type, int protocol)
       
    65 { return ::socket(domain, type, protocol); }
       
    66 #if defined(socket)
       
    67 # undef socket
       
    68 #endif
       
    69 
       
    70 #include "q3socketdevice.h"
       
    71 
       
    72 #ifndef QT_NO_NETWORK
       
    73 
       
    74 #include "qwindowdefs.h"
       
    75 
       
    76 #include <errno.h>
       
    77 #include <sys/types.h>
       
    78 
       
    79 QT_BEGIN_NAMESPACE
       
    80 
       
    81 static inline void qt_socket_getportaddr( struct sockaddr *sa,
       
    82 					  Q_UINT16 *port, QHostAddress *addr )
       
    83 {
       
    84 #if !defined(QT_NO_IPV6)
       
    85     if ( sa->sa_family == AF_INET6 ) {
       
    86 	struct sockaddr_in6 *sa6 = ( struct sockaddr_in6 * )sa;
       
    87 	Q_IPV6ADDR tmp;
       
    88 	memcpy( &tmp, &sa6->sin6_addr.s6_addr, sizeof(tmp) );
       
    89 	QHostAddress a( tmp );
       
    90 	*addr = a;
       
    91 	*port = ntohs( sa6->sin6_port );
       
    92 	return;
       
    93     }
       
    94 #endif
       
    95     struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
       
    96     QHostAddress a( ntohl( sa4->sin_addr.s_addr ) );
       
    97     *port = ntohs( sa4->sin_port );
       
    98     *addr = QHostAddress( ntohl( sa4->sin_addr.s_addr ) );
       
    99     return;
       
   100 }
       
   101 
       
   102 
       
   103 //#define QSOCKETDEVICE_DEBUG
       
   104 
       
   105 // internal
       
   106 void Q3SocketDevice::init()
       
   107 {
       
   108 }
       
   109 
       
   110 
       
   111 Q3SocketDevice::Protocol Q3SocketDevice::getProtocol() const
       
   112 {
       
   113     if ( isValid() ) {
       
   114 #if !defined (QT_NO_IPV6)
       
   115 	struct sockaddr_storage sa;
       
   116 #else
       
   117 	struct sockaddr sa;
       
   118 #endif
       
   119 	memset( &sa, 0, sizeof(sa) );
       
   120 	QT_SOCKLEN_T sz = sizeof( sa );
       
   121 #if !defined (QT_NO_IPV6)
       
   122 	struct sockaddr *sap = reinterpret_cast<struct sockaddr *>(&sa);
       
   123 	if ( !::getsockname(fd, sap, &sz) ) {
       
   124 	    switch ( sap->sa_family ) {
       
   125 		case AF_INET:
       
   126 		    return IPv4;
       
   127 		case AF_INET6:
       
   128 		    return IPv6;
       
   129 		default:
       
   130 		    return Unknown;
       
   131 	    }
       
   132 	}
       
   133 #else
       
   134 	if ( !::getsockname(fd, &sa, &sz) ) {
       
   135 	    switch ( sa.sa_family ) {
       
   136 		case AF_INET:
       
   137 		    return IPv4;
       
   138 		default:
       
   139 		    return Unknown;
       
   140 	    }
       
   141 	}
       
   142 #endif
       
   143     }
       
   144     return Unknown;
       
   145 }
       
   146 
       
   147 
       
   148 int Q3SocketDevice::createNewSocket()
       
   149 {
       
   150 #if !defined(QT_NO_IPV6)
       
   151     int s = qt_socket_socket( protocol() == IPv6 ? AF_INET6 : AF_INET,
       
   152 			      t == Datagram ? SOCK_DGRAM : SOCK_STREAM, 0 );
       
   153 #else
       
   154     int s = qt_socket_socket( AF_INET, t==Datagram?SOCK_DGRAM:SOCK_STREAM, 0 );
       
   155 #endif
       
   156     if ( s < 0 ) {
       
   157 	switch( errno ) {
       
   158 	case EPROTONOSUPPORT:
       
   159 	    e = InternalError; // 0 is supposed to work for both types
       
   160 	    break;
       
   161 	case ENFILE:
       
   162 	    e = NoFiles; // special case for this
       
   163 	    break;
       
   164 	case EACCES:
       
   165 	    e = Inaccessible;
       
   166 	    break;
       
   167 	case ENOBUFS:
       
   168 	case ENOMEM:
       
   169 	    e = NoResources;
       
   170 	    break;
       
   171 	case EINVAL:
       
   172 	    e = Impossible;
       
   173 	    break;
       
   174 	default:
       
   175 	    e = UnknownError;
       
   176 	    break;
       
   177 	}
       
   178     } else {
       
   179 	return s;
       
   180     }
       
   181     return -1;
       
   182 }
       
   183 
       
   184 void Q3SocketDevice::close()
       
   185 {
       
   186     if ( fd == -1 || !isOpen() )		// already closed
       
   187 	return;
       
   188     resetStatus();
       
   189     setOpenMode(NotOpen);
       
   190     ::close( fd );
       
   191 #if defined(QSOCKETDEVICE_DEBUG)
       
   192     qDebug( "Q3SocketDevice::close: Closed socket %x", fd );
       
   193 #endif
       
   194     fd = -1;
       
   195     fetchConnectionParameters();
       
   196     QIODevice::close();
       
   197 }
       
   198 
       
   199 
       
   200 bool Q3SocketDevice::blocking() const
       
   201 {
       
   202     if ( !isValid() )
       
   203 	return true;
       
   204     int s = fcntl(fd, F_GETFL, 0);
       
   205     return !(s >= 0 && ((s & O_NDELAY) != 0));
       
   206 }
       
   207 
       
   208 
       
   209 void Q3SocketDevice::setBlocking( bool enable )
       
   210 {
       
   211 #if defined(QSOCKETDEVICE_DEBUG)
       
   212     qDebug( "Q3SocketDevice::setBlocking( %d )", enable );
       
   213 #endif
       
   214     if ( !isValid() )
       
   215 	return;
       
   216     int tmp = ::fcntl(fd, F_GETFL, 0);
       
   217     if ( tmp >= 0 )
       
   218 	tmp = ::fcntl( fd, F_SETFL, enable ? (tmp&~O_NDELAY) : (tmp|O_NDELAY) );
       
   219     if ( tmp >= 0 )
       
   220 	return;
       
   221     if ( e )
       
   222 	return;
       
   223     switch( errno ) {
       
   224     case EACCES:
       
   225     case EBADF:
       
   226 	e = Impossible;
       
   227 	break;
       
   228     case EFAULT:
       
   229     case EAGAIN:
       
   230 #if EAGAIN != EWOULDBLOCK
       
   231     case EWOULDBLOCK:
       
   232 #endif
       
   233     case EDEADLK:
       
   234     case EINTR:
       
   235     case EINVAL:
       
   236     case EMFILE:
       
   237     case ENOLCK:
       
   238     case EPERM:
       
   239     default:
       
   240 	e = UnknownError;
       
   241     }
       
   242 }
       
   243 
       
   244 
       
   245 int Q3SocketDevice::option( Option opt ) const
       
   246 {
       
   247     if ( !isValid() )
       
   248 	return -1;
       
   249     int n = -1;
       
   250     int v = -1;
       
   251     switch ( opt ) {
       
   252     case Broadcast:
       
   253 	n = SO_BROADCAST;
       
   254 	break;
       
   255     case ReceiveBuffer:
       
   256 	n = SO_RCVBUF;
       
   257 	break;
       
   258     case ReuseAddress:
       
   259 	n = SO_REUSEADDR;
       
   260 	break;
       
   261     case SendBuffer:
       
   262 	n = SO_SNDBUF;
       
   263 	break;
       
   264     }
       
   265     if ( n != -1 ) {
       
   266 	QT_SOCKOPTLEN_T len;
       
   267 	len = sizeof(v);
       
   268 	int r = ::getsockopt( fd, SOL_SOCKET, n, (char*)&v, &len );
       
   269 	if ( r >= 0 )
       
   270 	    return v;
       
   271 	if ( !e ) {
       
   272 	    Q3SocketDevice *that = (Q3SocketDevice*)this; // mutable function
       
   273 	    switch( errno ) {
       
   274 	    case EBADF:
       
   275 	    case ENOTSOCK:
       
   276 		that->e = Impossible;
       
   277 		break;
       
   278 	    case EFAULT:
       
   279 		that->e = InternalError;
       
   280 		break;
       
   281 	    default:
       
   282 		that->e = UnknownError;
       
   283 		break;
       
   284 	    }
       
   285 	}
       
   286 	return -1;
       
   287     }
       
   288     return v;
       
   289 }
       
   290 
       
   291 
       
   292 void Q3SocketDevice::setOption( Option opt, int v )
       
   293 {
       
   294     if ( !isValid() )
       
   295 	return;
       
   296     int n = -1; // for really, really bad compilers
       
   297     switch ( opt ) {
       
   298     case Broadcast:
       
   299 	n = SO_BROADCAST;
       
   300 	break;
       
   301     case ReceiveBuffer:
       
   302 	n = SO_RCVBUF;
       
   303 	break;
       
   304     case ReuseAddress:
       
   305 	n = SO_REUSEADDR;
       
   306 	break;
       
   307     case SendBuffer:
       
   308 	n = SO_SNDBUF;
       
   309 	break;
       
   310     default:
       
   311 	return;
       
   312     }
       
   313     if ( ::setsockopt( fd, SOL_SOCKET, n, (char*)&v, sizeof(v)) < 0 &&
       
   314 	 e == NoError ) {
       
   315 	switch( errno ) {
       
   316 	case EBADF:
       
   317 	case ENOTSOCK:
       
   318 	    e = Impossible;
       
   319 	    break;
       
   320 	case EFAULT:
       
   321 	    e = InternalError;
       
   322 	    break;
       
   323 	default:
       
   324 	    e = UnknownError;
       
   325 	    break;
       
   326 	}
       
   327     }
       
   328 }
       
   329 
       
   330 
       
   331 bool Q3SocketDevice::connect( const QHostAddress &addr, Q_UINT16 port )
       
   332 {
       
   333     if ( !isValid() )
       
   334 	return false;
       
   335 
       
   336     pa = addr;
       
   337     pp = port;
       
   338 
       
   339     struct sockaddr_in a4;
       
   340     struct sockaddr *aa;
       
   341     QT_SOCKLEN_T aalen;
       
   342 
       
   343 #if !defined(QT_NO_IPV6)
       
   344     struct sockaddr_in6 a6;
       
   345 
       
   346     if ( addr.isIPv6Address() ) {
       
   347 	memset( &a6, 0, sizeof(a6) );
       
   348 	a6.sin6_family = AF_INET6;
       
   349 	a6.sin6_port = htons( port );
       
   350 	Q_IPV6ADDR ip6 = addr.toIPv6Address();
       
   351 	memcpy( &a6.sin6_addr.s6_addr, &ip6, sizeof(ip6) );
       
   352 
       
   353 	aalen = sizeof( a6 );
       
   354 	aa = (struct sockaddr *)&a6;
       
   355     } else
       
   356 #endif
       
   357     if ( addr.isIPv4Address() ) {
       
   358 	memset( &a4, 0, sizeof(a4) );
       
   359 	a4.sin_family = AF_INET;
       
   360 	a4.sin_port = htons( port );
       
   361 	a4.sin_addr.s_addr = htonl( addr.toIPv4Address() );
       
   362 
       
   363 	aalen = sizeof(a4);
       
   364 	aa = (struct sockaddr *)&a4;
       
   365     } else {
       
   366 	e = Impossible;
       
   367 	return false;
       
   368     }
       
   369 
       
   370     int r = QT_SOCKET_CONNECT( fd, aa, aalen );
       
   371     if ( r == 0 ) {
       
   372 	fetchConnectionParameters();
       
   373 	return true;
       
   374     }
       
   375     if ( errno == EISCONN || errno == EALREADY || errno == EINPROGRESS ) {
       
   376 	fetchConnectionParameters();
       
   377 	return true;
       
   378     }
       
   379     if ( e != NoError || errno == EAGAIN || errno == EWOULDBLOCK ) {
       
   380 	return false;
       
   381     }
       
   382     switch( errno ) {
       
   383     case EBADF:
       
   384     case ENOTSOCK:
       
   385 	e = Impossible;
       
   386 	break;
       
   387     case EFAULT:
       
   388     case EAFNOSUPPORT:
       
   389 	e = InternalError;
       
   390 	break;
       
   391     case ECONNREFUSED:
       
   392 	e = ConnectionRefused;
       
   393 	break;
       
   394     case ETIMEDOUT:
       
   395     case ENETUNREACH:
       
   396 	e = NetworkFailure;
       
   397 	break;
       
   398     case EADDRINUSE:
       
   399 	e = NoResources;
       
   400 	break;
       
   401     case EACCES:
       
   402     case EPERM:
       
   403 	e = Inaccessible;
       
   404 	break;
       
   405     default:
       
   406 	e = UnknownError;
       
   407 	break;
       
   408     }
       
   409     return false;
       
   410 }
       
   411 
       
   412 
       
   413 bool Q3SocketDevice::bind( const QHostAddress &address, Q_UINT16 port )
       
   414 {
       
   415     if ( !isValid() )
       
   416 	return false;
       
   417     int r;
       
   418     struct sockaddr_in a4;
       
   419 #if !defined(QT_NO_IPV6)
       
   420     struct sockaddr_in6 a6;
       
   421 
       
   422     if ( address.isIPv6Address() ) {
       
   423 	memset( &a6, 0, sizeof(a6) );
       
   424 	a6.sin6_family = AF_INET6;
       
   425 	a6.sin6_port = htons( port );
       
   426 	Q_IPV6ADDR tmp = address.toIPv6Address();
       
   427 	memcpy( &a6.sin6_addr.s6_addr, &tmp, sizeof(tmp) );
       
   428 
       
   429 	r = QT_SOCKET_BIND( fd, (struct sockaddr *)&a6, sizeof(a6) );
       
   430     } else
       
   431 #endif
       
   432     if ( address.isIPv4Address() ) {
       
   433 	memset( &a4, 0, sizeof(a4) );
       
   434 	a4.sin_family = AF_INET;
       
   435 	a4.sin_port = htons( port );
       
   436 	a4.sin_addr.s_addr = htonl( address.toIPv4Address() );
       
   437 
       
   438 	r = QT_SOCKET_BIND( fd, (struct sockaddr*)&a4, sizeof(a4) );
       
   439     } else {
       
   440 	e = Impossible;
       
   441 	return false;
       
   442     }
       
   443 
       
   444     if ( r < 0 ) {
       
   445 	switch( errno ) {
       
   446 	case EINVAL:
       
   447 	    e = AlreadyBound;
       
   448 	    break;
       
   449 	case EACCES:
       
   450 	    e = Inaccessible;
       
   451 	    break;
       
   452 	case ENOMEM:
       
   453 	    e = NoResources;
       
   454 	    break;
       
   455 	case EFAULT: // a was illegal
       
   456 	case ENAMETOOLONG: // sz was wrong
       
   457 	    e = InternalError;
       
   458 	    break;
       
   459 	case EBADF: // AF_UNIX only
       
   460 	case ENOTSOCK: // AF_UNIX only
       
   461 	case EROFS: // AF_UNIX only
       
   462 	case ENOENT: // AF_UNIX only
       
   463 	case ENOTDIR: // AF_UNIX only
       
   464 	case ELOOP: // AF_UNIX only
       
   465 	    e = Impossible;
       
   466 	    break;
       
   467 	default:
       
   468 	    e = UnknownError;
       
   469 	    break;
       
   470 	}
       
   471 	return false;
       
   472     }
       
   473     fetchConnectionParameters();
       
   474     return true;
       
   475 }
       
   476 
       
   477 
       
   478 bool Q3SocketDevice::listen( int backlog )
       
   479 {
       
   480     if ( !isValid() )
       
   481 	return false;
       
   482     if ( qt_socket_listen( fd, backlog ) >= 0 )
       
   483 	return true;
       
   484     if ( !e )
       
   485 	e = Impossible;
       
   486     return false;
       
   487 }
       
   488 
       
   489 
       
   490 int Q3SocketDevice::accept()
       
   491 {
       
   492     if ( !isValid() )
       
   493 	return -1;
       
   494 
       
   495 #if !defined (QT_NO_IPV6)
       
   496     struct sockaddr_storage aa;
       
   497 #else
       
   498     struct sockaddr aa;
       
   499 #endif
       
   500     QT_SOCKLEN_T l = sizeof( aa );
       
   501     bool done;
       
   502     int s;
       
   503     do {
       
   504         s = qt_socket_accept( fd, (struct sockaddr*)&aa, &l );
       
   505         // we'll blithely throw away the stuff accept() wrote to aa
       
   506         done = true;
       
   507         if ( s < 0 && e == NoError ) {
       
   508             switch( errno ) {
       
   509             case EINTR:
       
   510                 done = false;
       
   511                 break;
       
   512 #if defined(EPROTO)
       
   513 	    case EPROTO:
       
   514 #endif
       
   515 #if defined(ENONET)
       
   516 	    case ENONET:
       
   517 #endif
       
   518 	    case ENOPROTOOPT:
       
   519 	    case EHOSTDOWN:
       
   520 	    case EOPNOTSUPP:
       
   521 	    case EHOSTUNREACH:
       
   522 	    case ENETDOWN:
       
   523 	    case ENETUNREACH:
       
   524 	    case ETIMEDOUT:
       
   525 		// in all these cases, an error happened during connection
       
   526 		// setup.  we're not interested in what happened, so we
       
   527 		// just treat it like the client-closed-quickly case.
       
   528 	    case EPERM:
       
   529 		// firewalling wouldn't let us accept.  we treat it like
       
   530 		// the client-closed-quickly case.
       
   531 	    case EAGAIN:
       
   532 #if EAGAIN != EWOULDBLOCK
       
   533 	    case EWOULDBLOCK:
       
   534 #endif
       
   535 		// the client closed the connection before we got around
       
   536 		// to accept()ing it.
       
   537 		break;
       
   538 	    case EBADF:
       
   539 	    case ENOTSOCK:
       
   540 		e = Impossible;
       
   541 		break;
       
   542 	    case EFAULT:
       
   543 		e = InternalError;
       
   544 		break;
       
   545 	    case ENOMEM:
       
   546 	    case ENOBUFS:
       
   547 		e = NoResources;
       
   548 		break;
       
   549 	    default:
       
   550 		e = UnknownError;
       
   551 		break;
       
   552 	    }
       
   553 	}
       
   554     } while (!done);
       
   555     return s;
       
   556 }
       
   557 
       
   558 
       
   559 qint64 Q3SocketDevice::bytesAvailable() const
       
   560 {
       
   561     if ( !isValid() )
       
   562 	return -1;
       
   563 
       
   564     /*
       
   565       Apparently, there is not consistency among different operating
       
   566       systems on how to use FIONREAD.
       
   567 
       
   568       FreeBSD, Linux and Solaris all expect the 3rd argument to
       
   569       ioctl() to be an int, which is normally 32-bit even on 64-bit
       
   570       machines.
       
   571 
       
   572       IRIX, on the other hand, expects a size_t, which is 64-bit on
       
   573       64-bit machines.
       
   574 
       
   575       So, the solution is to use size_t initialized to zero to make
       
   576       sure all bits are set to zero, preventing underflow with the
       
   577       FreeBSD/Linux/Solaris ioctls.
       
   578     */
       
   579     size_t nbytes = 0;
       
   580     // gives shorter than true amounts on Unix domain sockets.
       
   581     if ( ::ioctl(fd, FIONREAD, (char*)&nbytes) < 0 )
       
   582 	return -1;
       
   583     return (Q_LONG) *((int *) &nbytes) + QIODevice::bytesAvailable();
       
   584 }
       
   585 
       
   586 
       
   587 Q_LONG Q3SocketDevice::waitForMore( int msecs, bool *timeout ) const
       
   588 {
       
   589     if ( !isValid() )
       
   590 	return -1;
       
   591     if ( fd >= FD_SETSIZE )
       
   592 	return -1;
       
   593 
       
   594     fd_set fds;
       
   595     struct timeval tv;
       
   596 
       
   597     FD_ZERO( &fds );
       
   598     FD_SET( fd, &fds );
       
   599 
       
   600     tv.tv_sec = msecs / 1000;
       
   601     tv.tv_usec = (msecs % 1000) * 1000;
       
   602 
       
   603     int rv = select( fd+1, &fds, 0, 0, msecs < 0 ? 0 : &tv );
       
   604 
       
   605     if ( rv < 0 )
       
   606 	return -1;
       
   607 
       
   608     if ( timeout ) {
       
   609 	if ( rv == 0 )
       
   610 	    *timeout = true;
       
   611 	else
       
   612 	    *timeout = false;
       
   613     }
       
   614 
       
   615     return bytesAvailable();
       
   616 }
       
   617 
       
   618 
       
   619 qint64 Q3SocketDevice::readData( char *data, qint64 maxlen )
       
   620 {
       
   621 #if defined(QT_CHECK_NULL)
       
   622     if ( data == 0 && maxlen != 0 ) {
       
   623 	qWarning( "Q3SocketDevice::readBlock: Null pointer error" );
       
   624     }
       
   625 #endif
       
   626 #if defined(QT_CHECK_STATE)
       
   627     if ( !isValid() ) {
       
   628 	qWarning( "Q3SocketDevice::readBlock: Invalid socket" );
       
   629 	return -1;
       
   630     }
       
   631     if ( !isOpen() ) {
       
   632 	qWarning( "Q3SocketDevice::readBlock: Device is not open" );
       
   633 	return -1;
       
   634     }
       
   635     if ( !isReadable() ) {
       
   636 	qWarning( "Q3SocketDevice::readBlock: Read operation not permitted" );
       
   637 	return -1;
       
   638     }
       
   639 #endif
       
   640     bool done = false;
       
   641     int r = 0;
       
   642     while ( done == false ) {
       
   643 	if ( t == Datagram ) {
       
   644 #if !defined(QT_NO_IPV6)
       
   645             struct sockaddr_storage aa;
       
   646 #else
       
   647             struct sockaddr_in aa;
       
   648 #endif
       
   649 	    memset( &aa, 0, sizeof(aa) );
       
   650 	    QT_SOCKLEN_T sz;
       
   651 	    sz = sizeof( aa );
       
   652 	    r = ::recvfrom( fd, data, maxlen, 0,
       
   653 			    (struct sockaddr *)&aa, &sz );
       
   654 
       
   655 	    qt_socket_getportaddr( (struct sockaddr *)&aa, &pp, &pa);
       
   656 
       
   657 	} else {
       
   658 	    r = ::read( fd, data, maxlen );
       
   659 	}
       
   660 	done = true;
       
   661         if ( r == 0 && t == Stream && maxlen > 0 ) {
       
   662             // connection closed
       
   663             close();
       
   664         } else if ( r >= 0 || errno == EAGAIN || errno == EWOULDBLOCK ) {
       
   665 	    // nothing
       
   666 	} else if ( errno == EINTR ) {
       
   667 	    done = false;
       
   668 	} else if ( e == NoError ) {
       
   669 	    switch( errno ) {
       
   670 	    case EIO:
       
   671 	    case EISDIR:
       
   672 	    case EBADF:
       
   673 	    case EINVAL:
       
   674 	    case EFAULT:
       
   675 	    case ENOTCONN:
       
   676 	    case ENOTSOCK:
       
   677 		e = Impossible;
       
   678 		break;
       
   679 #if defined(ENONET)
       
   680 	    case ENONET:
       
   681 #endif
       
   682 	    case EHOSTUNREACH:
       
   683 	    case ENETDOWN:
       
   684 	    case ENETUNREACH:
       
   685 	    case ETIMEDOUT:
       
   686 		e = NetworkFailure;
       
   687 		break;
       
   688 	    case EPIPE:
       
   689 	    case ECONNRESET:
       
   690 		// connection closed
       
   691 		close();
       
   692 		r = 0;
       
   693 		break;
       
   694 	    default:
       
   695 		e = UnknownError;
       
   696 		break;
       
   697 	    }
       
   698 	}
       
   699     }
       
   700     return r;
       
   701 }
       
   702 
       
   703 
       
   704 qint64 Q3SocketDevice::writeData( const char *data, qint64 len )
       
   705 {
       
   706     if ( data == 0 && len != 0 ) {
       
   707 #if defined(QT_CHECK_NULL) || defined(QSOCKETDEVICE_DEBUG)
       
   708 	qWarning( "Q3SocketDevice::writeBlock: Null pointer error" );
       
   709 #endif
       
   710 	return -1;
       
   711     }
       
   712     if ( !isValid() ) {
       
   713 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   714 	qWarning( "Q3SocketDevice::writeBlock: Invalid socket" );
       
   715 #endif
       
   716 	return -1;
       
   717     }
       
   718     if ( !isOpen() ) {
       
   719 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   720 	qWarning( "Q3SocketDevice::writeBlock: Device is not open" );
       
   721 #endif
       
   722 	return -1;
       
   723     }
       
   724     if ( !isWritable() ) {
       
   725 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   726 	qWarning( "Q3SocketDevice::writeBlock: Write operation not permitted" );
       
   727 #endif
       
   728 	return -1;
       
   729     }
       
   730     bool done = false;
       
   731     int r = 0;
       
   732     bool timeout;
       
   733     while ( !done ) {
       
   734 	r = ::write( fd, data, len );
       
   735 	done = true;
       
   736 	if ( r < 0 && e == NoError &&
       
   737 	     errno != EAGAIN && errno != EWOULDBLOCK ) {
       
   738 	    switch( errno ) {
       
   739 	    case EINTR: // signal - call read() or whatever again
       
   740 		done = false;
       
   741 		break;
       
   742 	    case EPIPE:
       
   743             case ECONNRESET:
       
   744 		// connection closed
       
   745 		close();
       
   746 		r = 0;
       
   747 		break;
       
   748 	    case ENOSPC:
       
   749 	    case EIO:
       
   750 	    case EISDIR:
       
   751 	    case EBADF:
       
   752 	    case EINVAL:
       
   753 	    case EFAULT:
       
   754 	    case ENOTCONN:
       
   755 	    case ENOTSOCK:
       
   756 		e = Impossible;
       
   757 		break;
       
   758 #if defined(ENONET)
       
   759 	    case ENONET:
       
   760 #endif
       
   761 	    case EHOSTUNREACH:
       
   762 	    case ENETDOWN:
       
   763 	    case ENETUNREACH:
       
   764 	    case ETIMEDOUT:
       
   765 		e = NetworkFailure;
       
   766 		break;
       
   767 	    default:
       
   768 		e = UnknownError;
       
   769 		break;
       
   770 	    }
       
   771 	} else if ( waitForMore( 0, &timeout ) == 0 ) {
       
   772 	    if ( !timeout ) {
       
   773 		// connection closed
       
   774 		close();
       
   775 	    }
       
   776 	}
       
   777     }
       
   778     return r;
       
   779 }
       
   780 
       
   781 
       
   782 Q_LONG Q3SocketDevice::writeBlock( const char * data, Q_ULONG len,
       
   783 			       const QHostAddress & host, Q_UINT16 port )
       
   784 {
       
   785     if ( t != Datagram ) {
       
   786 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   787 	qWarning( "Q3SocketDevice::sendBlock: Not datagram" );
       
   788 #endif
       
   789 	return -1; // for now - later we can do t/tcp
       
   790     }
       
   791 
       
   792     if ( data == 0 && len != 0 ) {
       
   793 #if defined(QT_CHECK_NULL) || defined(QSOCKETDEVICE_DEBUG)
       
   794 	qWarning( "Q3SocketDevice::sendBlock: Null pointer error" );
       
   795 #endif
       
   796 	return -1;
       
   797     }
       
   798     if ( !isValid() ) {
       
   799 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   800 	qWarning( "Q3SocketDevice::sendBlock: Invalid socket" );
       
   801 #endif
       
   802 	return -1;
       
   803     }
       
   804     if ( !isOpen() ) {
       
   805 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   806 	qWarning( "Q3SocketDevice::sendBlock: Device is not open" );
       
   807 #endif
       
   808 	return -1;
       
   809     }
       
   810     if ( !isWritable() ) {
       
   811 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   812 	qWarning( "Q3SocketDevice::sendBlock: Write operation not permitted" );
       
   813 #endif
       
   814 	return -1;
       
   815     }
       
   816     struct sockaddr_in a4;
       
   817     struct sockaddr *aa;
       
   818     QT_SOCKLEN_T slen;
       
   819 #if !defined(QT_NO_IPV6)
       
   820     struct sockaddr_in6 a6;
       
   821     if ( host.isIPv6Address() ) {
       
   822 	memset( &a6, 0, sizeof(a6) );
       
   823 	a6.sin6_family = AF_INET6;
       
   824 	a6.sin6_port = htons( port );
       
   825 
       
   826 	Q_IPV6ADDR tmp = host.toIPv6Address();
       
   827 	memcpy( &a6.sin6_addr.s6_addr, &tmp, sizeof(tmp) );
       
   828 	slen = sizeof( a6 );
       
   829 	aa = (struct sockaddr *)&a6;
       
   830     } else
       
   831 #endif
       
   832     if ( host.isIPv4Address() ) {
       
   833 	memset( &a4, 0, sizeof(a4) );
       
   834 	a4.sin_family = AF_INET;
       
   835 	a4.sin_port = htons( port );
       
   836 	a4.sin_addr.s_addr = htonl( host.toIPv4Address() );
       
   837 	slen = sizeof(a4);
       
   838 	aa = (struct sockaddr *)&a4;
       
   839     } else {
       
   840 	e = Impossible;
       
   841 	return -1;
       
   842     }
       
   843 
       
   844     // we'd use MSG_DONTWAIT + MSG_NOSIGNAL if Stevens were right.
       
   845     // but apparently Stevens and most implementors disagree
       
   846     bool done = false;
       
   847     int r = 0;
       
   848     while ( !done ) {
       
   849 	r = ::sendto( fd, data, len, 0, aa, slen);
       
   850 	done = true;
       
   851 	if ( r < 0 && e == NoError &&
       
   852 	     errno != EAGAIN && errno != EWOULDBLOCK ) {
       
   853 	    switch( errno ) {
       
   854 	    case EINTR: // signal - call read() or whatever again
       
   855 		done = false;
       
   856 		break;
       
   857 	    case ENOSPC:
       
   858 	    case EPIPE:
       
   859 	    case EIO:
       
   860 	    case EISDIR:
       
   861 	    case EBADF:
       
   862 	    case EINVAL:
       
   863 	    case EFAULT:
       
   864 	    case ENOTCONN:
       
   865 	    case ENOTSOCK:
       
   866 		e = Impossible;
       
   867 		break;
       
   868 #if defined(ENONET)
       
   869 	    case ENONET:
       
   870 #endif
       
   871 	    case EHOSTUNREACH:
       
   872 	    case ENETDOWN:
       
   873 	    case ENETUNREACH:
       
   874 	    case ETIMEDOUT:
       
   875 		e = NetworkFailure;
       
   876 		break;
       
   877 	    default:
       
   878 		e = UnknownError;
       
   879 		break;
       
   880 	    }
       
   881 	}
       
   882     }
       
   883     return r;
       
   884 }
       
   885 
       
   886 
       
   887 void Q3SocketDevice::fetchConnectionParameters()
       
   888 {
       
   889     if ( !isValid() ) {
       
   890 	p = 0;
       
   891 	a = QHostAddress();
       
   892 	pp = 0;
       
   893 	pa = QHostAddress();
       
   894 	return;
       
   895     }
       
   896 #if !defined(QT_NO_IPV6)
       
   897     struct sockaddr_storage sa;
       
   898 #else
       
   899     struct sockaddr_in sa;
       
   900 #endif
       
   901     memset( &sa, 0, sizeof(sa) );
       
   902     QT_SOCKLEN_T sz;
       
   903     sz = sizeof( sa );
       
   904     if ( !::getsockname( fd, (struct sockaddr *)(&sa), &sz ) )
       
   905 	qt_socket_getportaddr( (struct sockaddr *)&sa, &p, &a );
       
   906 
       
   907     sz = sizeof( sa );
       
   908     if ( !::getpeername( fd, (struct sockaddr *)(&sa), &sz ) )
       
   909 	qt_socket_getportaddr( (struct sockaddr *)&sa, &pp, &pa );
       
   910 }
       
   911 
       
   912 
       
   913 Q_UINT16 Q3SocketDevice::peerPort() const
       
   914 {
       
   915     return pp;
       
   916 }
       
   917 
       
   918 
       
   919 QHostAddress Q3SocketDevice::peerAddress() const
       
   920 {
       
   921     return pa;
       
   922 }
       
   923 
       
   924 QT_END_NAMESPACE
       
   925 
       
   926 #endif //QT_NO_NETWORK