source: trunk/src/network/socket/qnativesocketengine_win.cpp@ 318

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

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

File size: 39.6 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 QtNetwork 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 <winsock2.h>
43
44#include "qnativesocketengine_p.h"
45
46#include <qabstracteventdispatcher.h>
47#include <qsocketnotifier.h>
48#include <qdebug.h>
49#include <qdatetime.h>
50
51//#define QNATIVESOCKETENGINE_DEBUG
52#if defined(QNATIVESOCKETENGINE_DEBUG)
53# include <qstring.h>
54# include <qbytearray.h>
55#endif
56
57QT_BEGIN_NAMESPACE
58
59#if defined(QNATIVESOCKETENGINE_DEBUG)
60
61void verboseWSErrorDebug(int r)
62{
63 switch (r) {
64 case WSANOTINITIALISED : qDebug("WSA error : WSANOTINITIALISED"); break;
65 case WSAEINTR: qDebug("WSA error : WSAEINTR"); break;
66 case WSAEBADF: qDebug("WSA error : WSAEBADF"); break;
67 case WSAEACCES: qDebug("WSA error : WSAEACCES"); break;
68 case WSAEFAULT: qDebug("WSA error : WSAEFAULT"); break;
69 case WSAEINVAL: qDebug("WSA error : WSAEINVAL"); break;
70 case WSAEMFILE: qDebug("WSA error : WSAEMFILE"); break;
71 case WSAEWOULDBLOCK: qDebug("WSA error : WSAEWOULDBLOCK"); break;
72 case WSAEINPROGRESS: qDebug("WSA error : WSAEINPROGRESS"); break;
73 case WSAEALREADY: qDebug("WSA error : WSAEALREADY"); break;
74 case WSAENOTSOCK: qDebug("WSA error : WSAENOTSOCK"); break;
75 case WSAEDESTADDRREQ: qDebug("WSA error : WSAEDESTADDRREQ"); break;
76 case WSAEMSGSIZE: qDebug("WSA error : WSAEMSGSIZE"); break;
77 case WSAEPROTOTYPE: qDebug("WSA error : WSAEPROTOTYPE"); break;
78 case WSAENOPROTOOPT: qDebug("WSA error : WSAENOPROTOOPT"); break;
79 case WSAEPROTONOSUPPORT: qDebug("WSA error : WSAEPROTONOSUPPORT"); break;
80 case WSAESOCKTNOSUPPORT: qDebug("WSA error : WSAESOCKTNOSUPPORT"); break;
81 case WSAEOPNOTSUPP: qDebug("WSA error : WSAEOPNOTSUPP"); break;
82 case WSAEPFNOSUPPORT: qDebug("WSA error : WSAEPFNOSUPPORT"); break;
83 case WSAEAFNOSUPPORT: qDebug("WSA error : WSAEAFNOSUPPORT"); break;
84 case WSAEADDRINUSE: qDebug("WSA error : WSAEADDRINUSE"); break;
85 case WSAEADDRNOTAVAIL: qDebug("WSA error : WSAEADDRNOTAVAIL"); break;
86 case WSAENETDOWN: qDebug("WSA error : WSAENETDOWN"); break;
87 case WSAENETUNREACH: qDebug("WSA error : WSAENETUNREACH"); break;
88 case WSAENETRESET: qDebug("WSA error : WSAENETRESET"); break;
89 case WSAECONNABORTED: qDebug("WSA error : WSAECONNABORTED"); break;
90 case WSAECONNRESET: qDebug("WSA error : WSAECONNRESET"); break;
91 case WSAENOBUFS: qDebug("WSA error : WSAENOBUFS"); break;
92 case WSAEISCONN: qDebug("WSA error : WSAEISCONN"); break;
93 case WSAENOTCONN: qDebug("WSA error : WSAENOTCONN"); break;
94 case WSAESHUTDOWN: qDebug("WSA error : WSAESHUTDOWN"); break;
95 case WSAETOOMANYREFS: qDebug("WSA error : WSAETOOMANYREFS"); break;
96 case WSAETIMEDOUT: qDebug("WSA error : WSAETIMEDOUT"); break;
97 case WSAECONNREFUSED: qDebug("WSA error : WSAECONNREFUSED"); break;
98 case WSAELOOP: qDebug("WSA error : WSAELOOP"); break;
99 case WSAENAMETOOLONG: qDebug("WSA error : WSAENAMETOOLONG"); break;
100 case WSAEHOSTDOWN: qDebug("WSA error : WSAEHOSTDOWN"); break;
101 case WSAEHOSTUNREACH: qDebug("WSA error : WSAEHOSTUNREACH"); break;
102 case WSAENOTEMPTY: qDebug("WSA error : WSAENOTEMPTY"); break;
103 case WSAEPROCLIM: qDebug("WSA error : WSAEPROCLIM"); break;
104 case WSAEUSERS: qDebug("WSA error : WSAEUSERS"); break;
105 case WSAEDQUOT: qDebug("WSA error : WSAEDQUOT"); break;
106 case WSAESTALE: qDebug("WSA error : WSAESTALE"); break;
107 case WSAEREMOTE: qDebug("WSA error : WSAEREMOTE"); break;
108 case WSAEDISCON: qDebug("WSA error : WSAEDISCON"); break;
109 default: qDebug("WSA error : Unknown"); break;
110 }
111 qErrnoWarning(r, "more details");
112}
113
114/*
115 Returns a human readable representation of the first \a len
116 characters in \a data.
117*/
118static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
119{
120 if (!data) return "(null)";
121 QByteArray out;
122 for (int i = 0; i < len; ++i) {
123 char c = data[i];
124 if (isprint(int(uchar(c)))) {
125 out += c;
126 } else switch (c) {
127 case '\n': out += "\\n"; break;
128 case '\r': out += "\\r"; break;
129 case '\t': out += "\\t"; break;
130 default:
131 QString tmp;
132 tmp.sprintf("\\%o", c);
133 out += tmp.toLatin1().constData();
134 }
135 }
136
137 if (len < maxLength)
138 out += "...";
139
140 return out;
141}
142
143
144#define WS_ERROR_DEBUG(x) verboseWSErrorDebug(x);
145
146#else
147
148#define WS_ERROR_DEBUG(x) Q_UNUSED(x)
149
150#endif
151
152#if !defined (QT_NO_IPV6)
153
154// Use our own defines and structs which we know are correct
155# define QT_SS_MAXSIZE 128
156# define QT_SS_ALIGNSIZE (sizeof(__int64))
157# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short))
158# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE))
159struct qt_sockaddr_storage {
160 short ss_family;
161 char __ss_pad1[QT_SS_PAD1SIZE];
162 __int64 __ss_align;
163 char __ss_pad2[QT_SS_PAD2SIZE];
164};
165
166// sockaddr_in6 size changed between old and new SDK
167// Only the new version is the correct one, so always
168// use this structure.
169struct qt_in6_addr {
170 u_char qt_s6_addr[16];
171};
172typedef struct {
173 short sin6_family; /* AF_INET6 */
174 u_short sin6_port; /* Transport level port number */
175 u_long sin6_flowinfo; /* IPv6 flow information */
176 struct qt_in6_addr sin6_addr; /* IPv6 address */
177 u_long sin6_scope_id; /* set of interfaces for a scope */
178} qt_sockaddr_in6;
179
180#else
181
182typedef void * qt_sockaddr_in6 ;
183
184
185#endif
186
187#ifndef AF_INET6
188#define AF_INET6 23 /* Internetwork Version 6 */
189#endif
190
191#ifndef SO_EXCLUSIVEADDRUSE
192#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) /* disallow local address reuse */
193#endif
194
195//###
196#define QT_SOCKLEN_T int
197#define QT_SOCKOPTLEN_T int
198
199
200/*
201 Extracts the port and address from a sockaddr, and stores them in
202 \a port and \a addr if they are non-null.
203*/
204static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, struct sockaddr *sa, quint16 *port, QHostAddress *address)
205{
206#if !defined (QT_NO_IPV6)
207 if (sa->sa_family == AF_INET6) {
208 qt_sockaddr_in6 *sa6 = (qt_sockaddr_in6 *)sa;
209 Q_IPV6ADDR tmp;
210 for (int i = 0; i < 16; ++i)
211 tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i];
212 QHostAddress a;
213 a.setAddress(tmp);
214 if (address)
215 *address = a;
216 if (port)
217 WSANtohs(socketDescriptor, sa6->sin6_port, port);
218 } else
219#endif
220 if (sa->sa_family == AF_INET) {
221 struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
222 unsigned long addr;
223 WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr);
224 QHostAddress a;
225 a.setAddress(addr);
226 if (address)
227 *address = a;
228 if (port)
229 WSANtohs(socketDescriptor, sa4->sin_port, port);
230 }
231}
232
233
234/*! \internal
235
236 Sets the port and address to a sockaddr. Requires that sa point to the IPv6 struct if the address is IPv6.
237*/
238static inline void qt_socket_setPortAndAddress(SOCKET socketDescriptor, sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6,
239 quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize)
240{
241#if !defined(QT_NO_IPV6)
242 if (address.protocol() == QAbstractSocket::IPv6Protocol) {
243 memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6));
244 sockAddrIPv6->sin6_family = AF_INET6;
245 WSAHtons(socketDescriptor, port, &(sockAddrIPv6->sin6_port));
246 Q_IPV6ADDR tmp = address.toIPv6Address();
247 memcpy(&(sockAddrIPv6->sin6_addr.qt_s6_addr), &tmp, sizeof(tmp));
248 *sockAddrSize = sizeof(qt_sockaddr_in6);
249 *sockAddrPtr = (struct sockaddr *) sockAddrIPv6;
250 } else
251#endif
252 if (address.protocol() == QAbstractSocket::IPv4Protocol
253 || address.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) {
254 memset(sockAddrIPv4, 0, sizeof(sockaddr_in));
255 sockAddrIPv4->sin_family = AF_INET;
256 WSAHtons(socketDescriptor, port, &(sockAddrIPv4->sin_port));
257 WSAHtonl(socketDescriptor, address.toIPv4Address(), &(sockAddrIPv4->sin_addr.s_addr));
258 *sockAddrSize = sizeof(sockaddr_in);
259 *sockAddrPtr = (struct sockaddr *) sockAddrIPv4;
260 } else {
261 // unreachable
262 }
263}
264
265/*! \internal
266
267*/
268static inline QAbstractSocket::SocketType qt_socket_getType(int socketDescriptor)
269{
270 int value = 0;
271 QT_SOCKLEN_T valueSize = sizeof(value);
272 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, (char *) &value, &valueSize) != 0) {
273 WS_ERROR_DEBUG(WSAGetLastError());
274 } else {
275 if (value == SOCK_STREAM)
276 return QAbstractSocket::TcpSocket;
277 else if (value == SOCK_DGRAM)
278 return QAbstractSocket::UdpSocket;
279 }
280 return QAbstractSocket::UnknownSocketType;
281}
282
283/*! \internal
284
285*/
286static inline int qt_socket_getMaxMsgSize(int socketDescriptor)
287{
288 int value = 0;
289 QT_SOCKLEN_T valueSize = sizeof(value);
290 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *) &value, &valueSize) != 0) {
291 WS_ERROR_DEBUG(WSAGetLastError());
292 }
293 return value;
294}
295
296QWindowsSockInit::QWindowsSockInit()
297: version(0)
298{
299 //### should we try for 2.2 on all platforms ??
300 WSAData wsadata;
301
302 // IPv6 requires Winsock v2.0 or better.
303 if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
304 qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
305 } else {
306 version = 0x20;
307 }
308}
309
310QWindowsSockInit::~QWindowsSockInit()
311{
312 WSACleanup();
313}
314
315// MS Transport Provider IOCTL to control
316// reporting PORT_UNREACHABLE messages
317// on UDP sockets via recv/WSARecv/etc.
318// Path TRUE in input buffer to enable (default if supported),
319// FALSE to disable.
320#ifndef SIO_UDP_CONNRESET
321# ifndef IOC_VENDOR
322# define IOC_VENDOR 0x18000000
323# endif
324# ifndef _WSAIOW
325# define _WSAIOW(x,y) (IOC_IN|(x)|(y))
326# endif
327# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
328#endif
329
330bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol socketProtocol)
331{
332
333 //### no ip6 support on winsocket 1.1 but we will try not to use this !!!!!!!!!!!!1
334 /*
335 if (winsockVersion < 0x20 && socketProtocol == QAbstractSocket::IPv6Protocol) {
336 //### no ip6 support
337 return -1;
338 }
339 */
340
341 int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET;
342 int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
343 // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking
344 // and recomends alwasy doing it for cross windows version comapablity.
345 SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
346
347 if (socket == INVALID_SOCKET) {
348 int err = WSAGetLastError();
349 WS_ERROR_DEBUG(err);
350 switch (err) {
351 case WSANOTINITIALISED:
352 //###
353 break;
354 case WSAEAFNOSUPPORT:
355 case WSAESOCKTNOSUPPORT:
356 case WSAEPROTOTYPE:
357 case WSAEINVAL:
358 setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
359 break;
360 case WSAEMFILE:
361 case WSAENOBUFS:
362 setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
363 break;
364 default:
365 break;
366 }
367
368 return false;
369 }
370
371#if !defined(Q_OS_WINCE)
372 // enable new behavior using
373 // SIO_UDP_CONNRESET
374 DWORD dwBytesReturned = 0;
375 int bNewBehavior = 1;
376 if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
377 NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) {
378 // not to worry isBogusUdpReadNotification() should handle this otherwise
379 int err = WSAGetLastError();
380 WS_ERROR_DEBUG(err);
381 }
382#endif
383
384 socketDescriptor = socket;
385 return true;
386
387}
388
389/*! \internal
390
391 Returns the value of the socket option \a opt.
392*/
393int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const
394{
395 Q_Q(const QNativeSocketEngine);
396 if (!q->isValid())
397 return -1;
398
399 int n = -1;
400 switch (opt) {
401 case QNativeSocketEngine::ReceiveBufferSocketOption:
402 n = SO_RCVBUF;
403 break;
404 case QNativeSocketEngine::SendBufferSocketOption:
405 n = SO_SNDBUF;
406 break;
407 case QNativeSocketEngine::BroadcastSocketOption:
408 n = SO_BROADCAST;
409 break;
410 case QNativeSocketEngine::NonBlockingSocketOption: {
411 unsigned long buf = 0;
412 if (WSAIoctl(socketDescriptor, FIONBIO, 0,0, &buf, sizeof(buf), 0,0,0) == 0)
413 return buf;
414 else
415 return -1;
416 break;
417 }
418 case QNativeSocketEngine::AddressReusable:
419 n = SO_REUSEADDR;
420 break;
421 case QNativeSocketEngine::BindExclusively:
422 n = SO_EXCLUSIVEADDRUSE;
423 break;
424 case QNativeSocketEngine::ReceiveOutOfBandData:
425 n = SO_OOBINLINE;
426 break;
427 }
428
429 int v = -1;
430 QT_SOCKOPTLEN_T len = sizeof(v);
431 if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1)
432 return v;
433 return -1;
434}
435
436
437/*! \internal
438 Sets the socket option \a opt to \a v.
439*/
440bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v)
441{
442 Q_Q(const QNativeSocketEngine);
443 if (!q->isValid())
444 return false;
445
446 int n = 0;
447 switch (opt) {
448 case QNativeSocketEngine::ReceiveBufferSocketOption:
449 n = SO_RCVBUF;
450 break;
451 case QNativeSocketEngine::SendBufferSocketOption:
452 n = SO_SNDBUF;
453 break;
454 case QNativeSocketEngine::BroadcastSocketOption:
455 n = SO_BROADCAST;
456 break;
457 case QNativeSocketEngine::NonBlockingSocketOption:
458 {
459 unsigned long buf = v;
460 unsigned long outBuf;
461 DWORD sizeWritten = 0;
462 if (::WSAIoctl(socketDescriptor, FIONBIO, &buf, sizeof(unsigned long), &outBuf, sizeof(unsigned long), &sizeWritten, 0,0) == SOCKET_ERROR) {
463 WS_ERROR_DEBUG(WSAGetLastError());
464 return false;
465 }
466 return true;
467 break;
468 }
469 case QNativeSocketEngine::AddressReusable:
470 n = SO_REUSEADDR;
471 break;
472 case QNativeSocketEngine::BindExclusively:
473 n = SO_EXCLUSIVEADDRUSE;
474 break;
475 case QNativeSocketEngine::ReceiveOutOfBandData:
476 n = SO_OOBINLINE;
477 break;
478 }
479
480 if (::setsockopt(socketDescriptor, SOL_SOCKET, n, (char*)&v, sizeof(v)) != 0) {
481 WS_ERROR_DEBUG(WSAGetLastError());
482 return false;
483 }
484 return true;
485}
486
487/*!
488 Fetches information about both ends of the connection: whatever is
489 available.
490*/
491bool QNativeSocketEnginePrivate::fetchConnectionParameters()
492{
493 localPort = 0;
494 localAddress.clear();
495 peerPort = 0;
496 peerAddress.clear();
497
498 if (socketDescriptor == -1)
499 return false;
500
501#if !defined (QT_NO_IPV6)
502 struct qt_sockaddr_storage sa;
503#else
504 struct sockaddr_in sa;
505#endif
506 struct sockaddr *pSa = (struct sockaddr *) &sa;
507
508 QT_SOCKLEN_T sz = sizeof(sa);
509
510 memset(&sa, 0, sizeof(sa));
511 if (::getsockname(socketDescriptor, pSa, &sz) == 0) {
512 qt_socket_getPortAndAddress(socketDescriptor, pSa, &localPort, &localAddress);
513 // Determine protocol family
514 switch (pSa->sa_family) {
515 case AF_INET:
516 socketProtocol = QAbstractSocket::IPv4Protocol;
517 break;
518#if !defined (QT_NO_IPV6)
519 case AF_INET6:
520 socketProtocol = QAbstractSocket::IPv6Protocol;
521 break;
522#endif
523 default:
524 socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
525 break;
526 }
527 } else {
528 int err = WSAGetLastError();
529 WS_ERROR_DEBUG(err);
530 if (err == WSAENOTSOCK) {
531 setError(QAbstractSocket::UnsupportedSocketOperationError,
532 InvalidSocketErrorString);
533 return false;
534 }
535 }
536
537 memset(&sa, 0, sizeof(sa));
538 if (::getpeername(socketDescriptor, pSa, &sz) == 0) {
539 qt_socket_getPortAndAddress(socketDescriptor, pSa, &peerPort, &peerAddress);
540 } else {
541 WS_ERROR_DEBUG(WSAGetLastError());
542 }
543
544 socketType = qt_socket_getType(socketDescriptor);
545
546#if defined (QNATIVESOCKETENGINE_DEBUG)
547 QString socketProtocolStr = "UnknownProtocol";
548 if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol";
549 else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol";
550
551 QString socketTypeStr = "UnknownSocketType";
552 if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket";
553 else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket";
554
555 qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() localAddress == %s, localPort = %i, peerAddress == %s, peerPort = %i, socketProtocol == %s, socketType == %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort, socketProtocolStr.toLatin1().constData(), socketTypeStr.toLatin1().constData());
556#endif
557
558 return true;
559}
560
561
562bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quint16 port)
563{
564
565#if defined (QNATIVESOCKETENGINE_DEBUG)
566 qDebug("QNativeSocketEnginePrivate::nativeConnect() to %s :: %i", address.toString().toLatin1().constData(), port);
567#endif
568
569 struct sockaddr_in sockAddrIPv4;
570 qt_sockaddr_in6 sockAddrIPv6;
571 struct sockaddr *sockAddrPtr;
572 QT_SOCKLEN_T sockAddrSize;
573
574 qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
575
576 forever {
577 int connectResult = ::WSAConnect(socketDescriptor, sockAddrPtr, sockAddrSize, 0,0,0,0);
578 if (connectResult == SOCKET_ERROR) {
579 int err = WSAGetLastError();
580 WS_ERROR_DEBUG(err);
581
582 switch (err) {
583 case WSANOTINITIALISED:
584 //###
585 break;
586 case WSAEISCONN:
587 socketState = QAbstractSocket::ConnectedState;
588 break;
589 case WSAEWOULDBLOCK: {
590 // If WSAConnect returns WSAEWOULDBLOCK on the second
591 // connection attempt, we have to check SO_ERROR's
592 // value to detect ECONNREFUSED. If we don't get
593 // ECONNREFUSED, we'll have to treat it as an
594 // unfinished operation.
595 int value = 0;
596 QT_SOCKLEN_T valueSize = sizeof(value);
597 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
598 if (value == WSAECONNREFUSED) {
599 setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
600 socketState = QAbstractSocket::UnconnectedState;
601 break;
602 }
603 if (value == WSAETIMEDOUT) {
604 setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
605 socketState = QAbstractSocket::UnconnectedState;
606 break;
607 }
608 }
609 // fall through
610 }
611 case WSAEINPROGRESS:
612 setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
613 socketState = QAbstractSocket::ConnectingState;
614 break;
615 case WSAEADDRINUSE:
616 setError(QAbstractSocket::NetworkError, AddressInuseErrorString);
617 break;
618 case WSAECONNREFUSED:
619 setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
620 socketState = QAbstractSocket::UnconnectedState;
621 break;
622 case WSAETIMEDOUT:
623 setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
624 break;
625 case WSAEACCES:
626 setError(QAbstractSocket::SocketAccessError, AccessErrorString);
627 socketState = QAbstractSocket::UnconnectedState;
628 break;
629 case WSAEHOSTUNREACH:
630 setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
631 socketState = QAbstractSocket::UnconnectedState;
632 break;
633 case WSAENETUNREACH:
634 setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
635 socketState = QAbstractSocket::UnconnectedState;
636 break;
637 case WSAEINVAL:
638 case WSAEALREADY:
639 setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
640 break;
641 default:
642 break;
643 }
644 if (socketState != QAbstractSocket::ConnectedState) {
645#if defined (QNATIVESOCKETENGINE_DEBUG)
646 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
647 address.toString().toLatin1().constData(), port,
648 socketState == QAbstractSocket::ConnectingState
649 ? "Connection in progress" : socketErrorString.toLatin1().constData());
650#endif
651 return false;
652 }
653 }
654 break;
655 }
656
657#if defined (QNATIVESOCKETENGINE_DEBUG)
658 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
659 address.toString().toLatin1().constData(), port);
660#endif
661
662 socketState = QAbstractSocket::ConnectedState;
663 return true;
664}
665
666
667bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
668{
669 struct sockaddr_in sockAddrIPv4;
670 qt_sockaddr_in6 sockAddrIPv6;
671 struct sockaddr *sockAddrPtr;
672 QT_SOCKLEN_T sockAddrSize;
673
674 qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
675
676
677 int bindResult = ::bind(socketDescriptor, sockAddrPtr, sockAddrSize);
678 if (bindResult == SOCKET_ERROR) {
679 int err = WSAGetLastError();
680 WS_ERROR_DEBUG(err);
681 switch (err) {
682 case WSANOTINITIALISED:
683 //###
684 break;
685 case WSAEADDRINUSE:
686 case WSAEINVAL:
687 setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
688 break;
689 case WSAEACCES:
690 setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
691 break;
692 case WSAEADDRNOTAVAIL:
693 setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
694 break;
695 default:
696 break;
697 }
698
699#if defined (QNATIVESOCKETENGINE_DEBUG)
700 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
701 address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData());
702#endif
703
704 return false;
705 }
706
707#if defined (QNATIVESOCKETENGINE_DEBUG)
708 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
709 address.toString().toLatin1().constData(), port);
710#endif
711 socketState = QAbstractSocket::BoundState;
712 return true;
713}
714
715
716bool QNativeSocketEnginePrivate::nativeListen(int backlog)
717{
718 if (::listen(socketDescriptor, backlog) == SOCKET_ERROR) {
719 int err = WSAGetLastError();
720 WS_ERROR_DEBUG(err);
721 switch (err) {
722 case WSANOTINITIALISED:
723 //###
724 break;
725 case WSAEADDRINUSE:
726 setError(QAbstractSocket::AddressInUseError,
727 PortInuseErrorString);
728 break;
729 default:
730 break;
731 }
732
733#if defined (QNATIVESOCKETENGINE_DEBUG)
734 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
735 backlog, socketErrorString.toLatin1().constData());
736#endif
737 return false;
738 }
739
740#if defined (QNATIVESOCKETENGINE_DEBUG)
741 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
742#endif
743
744 socketState = QAbstractSocket::ListeningState;
745 return true;
746}
747
748int QNativeSocketEnginePrivate::nativeAccept()
749{
750 int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0);
751 if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) {
752 // Becuase of WSAAsyncSelect() WSAAccept returns a non blocking socket
753 // with the same attributes as the listening socket including the current
754 // WSAAsyncSelect(). To be able to change the socket to blocking mode the
755 // WSAAsyncSelect() call must be cancled.
756 QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read);
757 n.setEnabled(true);
758 n.setEnabled(false);
759 }
760#if defined (QNATIVESOCKETENGINE_DEBUG)
761 qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
762#endif
763 return acceptedDescriptor;
764}
765
766
767qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
768{
769 unsigned long nbytes = 0;
770 unsigned long dummy = 0;
771 DWORD sizeWritten = 0;
772 if (::WSAIoctl(socketDescriptor, FIONREAD, &dummy, sizeof(dummy), &nbytes, sizeof(nbytes), &sizeWritten, 0,0) == SOCKET_ERROR) {
773 WS_ERROR_DEBUG(WSAGetLastError());
774 return -1;
775 }
776
777 // ioctlsocket sometimes reports 1 byte available for datagrams
778 // while the following recvfrom returns -1 and claims connection
779 // was reset (udp is connectionless). so we peek one byte to
780 // catch this case and return 0 bytes available if recvfrom
781 // fails.
782 if (nbytes == 1 && socketType == QAbstractSocket::UdpSocket) {
783 char c;
784 WSABUF buf;
785 buf.buf = &c;
786 buf.len = sizeof(c);
787 DWORD flags = MSG_PEEK;
788 if (::WSARecvFrom(socketDescriptor, &buf, 1, 0, &flags, 0,0,0,0) == SOCKET_ERROR)
789 return 0;
790 }
791 return nbytes;
792}
793
794
795bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
796{
797#if !defined(Q_OS_WINCE)
798 // Create a sockaddr struct and reset its port number.
799#if !defined(QT_NO_IPV6)
800 qt_sockaddr_in6 storage;
801 qt_sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<qt_sockaddr_in6 *>(&storage);
802 storagePtrIPv6->sin6_port = 0;
803#else
804 struct sockaddr storage;
805#endif
806 sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage);
807 storagePtr->sa_family = 0;
808
809 sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage);
810 storagePtrIPv4->sin_port = 0;
811 QT_SOCKLEN_T storageSize = sizeof(storage);
812
813
814 bool result = false;
815
816 // Peek 0 bytes into the next message. The size of the message may
817 // well be 0, so we check if there was a sender.
818 char c;
819 WSABUF buf;
820 buf.buf = &c;
821 buf.len = sizeof(c);
822 DWORD available = 0;
823 DWORD flags = MSG_PEEK;
824 int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, storagePtr, &storageSize,0,0);
825 int err = WSAGetLastError();
826 if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) {
827 WS_ERROR_DEBUG(err);
828 if (err == WSAECONNRESET) {
829 // Discard error message to prevent QAbstractSocket from
830 // getting this message repeatedly after reenabling the
831 // notifiers.
832 flags = 0;
833 ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags,
834 storagePtr, &storageSize, 0, 0);
835 }
836 } else {
837 // If there's no error, or if our buffer was too small, there must be
838 // a pending datagram.
839 result = true;
840 }
841
842#else // Q_OS_WINCE
843 bool result = false;
844 fd_set readS;
845 FD_ZERO(&readS);
846 FD_SET(socketDescriptor, &readS);
847 timeval timeout;
848 timeout.tv_sec = 0;
849 timeout.tv_usec = 5000;
850 int available = ::select(1, &readS, 0, 0, &timeout);
851 result = available > 0 ? true : false;
852#endif
853
854#if defined (QNATIVESOCKETENGINE_DEBUG)
855 qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
856 result ? "true" : "false");
857#endif
858 return result;
859}
860
861
862qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
863{
864 qint64 ret = -1;
865#if !defined(Q_OS_WINCE)
866 int recvResult = 0;
867 DWORD flags;
868 DWORD bufferCount = 5;
869 WSABUF * buf = 0;
870 for (;;) {
871 // the data written to udpMessagePeekBuffer is discarded, so
872 // this function is still reentrant although it might not look
873 // so.
874 static char udpMessagePeekBuffer[8192];
875
876 buf = new WSABUF[bufferCount];
877 for (DWORD i=0; i<bufferCount; i++) {
878 buf[i].buf = udpMessagePeekBuffer;
879 buf[i].len = sizeof(udpMessagePeekBuffer);
880 }
881 flags = MSG_PEEK;
882 DWORD bytesRead = 0;
883 recvResult = ::WSARecv(socketDescriptor, buf, bufferCount, &bytesRead, &flags, 0,0);
884 int err = WSAGetLastError();
885 if (recvResult != SOCKET_ERROR) {
886 ret = qint64(bytesRead);
887 break;
888 } else if (recvResult == SOCKET_ERROR && err == WSAEMSGSIZE) {
889 bufferCount += 5;
890 delete[] buf;
891 } else if (recvResult == SOCKET_ERROR) {
892 WS_ERROR_DEBUG(err);
893 ret = -1;
894 break;
895 }
896 }
897
898 if (buf)
899 delete[] buf;
900
901#else // Q_OS_WINCE
902 DWORD size = -1;
903 DWORD bytesReturned;
904 int ioResult = WSAIoctl(socketDescriptor, FIONREAD, 0,0, &size, sizeof(size), &bytesReturned, 0, 0);
905 if (ioResult == SOCKET_ERROR) {
906 int err = WSAGetLastError();
907 WS_ERROR_DEBUG(err);
908 } else {
909 ret = qint64(size);
910 }
911#endif
912
913#if defined (QNATIVESOCKETENGINE_DEBUG)
914 qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %li", ret);
915#endif
916
917 return ret;
918}
919
920
921qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength,
922 QHostAddress *address, quint16 *port)
923{
924 qint64 ret = 0;
925
926#if !defined(QT_NO_IPV6)
927 qt_sockaddr_storage aa;
928#else
929 struct sockaddr_in aa;
930#endif
931 memset(&aa, 0, sizeof(aa));
932 QT_SOCKLEN_T sz;
933 sz = sizeof(aa);
934 WSABUF buf;
935 buf.buf = data;
936 buf.len = maxLength;
937#if !defined(Q_OS_WINCE)
938 buf.buf = data;
939 buf.len = maxLength;
940#else
941 char tmpChar;
942 buf.buf = data ? data : &tmpChar;
943 buf.len = maxLength;
944#endif
945
946 DWORD flags = 0;
947 DWORD bytesRead = 0;
948 int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, (struct sockaddr *) &aa, &sz,0,0);
949 if (wsaRet == SOCKET_ERROR) {
950 int err = WSAGetLastError();
951 if (err == WSAEMSGSIZE) {
952 // it is ok the buffer was to small if bytesRead is larger than
953 // maxLength (win 9x) then assume bytes read is really maxLenth
954 ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead);
955 } else {
956 WS_ERROR_DEBUG(err);
957 setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
958 ret = -1;
959 }
960 } else {
961 ret = qint64(bytesRead);
962 }
963
964 qt_socket_getPortAndAddress(socketDescriptor, (struct sockaddr *) &aa, port, address);
965
966#if defined (QNATIVESOCKETENGINE_DEBUG)
967 qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li",
968 data, qt_prettyDebug(data, qMin<qint64>(ret, 16), ret).data(), maxLength,
969 address ? address->toString().toLatin1().constData() : "(nil)",
970 port ? *port : 0, ret);
971#endif
972
973 return ret;
974}
975
976
977qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
978 const QHostAddress &address, quint16 port)
979{
980 qint64 ret = -1;
981 struct sockaddr_in sockAddrIPv4;
982 qt_sockaddr_in6 sockAddrIPv6;
983 struct sockaddr *sockAddrPtr;
984 QT_SOCKLEN_T sockAddrSize;
985
986 qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
987
988 if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based && len > qint64(qt_socket_getMaxMsgSize(socketDescriptor))) {
989 // WSAEMSGSIZE is not reliable enough (win 9x) so we check max size our self.
990 setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
991 } else {
992 WSABUF buf;
993#if !defined(Q_OS_WINCE)
994 buf.buf = len ? (char*)data : 0;
995#else
996 char tmp;
997 buf.buf = len ? (char*)data : &tmp;
998#endif
999 buf.len = len;
1000 DWORD flags = 0;
1001 DWORD bytesSent = 0;
1002 if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) {
1003 int err = WSAGetLastError();
1004 WS_ERROR_DEBUG(err);
1005 switch (err) {
1006 case WSAEMSGSIZE:
1007 setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
1008 break;
1009 default:
1010 setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
1011 break;
1012 }
1013 ret = -1;
1014 } else {
1015 ret = qint64(bytesSent);
1016 }
1017 }
1018#if defined (QNATIVESOCKETENGINE_DEBUG)
1019 qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %li, \"%s\", %i) == %li", data,
1020 qt_prettyDebug(data, qMin<qint64>(len, 16), len).data(), 0, address.toString().toLatin1().constData(),
1021 port, ret);
1022#endif
1023
1024 return ret;
1025}
1026
1027
1028qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
1029{
1030 Q_Q(QNativeSocketEngine);
1031 qint64 ret = 0;
1032 // don't send more than 49152 per call to WSASendTo to avoid getting a WSAENOBUFS
1033 for (;;) {
1034 qint64 bytesToSend = qMin<qint64>(49152, len - ret);
1035 WSABUF buf;
1036 buf.buf = (char*)data + ret;
1037 buf.len = bytesToSend;
1038 DWORD flags = 0;
1039 DWORD bytesWritten = 0;
1040
1041 int socketRet = ::WSASend(socketDescriptor, &buf, 1, &bytesWritten, flags, 0,0);
1042
1043 ret += qint64(bytesWritten);
1044
1045 if (socketRet != SOCKET_ERROR) {
1046 if (ret == len)
1047 break;
1048 else
1049 continue;
1050 } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
1051 break;
1052 } else {
1053 int err = WSAGetLastError();
1054 WS_ERROR_DEBUG(err);
1055 switch (err) {
1056 case WSAECONNRESET:
1057 case WSAECONNABORTED:
1058 ret = -1;
1059 setError(QAbstractSocket::NetworkError, WriteErrorString);
1060 q->close();
1061 break;
1062 default:
1063 break;
1064 }
1065 break;
1066 }
1067 }
1068
1069#if defined (QNATIVESOCKETENGINE_DEBUG)
1070 qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %li) == %li",
1071 data, qt_prettyDebug(data, qMin((int)ret, 16), (int)ret).data(), (int)len, (int)ret);
1072#endif
1073
1074 return ret;
1075}
1076
1077qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength)
1078{
1079 qint64 ret = -1;
1080 WSABUF buf;
1081 buf.buf = data;
1082 buf.len = maxLength;
1083 DWORD flags = 0;
1084 DWORD bytesRead = 0;
1085#if defined(Q_OS_WINCE)
1086 WSASetLastError(0);
1087#endif
1088 if (::WSARecv(socketDescriptor, &buf, 1, &bytesRead, &flags, 0,0) == SOCKET_ERROR) {
1089 int err = WSAGetLastError();
1090 WS_ERROR_DEBUG(err);
1091 switch (err) {
1092 case WSAEWOULDBLOCK:
1093 ret = -2;
1094 break;
1095 case WSAEBADF:
1096 case WSAEINVAL:
1097 setError(QAbstractSocket::NetworkError, ReadErrorString);
1098 break;
1099 case WSAECONNRESET:
1100 case WSAECONNABORTED:
1101 // for tcp sockets this will be handled in QNativeSocketEngine::read
1102 ret = 0;
1103 break;
1104 default:
1105 break;
1106 }
1107 } else {
1108 if (WSAGetLastError() == WSAEWOULDBLOCK)
1109 ret = -2;
1110 else
1111 ret = qint64(bytesRead);
1112 }
1113
1114#if defined (QNATIVESOCKETENGINE_DEBUG)
1115 if (ret != -2) {
1116 qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %l) == %li",
1117 data, qt_prettyDebug(data, qMin((int)bytesRead, 16), (int)bytesRead).data(), (int)maxLength, (int)ret);
1118 } else {
1119 qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %l) == -2 (WOULD BLOCK)",
1120 data, int(maxLength));
1121 }
1122#endif
1123
1124 return ret;
1125}
1126
1127int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
1128{
1129 bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled();
1130 if (readEnabled)
1131 readNotifier->setEnabled(false);
1132
1133 fd_set fds;
1134
1135 int ret = 0;
1136
1137 memset(&fds, 0, sizeof(fd_set));
1138 fds.fd_count = 1;
1139 fds.fd_array[0] = socketDescriptor;
1140
1141 struct timeval tv;
1142 tv.tv_sec = timeout / 1000;
1143 tv.tv_usec = (timeout % 1000) * 1000;
1144
1145 if (selectForRead)
1146 ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv);
1147 else
1148 ret = select(0, 0, &fds, 0, timeout < 0 ? 0 : &tv);
1149
1150 if (readEnabled)
1151 readNotifier->setEnabled(true);
1152
1153 return ret;
1154}
1155
1156int QNativeSocketEnginePrivate::nativeSelect(int timeout,
1157 bool checkRead, bool checkWrite,
1158 bool *selectForRead, bool *selectForWrite) const
1159{
1160 bool readEnabled = checkRead && readNotifier && readNotifier->isEnabled();
1161 if (readEnabled)
1162 readNotifier->setEnabled(false);
1163
1164 fd_set fdread;
1165 fd_set fdwrite;
1166
1167 int ret = 0;
1168
1169 memset(&fdread, 0, sizeof(fd_set));
1170 if (checkRead) {
1171 fdread.fd_count = 1;
1172 fdread.fd_array[0] = socketDescriptor;
1173 }
1174 memset(&fdwrite, 0, sizeof(fd_set));
1175 if (checkWrite) {
1176 fdwrite.fd_count = 1;
1177 fdwrite.fd_array[0] = socketDescriptor;
1178 }
1179
1180 struct timeval tv;
1181 tv.tv_sec = timeout / 1000;
1182 tv.tv_usec = (timeout % 1000) * 1000;
1183
1184#if !defined(Q_OS_WINCE)
1185 ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
1186#else
1187 ret = select(1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
1188#endif
1189 if (readEnabled)
1190 readNotifier->setEnabled(true);
1191
1192 if (ret <= 0)
1193 return ret;
1194
1195 *selectForRead = FD_ISSET(socketDescriptor, &fdread);
1196 *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
1197
1198 return ret;
1199}
1200
1201void QNativeSocketEnginePrivate::nativeClose()
1202{
1203#if defined (QTCPSOCKETENGINE_DEBUG)
1204 qDebug("QNativeSocketEnginePrivate::nativeClose()");
1205#endif
1206 linger l = {1, 0};
1207 ::setsockopt(socketDescriptor, SOL_SOCKET, SO_DONTLINGER, (char*)&l, sizeof(l));
1208 ::closesocket(socketDescriptor);
1209}
1210
1211QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.