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

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 24.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt3Support module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia 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# 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
65QT_BEGIN_NAMESPACE
66
67struct 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.
77struct qt_in6_addr {
78 u_char qt_s6_addr[16];
79};
80typedef 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
94QT_BEGIN_INCLUDE_NAMESPACE
95# if defined(Q_OS_WINCE)
96# include "qfunctions_wince.h"
97# else
98# include <errno.h>
99# endif
100QT_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
110static int initialized = 0x00; // Holds the Winsock version
111
112static void cleanupWinSock() // post-routine
113{
114 WSACleanup();
115 initialized = 0x00;
116}
117
118static 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
139void 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
173Q3SocketDevice::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
206int 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
253void 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
269bool Q3SocketDevice::blocking() const
270{
271 return true;
272}
273
274
275void 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
288int 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
344void 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
397bool 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 }
494successful:
495 fetchConnectionParameters();
496 return true;
497}
498
499
500bool 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
570bool 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
582int 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
636qint64 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
659Q_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
690qint64 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
797qint64 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
882Q_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
1004void 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
1028void 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
1044quint16 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
1054QHostAddress Q3SocketDevice::peerAddress() const
1055{
1056 if ( pp==0 && isValid() ) {
1057 Q3SocketDevice *that = (Q3SocketDevice*)this; // mutable
1058 that->fetchPeerConnectionParameters();
1059 }
1060 return pa;
1061}
1062
1063QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.