|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtNetwork module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 //#define QNATIVESOCKETENGINE_DEBUG |
|
43 |
|
44 /*! \class QNativeSocketEngine |
|
45 \internal |
|
46 |
|
47 \brief The QNativeSocketEngine class provides low level access to a socket. |
|
48 |
|
49 \reentrant |
|
50 \ingroup network |
|
51 \inmodule QtNetwork |
|
52 |
|
53 QtSocketLayer provides basic socket functionality provided by the |
|
54 operating system. It also keeps track of what state the socket is |
|
55 in, and which errors that occur. |
|
56 |
|
57 The classes QTcpSocket, QUdpSocket and QTcpServer provide a |
|
58 higher level API, and are in general more useful for the common |
|
59 application. |
|
60 |
|
61 There are two main ways of initializing the a QNativeSocketEngine; either |
|
62 create a new socket by passing the socket type (TcpSocket or |
|
63 UdpSocket) and network layer protocol (IPv4Protocol or |
|
64 IPv6Protocol) to initialize(), or pass an existing socket |
|
65 descriptor and have QNativeSocketEngine determine the type and protocol |
|
66 itself. The native socket descriptor can later be fetched by |
|
67 calling socketDescriptor(). The socket is made non-blocking, but |
|
68 blocking behavior can still be achieved by calling waitForRead() |
|
69 and waitForWrite(). isValid() can be called to check if the socket |
|
70 has been successfully initialized and is ready to use. |
|
71 |
|
72 To connect to a host, determine its address and pass this and the |
|
73 port number to connectToHost(). The socket can then be used as a |
|
74 TCP or UDP client. Otherwise; bind(), listen() and accept() are |
|
75 used to have the socket function as a TCP or UDP server. Call |
|
76 close() to close the socket. |
|
77 |
|
78 bytesAvailable() is called to determine how much data is available |
|
79 for reading. read() and write() are used by both TCP and UDP |
|
80 clients to exchange data with the connected peer. UDP clients can |
|
81 also call hasMoreDatagrams(), nextDatagramSize(), |
|
82 readDatagram(), and writeDatagram(). |
|
83 |
|
84 Call state() to determine the state of the socket, for |
|
85 example, ListeningState or ConnectedState. socketType() tells |
|
86 whether the socket is a TCP socket or a UDP socket, or if the |
|
87 socket type is unknown. protocol() is used to determine the |
|
88 socket's network layer protocol. |
|
89 |
|
90 localAddress(), localPort() are called to find the address and |
|
91 port that are currently bound to the socket. If the socket is |
|
92 connected, peerAddress() and peerPort() determine the address and |
|
93 port of the connected peer. |
|
94 |
|
95 Finally, if any function should fail, error() and |
|
96 errorString() can be called to determine the cause of the error. |
|
97 */ |
|
98 |
|
99 #include <qabstracteventdispatcher.h> |
|
100 #include <qsocketnotifier.h> |
|
101 |
|
102 #include "qnativesocketengine_p.h" |
|
103 #include <private/qthread_p.h> |
|
104 #include <private/qobject_p.h> |
|
105 |
|
106 #if !defined(QT_NO_NETWORKPROXY) |
|
107 # include "qnetworkproxy.h" |
|
108 # include "qabstractsocket.h" |
|
109 # include "qtcpserver.h" |
|
110 #endif |
|
111 |
|
112 QT_BEGIN_NAMESPACE |
|
113 |
|
114 //#define QNATIVESOCKETENGINE_DEBUG |
|
115 |
|
116 #define Q_VOID |
|
117 |
|
118 // Common constructs |
|
119 #define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \ |
|
120 if (!isValid()) { \ |
|
121 qWarning(""#function" was called on an uninitialized socket device"); \ |
|
122 return returnValue; \ |
|
123 } } while (0) |
|
124 #define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \ |
|
125 if (isValid()) { \ |
|
126 qWarning(""#function" was called on an already initialized socket device"); \ |
|
127 return returnValue; \ |
|
128 } } while (0) |
|
129 #define Q_CHECK_STATE(function, checkState, returnValue) do { \ |
|
130 if (d->socketState != (checkState)) { \ |
|
131 qWarning(""#function" was not called in "#checkState); \ |
|
132 return (returnValue); \ |
|
133 } } while (0) |
|
134 #define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \ |
|
135 if (d->socketState == (checkState)) { \ |
|
136 qWarning(""#function" was called in "#checkState); \ |
|
137 return (returnValue); \ |
|
138 } } while (0) |
|
139 #define Q_CHECK_STATES(function, state1, state2, returnValue) do { \ |
|
140 if (d->socketState != (state1) && d->socketState != (state2)) { \ |
|
141 qWarning(""#function" was called" \ |
|
142 " not in "#state1" or "#state2); \ |
|
143 return (returnValue); \ |
|
144 } } while (0) |
|
145 #define Q_CHECK_TYPE(function, type, returnValue) do { \ |
|
146 if (d->socketType != (type)) { \ |
|
147 qWarning(#function" was called by a" \ |
|
148 " socket other than "#type""); \ |
|
149 return (returnValue); \ |
|
150 } } while (0) |
|
151 #define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a) |
|
152 |
|
153 /*! \internal |
|
154 Constructs the private class and initializes all data members. |
|
155 |
|
156 On Windows, WSAStartup is called "recursively" for every |
|
157 concurrent QNativeSocketEngine. This is safe, because WSAStartup and |
|
158 WSACleanup are reference counted. |
|
159 */ |
|
160 QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() |
|
161 { |
|
162 socketDescriptor = -1; |
|
163 readNotifier = 0; |
|
164 writeNotifier = 0; |
|
165 exceptNotifier = 0; |
|
166 } |
|
167 |
|
168 /*! \internal |
|
169 Destructs the private class. |
|
170 */ |
|
171 QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate() |
|
172 { |
|
173 } |
|
174 |
|
175 /*! \internal |
|
176 |
|
177 Sets the error and error string if not set already. The only |
|
178 interesting error is the first one that occurred, and not the last |
|
179 one. |
|
180 */ |
|
181 void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const |
|
182 { |
|
183 if (hasSetSocketError) { |
|
184 // Only set socket errors once for one engine; expect the |
|
185 // socket to recreate its engine after an error. Note: There's |
|
186 // one exception: SocketError(11) bypasses this as it's purely |
|
187 // a temporary internal error condition. |
|
188 return; |
|
189 } |
|
190 if (error != QAbstractSocket::SocketError(11)) |
|
191 hasSetSocketError = true; |
|
192 |
|
193 socketError = error; |
|
194 |
|
195 switch (errorString) { |
|
196 case NonBlockingInitFailedErrorString: |
|
197 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to initialize non-blocking socket")); |
|
198 break; |
|
199 case BroadcastingInitFailedErrorString: |
|
200 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to initialize broadcast socket")); |
|
201 break; |
|
202 case NoIpV6ErrorString: |
|
203 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Attempt to use IPv6 socket on a platform with no IPv6 support")); |
|
204 break; |
|
205 case RemoteHostClosedErrorString: |
|
206 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The remote host closed the connection")); |
|
207 break; |
|
208 case TimeOutErrorString: |
|
209 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Network operation timed out")); |
|
210 break; |
|
211 case ResourceErrorString: |
|
212 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Out of resources")); |
|
213 break; |
|
214 case OperationUnsupportedErrorString: |
|
215 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unsupported socket operation")); |
|
216 break; |
|
217 case ProtocolUnsupportedErrorString: |
|
218 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Protocol type not supported")); |
|
219 break; |
|
220 case InvalidSocketErrorString: |
|
221 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Invalid socket descriptor")); |
|
222 break; |
|
223 case HostUnreachableErrorString: |
|
224 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Host unreachable")); |
|
225 break; |
|
226 case NetworkUnreachableErrorString: |
|
227 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Network unreachable")); |
|
228 break; |
|
229 case AccessErrorString: |
|
230 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Permission denied")); |
|
231 break; |
|
232 case ConnectionTimeOutErrorString: |
|
233 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Connection timed out")); |
|
234 break; |
|
235 case ConnectionRefusedErrorString: |
|
236 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Connection refused")); |
|
237 break; |
|
238 case AddressInuseErrorString: |
|
239 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The bound address is already in use")); |
|
240 break; |
|
241 case AddressNotAvailableErrorString: |
|
242 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The address is not available")); |
|
243 break; |
|
244 case AddressProtectedErrorString: |
|
245 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The address is protected")); |
|
246 break; |
|
247 case DatagramTooLargeErrorString: |
|
248 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Datagram was too large to send")); |
|
249 break; |
|
250 case SendDatagramErrorString: |
|
251 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to send a message")); |
|
252 break; |
|
253 case ReceiveDatagramErrorString: |
|
254 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to receive a message")); |
|
255 break; |
|
256 case WriteErrorString: |
|
257 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unable to write")); |
|
258 break; |
|
259 case ReadErrorString: |
|
260 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Network error")); |
|
261 break; |
|
262 case PortInuseErrorString: |
|
263 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Another socket is already listening on the same port")); |
|
264 break; |
|
265 case NotSocketErrorString: |
|
266 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Operation on non-socket")); |
|
267 break; |
|
268 case InvalidProxyTypeString: |
|
269 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "The proxy type is invalid for this operation")); |
|
270 break; |
|
271 case UnknownSocketErrorString: |
|
272 socketErrorString = QLatin1String(QT_TRANSLATE_NOOP("QNativeSocketEngine", "Unknown error")); |
|
273 break; |
|
274 } |
|
275 } |
|
276 |
|
277 bool QNativeSocketEnginePrivate::checkProxy(const QHostAddress &address) |
|
278 { |
|
279 if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6) |
|
280 return true; |
|
281 |
|
282 #if !defined(QT_NO_NETWORKPROXY) |
|
283 QObject *parent = q_func()->parent(); |
|
284 QNetworkProxy proxy; |
|
285 if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) { |
|
286 proxy = socket->proxy(); |
|
287 } else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) { |
|
288 proxy = server->proxy(); |
|
289 } else { |
|
290 // no parent -> no proxy |
|
291 return true; |
|
292 } |
|
293 |
|
294 if (proxy.type() == QNetworkProxy::DefaultProxy) |
|
295 proxy = QNetworkProxy::applicationProxy(); |
|
296 |
|
297 if (proxy.type() != QNetworkProxy::DefaultProxy && |
|
298 proxy.type() != QNetworkProxy::NoProxy) { |
|
299 // QNativeSocketEngine doesn't do proxies |
|
300 setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
301 QNativeSocketEnginePrivate::InvalidProxyTypeString); |
|
302 return false; |
|
303 } |
|
304 #endif |
|
305 |
|
306 return true; |
|
307 } |
|
308 |
|
309 /*! |
|
310 Constructs a QNativeSocketEngine. |
|
311 |
|
312 \sa initialize() |
|
313 */ |
|
314 QNativeSocketEngine::QNativeSocketEngine(QObject *parent) |
|
315 : QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent) |
|
316 { |
|
317 } |
|
318 |
|
319 /*! |
|
320 Destructs a QNativeSocketEngine. |
|
321 */ |
|
322 QNativeSocketEngine::~QNativeSocketEngine() |
|
323 { |
|
324 close(); |
|
325 } |
|
326 |
|
327 /*! |
|
328 Initializes a QNativeSocketEngine by creating a new socket of type \a |
|
329 socketType and network layer protocol \a protocol. Returns true on |
|
330 success; otherwise returns false. |
|
331 |
|
332 If the socket was already initialized, this function closes the |
|
333 socket before reeinitializing it. |
|
334 |
|
335 The new socket is non-blocking, and for UDP sockets it's also |
|
336 broadcast enabled. |
|
337 */ |
|
338 bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol) |
|
339 { |
|
340 Q_D(QNativeSocketEngine); |
|
341 if (isValid()) |
|
342 close(); |
|
343 |
|
344 #if defined(QT_NO_IPV6) |
|
345 if (protocol == QAbstractSocket::IPv6Protocol) { |
|
346 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
347 QNativeSocketEnginePrivate::NoIpV6ErrorString); |
|
348 return false; |
|
349 } |
|
350 #endif |
|
351 |
|
352 // Create the socket |
|
353 if (!d->createNewSocket(socketType, protocol)) { |
|
354 #if defined (QNATIVESOCKETENGINE_DEBUG) |
|
355 QString typeStr = QLatin1String("UnknownSocketType"); |
|
356 if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket"); |
|
357 else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket"); |
|
358 QString protocolStr = QLatin1String("UnknownProtocol"); |
|
359 if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol"); |
|
360 else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol"); |
|
361 qDebug("QNativeSocketEngine::initialize(type == %s, protocol == %s) failed: %s", |
|
362 typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData()); |
|
363 #endif |
|
364 return false; |
|
365 } |
|
366 |
|
367 // Make the socket nonblocking. |
|
368 if (!setOption(NonBlockingSocketOption, 1)) { |
|
369 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
370 QNativeSocketEnginePrivate::NonBlockingInitFailedErrorString); |
|
371 close(); |
|
372 return false; |
|
373 } |
|
374 |
|
375 // Set the broadcasting flag if it's a UDP socket. |
|
376 if (socketType == QAbstractSocket::UdpSocket |
|
377 && !setOption(BroadcastSocketOption, 1)) { |
|
378 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
379 QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString); |
|
380 close(); |
|
381 return false; |
|
382 } |
|
383 |
|
384 |
|
385 // Make sure we receive out-of-band data |
|
386 // On Symbian OS this works only with native IP stack, not with WinSock |
|
387 if (socketType == QAbstractSocket::TcpSocket |
|
388 && !setOption(ReceiveOutOfBandData, 1)) { |
|
389 qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); |
|
390 } |
|
391 |
|
392 // Before Qt 4.6, we always set the send and receive buffer size to 49152 as |
|
393 // this was found to be an optimal value. However, modern OS |
|
394 // all have some kind of auto tuning for this and we therefore don't set |
|
395 // this explictly anymore. |
|
396 // If it introduces any performance regressions for Qt 4.6.x (x > 0) then |
|
397 // it will be put back in. |
|
398 // |
|
399 // You can use tests/manual/qhttpnetworkconnection to test HTTP download speed |
|
400 // with this. |
|
401 // |
|
402 // pre-4.6: |
|
403 // setReceiveBufferSize(49152); |
|
404 // setSendBufferSize(49152); |
|
405 |
|
406 d->socketType = socketType; |
|
407 d->socketProtocol = protocol; |
|
408 return true; |
|
409 } |
|
410 |
|
411 /*! \overload |
|
412 |
|
413 Initializes the socket using \a socketDescriptor instead of |
|
414 creating a new one. The socket type and network layer protocol are |
|
415 determined automatically. The socket's state is set to \a |
|
416 socketState. |
|
417 |
|
418 If the socket type is either TCP or UDP, it is made non-blocking. |
|
419 UDP sockets are also broadcast enabled. |
|
420 */ |
|
421 bool QNativeSocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState) |
|
422 { |
|
423 Q_D(QNativeSocketEngine); |
|
424 |
|
425 if (isValid()) |
|
426 close(); |
|
427 |
|
428 d->socketDescriptor = socketDescriptor; |
|
429 |
|
430 // determine socket type and protocol |
|
431 if (!d->fetchConnectionParameters()) { |
|
432 #if defined (QNATIVESOCKETENGINE_DEBUG) |
|
433 qDebug("QNativeSocketEngine::initialize(socketDescriptor == %i) failed: %s", |
|
434 socketDescriptor, d->socketErrorString.toLatin1().constData()); |
|
435 #endif |
|
436 d->socketDescriptor = -1; |
|
437 return false; |
|
438 } |
|
439 |
|
440 if (d->socketType != QAbstractSocket::UnknownSocketType) { |
|
441 // Make the socket nonblocking. |
|
442 if (!setOption(NonBlockingSocketOption, 1)) { |
|
443 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
444 QNativeSocketEnginePrivate::NonBlockingInitFailedErrorString); |
|
445 close(); |
|
446 return false; |
|
447 } |
|
448 |
|
449 // Set the broadcasting flag if it's a UDP socket. |
|
450 if (d->socketType == QAbstractSocket::UdpSocket |
|
451 && !setOption(BroadcastSocketOption, 1)) { |
|
452 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
453 QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString); |
|
454 close(); |
|
455 return false; |
|
456 } |
|
457 } |
|
458 |
|
459 d->socketState = socketState; |
|
460 return true; |
|
461 } |
|
462 |
|
463 /*! |
|
464 Returns true if the socket is valid; otherwise returns false. A |
|
465 socket is valid if it has not been successfully initialized, or if |
|
466 it has been closed. |
|
467 */ |
|
468 bool QNativeSocketEngine::isValid() const |
|
469 { |
|
470 Q_D(const QNativeSocketEngine); |
|
471 return d->socketDescriptor != -1; |
|
472 } |
|
473 |
|
474 /*! |
|
475 Returns the native socket descriptor. Any use of this descriptor |
|
476 stands the risk of being non-portable. |
|
477 */ |
|
478 int QNativeSocketEngine::socketDescriptor() const |
|
479 { |
|
480 Q_D(const QNativeSocketEngine); |
|
481 return d->socketDescriptor; |
|
482 } |
|
483 |
|
484 /*! |
|
485 Connects to the IP address and port specified by \a address and \a |
|
486 port. If the connection is established, this function returns true |
|
487 and the socket enters ConnectedState. Otherwise, false is |
|
488 returned. |
|
489 |
|
490 If false is returned, state() should be called to see if the |
|
491 socket is in ConnectingState. If so, a delayed TCP connection is |
|
492 taking place, and connectToHost() must be called again later to |
|
493 determine if the connection was established successfully or |
|
494 not. The second connection attempt must be made when the socket is |
|
495 ready for writing. This state can be determined either by |
|
496 connecting a QSocketNotifier to the socket descriptor returned by |
|
497 socketDescriptor(), or by calling the blocking function |
|
498 waitForWrite(). |
|
499 |
|
500 Example: |
|
501 \snippet doc/src/snippets/code/src_network_socket_qnativesocketengine.cpp 0 |
|
502 |
|
503 Otherwise, error() should be called to determine the cause of the |
|
504 error. |
|
505 */ |
|
506 bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 port) |
|
507 { |
|
508 Q_D(QNativeSocketEngine); |
|
509 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::connectToHost(), false); |
|
510 |
|
511 #if defined (QT_NO_IPV6) |
|
512 if (address.protocol() == QAbstractSocket::IPv6Protocol) { |
|
513 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
514 QNativeSocketEnginePrivate::NoIpV6ErrorString); |
|
515 return false; |
|
516 } |
|
517 #endif |
|
518 if (!d->checkProxy(address)) |
|
519 return false; |
|
520 |
|
521 Q_CHECK_STATES(QNativeSocketEngine::connectToHost(), |
|
522 QAbstractSocket::UnconnectedState, QAbstractSocket::ConnectingState, false); |
|
523 |
|
524 d->peerAddress = address; |
|
525 d->peerPort = port; |
|
526 bool connected = d->nativeConnect(address, port); |
|
527 if (connected) |
|
528 d->fetchConnectionParameters(); |
|
529 |
|
530 return connected; |
|
531 } |
|
532 |
|
533 /*! |
|
534 If there's a connection activity on the socket, process it. Then |
|
535 notify our parent if there really was activity. |
|
536 */ |
|
537 void QNativeSocketEngine::connectionNotification() |
|
538 { |
|
539 Q_D(QNativeSocketEngine); |
|
540 Q_ASSERT(state() == QAbstractSocket::ConnectingState); |
|
541 |
|
542 connectToHost(d->peerAddress, d->peerPort); |
|
543 if (state() != QAbstractSocket::ConnectingState) { |
|
544 // we changed states |
|
545 QAbstractSocketEngine::connectionNotification(); |
|
546 } |
|
547 } |
|
548 |
|
549 /*! |
|
550 Connects to the remote host name given by \a name on port \a |
|
551 port. When this function is called, the upper-level will not |
|
552 perform a hostname lookup. |
|
553 |
|
554 The native socket engine does not support this operation, |
|
555 but some other socket engines (notably proxy-based ones) do. |
|
556 */ |
|
557 bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port) |
|
558 { |
|
559 Q_UNUSED(name); |
|
560 Q_UNUSED(port); |
|
561 Q_D(QNativeSocketEngine); |
|
562 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
563 QNativeSocketEnginePrivate::OperationUnsupportedErrorString); |
|
564 return false; |
|
565 } |
|
566 |
|
567 /*! |
|
568 Binds the socket to the address \a address and port \a |
|
569 port. Returns true on success; otherwise false is returned. The |
|
570 port may be 0, in which case an arbitrary unused port is assigned |
|
571 automatically by the operating system. |
|
572 |
|
573 Servers call this function to set up the server's address and |
|
574 port. TCP servers must in addition call listen() after bind(). |
|
575 */ |
|
576 bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port) |
|
577 { |
|
578 Q_D(QNativeSocketEngine); |
|
579 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bind(), false); |
|
580 |
|
581 #if defined (QT_NO_IPV6) |
|
582 if (address.protocol() == QAbstractSocket::IPv6Protocol) { |
|
583 d->setError(QAbstractSocket::UnsupportedSocketOperationError, |
|
584 QNativeSocketEnginePrivate::NoIpV6ErrorString); |
|
585 return false; |
|
586 } |
|
587 #endif |
|
588 if (!d->checkProxy(address)) |
|
589 return false; |
|
590 |
|
591 Q_CHECK_STATE(QNativeSocketEngine::bind(), QAbstractSocket::UnconnectedState, false); |
|
592 |
|
593 if (!d->nativeBind(address, port)) |
|
594 return false; |
|
595 |
|
596 d->fetchConnectionParameters(); |
|
597 return true; |
|
598 } |
|
599 |
|
600 /*! |
|
601 Prepares a TCP server for accepting incoming connections. This |
|
602 function must be called after bind(), and only by TCP sockets. |
|
603 |
|
604 After this function has been called, pending client connections |
|
605 are detected by checking if the socket is ready for reading. This |
|
606 can be done by either creating a QSocketNotifier, passing the |
|
607 socket descriptor returned by socketDescriptor(), or by calling |
|
608 the blocking function waitForRead(). |
|
609 |
|
610 Example: |
|
611 \snippet doc/src/snippets/code/src_network_socket_qnativesocketengine.cpp 1 |
|
612 |
|
613 \sa bind(), accept() |
|
614 */ |
|
615 bool QNativeSocketEngine::listen() |
|
616 { |
|
617 Q_D(QNativeSocketEngine); |
|
618 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false); |
|
619 Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, false); |
|
620 Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false); |
|
621 |
|
622 // We're using a backlog of 50. Most modern kernels support TCP |
|
623 // syncookies by default, and if they do, the backlog is ignored. |
|
624 // When there is no support for TCP syncookies, this value is |
|
625 // fine. |
|
626 return d->nativeListen(50); |
|
627 } |
|
628 |
|
629 /*! |
|
630 Accepts a pending connection from the socket, which must be in |
|
631 ListeningState, and returns its socket descriptor. If no pending |
|
632 connections are available, -1 is returned. |
|
633 |
|
634 \sa bind(), listen() |
|
635 */ |
|
636 int QNativeSocketEngine::accept() |
|
637 { |
|
638 Q_D(QNativeSocketEngine); |
|
639 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1); |
|
640 Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, false); |
|
641 Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, false); |
|
642 |
|
643 return d->nativeAccept(); |
|
644 } |
|
645 |
|
646 /*! |
|
647 Returns the number of bytes that are currently available for |
|
648 reading. On error, -1 is returned. |
|
649 |
|
650 For UDP sockets, this function returns the accumulated size of all |
|
651 pending datagrams, and it is therefore more useful for UDP sockets |
|
652 to call hasPendingDatagrams() and pendingDatagramSize(). |
|
653 */ |
|
654 qint64 QNativeSocketEngine::bytesAvailable() const |
|
655 { |
|
656 Q_D(const QNativeSocketEngine); |
|
657 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bytesAvailable(), -1); |
|
658 Q_CHECK_NOT_STATE(QNativeSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false); |
|
659 |
|
660 return d->nativeBytesAvailable(); |
|
661 } |
|
662 |
|
663 /*! |
|
664 Returns true if there is at least one datagram pending. This |
|
665 function is only called by UDP sockets, where a datagram can have |
|
666 a size of 0. TCP sockets call bytesAvailable(). |
|
667 */ |
|
668 bool QNativeSocketEngine::hasPendingDatagrams() const |
|
669 { |
|
670 Q_D(const QNativeSocketEngine); |
|
671 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::hasPendingDatagrams(), false); |
|
672 Q_CHECK_NOT_STATE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false); |
|
673 Q_CHECK_TYPE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); |
|
674 |
|
675 return d->nativeHasPendingDatagrams(); |
|
676 } |
|
677 |
|
678 /*! |
|
679 Returns the size of the pending datagram, or -1 if no datagram is |
|
680 pending. A datagram size of 0 is perfectly valid. This function is |
|
681 called by UDP sockets before receiveMessage(). For TCP sockets, |
|
682 call bytesAvailable(). |
|
683 */ |
|
684 qint64 QNativeSocketEngine::pendingDatagramSize() const |
|
685 { |
|
686 Q_D(const QNativeSocketEngine); |
|
687 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::pendingDatagramSize(), -1); |
|
688 Q_CHECK_TYPE(QNativeSocketEngine::pendingDatagramSize(), QAbstractSocket::UdpSocket, false); |
|
689 |
|
690 return d->nativePendingDatagramSize(); |
|
691 } |
|
692 |
|
693 /*! |
|
694 Reads up to \a maxSize bytes of a datagram from the socket, |
|
695 stores it in \a data and returns the number of bytes read. The |
|
696 address and port of the sender are stored in \a address and \a |
|
697 port. If either of these pointers is 0, the corresponding value is |
|
698 discarded. |
|
699 |
|
700 To avoid unnecessarily loss of data, call pendingDatagramSize() to |
|
701 determine the size of the pending message before reading it. If \a |
|
702 maxSize is too small, the rest of the datagram will be lost. |
|
703 |
|
704 Returns -1 if an error occurred. |
|
705 |
|
706 \sa hasPendingDatagrams() |
|
707 */ |
|
708 qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddress *address, |
|
709 quint16 *port) |
|
710 { |
|
711 Q_D(QNativeSocketEngine); |
|
712 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1); |
|
713 Q_CHECK_TYPE(QNativeSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, false); |
|
714 |
|
715 return d->nativeReceiveDatagram(data, maxSize, address, port); |
|
716 } |
|
717 |
|
718 /*! |
|
719 Writes a UDP datagram of size \a size bytes to the socket from |
|
720 \a data to the address \a host on port \a port, and returns the |
|
721 number of bytes written, or -1 if an error occurred. |
|
722 |
|
723 Only one datagram is sent, and if there is too much data to fit |
|
724 into a single datagram, the operation will fail and error() |
|
725 will return QAbstractSocket::DatagramTooLargeError. Operating systems impose an |
|
726 upper limit to the size of a datagram, but this size is different |
|
727 on almost all platforms. Sending large datagrams is in general |
|
728 disadvised, as even if they are sent successfully, they are likely |
|
729 to be fragmented before arriving at their destination. |
|
730 |
|
731 Experience has shown that it is in general safe to send datagrams |
|
732 no larger than 512 bytes. |
|
733 |
|
734 \sa readDatagram() |
|
735 */ |
|
736 qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size, |
|
737 const QHostAddress &host, quint16 port) |
|
738 { |
|
739 Q_D(QNativeSocketEngine); |
|
740 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1); |
|
741 Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1); |
|
742 return d->nativeSendDatagram(data, size, host, port); |
|
743 } |
|
744 |
|
745 /*! |
|
746 Writes a block of \a size bytes from \a data to the socket. |
|
747 Returns the number of bytes written, or -1 if an error occurred. |
|
748 */ |
|
749 qint64 QNativeSocketEngine::write(const char *data, qint64 size) |
|
750 { |
|
751 Q_D(QNativeSocketEngine); |
|
752 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::write(), -1); |
|
753 Q_CHECK_STATE(QNativeSocketEngine::write(), QAbstractSocket::ConnectedState, -1); |
|
754 return d->nativeWrite(data, size); |
|
755 } |
|
756 |
|
757 /*! |
|
758 Reads up to \a maxSize bytes into \a data from the socket. |
|
759 Returns the number of bytes read, or -1 if an error occurred. |
|
760 */ |
|
761 qint64 QNativeSocketEngine::read(char *data, qint64 maxSize) |
|
762 { |
|
763 Q_D(QNativeSocketEngine); |
|
764 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::read(), -1); |
|
765 Q_CHECK_STATES(QNativeSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1); |
|
766 |
|
767 qint64 readBytes = d->nativeRead(data, maxSize); |
|
768 |
|
769 // Handle remote close |
|
770 if (readBytes == 0 && d->socketType == QAbstractSocket::TcpSocket) { |
|
771 d->setError(QAbstractSocket::RemoteHostClosedError, |
|
772 QNativeSocketEnginePrivate::RemoteHostClosedErrorString); |
|
773 close(); |
|
774 return -1; |
|
775 } |
|
776 return readBytes; |
|
777 } |
|
778 |
|
779 /*! |
|
780 Closes the socket. In order to use the socket again, initialize() |
|
781 must be called. |
|
782 */ |
|
783 void QNativeSocketEngine::close() |
|
784 { |
|
785 Q_D(QNativeSocketEngine); |
|
786 if (d->readNotifier) |
|
787 d->readNotifier->setEnabled(false); |
|
788 if (d->writeNotifier) |
|
789 d->writeNotifier->setEnabled(false); |
|
790 if (d->exceptNotifier) |
|
791 d->exceptNotifier->setEnabled(false); |
|
792 |
|
793 if(d->socketDescriptor != -1) { |
|
794 d->nativeClose(); |
|
795 d->socketDescriptor = -1; |
|
796 } |
|
797 d->socketState = QAbstractSocket::UnconnectedState; |
|
798 d->hasSetSocketError = false; |
|
799 d->localPort = 0; |
|
800 d->localAddress.clear(); |
|
801 d->peerPort = 0; |
|
802 d->peerAddress.clear(); |
|
803 if (d->readNotifier) { |
|
804 qDeleteInEventHandler(d->readNotifier); |
|
805 d->readNotifier = 0; |
|
806 } |
|
807 if (d->writeNotifier) { |
|
808 qDeleteInEventHandler(d->writeNotifier); |
|
809 d->writeNotifier = 0; |
|
810 } |
|
811 if (d->exceptNotifier) { |
|
812 qDeleteInEventHandler(d->exceptNotifier); |
|
813 d->exceptNotifier = 0; |
|
814 } |
|
815 } |
|
816 |
|
817 /*! |
|
818 Waits for \a msecs milliseconds or until the socket is ready for |
|
819 reading. If \a timedOut is not 0 and \a msecs milliseconds have |
|
820 passed, the value of \a timedOut is set to true. |
|
821 |
|
822 Returns true if data is available for reading; otherwise returns |
|
823 false. |
|
824 |
|
825 This is a blocking function call; its use is disadvised in a |
|
826 single threaded application, as the whole thread will stop |
|
827 responding until the function returns. waitForRead() is most |
|
828 useful when there is no event loop available. The general approach |
|
829 is to create a QSocketNotifier, passing the socket descriptor |
|
830 returned by socketDescriptor() to its constructor. |
|
831 */ |
|
832 bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) |
|
833 { |
|
834 Q_D(const QNativeSocketEngine); |
|
835 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false); |
|
836 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForRead(), |
|
837 QAbstractSocket::UnconnectedState, false); |
|
838 |
|
839 if (timedOut) |
|
840 *timedOut = false; |
|
841 |
|
842 int ret = d->nativeSelect(msecs, true); |
|
843 if (ret == 0) { |
|
844 if (timedOut) |
|
845 *timedOut = true; |
|
846 d->setError(QAbstractSocket::SocketTimeoutError, |
|
847 QNativeSocketEnginePrivate::TimeOutErrorString); |
|
848 return false; |
|
849 } else if (state() == QAbstractSocket::ConnectingState) { |
|
850 connectToHost(d->peerAddress, d->peerPort); |
|
851 } |
|
852 |
|
853 return ret > 0; |
|
854 } |
|
855 |
|
856 /*! |
|
857 Waits for \a msecs milliseconds or until the socket is ready for |
|
858 writing. If \a timedOut is not 0 and \a msecs milliseconds have |
|
859 passed, the value of \a timedOut is set to true. |
|
860 |
|
861 Returns true if data is available for writing; otherwise returns |
|
862 false. |
|
863 |
|
864 This is a blocking function call; its use is disadvised in a |
|
865 single threaded application, as the whole thread will stop |
|
866 responding until the function returns. waitForWrite() is most |
|
867 useful when there is no event loop available. The general approach |
|
868 is to create a QSocketNotifier, passing the socket descriptor |
|
869 returned by socketDescriptor() to its constructor. |
|
870 */ |
|
871 bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) |
|
872 { |
|
873 Q_D(const QNativeSocketEngine); |
|
874 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false); |
|
875 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForWrite(), |
|
876 QAbstractSocket::UnconnectedState, false); |
|
877 |
|
878 if (timedOut) |
|
879 *timedOut = false; |
|
880 |
|
881 int ret = d->nativeSelect(msecs, false); |
|
882 // On Windows, the socket is in connected state if a call to |
|
883 // select(writable) is successful. In this case we should not |
|
884 // issue a second call to WSAConnect() |
|
885 #if defined (Q_WS_WIN) |
|
886 if (ret > 0) { |
|
887 setState(QAbstractSocket::ConnectedState); |
|
888 d_func()->fetchConnectionParameters(); |
|
889 return true; |
|
890 } |
|
891 #endif |
|
892 |
|
893 if (ret == 0) { |
|
894 if (timedOut) |
|
895 *timedOut = true; |
|
896 d->setError(QAbstractSocket::SocketTimeoutError, |
|
897 QNativeSocketEnginePrivate::TimeOutErrorString); |
|
898 return false; |
|
899 } else if (state() == QAbstractSocket::ConnectingState) { |
|
900 connectToHost(d->peerAddress, d->peerPort); |
|
901 } |
|
902 |
|
903 return ret > 0; |
|
904 } |
|
905 |
|
906 bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, |
|
907 bool checkRead, bool checkWrite, |
|
908 int msecs, bool *timedOut) |
|
909 { |
|
910 Q_D(const QNativeSocketEngine); |
|
911 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false); |
|
912 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(), |
|
913 QAbstractSocket::UnconnectedState, false); |
|
914 |
|
915 int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite); |
|
916 // On Windows, the socket is in connected state if a call to |
|
917 // select(writable) is successful. In this case we should not |
|
918 // issue a second call to WSAConnect() |
|
919 #if defined (Q_WS_WIN) |
|
920 if (checkWrite && ((readyToWrite && *readyToWrite) || !readyToWrite) && ret > 0) { |
|
921 setState(QAbstractSocket::ConnectedState); |
|
922 d_func()->fetchConnectionParameters(); |
|
923 return true; |
|
924 } |
|
925 #endif |
|
926 if (ret == 0) { |
|
927 if (timedOut) |
|
928 *timedOut = true; |
|
929 d->setError(QAbstractSocket::SocketTimeoutError, |
|
930 QNativeSocketEnginePrivate::TimeOutErrorString); |
|
931 return false; |
|
932 } else if (state() == QAbstractSocket::ConnectingState) { |
|
933 connectToHost(d->peerAddress, d->peerPort); |
|
934 } |
|
935 |
|
936 return ret > 0; |
|
937 } |
|
938 |
|
939 /*! |
|
940 Returns the size of the operating system's socket receive |
|
941 buffer. Depending on the operating system, this size may be |
|
942 different from what has been set earlier with |
|
943 setReceiveBufferSize(). |
|
944 */ |
|
945 qint64 QNativeSocketEngine::receiveBufferSize() const |
|
946 { |
|
947 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::receiveBufferSize(), -1); |
|
948 return option(ReceiveBufferSocketOption); |
|
949 } |
|
950 |
|
951 /*! |
|
952 Sets the size of the operating system receive buffer to \a size. |
|
953 |
|
954 For clients, this should be set before connectToHost() is called; |
|
955 otherwise it will have no effect. For servers, it should be called |
|
956 before listen(). |
|
957 |
|
958 The operating system receive buffer size effectively limits two |
|
959 things: how much data can be in transit at any one moment, and how |
|
960 much data can be received in one iteration of the main event loop. |
|
961 Setting the size of the receive buffer may have an impact on the |
|
962 socket's performance. |
|
963 |
|
964 The default value is operating system-dependent. |
|
965 */ |
|
966 void QNativeSocketEngine::setReceiveBufferSize(qint64 size) |
|
967 { |
|
968 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setReceiveBufferSize(), Q_VOID); |
|
969 setOption(ReceiveBufferSocketOption, size); |
|
970 } |
|
971 |
|
972 /*! |
|
973 Returns the size of the operating system send buffer. Depending on |
|
974 the operating system, this size may be different from what has |
|
975 been set earlier with setSendBufferSize(). |
|
976 */ |
|
977 qint64 QNativeSocketEngine::sendBufferSize() const |
|
978 { |
|
979 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), -1); |
|
980 return option(SendBufferSocketOption); |
|
981 } |
|
982 |
|
983 /*! |
|
984 Sets the size of the operating system send buffer to \a size. |
|
985 |
|
986 The operating system send buffer size effectively limits how much |
|
987 data can be in transit at any one moment. Setting the size of the |
|
988 send buffer may have an impact on the socket's performance. |
|
989 |
|
990 The default value is operating system-dependent. |
|
991 */ |
|
992 void QNativeSocketEngine::setSendBufferSize(qint64 size) |
|
993 { |
|
994 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), Q_VOID); |
|
995 setOption(SendBufferSocketOption, size); |
|
996 } |
|
997 |
|
998 |
|
999 /*! |
|
1000 Sets the option \a option to the value \a value. |
|
1001 */ |
|
1002 bool QNativeSocketEngine::setOption(SocketOption option, int value) |
|
1003 { |
|
1004 Q_D(QNativeSocketEngine); |
|
1005 return d->setOption(option, value); |
|
1006 } |
|
1007 |
|
1008 /*! |
|
1009 Returns the value of the option \a socketOption. |
|
1010 */ |
|
1011 int QNativeSocketEngine::option(SocketOption socketOption) const |
|
1012 { |
|
1013 Q_D(const QNativeSocketEngine); |
|
1014 return d->option(socketOption); |
|
1015 } |
|
1016 |
|
1017 bool QNativeSocketEngine::isReadNotificationEnabled() const |
|
1018 { |
|
1019 Q_D(const QNativeSocketEngine); |
|
1020 return d->readNotifier && d->readNotifier->isEnabled(); |
|
1021 } |
|
1022 |
|
1023 /* |
|
1024 \internal |
|
1025 \class QReadNotifier |
|
1026 \brief The QReadNotifer class is used to improve performance. |
|
1027 |
|
1028 QReadNotifier is a private class used for performance reasons vs |
|
1029 connecting to the QSocketNotifier activated() signal. |
|
1030 */ |
|
1031 class QReadNotifier : public QSocketNotifier |
|
1032 { |
|
1033 public: |
|
1034 QReadNotifier(int fd, QNativeSocketEngine *parent) |
|
1035 : QSocketNotifier(fd, QSocketNotifier::Read, parent) |
|
1036 { engine = parent; } |
|
1037 |
|
1038 protected: |
|
1039 bool event(QEvent *); |
|
1040 |
|
1041 QNativeSocketEngine *engine; |
|
1042 }; |
|
1043 |
|
1044 bool QReadNotifier::event(QEvent *e) |
|
1045 { |
|
1046 if (e->type() == QEvent::SockAct) { |
|
1047 engine->readNotification(); |
|
1048 return true; |
|
1049 } |
|
1050 return QSocketNotifier::event(e); |
|
1051 } |
|
1052 |
|
1053 /* |
|
1054 \internal |
|
1055 \class QWriteNotifier |
|
1056 \brief The QWriteNotifer class is used to improve performance. |
|
1057 |
|
1058 QWriteNotifier is a private class used for performance reasons vs |
|
1059 connecting to the QSocketNotifier activated() signal. |
|
1060 */ |
|
1061 class QWriteNotifier : public QSocketNotifier |
|
1062 { |
|
1063 public: |
|
1064 QWriteNotifier(int fd, QNativeSocketEngine *parent) |
|
1065 : QSocketNotifier(fd, QSocketNotifier::Write, parent) { engine = parent; } |
|
1066 |
|
1067 protected: |
|
1068 bool event(QEvent *); |
|
1069 |
|
1070 QNativeSocketEngine *engine; |
|
1071 }; |
|
1072 |
|
1073 bool QWriteNotifier::event(QEvent *e) |
|
1074 { |
|
1075 if (e->type() == QEvent::SockAct) { |
|
1076 if (engine->state() == QAbstractSocket::ConnectingState) |
|
1077 engine->connectionNotification(); |
|
1078 else |
|
1079 engine->writeNotification(); |
|
1080 return true; |
|
1081 } |
|
1082 return QSocketNotifier::event(e); |
|
1083 } |
|
1084 |
|
1085 class QExceptionNotifier : public QSocketNotifier |
|
1086 { |
|
1087 public: |
|
1088 QExceptionNotifier(int fd, QNativeSocketEngine *parent) |
|
1089 : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; } |
|
1090 |
|
1091 protected: |
|
1092 bool event(QEvent *); |
|
1093 |
|
1094 QNativeSocketEngine *engine; |
|
1095 }; |
|
1096 |
|
1097 bool QExceptionNotifier::event(QEvent *e) |
|
1098 { |
|
1099 if (e->type() == QEvent::SockAct) { |
|
1100 if (engine->state() == QAbstractSocket::ConnectingState) |
|
1101 engine->connectionNotification(); |
|
1102 else |
|
1103 engine->exceptionNotification(); |
|
1104 return true; |
|
1105 } |
|
1106 return QSocketNotifier::event(e); |
|
1107 } |
|
1108 |
|
1109 void QNativeSocketEngine::setReadNotificationEnabled(bool enable) |
|
1110 { |
|
1111 Q_D(QNativeSocketEngine); |
|
1112 if (d->readNotifier) { |
|
1113 d->readNotifier->setEnabled(enable); |
|
1114 } else if (enable && d->threadData->eventDispatcher) { |
|
1115 d->readNotifier = new QReadNotifier(d->socketDescriptor, this); |
|
1116 d->readNotifier->setEnabled(true); |
|
1117 } |
|
1118 } |
|
1119 |
|
1120 bool QNativeSocketEngine::isWriteNotificationEnabled() const |
|
1121 { |
|
1122 Q_D(const QNativeSocketEngine); |
|
1123 return d->writeNotifier && d->writeNotifier->isEnabled(); |
|
1124 } |
|
1125 |
|
1126 void QNativeSocketEngine::setWriteNotificationEnabled(bool enable) |
|
1127 { |
|
1128 Q_D(QNativeSocketEngine); |
|
1129 if (d->writeNotifier) { |
|
1130 d->writeNotifier->setEnabled(enable); |
|
1131 } else if (enable && d->threadData->eventDispatcher) { |
|
1132 d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this); |
|
1133 d->writeNotifier->setEnabled(true); |
|
1134 } |
|
1135 } |
|
1136 |
|
1137 bool QNativeSocketEngine::isExceptionNotificationEnabled() const |
|
1138 { |
|
1139 Q_D(const QNativeSocketEngine); |
|
1140 return d->exceptNotifier && d->exceptNotifier->isEnabled(); |
|
1141 } |
|
1142 |
|
1143 void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable) |
|
1144 { |
|
1145 Q_D(QNativeSocketEngine); |
|
1146 if (d->exceptNotifier) { |
|
1147 d->exceptNotifier->setEnabled(enable); |
|
1148 } else if (enable && d->threadData->eventDispatcher) { |
|
1149 d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this); |
|
1150 d->exceptNotifier->setEnabled(true); |
|
1151 } |
|
1152 } |
|
1153 |
|
1154 QT_END_NAMESPACE |