source: trunk/src/qt3support/network/q3socketdevice_win.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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