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