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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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