src/qt3support/network/q3socketdevice_win.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 "q3socketdevice.h"
       
    43 #include "qwindowdefs.h"
       
    44 #include "qdatetime.h"
       
    45 
       
    46 #include <qcoreapplication.h>
       
    47 
       
    48 #include <string.h>
       
    49 
       
    50 #  include <qt_windows.h>
       
    51 #if defined (QT_NO_IPV6)
       
    52 #  include <winsock.h>
       
    53 #else
       
    54 #  if defined (Q_CC_BOR) || defined (Q_CC_GNU)
       
    55 #    include <winsock2.h>
       
    56 #  else
       
    57 #    include <winsock.h>
       
    58 #  endif
       
    59 // Use our own defines and structs which we know are correct
       
    60 #  define QT_SS_MAXSIZE 128
       
    61 #  define QT_SS_ALIGNSIZE (sizeof(__int64))
       
    62 #  define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short))
       
    63 #  define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE))
       
    64 
       
    65 QT_BEGIN_NAMESPACE
       
    66 
       
    67 struct qt_sockaddr_storage {
       
    68       short ss_family;
       
    69       char __ss_pad1[QT_SS_PAD1SIZE];
       
    70       __int64 __ss_align;
       
    71       char __ss_pad2[QT_SS_PAD2SIZE];
       
    72 };
       
    73 
       
    74 // sockaddr_in6 size changed between old and new SDK
       
    75 // Only the new version is the correct one, so always
       
    76 // use this structure.
       
    77 struct qt_in6_addr {
       
    78     u_char qt_s6_addr[16];
       
    79 };
       
    80 typedef struct {
       
    81     short   sin6_family;            /* AF_INET6 */
       
    82     u_short sin6_port;              /* Transport level port number */
       
    83     u_long  sin6_flowinfo;          /* IPv6 flow information */
       
    84     struct  qt_in6_addr sin6_addr;  /* IPv6 address */
       
    85     u_long  sin6_scope_id;          /* set of interfaces for a scope */
       
    86 } qt_sockaddr_in6;
       
    87 #endif
       
    88 
       
    89 #ifndef AF_INET6
       
    90 #define AF_INET6        23              /* Internetwork Version 6 */
       
    91 #endif
       
    92 
       
    93 #ifndef NO_ERRNO_H
       
    94 QT_BEGIN_INCLUDE_NAMESPACE
       
    95 #  if defined(Q_OS_WINCE)
       
    96 #     include "qfunctions_wince.h"
       
    97 #  else
       
    98 #     include <errno.h>
       
    99 #  endif
       
   100 QT_END_INCLUDE_NAMESPACE
       
   101 #endif
       
   102 
       
   103 
       
   104 #if defined(SOCKLEN_T)
       
   105 #undef SOCKLEN_T
       
   106 #endif
       
   107 
       
   108 #define SOCKLEN_T int // #### Winsock 1.1
       
   109 
       
   110 static int initialized = 0x00; // Holds the Winsock version
       
   111 
       
   112 static void cleanupWinSock() // post-routine
       
   113 {
       
   114     WSACleanup();
       
   115     initialized = 0x00;
       
   116 }
       
   117 
       
   118 static inline void qt_socket_getportaddr( struct sockaddr *sa,
       
   119 					  quint16 *port, QHostAddress *addr )
       
   120 {
       
   121 #if !defined (QT_NO_IPV6)
       
   122     if (sa->sa_family == AF_INET6) {
       
   123 	qt_sockaddr_in6 *sa6 = (qt_sockaddr_in6 *)sa;
       
   124 	Q_IPV6ADDR tmp;
       
   125 	for ( int i = 0; i < 16; ++i )
       
   126 	    tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i];
       
   127 	QHostAddress a( tmp );
       
   128         *addr = a;
       
   129         *port = ntohs( sa6->sin6_port );
       
   130 	return;
       
   131     }
       
   132 #endif
       
   133     struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
       
   134     QHostAddress a( ntohl( sa4->sin_addr.s_addr ) );
       
   135     *port = ntohs( sa4->sin_port );
       
   136     *addr = a;
       
   137 }
       
   138 
       
   139 void Q3SocketDevice::init()
       
   140 {
       
   141 #if !defined(QT_NO_IPV6)
       
   142     if ( !initialized ) {
       
   143 	WSAData wsadata;
       
   144 	// IPv6 requires Winsock v2.0 or better.
       
   145 	if ( WSAStartup( MAKEWORD(2,0), &wsadata ) != 0 ) {
       
   146 #  if defined(QSOCKETDEVICE_DEBUG)
       
   147 	    qDebug( "Q3SocketDevice: WinSock v2.0 initialization failed, disabling IPv6 support." );
       
   148 #  endif
       
   149 	} else {
       
   150 	    qAddPostRoutine( cleanupWinSock );
       
   151 	    initialized = 0x20;
       
   152 	    return;
       
   153 	}
       
   154     }
       
   155 #endif
       
   156 
       
   157     if (!initialized) {
       
   158 	WSAData wsadata;
       
   159 	if ( WSAStartup( MAKEWORD(1,1), &wsadata ) != 0 ) {
       
   160 #if defined(QT_CHECK_NULL)
       
   161 	    qWarning( "Q3SocketDevice: WinSock initialization failed" );
       
   162 #endif
       
   163 #if defined(QSOCKETDEVICE_DEBUG)
       
   164 	    qDebug( "Q3SocketDevice: WinSock initialization failed"  );
       
   165 #endif
       
   166 	    return;
       
   167 	}
       
   168 	qAddPostRoutine( cleanupWinSock );
       
   169 	initialized = 0x11;
       
   170     }
       
   171 }
       
   172 
       
   173 Q3SocketDevice::Protocol Q3SocketDevice::getProtocol() const
       
   174 {
       
   175     if ( isValid() ) {
       
   176 #if !defined (QT_NO_IPV6)
       
   177 	struct qt_sockaddr_storage sa;
       
   178 #else
       
   179 	struct sockaddr_in sa;
       
   180 #endif
       
   181 	memset( &sa, 0, sizeof(sa) );
       
   182 	SOCKLEN_T sz = sizeof( sa );
       
   183 	if ( !::getsockname(fd, (struct sockaddr *)&sa, &sz) ) {
       
   184 #if !defined (QT_NO_IPV6)
       
   185 	    switch ( sa.ss_family ) {
       
   186 		case AF_INET:
       
   187 		    return IPv4;
       
   188 		case AF_INET6:
       
   189 		    return IPv6;
       
   190 		default:
       
   191 		    return Unknown;
       
   192 	    }
       
   193 #else
       
   194 	    switch ( sa.sin_family ) {
       
   195 		case AF_INET:
       
   196 		    return IPv4;
       
   197 		default:
       
   198 		    return Unknown;
       
   199 	    }
       
   200 #endif
       
   201 	}
       
   202     }
       
   203     return Unknown;
       
   204 }
       
   205 
       
   206 int Q3SocketDevice::createNewSocket( )
       
   207 {
       
   208 #if !defined(QT_NO_IPV6)
       
   209     SOCKET s;
       
   210     // Support IPv6 for Winsock v2.0++
       
   211     if ( initialized >= 0x20 && protocol() == IPv6 ) {
       
   212 	s = ::socket( AF_INET6, t==Datagram?SOCK_DGRAM:SOCK_STREAM, 0 );
       
   213     } else {
       
   214 	s = ::socket( AF_INET, t==Datagram?SOCK_DGRAM:SOCK_STREAM, 0 );
       
   215     }
       
   216 #else
       
   217     SOCKET s = ::socket( AF_INET, t==Datagram?SOCK_DGRAM:SOCK_STREAM, 0 );
       
   218 #endif
       
   219     if ( s == INVALID_SOCKET ) {
       
   220 	switch( WSAGetLastError() ) {
       
   221 	    case WSANOTINITIALISED:
       
   222 		e = Impossible;
       
   223 		break;
       
   224 	    case WSAENETDOWN:
       
   225 		// ### what to use here?
       
   226 		e = NetworkFailure;
       
   227 		//e = Inaccessible;
       
   228 		break;
       
   229 	    case WSAEMFILE:
       
   230 		e = NoFiles; // special case for this
       
   231 		break;
       
   232 	    case WSAEINPROGRESS:
       
   233 	    case WSAENOBUFS:
       
   234 		e = NoResources;
       
   235 		break;
       
   236 	    case WSAEAFNOSUPPORT:
       
   237 	    case WSAEPROTOTYPE:
       
   238 	    case WSAEPROTONOSUPPORT:
       
   239 	    case WSAESOCKTNOSUPPORT:
       
   240 		e = InternalError;
       
   241 		break;
       
   242 	    default:
       
   243 		e = UnknownError;
       
   244 		break;
       
   245 	}
       
   246     } else {
       
   247 	return s;
       
   248     }
       
   249     return -1;
       
   250 }
       
   251 
       
   252 
       
   253 void Q3SocketDevice::close()
       
   254 {
       
   255     if ( fd == -1 || !isOpen() )		// already closed
       
   256 	return;
       
   257     resetStatus();
       
   258     setOpenMode(NotOpen);
       
   259     ::closesocket( fd );
       
   260 #if defined(QSOCKETDEVICE_DEBUG)
       
   261     qDebug( "Q3SocketDevice::close: Closed socket %x", fd );
       
   262 #endif
       
   263     fd = -1;
       
   264     fetchConnectionParameters();
       
   265     QIODevice::close();
       
   266 }
       
   267 
       
   268 
       
   269 bool Q3SocketDevice::blocking() const
       
   270 {
       
   271     return true;
       
   272 }
       
   273 
       
   274 
       
   275 void Q3SocketDevice::setBlocking( bool enable )
       
   276 {
       
   277 #if defined(QSOCKETDEVICE_DEBUG)
       
   278     qDebug( "Q3SocketDevice::setBlocking( %d )", enable );
       
   279 #endif
       
   280     if ( !isValid() )
       
   281 	return;
       
   282 
       
   283     unsigned long dummy = enable ? 0 : 1;
       
   284     ioctlsocket( fd, FIONBIO, &dummy );
       
   285 }
       
   286 
       
   287 
       
   288 int Q3SocketDevice::option( Option opt ) const
       
   289 {
       
   290     if ( !isValid() )
       
   291 	return -1;
       
   292     int n = -1;
       
   293     int v = -1;
       
   294     switch ( opt ) {
       
   295 	case Broadcast:
       
   296 	    n = SO_BROADCAST;
       
   297 	    break;
       
   298 	case ReceiveBuffer:
       
   299 	    n = SO_RCVBUF;
       
   300 	    break;
       
   301 	case ReuseAddress:
       
   302 	    n = SO_REUSEADDR;
       
   303 	    break;
       
   304 	case SendBuffer:
       
   305 	    n = SO_SNDBUF;
       
   306 	    break;
       
   307     }
       
   308     if ( n != -1 ) {
       
   309 	SOCKLEN_T len = sizeof(v);
       
   310 	int r = ::getsockopt( fd, SOL_SOCKET, n, (char*)&v, &len );
       
   311 	if ( r != SOCKET_ERROR )
       
   312 	    return v;
       
   313 	if ( !e ) {
       
   314             Q3SocketDevice *that = (Q3SocketDevice*)this; // mutable function
       
   315 	    switch( WSAGetLastError() ) {
       
   316 		case WSANOTINITIALISED:
       
   317 		    that->e = Impossible;
       
   318 		    break;
       
   319 		case WSAENETDOWN:
       
   320 		    that->e = NetworkFailure;
       
   321 		    break;
       
   322 		case WSAEFAULT:
       
   323 		case WSAEINVAL:
       
   324 		case WSAENOPROTOOPT:
       
   325 		    that->e = InternalError;
       
   326 		    break;
       
   327 		case WSAEINPROGRESS:
       
   328 		    that->e = NoResources;
       
   329 		    break;
       
   330 		case WSAENOTSOCK:
       
   331 		    that->e = Impossible;
       
   332 		    break;
       
   333 		default:
       
   334 		    that->e = UnknownError;
       
   335 		    break;
       
   336 	    }
       
   337 	}
       
   338 	return -1;
       
   339     }
       
   340     return v;
       
   341 }
       
   342 
       
   343 
       
   344 void Q3SocketDevice::setOption( Option opt, int v )
       
   345 {
       
   346     if ( !isValid() )
       
   347 	return;
       
   348     int n = -1; // for really, really bad compilers
       
   349     switch ( opt ) {
       
   350 	case Broadcast:
       
   351 	    n = SO_BROADCAST;
       
   352 	    break;
       
   353 	case ReceiveBuffer:
       
   354 	    n = SO_RCVBUF;
       
   355 	    break;
       
   356 	case ReuseAddress:
       
   357 	    n = SO_REUSEADDR;
       
   358 	    break;
       
   359 	case SendBuffer:
       
   360 	    n = SO_SNDBUF;
       
   361 	    break;
       
   362 	default:
       
   363 	    return;
       
   364     }
       
   365     int r = ::setsockopt( fd, SOL_SOCKET, n, (char*)&v, sizeof(v) );
       
   366     if ( r == SOCKET_ERROR && e == NoError ) {
       
   367 	switch( WSAGetLastError() ) {
       
   368 	    case WSANOTINITIALISED:
       
   369 		e = Impossible;
       
   370 		break;
       
   371 	    case WSAENETDOWN:
       
   372 		e = NetworkFailure;
       
   373 		break;
       
   374 	    case WSAEFAULT:
       
   375 	    case WSAEINVAL:
       
   376 	    case WSAENOPROTOOPT:
       
   377 		e = InternalError;
       
   378 		break;
       
   379 	    case WSAEINPROGRESS:
       
   380 		e = NoResources;
       
   381 		break;
       
   382 	    case WSAENETRESET:
       
   383 	    case WSAENOTCONN:
       
   384 		e =  Impossible; // ### ?
       
   385 		break;
       
   386 	    case WSAENOTSOCK:
       
   387 		e = Impossible;
       
   388 		break;
       
   389 	    default:
       
   390 		e = UnknownError;
       
   391 		break;
       
   392 	}
       
   393     }
       
   394 }
       
   395 
       
   396 
       
   397 bool Q3SocketDevice::connect( const QHostAddress &addr, quint16 port )
       
   398 {
       
   399     if ( !isValid() )
       
   400 	return false;
       
   401 
       
   402     pa = addr;
       
   403     pp = port;
       
   404 
       
   405     struct sockaddr_in a4;
       
   406     struct sockaddr *aa;
       
   407     SOCKLEN_T aalen;
       
   408 
       
   409 #if !defined(QT_NO_IPV6)
       
   410     qt_sockaddr_in6 a6;
       
   411 
       
   412     if ( initialized >= 0x20 && addr.isIPv6Address() ) {
       
   413         memset(&a6, 0, sizeof(a6));
       
   414 	a6.sin6_family = AF_INET6;
       
   415 	a6.sin6_port = htons( port );
       
   416 	Q_IPV6ADDR ip6 = addr.toIPv6Address();
       
   417 	memcpy( &a6.sin6_addr.qt_s6_addr, &ip6, sizeof(ip6) );
       
   418 
       
   419 	aalen = sizeof( a6 );
       
   420 	aa = (struct sockaddr *)&a6;
       
   421     } else
       
   422 #endif
       
   423     if ( addr.isIPv4Address() ) {
       
   424 	memset(&a4, 0, sizeof(a4));
       
   425 	a4.sin_family = AF_INET;
       
   426 	a4.sin_port = htons(port);
       
   427 	a4.sin_addr.s_addr = htonl(addr.toIPv4Address());
       
   428 
       
   429 	aalen = sizeof(a4);
       
   430 	aa = (struct sockaddr *)&a4;
       
   431     } else {
       
   432 	e = Impossible;
       
   433 	return false;
       
   434     }
       
   435 
       
   436     int r = ::connect( fd, aa, aalen );
       
   437 
       
   438     if ( r == SOCKET_ERROR )
       
   439     {
       
   440 	switch( WSAGetLastError() ) {
       
   441 	    case WSANOTINITIALISED:
       
   442 		e = Impossible;
       
   443 		break;
       
   444 	    case WSAENETDOWN:
       
   445 		e = NetworkFailure;
       
   446 		break;
       
   447 	    case WSAEADDRINUSE:
       
   448 	    case WSAEINPROGRESS:
       
   449 	    case WSAENOBUFS:
       
   450 		e = NoResources;
       
   451 		break;
       
   452 	    case WSAEINTR:
       
   453 		e = UnknownError; // ### ?
       
   454 		break;
       
   455 	    case WSAEALREADY:
       
   456 		// ### ?
       
   457 		break;
       
   458 	    case WSAEADDRNOTAVAIL:
       
   459 		e = ConnectionRefused; // ### ?
       
   460 		break;
       
   461 	    case WSAEAFNOSUPPORT:
       
   462 	    case WSAEFAULT:
       
   463 		e = InternalError;
       
   464 		break;
       
   465 	    case WSAEINVAL:
       
   466 		break;
       
   467 	    case WSAECONNREFUSED:
       
   468 		e = ConnectionRefused;
       
   469 		break;
       
   470 	    case WSAEISCONN:
       
   471 		goto successful;
       
   472 	    case WSAENETUNREACH:
       
   473 	    case WSAETIMEDOUT:
       
   474 		e = NetworkFailure;
       
   475 		break;
       
   476 	    case WSAENOTSOCK:
       
   477 		e = Impossible;
       
   478 		break;
       
   479 	    case WSAEWOULDBLOCK:
       
   480 		break;
       
   481 	    case WSAEACCES:
       
   482 		e = Inaccessible;
       
   483 		break;
       
   484 	    case 10107:
       
   485 		// Workaround for a problem with the WinSock Proxy Server. See
       
   486 		// also support/arc-12/25557 for details on the problem.
       
   487 		goto successful;
       
   488 	    default:
       
   489 		e = UnknownError;
       
   490 		break;
       
   491 	}
       
   492 	return false;
       
   493     }
       
   494 successful:
       
   495     fetchConnectionParameters();
       
   496     return true;
       
   497 }
       
   498 
       
   499 
       
   500 bool Q3SocketDevice::bind( const QHostAddress &address, quint16 port )
       
   501 {
       
   502     if ( !isValid() )
       
   503 	return false;
       
   504     int r;
       
   505     struct sockaddr_in a4;
       
   506 #if !defined(QT_NO_IPV6)
       
   507     qt_sockaddr_in6 a6;
       
   508 
       
   509     if ( initialized >= 0x20 && address.isIPv6Address() ) {
       
   510 	memset( &a6, 0, sizeof(a6) );
       
   511 	a6.sin6_family = AF_INET6;
       
   512 	a6.sin6_port = htons( port );
       
   513 	Q_IPV6ADDR tmp = address.toIPv6Address();
       
   514 	memcpy( &a6.sin6_addr.qt_s6_addr, &tmp, sizeof(tmp) );
       
   515 
       
   516 	r = ::bind( fd, (struct sockaddr *)&a6, sizeof(struct qt_sockaddr_storage) );
       
   517     } else
       
   518 #endif
       
   519     if ( address.isIPv4Address() ) {
       
   520 	memset( &a4, 0, sizeof(a4) );
       
   521 	a4.sin_family = AF_INET;
       
   522 	a4.sin_port = htons( port );
       
   523 	a4.sin_addr.s_addr = htonl( address.toIPv4Address() );
       
   524 
       
   525 	r = ::bind( fd, (struct sockaddr*)&a4, sizeof(struct sockaddr_in) );
       
   526     } else {
       
   527 	e = Impossible;
       
   528 	return false;
       
   529     }
       
   530 
       
   531     if ( r == SOCKET_ERROR ) {
       
   532 	switch( WSAGetLastError() ) {
       
   533 	    case WSANOTINITIALISED:
       
   534 		e = Impossible;
       
   535 		break;
       
   536 	    case WSAENETDOWN:
       
   537 		e = NetworkFailure;
       
   538 		break;
       
   539 	    case WSAEACCES:
       
   540 		e = Inaccessible;
       
   541 		break;
       
   542 	    case WSAEADDRNOTAVAIL:
       
   543 		e = Inaccessible;
       
   544 		break;
       
   545 	    case WSAEFAULT:
       
   546 		e = InternalError;
       
   547 		break;
       
   548 	    case WSAEINPROGRESS:
       
   549 	    case WSAENOBUFS:
       
   550 		e = NoResources;
       
   551 		break;
       
   552 	    case WSAEADDRINUSE:
       
   553 	    case WSAEINVAL:
       
   554 		e = AlreadyBound;
       
   555 		break;
       
   556 	    case WSAENOTSOCK:
       
   557 		e = Impossible;
       
   558 		break;
       
   559 	    default:
       
   560 		e = UnknownError;
       
   561 		break;
       
   562 	}
       
   563 	return false;
       
   564     }
       
   565     fetchConnectionParameters();
       
   566     return true;
       
   567 }
       
   568 
       
   569 
       
   570 bool Q3SocketDevice::listen( int backlog )
       
   571 {
       
   572     if ( !isValid() )
       
   573 	return false;
       
   574     if ( ::listen( fd, backlog ) >= 0 )
       
   575 	return true;
       
   576     if ( !e )
       
   577 	e = Impossible;
       
   578     return false;
       
   579 }
       
   580 
       
   581 
       
   582 int Q3SocketDevice::accept()
       
   583 {
       
   584     if ( !isValid() )
       
   585 	return -1;
       
   586 #if !defined(QT_NO_IPV6)
       
   587     struct qt_sockaddr_storage a;
       
   588 #else
       
   589     struct sockaddr a;
       
   590 #endif
       
   591     SOCKLEN_T l = sizeof(a);
       
   592     bool done;
       
   593     SOCKET s;
       
   594     do {
       
   595         s = ::accept( fd, (struct sockaddr*)&a, &l );
       
   596         // we'll blithely throw away the stuff accept() wrote to a
       
   597         done = true;
       
   598         if ( s == INVALID_SOCKET && e == NoError ) {
       
   599 	    switch( WSAGetLastError() ) {
       
   600                 case WSAEINTR:
       
   601                     done = false;
       
   602                     break;
       
   603 		case WSANOTINITIALISED:
       
   604 		    e = Impossible;
       
   605 		    break;
       
   606 		case WSAENETDOWN:
       
   607 		case WSAEOPNOTSUPP:
       
   608 		    // in all these cases, an error happened during connection
       
   609 		    // setup.  we're not interested in what happened, so we
       
   610 		    // just treat it like the client-closed-quickly case.
       
   611 		    break;
       
   612 		case WSAEFAULT:
       
   613 		    e = InternalError;
       
   614 		    break;
       
   615 		case WSAEMFILE:
       
   616 		case WSAEINPROGRESS:
       
   617 		case WSAENOBUFS:
       
   618 		    e = NoResources;
       
   619 		    break;
       
   620 		case WSAEINVAL:
       
   621 		case WSAENOTSOCK:
       
   622 		    e = Impossible;
       
   623 		    break;
       
   624 		case WSAEWOULDBLOCK:
       
   625 		    break;
       
   626 		default:
       
   627 		    e = UnknownError;
       
   628 		    break;
       
   629             }
       
   630 	}
       
   631     } while (!done);
       
   632     return s;
       
   633 }
       
   634 
       
   635 
       
   636 qint64 Q3SocketDevice::bytesAvailable() const
       
   637 {
       
   638     if ( !isValid() )
       
   639 	return -1;
       
   640     u_long nbytes = 0;
       
   641     if ( ::ioctlsocket(fd, FIONREAD, &nbytes) < 0 )
       
   642 	return -1;
       
   643 
       
   644      // ioctlsocket sometimes reports 1 byte available for datagrams
       
   645      // while the following recvfrom returns -1 and claims connection
       
   646      // was reset (udp is connectionless). so we peek one byte to
       
   647      // catch this case and return 0 bytes available if recvfrom
       
   648      // fails.
       
   649      if (nbytes == 1 && t == Datagram) {
       
   650          char c;
       
   651          if (::recvfrom(fd, &c, sizeof(c), MSG_PEEK, 0, 0) == SOCKET_ERROR)
       
   652              return 0;
       
   653      }
       
   654 
       
   655     return nbytes;
       
   656 }
       
   657 
       
   658 
       
   659 Q_LONG Q3SocketDevice::waitForMore( int msecs, bool *timeout ) const
       
   660 {
       
   661     if ( !isValid() )
       
   662 	return -1;
       
   663 
       
   664     fd_set fds;
       
   665     memset(&fds, 0, sizeof(fd_set));
       
   666     fds.fd_count = 1;
       
   667     fds.fd_array[0] = fd;
       
   668 
       
   669     struct timeval tv;
       
   670 
       
   671     tv.tv_sec = msecs / 1000;
       
   672     tv.tv_usec = (msecs % 1000) * 1000;
       
   673 
       
   674     int rv = select( fd+1, &fds, 0, 0, msecs < 0 ? 0 : &tv );
       
   675 
       
   676     if ( rv < 0 )
       
   677 	return -1;
       
   678 
       
   679     if ( timeout ) {
       
   680 	if ( rv == 0 )
       
   681 	    *timeout = true;
       
   682 	else
       
   683 	    *timeout = false;
       
   684     }
       
   685 
       
   686     return bytesAvailable();
       
   687 }
       
   688 
       
   689 
       
   690 qint64 Q3SocketDevice::readData( char *data, qint64 maxlen )
       
   691 {
       
   692 #if defined(QT_CHECK_NULL)
       
   693     if ( data == 0 && maxlen != 0 ) {
       
   694 	qWarning( "Q3SocketDevice::readBlock: Null pointer error" );
       
   695     }
       
   696 #endif
       
   697 #if defined(QT_CHECK_STATE)
       
   698     if ( !isValid() ) {
       
   699 	qWarning( "Q3SocketDevice::readBlock: Invalid socket" );
       
   700 	return -1;
       
   701     }
       
   702     if ( !isOpen() ) {
       
   703 	qWarning( "Q3SocketDevice::readBlock: Device is not open" );
       
   704 	return -1;
       
   705     }
       
   706     if ( !isReadable() ) {
       
   707 	qWarning( "Q3SocketDevice::readBlock: Read operation not permitted" );
       
   708 	return -1;
       
   709     }
       
   710 #endif
       
   711     qint64 r = 0;
       
   712     if ( t == Datagram ) {
       
   713 #if !defined(QT_NO_IPV6)
       
   714 	// With IPv6 support, we must be prepared to receive both IPv4
       
   715 	// and IPv6 packets. The generic SOCKADDR_STORAGE (struct
       
   716 	// sockaddr_storage on unix) replaces struct sockaddr.
       
   717 	struct qt_sockaddr_storage a;
       
   718 #else
       
   719 	struct sockaddr_in a;
       
   720 #endif
       
   721 	memset( &a, 0, sizeof(a) );
       
   722 	SOCKLEN_T sz;
       
   723 	sz = sizeof( a );
       
   724 	r = ::recvfrom( fd, data, maxlen, 0, (struct sockaddr *)&a, &sz );
       
   725 	qt_socket_getportaddr( (struct sockaddr *)(&a), &pp, &pa );
       
   726     } else {
       
   727 	r = ::recv( fd, data, maxlen, 0 );
       
   728     }
       
   729     if ( r == 0 && t == Stream && maxlen > 0 ) {
       
   730         if ( WSAGetLastError() != WSAEWOULDBLOCK ) {
       
   731             // connection closed
       
   732             close();
       
   733         }
       
   734     } else if ( r == SOCKET_ERROR && e == NoError ) {
       
   735 	switch( WSAGetLastError() ) {
       
   736 	    case WSANOTINITIALISED:
       
   737 		e = Impossible;
       
   738 		break;
       
   739 	    case WSAECONNABORTED:
       
   740 	    	close();
       
   741 		r = 0;
       
   742 		break;
       
   743 	    case WSAETIMEDOUT:
       
   744 	    case WSAECONNRESET:
       
   745 		/*
       
   746 		From msdn doc:
       
   747 		On a UDP datagram socket this error would indicate that a previous
       
   748 		send operation resulted in an ICMP "Port Unreachable" message.
       
   749 
       
   750 		So we should not close this socket just because one sendto failed.
       
   751 		*/
       
   752 		if ( t != Datagram )
       
   753 		    close(); // connection closed
       
   754 		r = 0;
       
   755 		break;
       
   756 	    case WSAENETDOWN:
       
   757 	    case WSAENETRESET:
       
   758 		e = NetworkFailure;
       
   759 		break;
       
   760 	    case WSAEFAULT:
       
   761 	    case WSAENOTCONN:
       
   762 	    case WSAESHUTDOWN:
       
   763 	    case WSAEINVAL:
       
   764 		e = Impossible;
       
   765 		break;
       
   766 	    case WSAEINTR:
       
   767 		// ### ?
       
   768 		r = 0;
       
   769 		break;
       
   770 	    case WSAEINPROGRESS:
       
   771 		e = NoResources;
       
   772 		break;
       
   773 	    case WSAENOTSOCK:
       
   774 		e = Impossible;
       
   775 		break;
       
   776 	    case WSAEOPNOTSUPP:
       
   777 		e = InternalError; // ### ?
       
   778 		break;
       
   779 	    case WSAEWOULDBLOCK:
       
   780 		break;
       
   781 	    case WSAEMSGSIZE:
       
   782 		e = NoResources; // ### ?
       
   783 		break;
       
   784 	    case WSAEISCONN:
       
   785 		// ### ?
       
   786 		r = 0;
       
   787 		break;
       
   788 	    default:
       
   789 		e = UnknownError;
       
   790 		break;
       
   791 	}
       
   792     }
       
   793     return r;
       
   794 }
       
   795 
       
   796 
       
   797 qint64 Q3SocketDevice::writeData( const char *data, qint64 len )
       
   798 {
       
   799     if ( data == 0 && len != 0 ) {
       
   800 #if defined(QT_CHECK_NULL) || defined(QSOCKETDEVICE_DEBUG)
       
   801 	qWarning( "Q3SocketDevice::writeBlock: Null pointer error" );
       
   802 #endif
       
   803 	return -1;
       
   804     }
       
   805     if ( !isValid() ) {
       
   806 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   807 	qWarning( "Q3SocketDevice::writeBlock: Invalid socket" );
       
   808 #endif
       
   809 	return -1;
       
   810     }
       
   811     if ( !isOpen() ) {
       
   812 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   813 	qWarning( "Q3SocketDevice::writeBlock: Device is not open" );
       
   814 #endif
       
   815 	return -1;
       
   816     }
       
   817     if ( !isWritable() ) {
       
   818 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   819 	qWarning( "Q3SocketDevice::writeBlock: Write operation not permitted" );
       
   820 #endif
       
   821 	return -1;
       
   822     }
       
   823     bool done = false;
       
   824     qint64 r = 0;
       
   825     while ( !done ) {
       
   826 	// Don't write more than 64K (see Knowledge Base Q201213).
       
   827 	r = ::send( fd, data, ( len>64*1024 ? 64*1024 : len ), 0 );
       
   828 	done = true;
       
   829 	if ( r == SOCKET_ERROR && e == NoError ) {//&& errno != WSAEAGAIN ) {
       
   830 	    switch( WSAGetLastError() ) {
       
   831 		case WSANOTINITIALISED:
       
   832 		    e = Impossible;
       
   833 		    break;
       
   834 		case WSAENETDOWN:
       
   835 		case WSAEACCES:
       
   836 		case WSAENETRESET:
       
   837 		case WSAESHUTDOWN:
       
   838 		case WSAEHOSTUNREACH:
       
   839 		    e = NetworkFailure;
       
   840 		    break;
       
   841 		case WSAECONNABORTED:
       
   842 		case WSAECONNRESET:
       
   843 		    // connection closed
       
   844 		    close();
       
   845 		    r = 0;
       
   846 		    break;
       
   847 		case WSAEINTR:
       
   848 		    done = false;
       
   849 		    break;
       
   850 		case WSAEINPROGRESS:
       
   851 		    e = NoResources;
       
   852 		    // ### perhaps try it later?
       
   853 		    break;
       
   854 		case WSAEFAULT:
       
   855 		case WSAEOPNOTSUPP:
       
   856 		    e = InternalError;
       
   857 		    break;
       
   858 		case WSAENOBUFS:
       
   859 		    // ### try later?
       
   860 		    break;
       
   861 		case WSAEMSGSIZE:
       
   862 		    e = NoResources;
       
   863 		    break;
       
   864 		case WSAENOTCONN:
       
   865 		case WSAENOTSOCK:
       
   866 		case WSAEINVAL:
       
   867 		    e = Impossible;
       
   868 		    break;
       
   869 		case WSAEWOULDBLOCK:
       
   870 		    r = 0;
       
   871 		    break;
       
   872 		default:
       
   873 		    e = UnknownError;
       
   874 		    break;
       
   875 	    }
       
   876 	}
       
   877     }
       
   878     return r;
       
   879 }
       
   880 
       
   881 
       
   882 Q_LONG Q3SocketDevice::writeBlock( const char * data, Q_ULONG len,
       
   883 			       const QHostAddress & host, quint16 port )
       
   884 {
       
   885     if ( t != Datagram ) {
       
   886 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   887 	qWarning( "Q3SocketDevice::sendBlock: Not datagram" );
       
   888 #endif
       
   889 	return -1; // for now - later we can do t/tcp
       
   890     }
       
   891 
       
   892     if ( data == 0 && len != 0 ) {
       
   893 #if defined(QT_CHECK_NULL) || defined(QSOCKETDEVICE_DEBUG)
       
   894 	qWarning( "Q3SocketDevice::sendBlock: Null pointer error" );
       
   895 #endif
       
   896 	return -1;
       
   897     }
       
   898     if ( !isValid() ) {
       
   899 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   900 	qWarning( "Q3SocketDevice::sendBlock: Invalid socket" );
       
   901 #endif
       
   902 	return -1;
       
   903     }
       
   904     if ( !isOpen() ) {
       
   905 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   906 	qWarning( "Q3SocketDevice::sendBlock: Device is not open" );
       
   907 #endif
       
   908 	return -1;
       
   909     }
       
   910     if ( !isWritable() ) {
       
   911 #if defined(QT_CHECK_STATE) || defined(QSOCKETDEVICE_DEBUG)
       
   912 	qWarning( "Q3SocketDevice::sendBlock: Write operation not permitted" );
       
   913 #endif
       
   914 	return -1;
       
   915     }
       
   916     struct sockaddr_in a4;
       
   917     struct sockaddr *aa;
       
   918     SOCKLEN_T slen;
       
   919 #if !defined(QT_NO_IPV6)
       
   920     qt_sockaddr_in6 a6;
       
   921     if ( initialized >= 0x20 && host.isIPv6Address() ) {
       
   922 	memset( &a6, 0, sizeof(a6) );
       
   923 	a6.sin6_family = AF_INET6;
       
   924 	a6.sin6_port = htons( port );
       
   925 
       
   926 	Q_IPV6ADDR tmp = host.toIPv6Address();
       
   927 	memcpy( &a6.sin6_addr.qt_s6_addr, &tmp, sizeof(tmp) );
       
   928 	slen = sizeof( a6 );
       
   929 	aa = (struct sockaddr *)&a6;
       
   930     } else
       
   931 #endif
       
   932     if ( host.isIPv4Address() ) {
       
   933 
       
   934 	memset( &a4, 0, sizeof(a4) );
       
   935 	a4.sin_family = AF_INET;
       
   936 	a4.sin_port = htons( port );
       
   937 	a4.sin_addr.s_addr = htonl( host.toIPv4Address() );
       
   938 	slen = sizeof(a4);
       
   939 	aa = (struct sockaddr *)&a4;
       
   940     } else {
       
   941 	e = Impossible;
       
   942 	return -1;
       
   943     }
       
   944 
       
   945     // we'd use MSG_DONTWAIT + MSG_NOSIGNAL if Stevens were right.
       
   946     // but apparently Stevens and most implementors disagree
       
   947     bool done = false;
       
   948     qint64 r = 0;
       
   949     while ( !done ) {
       
   950 	r = ::sendto( fd, data, len, 0, aa, slen );
       
   951 	done = true;
       
   952 	if ( r == SOCKET_ERROR && e == NoError ) {//&& e != EAGAIN ) {
       
   953 	    switch( WSAGetLastError() ) {
       
   954 		case WSANOTINITIALISED:
       
   955 		    e = Impossible;
       
   956 		    break;
       
   957 		case WSAENETDOWN:
       
   958 		case WSAEACCES:
       
   959 		case WSAENETRESET:
       
   960 		case WSAESHUTDOWN:
       
   961 		case WSAEHOSTUNREACH:
       
   962 		case WSAECONNABORTED:
       
   963 		case WSAECONNRESET:
       
   964 		case WSAEADDRNOTAVAIL:
       
   965 		case WSAENETUNREACH:
       
   966 		case WSAETIMEDOUT:
       
   967 		    e = NetworkFailure;
       
   968 		    break;
       
   969 		case WSAEINTR:
       
   970 		    done = false;
       
   971 		    break;
       
   972 		case WSAEINPROGRESS:
       
   973 		    e = NoResources;
       
   974 		    // ### perhaps try it later?
       
   975 		    break;
       
   976 		case WSAEFAULT:
       
   977 		case WSAEOPNOTSUPP:
       
   978 		case WSAEAFNOSUPPORT:
       
   979 		    e = InternalError;
       
   980 		    break;
       
   981 		case WSAENOBUFS:
       
   982 		case WSAEMSGSIZE:
       
   983 		    e = NoResources;
       
   984 		    break;
       
   985 		case WSAENOTCONN:
       
   986 		case WSAENOTSOCK:
       
   987 		case WSAEINVAL:
       
   988 		case WSAEDESTADDRREQ:
       
   989 		    e = Impossible;
       
   990 		    break;
       
   991 		case WSAEWOULDBLOCK:
       
   992 		    r = 0;
       
   993 		    break;
       
   994 		default:
       
   995 		    e = UnknownError;
       
   996 		    break;
       
   997 	    }
       
   998 	}
       
   999     }
       
  1000     return r;
       
  1001 }
       
  1002 
       
  1003 
       
  1004 void Q3SocketDevice::fetchConnectionParameters()
       
  1005 {
       
  1006     if ( !isValid() ) {
       
  1007 	p = 0;
       
  1008 	a = QHostAddress();
       
  1009 	pp = 0;
       
  1010 	pa = QHostAddress();
       
  1011 	return;
       
  1012     }
       
  1013 #if !defined (QT_NO_IPV6)
       
  1014     struct qt_sockaddr_storage sa;
       
  1015 #else
       
  1016     struct sockaddr_in sa;
       
  1017 #endif
       
  1018     memset( &sa, 0, sizeof(sa) );
       
  1019     SOCKLEN_T sz;
       
  1020     sz = sizeof( sa );
       
  1021     if ( !::getsockname( fd, (struct sockaddr *)(&sa), &sz ) )
       
  1022 	qt_socket_getportaddr( (struct sockaddr *)(&sa), &p, &a );
       
  1023     pp = 0;
       
  1024     pa = QHostAddress();
       
  1025 }
       
  1026 
       
  1027 
       
  1028 void Q3SocketDevice::fetchPeerConnectionParameters()
       
  1029 {
       
  1030     // do the getpeername() lazy on Windows (sales/arc-18/37759 claims that
       
  1031     // there will be problems otherwise if you use MS Proxy server)
       
  1032 #if !defined (QT_NO_IPV6)
       
  1033     struct qt_sockaddr_storage sa;
       
  1034 #else
       
  1035     struct sockaddr_in sa;
       
  1036 #endif
       
  1037     memset( &sa, 0, sizeof(sa) );
       
  1038     SOCKLEN_T sz;
       
  1039     sz = sizeof( sa );
       
  1040     if ( !::getpeername( fd, (struct sockaddr *)(&sa), &sz ) )
       
  1041 	qt_socket_getportaddr( (struct sockaddr *)(&sa), &pp, &pa );
       
  1042 }
       
  1043 
       
  1044 quint16 Q3SocketDevice::peerPort() const
       
  1045 {
       
  1046     if ( pp==0 && isValid() ) {
       
  1047 	Q3SocketDevice *that = (Q3SocketDevice*)this; // mutable
       
  1048 	that->fetchPeerConnectionParameters();
       
  1049     }
       
  1050     return pp;
       
  1051 }
       
  1052 
       
  1053 
       
  1054 QHostAddress Q3SocketDevice::peerAddress() const
       
  1055 {
       
  1056     if ( pp==0 && isValid() ) {
       
  1057 	Q3SocketDevice *that = (Q3SocketDevice*)this; // mutable
       
  1058 	that->fetchPeerConnectionParameters();
       
  1059     }
       
  1060     return pa;
       
  1061 }
       
  1062 
       
  1063 QT_END_NAMESPACE