1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include <qt_windows.h>
41
42 #include "qnativesocketengine_winrt_p.h"
43
44 #include <qcoreapplication.h>
45 #include <qabstracteventdispatcher.h>
46 #include <qsocketnotifier.h>
47 #include <qdatetime.h>
48 #include <qnetworkinterface.h>
49 #include <qelapsedtimer.h>
50 #include <qthread.h>
51 #include <qabstracteventdispatcher.h>
52 #include <qfunctions_winrt.h>
53
54 #include <private/qthread_p.h>
55 #include <private/qabstractsocket_p.h>
56 #include <private/qeventdispatcher_winrt_p.h>
57
58 #ifndef QT_NO_SSL
59 #include <QSslSocket>
60 #endif
61
62 #include <functional>
63 #include <wrl.h>
64 #include <windows.foundation.collections.h>
65 #include <windows.storage.streams.h>
66 #include <windows.networking.h>
67 #include <windows.networking.sockets.h>
68 #include <robuffer.h>
69
70 using namespace Microsoft::WRL;
71 using namespace Microsoft::WRL::Wrappers;
72 using namespace ABI::Windows::Foundation;
73 using namespace ABI::Windows::Foundation::Collections;
74 using namespace ABI::Windows::Storage::Streams;
75 using namespace ABI::Windows::Networking;
76 using namespace ABI::Windows::Networking::Connectivity;
77 using namespace ABI::Windows::Networking::Sockets;
78 #if _MSC_VER >= 1900
79 using namespace ABI::Windows::Security::EnterpriseData;
80 #endif
81
82 typedef ITypedEventHandler<StreamSocketListener *, StreamSocketListenerConnectionReceivedEventArgs *> ClientConnectedHandler;
83 typedef ITypedEventHandler<DatagramSocket *, DatagramSocketMessageReceivedEventArgs *> DatagramReceivedHandler;
84 typedef IAsyncOperationWithProgressCompletedHandler<IBuffer *, UINT32> SocketReadCompletedHandler;
85 typedef IAsyncOperationWithProgressCompletedHandler<UINT32, UINT32> SocketWriteCompletedHandler;
86 typedef IAsyncOperationWithProgress<IBuffer *, UINT32> IAsyncBufferOperation;
87
88 QT_BEGIN_NAMESPACE
89
90 Q_LOGGING_CATEGORY(lcNetworkSocket, "qt.network.socket");
91 Q_LOGGING_CATEGORY(lcNetworkSocketVerbose, "qt.network.socket.verbose");
92
93 #if _MSC_VER >= 1900
qt_winrt_try_create_thread_network_context(QString host,ComPtr<IThreadNetworkContext> & context)94 static HRESULT qt_winrt_try_create_thread_network_context(QString host, ComPtr<IThreadNetworkContext> &context)
95 {
96 HRESULT hr;
97 ComPtr<IProtectionPolicyManagerStatics> protectionPolicyManager;
98
99 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(),
100 &protectionPolicyManager);
101 RETURN_HR_IF_FAILED("Could not access ProtectionPolicyManager statics.");
102
103 ComPtr<IHostNameFactory> hostNameFactory;
104 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
105 &hostNameFactory);
106 RETURN_HR_IF_FAILED("Could not access HostName factory.");
107
108 ComPtr<IHostName> hostName;
109 HStringReference hostRef(reinterpret_cast<LPCWSTR>(host.utf16()), host.length());
110 hr = hostNameFactory->CreateHostName(hostRef.Get(), &hostName);
111 RETURN_HR_IF_FAILED("Could not create hostname.");
112
113 ComPtr<IAsyncOperation<HSTRING>> op;
114 hr = protectionPolicyManager->GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName.Get(), &op);
115 RETURN_HR_IF_FAILED("Could not get identity operation.");
116
117 HSTRING hIdentity;
118 hr = QWinRTFunctions::await(op, &hIdentity);
119 RETURN_HR_IF_FAILED("Could not wait for identity operation.");
120
121 // Implies there is no need for a network context for this address
122 if (hIdentity == nullptr)
123 return S_OK;
124
125 hr = protectionPolicyManager->CreateCurrentThreadNetworkContext(hIdentity, &context);
126 RETURN_HR_IF_FAILED("Could not create thread network context");
127
128 return S_OK;
129 }
130 #endif // _MSC_VER >= 1900
131
132 typedef QHash<qintptr, IStreamSocket *> TcpSocketHash;
133
134 struct SocketHandler
135 {
SocketHandlerSocketHandler136 SocketHandler() : socketCount(0) {}
137 qintptr socketCount;
138 TcpSocketHash pendingTcpSockets;
139 };
140
141 Q_GLOBAL_STATIC(SocketHandler, gSocketHandler)
142
143 struct SocketGlobal
144 {
SocketGlobalSocketGlobal145 SocketGlobal()
146 {
147 HRESULT hr;
148 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
149 &bufferFactory);
150 Q_ASSERT_SUCCEEDED(hr);
151 }
152
153 ComPtr<IBufferFactory> bufferFactory;
154 };
Q_GLOBAL_STATIC(SocketGlobal,g)155 Q_GLOBAL_STATIC(SocketGlobal, g)
156
157 #define READ_BUFFER_SIZE 65536
158
159 static inline QString qt_QStringFromHString(const HString &string)
160 {
161 UINT32 length;
162 PCWSTR rawString = string.GetRawBuffer(&length);
163 return QString::fromWCharArray(rawString, length);
164 }
165
166 class SocketEngineWorker : public QObject
167 {
168 Q_OBJECT
169 public:
SocketEngineWorker(QNativeSocketEnginePrivate * engine)170 SocketEngineWorker(QNativeSocketEnginePrivate *engine)
171 : enginePrivate(engine)
172 {
173 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << engine;
174 }
175
~SocketEngineWorker()176 ~SocketEngineWorker()
177 {
178 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
179 if (Q_UNLIKELY(initialReadOp)) {
180 qCDebug(lcNetworkSocket) << Q_FUNC_INFO << "Closing initial read operation";
181 ComPtr<IAsyncInfo> info;
182 HRESULT hr = initialReadOp.As(&info);
183 Q_ASSERT_SUCCEEDED(hr);
184 if (info) {
185 hr = info->Cancel();
186 Q_ASSERT_SUCCEEDED(hr);
187 hr = info->Close();
188 Q_ASSERT_SUCCEEDED(hr);
189 }
190 }
191
192 if (readOp) {
193 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "Closing read operation";
194 ComPtr<IAsyncInfo> info;
195 HRESULT hr = readOp.As(&info);
196 Q_ASSERT_SUCCEEDED(hr);
197 if (info) {
198 hr = info->Cancel();
199 Q_ASSERT_SUCCEEDED(hr);
200 hr = info->Close();
201 Q_ASSERT_SUCCEEDED(hr);
202 }
203 }
204
205 if (connectOp) {
206 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "Closing connect operation";
207 ComPtr<IAsyncInfo> info;
208 HRESULT hr = connectOp.As(&info);
209 Q_ASSERT_SUCCEEDED(hr);
210 if (info) {
211 hr = info->Cancel();
212 Q_ASSERT_SUCCEEDED(hr);
213 hr = info->Close();
214 Q_ASSERT_SUCCEEDED(hr);
215 }
216 }
217 }
218
219 signals:
220 void connectOpFinished(bool success, QAbstractSocket::SocketError error, WinRTSocketEngine::ErrorString errorString);
221 void newDataReceived();
222 void socketErrorOccured(QAbstractSocket::SocketError error);
223
224 public:
startReading()225 void startReading()
226 {
227 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
228 ComPtr<IBuffer> buffer;
229 HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
230 Q_ASSERT_SUCCEEDED(hr);
231 ComPtr<IInputStream> stream;
232 hr = tcpSocket->get_InputStream(&stream);
233 Q_ASSERT_SUCCEEDED(hr);
234 hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, initialReadOp.GetAddressOf());
235 Q_ASSERT_SUCCEEDED(hr);
236 enginePrivate->socketState = QAbstractSocket::ConnectedState;
237 hr = initialReadOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &SocketEngineWorker::onReadyRead).Get());
238 Q_ASSERT_SUCCEEDED(hr);
239 }
240
onConnectOpFinished(IAsyncAction * action,AsyncStatus)241 HRESULT onConnectOpFinished(IAsyncAction *action, AsyncStatus)
242 {
243 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
244 HRESULT hr = action->GetResults();
245 if (FAILED(hr)) {
246 if (hr == HRESULT_FROM_WIN32(WSAETIMEDOUT)) {
247 emit connectOpFinished(false, QAbstractSocket::NetworkError, WinRTSocketEngine::ConnectionTimeOutErrorString);
248 return S_OK;
249 } else if (hr == HRESULT_FROM_WIN32(WSAEHOSTUNREACH)) {
250 emit connectOpFinished(false, QAbstractSocket::HostNotFoundError, WinRTSocketEngine::HostUnreachableErrorString);
251 return S_OK;
252 } else if (hr == HRESULT_FROM_WIN32(WSAECONNREFUSED)) {
253 emit connectOpFinished(false, QAbstractSocket::ConnectionRefusedError, WinRTSocketEngine::ConnectionRefusedErrorString);
254 return S_OK;
255 } else {
256 emit connectOpFinished(false, QAbstractSocket::UnknownSocketError, WinRTSocketEngine::UnknownSocketErrorString);
257 return S_OK;
258 }
259 }
260
261 // The callback might be triggered several times if we do not cancel/reset it here
262 if (connectOp) {
263 ComPtr<IAsyncInfo> info;
264 hr = connectOp.As(&info);
265 Q_ASSERT_SUCCEEDED(hr);
266 if (info) {
267 hr = info->Cancel();
268 Q_ASSERT_SUCCEEDED(hr);
269 hr = info->Close();
270 Q_ASSERT_SUCCEEDED(hr);
271 }
272 hr = connectOp.Reset();
273 Q_ASSERT_SUCCEEDED(hr);
274 }
275
276 emit connectOpFinished(true, QAbstractSocket::UnknownSocketError, WinRTSocketEngine::UnknownSocketErrorString);
277 return S_OK;
278 }
279
OnNewDatagramReceived(IDatagramSocket *,IDatagramSocketMessageReceivedEventArgs * args)280 HRESULT OnNewDatagramReceived(IDatagramSocket *, IDatagramSocketMessageReceivedEventArgs *args)
281 {
282 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO;
283 WinRtDatagram datagram;
284 QHostAddress returnAddress;
285 ComPtr<IHostName> remoteHost;
286 HRESULT hr = args->get_RemoteAddress(&remoteHost);
287 RETURN_OK_IF_FAILED("Could not obtain remote host");
288 HString remoteHostString;
289 hr = remoteHost->get_CanonicalName(remoteHostString.GetAddressOf());
290 RETURN_OK_IF_FAILED("Could not obtain remote host's canonical name");
291 returnAddress.setAddress(qt_QStringFromHString(remoteHostString));
292 datagram.header.senderAddress = returnAddress;
293 HString remotePort;
294 hr = args->get_RemotePort(remotePort.GetAddressOf());
295 RETURN_OK_IF_FAILED("Could not obtain remote port");
296 datagram.header.senderPort = qt_QStringFromHString(remotePort).toInt();
297
298 ComPtr<IDataReader> reader;
299 hr = args->GetDataReader(&reader);
300 RETURN_OK_IF_FAILED("Could not obtain data reader");
301 quint32 length;
302 hr = reader->get_UnconsumedBufferLength(&length);
303 RETURN_OK_IF_FAILED("Could not obtain unconsumed buffer length");
304 datagram.data.resize(length);
305 hr = reader->ReadBytes(length, reinterpret_cast<BYTE *>(datagram.data.data()));
306 RETURN_OK_IF_FAILED("Could not read datagram");
307
308 QMutexLocker locker(&mutex);
309 // Notify the engine about new datagrams being present at the next event loop iteration
310 if (emitDataReceived)
311 emit newDataReceived();
312 pendingDatagrams << datagram;
313
314 return S_OK;
315 }
316
onReadyRead(IAsyncBufferOperation * asyncInfo,AsyncStatus status)317 HRESULT onReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status)
318 {
319 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO;
320 if (asyncInfo == initialReadOp.Get()) {
321 initialReadOp.Reset();
322 } else if (asyncInfo == readOp.Get()) {
323 readOp.Reset();
324 } else {
325 Q_ASSERT(false);
326 }
327
328 // A read in UnconnectedState will close the socket and return -1 and thus tell the caller,
329 // that the connection was closed. The socket cannot be closed here, as the subsequent read
330 // might fail then.
331 if (status == Error || status == Canceled) {
332 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "Remote host closed";
333 emit socketErrorOccured(QAbstractSocket::RemoteHostClosedError);
334 return S_OK;
335 }
336
337 ComPtr<IBuffer> buffer;
338 HRESULT hr = asyncInfo->GetResults(&buffer);
339 if (FAILED(hr)) {
340 qErrnoWarning(hr, "Failed to get read results buffer");
341 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
342 return S_OK;
343 }
344
345 UINT32 bufferLength;
346 hr = buffer->get_Length(&bufferLength);
347 if (FAILED(hr)) {
348 qErrnoWarning(hr, "Failed to get buffer length");
349 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
350 return S_OK;
351 }
352 // A zero sized buffer length signals, that the remote host closed the connection. The socket
353 // cannot be closed though, as the following read might have socket descriptor -1 and thus and
354 // the closing of the socket won't be communicated to the caller. So only the error is set. The
355 // actual socket close happens inside of read.
356 if (!bufferLength) {
357 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "Remote host closed";
358 emit socketErrorOccured(QAbstractSocket::RemoteHostClosedError);
359 return S_OK;
360 }
361
362 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
363 hr = buffer.As(&byteArrayAccess);
364 if (FAILED(hr)) {
365 qErrnoWarning(hr, "Failed to get cast buffer");
366 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
367 return S_OK;
368 }
369 byte *data;
370 hr = byteArrayAccess->Buffer(&data);
371 if (FAILED(hr)) {
372 qErrnoWarning(hr, "Failed to access buffer data");
373 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
374 return S_OK;
375 }
376
377 QByteArray newData(reinterpret_cast<const char*>(data), qint64(bufferLength));
378
379 QMutexLocker readLocker(&mutex);
380 emit newDataReceived();
381 pendingData.append(newData);
382 readLocker.unlock();
383
384 hr = QEventDispatcherWinRT::runOnXamlThread([buffer, this]() {
385 UINT32 readBufferLength;
386 ComPtr<IInputStream> stream;
387 HRESULT hr = tcpSocket->get_InputStream(&stream);
388 if (FAILED(hr)) {
389 qErrnoWarning(hr, "Failed to obtain input stream");
390 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
391 return S_OK;
392 }
393
394 // Reuse the stream buffer
395 hr = buffer->get_Capacity(&readBufferLength);
396 if (FAILED(hr)) {
397 qErrnoWarning(hr, "Failed to get buffer capacity");
398 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
399 return S_OK;
400 }
401 hr = buffer->put_Length(0);
402 if (FAILED(hr)) {
403 qErrnoWarning(hr, "Failed to set buffer length");
404 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
405 return S_OK;
406 }
407
408 hr = stream->ReadAsync(buffer.Get(), readBufferLength, InputStreamOptions_Partial, &readOp);
409 if (FAILED(hr)) {
410 qErrnoWarning(hr, "onReadyRead(): Could not read into socket stream buffer.");
411 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
412 return S_OK;
413 }
414 hr = readOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &SocketEngineWorker::onReadyRead).Get());
415 if (FAILED(hr)) {
416 qErrnoWarning(hr, "onReadyRead(): Failed to set socket read callback.");
417 emit socketErrorOccured(QAbstractSocket::UnknownSocketError);
418 return S_OK;
419 }
420 return S_OK;
421 });
422 Q_ASSERT_SUCCEEDED(hr);
423 return S_OK;
424 }
425
setTcpSocket(ComPtr<IStreamSocket> socket)426 void setTcpSocket(ComPtr<IStreamSocket> socket) { tcpSocket = socket; }
427
428 private:
429 friend class QNativeSocketEngine;
430 ComPtr<IStreamSocket> tcpSocket;
431
432 QList<WinRtDatagram> pendingDatagrams;
433 bool emitDataReceived = true;
434 QByteArray pendingData;
435
436 // Protects pendingData/pendingDatagrams which are accessed from native callbacks
437 QMutex mutex;
438
439 ComPtr<IAsyncAction> connectOp;
440 ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> initialReadOp;
441 ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> readOp;
442
443 QNativeSocketEnginePrivate *enginePrivate;
444 };
445
socketDescription(const QAbstractSocketEngine * s)446 static QByteArray socketDescription(const QAbstractSocketEngine *s)
447 {
448 QByteArray result;
449 if (const QObject *o = s->parent()) {
450 const QString name = o->objectName();
451 if (!name.isEmpty()) {
452 result += '"';
453 result += name.toLocal8Bit();
454 result += "\"/";
455 }
456 result += o->metaObject()->className();
457 }
458 return result;
459 }
460
461 // Common constructs
462 #define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \
463 if (!isValid()) { \
464 qWarning(""#function" was called on an uninitialized socket device"); \
465 return returnValue; \
466 } } while (0)
467 #define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \
468 if (isValid()) { \
469 qWarning(""#function" was called on an already initialized socket device"); \
470 return returnValue; \
471 } } while (0)
472 #define Q_CHECK_STATE(function, checkState, returnValue) do { \
473 if (d->socketState != (checkState)) { \
474 qWarning(""#function" was not called in "#checkState); \
475 return (returnValue); \
476 } } while (0)
477 #define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \
478 if (d->socketState == (checkState)) { \
479 qWarning(""#function" was called in "#checkState); \
480 return (returnValue); \
481 } } while (0)
482 #define Q_CHECK_STATES(function, state1, state2, returnValue) do { \
483 if (d->socketState != (state1) && d->socketState != (state2)) { \
484 qWarning(""#function" was called" \
485 " not in "#state1" or "#state2); \
486 return (returnValue); \
487 } } while (0)
488 #define Q_CHECK_STATES3(function, state1, state2, state3, returnValue) do { \
489 if (d->socketState != (state1) && d->socketState != (state2) && d->socketState != (state3)) { \
490 qWarning(""#function" was called" \
491 " not in "#state1", "#state2" or "#state3); \
492 return (returnValue); \
493 } } while (0)
494 #define Q_CHECK_TYPE(function, type, returnValue) do { \
495 if (d->socketType != (type)) { \
496 qWarning(#function" was called by a" \
497 " socket other than "#type""); \
498 return (returnValue); \
499 } } while (0)
500 #define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a)
501
502 template <typename T>
opStatus(const ComPtr<T> & op)503 static AsyncStatus opStatus(const ComPtr<T> &op)
504 {
505 ComPtr<IAsyncInfo> info;
506 HRESULT hr = op.As(&info);
507 Q_ASSERT_SUCCEEDED(hr);
508 AsyncStatus status;
509 hr = info->get_Status(&status);
510 Q_ASSERT_SUCCEEDED(hr);
511 return status;
512 }
513
writeIOStream(ComPtr<IOutputStream> stream,const char * data,qint64 len)514 static qint64 writeIOStream(ComPtr<IOutputStream> stream, const char *data, qint64 len)
515 {
516 qCDebug(lcNetworkSocket) << Q_FUNC_INFO << data << len;
517 ComPtr<IBuffer> buffer;
518 HRESULT hr = g->bufferFactory->Create(len, &buffer);
519 Q_ASSERT_SUCCEEDED(hr);
520 hr = buffer->put_Length(len);
521 Q_ASSERT_SUCCEEDED(hr);
522 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
523 hr = buffer.As(&byteArrayAccess);
524 Q_ASSERT_SUCCEEDED(hr);
525 byte *bytes;
526 hr = byteArrayAccess->Buffer(&bytes);
527 Q_ASSERT_SUCCEEDED(hr);
528 memcpy(bytes, data, len);
529 ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
530 hr = stream->WriteAsync(buffer.Get(), &op);
531 RETURN_IF_FAILED("Failed to write to stream", return -1);
532 UINT32 bytesWritten;
533 hr = QWinRTFunctions::await(op, &bytesWritten);
534 RETURN_IF_FAILED("Failed to write to stream", return -1);
535 return bytesWritten;
536 }
537
QNativeSocketEngine(QObject * parent)538 QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
539 : QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
540 {
541 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << parent;
542 qRegisterMetaType<WinRtDatagram>();
543 qRegisterMetaType<WinRTSocketEngine::ErrorString>();
544 Q_D(QNativeSocketEngine);
545 #ifndef QT_NO_SSL
546 if (parent)
547 d->sslSocket = qobject_cast<QSslSocket *>(parent->parent());
548 #endif
549
550 connect(this, &QNativeSocketEngine::connectionReady,
551 this, &QNativeSocketEngine::connectionNotification, Qt::QueuedConnection);
552 connect(this, &QNativeSocketEngine::readReady,
553 this, &QNativeSocketEngine::processReadReady, Qt::QueuedConnection);
554 connect(this, &QNativeSocketEngine::writeReady,
555 this, &QNativeSocketEngine::writeNotification, Qt::QueuedConnection);
556 connect(d->worker, &SocketEngineWorker::connectOpFinished,
557 this, &QNativeSocketEngine::handleConnectOpFinished, Qt::QueuedConnection);
558 connect(d->worker, &SocketEngineWorker::newDataReceived, this, &QNativeSocketEngine::handleNewData, Qt::QueuedConnection);
559 connect(d->worker, &SocketEngineWorker::socketErrorOccured,
560 this, &QNativeSocketEngine::handleTcpError, Qt::QueuedConnection);
561 }
562
~QNativeSocketEngine()563 QNativeSocketEngine::~QNativeSocketEngine()
564 {
565 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
566 close();
567 }
568
initialize(QAbstractSocket::SocketType type,QAbstractSocket::NetworkLayerProtocol protocol)569 bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
570 {
571 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << type << protocol;
572 Q_D(QNativeSocketEngine);
573 if (isValid())
574 close();
575
576 // Create the socket
577 if (!d->createNewSocket(type, protocol))
578 return false;
579
580 if (type == QAbstractSocket::UdpSocket) {
581 // Set the broadcasting flag if it's a UDP socket.
582 if (!setOption(BroadcastSocketOption, 1)) {
583 d->setError(QAbstractSocket::UnsupportedSocketOperationError,
584 WinRTSocketEngine::BroadcastingInitFailedErrorString);
585 close();
586 return false;
587 }
588
589 // Set some extra flags that are interesting to us, but accept failure
590 setOption(ReceivePacketInformation, 1);
591 setOption(ReceiveHopLimit, 1);
592 }
593
594
595 // Make sure we receive out-of-band data
596 if (type == QAbstractSocket::TcpSocket
597 && !setOption(ReceiveOutOfBandData, 1)) {
598 qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data");
599 }
600
601
602 d->socketType = type;
603 d->socketProtocol = protocol;
604 return true;
605 }
606
initialize(qintptr socketDescriptor,QAbstractSocket::SocketState socketState)607 bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
608 {
609 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << socketDescriptor << socketState;
610 Q_D(QNativeSocketEngine);
611
612 if (isValid())
613 close();
614
615 // Currently, only TCP sockets are initialized this way.
616 IStreamSocket *socket = gSocketHandler->pendingTcpSockets.take(socketDescriptor);
617 d->socketDescriptor = qintptr(socket);
618 d->socketType = QAbstractSocket::TcpSocket;
619
620 if (!d->socketDescriptor || !d->fetchConnectionParameters()) {
621 d->setError(QAbstractSocket::UnsupportedSocketOperationError,
622 WinRTSocketEngine::InvalidSocketErrorString);
623 d->socketDescriptor = -1;
624 return false;
625 }
626
627 // Start processing incoming data
628 if (d->socketType == QAbstractSocket::TcpSocket) {
629 HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, socket, this]() {
630 d->worker->setTcpSocket(socket);
631 d->worker->startReading();
632 return S_OK;
633 });
634 if (FAILED(hr))
635 return false;
636 } else {
637 d->socketState = socketState;
638 }
639
640 return true;
641 }
642
socketDescriptor() const643 qintptr QNativeSocketEngine::socketDescriptor() const
644 {
645 Q_D(const QNativeSocketEngine);
646 return d->socketDescriptor;
647 }
648
isValid() const649 bool QNativeSocketEngine::isValid() const
650 {
651 Q_D(const QNativeSocketEngine);
652 return d->socketDescriptor != -1;
653 }
654
connectToHost(const QHostAddress & address,quint16 port)655 bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 port)
656 {
657 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << address << port;
658 Q_D(QNativeSocketEngine);
659 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::connectToHost(), false);
660 Q_CHECK_STATES3(QNativeSocketEngine::connectToHost(), QAbstractSocket::BoundState,
661 QAbstractSocket::UnconnectedState, QAbstractSocket::ConnectingState, false);
662 const QString addressString = address.toString();
663 return connectToHostByName(addressString, port);
664 }
665
connectToHostByName(const QString & name,quint16 port)666 bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
667 {
668 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << name << port;
669 Q_D(QNativeSocketEngine);
670 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::connectToHostByName(), false);
671 Q_CHECK_STATES3(QNativeSocketEngine::connectToHostByName(), QAbstractSocket::BoundState,
672 QAbstractSocket::UnconnectedState, QAbstractSocket::ConnectingState, false);
673 HRESULT hr;
674
675 #if _MSC_VER >= 1900
676 ComPtr<IThreadNetworkContext> networkContext;
677 if (!qEnvironmentVariableIsEmpty("QT_WINRT_USE_THREAD_NETWORK_CONTEXT")) {
678 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "Creating network context";
679 hr = qt_winrt_try_create_thread_network_context(name, networkContext);
680 if (FAILED(hr)) {
681 setError(QAbstractSocket::ConnectionRefusedError, QLatin1String("Could not create thread network context."));
682 d->socketState = QAbstractSocket::ConnectedState;
683 return true;
684 }
685 }
686 #endif // _MSC_VER >= 1900
687
688 HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(name.utf16()));
689 ComPtr<IHostNameFactory> hostNameFactory;
690 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
691 &hostNameFactory);
692 Q_ASSERT_SUCCEEDED(hr);
693 ComPtr<IHostName> remoteHost;
694 hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
695 RETURN_FALSE_IF_FAILED("QNativeSocketEngine::connectToHostByName: Could not create hostname.");
696
697 const QString portString = QString::number(port);
698 HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
699 if (d->socketType == QAbstractSocket::TcpSocket)
700 hr = d->tcpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->worker->connectOp);
701 else if (d->socketType == QAbstractSocket::UdpSocket)
702 hr = d->udpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->worker->connectOp);
703 if (hr == E_ACCESSDENIED) {
704 qErrnoWarning(hr, "QNativeSocketEngine::connectToHostByName: Unable to connect to host (%s:%hu/%s). "
705 "Please check your manifest capabilities.",
706 qPrintable(name), port, socketDescription(this).constData());
707 return false;
708 }
709 Q_ASSERT_SUCCEEDED(hr);
710
711 #if _MSC_VER >= 1900
712 if (networkContext != nullptr) {
713 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "Closing network context";
714 ComPtr<IClosable> networkContextCloser;
715 hr = networkContext.As(&networkContextCloser);
716 Q_ASSERT_SUCCEEDED(hr);
717 hr = networkContextCloser->Close();
718 Q_ASSERT_SUCCEEDED(hr);
719 }
720 #endif // _MSC_VER >= 1900
721
722 d->socketState = QAbstractSocket::ConnectingState;
723 QEventDispatcherWinRT::runOnXamlThread([d, &hr]() {
724 hr = d->worker->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
725 d->worker, &SocketEngineWorker::onConnectOpFinished).Get());
726 RETURN_OK_IF_FAILED("connectToHostByName: Could not register \"connectOp\" callback");
727 return S_OK;
728 });
729 if (FAILED(hr))
730 return false;
731
732 return d->socketState == QAbstractSocket::ConnectedState;
733 }
734
bind(const QHostAddress & address,quint16 port)735 bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
736 {
737 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << address << port;
738 Q_D(QNativeSocketEngine);
739 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bind(), false);
740 Q_CHECK_STATE(QNativeSocketEngine::bind(), QAbstractSocket::UnconnectedState, false);
741
742 HRESULT hr;
743 // runOnXamlThread may only return S_OK (will assert otherwise) so no need to check its result.
744 // hr is set inside the lambda though. If an error occurred hr will point that out.
745 bool specificErrorSet = false;
746 QEventDispatcherWinRT::runOnXamlThread([address, d, &hr, port, &specificErrorSet, this]() {
747 ComPtr<IHostName> hostAddress;
748
749 if (address != QHostAddress::Any && address != QHostAddress::AnyIPv4 && address != QHostAddress::AnyIPv6) {
750 ComPtr<IHostNameFactory> hostNameFactory;
751 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
752 &hostNameFactory);
753 RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not obtain hostname factory");
754 const QString addressString = address.toString();
755 HStringReference addressRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
756 hr = hostNameFactory->CreateHostName(addressRef.Get(), &hostAddress);
757 RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not create hostname.");
758 }
759
760 QString portQString = port ? QString::number(port) : QString();
761 HStringReference portString(reinterpret_cast<LPCWSTR>(portQString.utf16()));
762
763 ComPtr<IAsyncAction> op;
764 if (d->socketType == QAbstractSocket::TcpSocket) {
765 if (!d->tcpListener) {
766 hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
767 &d->tcpListener);
768 RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not create tcp listener");
769 }
770
771 hr = d->tcpListener->add_ConnectionReceived(
772 Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(),
773 &d->connectionToken);
774 RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not register client connection callback");
775 hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
776 } else if (d->socketType == QAbstractSocket::UdpSocket) {
777 hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
778 }
779 if (hr == E_ACCESSDENIED) {
780 qErrnoWarning(hr, "Unable to bind socket (%s:%hu/%s). Please check your manifest capabilities.",
781 qPrintable(address.toString()), port, socketDescription(this).constData());
782 d->setError(QAbstractSocket::SocketAccessError,
783 WinRTSocketEngine::AccessErrorString);
784 d->socketState = QAbstractSocket::UnconnectedState;
785 specificErrorSet = true;
786 return S_OK;
787 }
788 RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Unable to bind socket");
789
790 hr = QWinRTFunctions::await(op);
791 if (hr == 0x80072741) { // The requested address is not valid in its context
792 d->setError(QAbstractSocket::SocketAddressNotAvailableError,
793 WinRTSocketEngine::AddressNotAvailableErrorString);
794 d->socketState = QAbstractSocket::UnconnectedState;
795 specificErrorSet = true;
796 return S_OK;
797 // Only one usage of each socket address (protocol/network address/port) is normally permitted
798 } else if (hr == 0x80072740) {
799 d->setError(QAbstractSocket::AddressInUseError,
800 WinRTSocketEngine::AddressInuseErrorString);
801 d->socketState = QAbstractSocket::UnconnectedState;
802 specificErrorSet = true;
803 return S_OK;
804 }
805 RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not wait for bind to finish");
806 return S_OK;
807 });
808 if (FAILED(hr)) {
809 if (!specificErrorSet) {
810 d->setError(QAbstractSocket::UnknownSocketError,
811 WinRTSocketEngine::UnknownSocketErrorString);
812 d->socketState = QAbstractSocket::UnconnectedState;
813 }
814 return false;
815 }
816
817 d->socketState = QAbstractSocket::BoundState;
818 return d->fetchConnectionParameters();
819 }
820
listen()821 bool QNativeSocketEngine::listen()
822 {
823 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
824 Q_D(QNativeSocketEngine);
825 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
826 Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, false);
827 #if QT_CONFIG(sctp)
828 Q_CHECK_TYPES(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket,
829 QAbstractSocket::SctpSocket, false);
830 #else
831 Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
832 #endif
833
834 if (d->tcpListener && d->socketDescriptor != -1) {
835 d->socketState = QAbstractSocket::ListeningState;
836 return true;
837 }
838 return false;
839 }
840
accept()841 int QNativeSocketEngine::accept()
842 {
843 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
844 Q_D(QNativeSocketEngine);
845 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
846 Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, -1);
847 #if QT_CONFIG(sctp)
848 Q_CHECK_TYPES(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket,
849 QAbstractSocket::SctpSocket, -1);
850 #else
851 Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, -1);
852 #endif
853
854 if (d->socketDescriptor == -1 || d->pendingConnections.isEmpty()) {
855 d->setError(QAbstractSocket::TemporaryError, WinRTSocketEngine::TemporaryErrorString);
856 return -1;
857 }
858
859 if (d->socketType == QAbstractSocket::TcpSocket) {
860 IStreamSocket *socket = d->pendingConnections.takeFirst();
861
862 SocketHandler *handler = gSocketHandler();
863 handler->pendingTcpSockets.insert(++handler->socketCount, socket);
864 return handler->socketCount;
865 }
866
867 return -1;
868 }
869
close()870 void QNativeSocketEngine::close()
871 {
872 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
873 Q_D(QNativeSocketEngine);
874
875 if (d->closingDown)
876 return;
877
878 if (d->pendingReadNotification) {
879 // We use QPointer here to see if this QNativeSocketEngine was deleted as a result of
880 // finishing and cleaning up a network request when calling "processReadReady".
881 QPointer<QNativeSocketEngine> alive(this);
882 processReadReady();
883 if (alive.isNull())
884 return;
885 }
886
887 d->closingDown = true;
888
889 d->notifyOnRead = false;
890 d->notifyOnWrite = false;
891 d->notifyOnException = false;
892 d->emitReadReady = false;
893
894 HRESULT hr;
895 if (d->socketType == QAbstractSocket::TcpSocket) {
896 hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
897 HRESULT hr;
898 // To close the connection properly (not with a hard reset) all pending read operation have to
899 // be finished or cancelled. The API isn't available on Windows 8.1 though.
900 ComPtr<IStreamSocket3> socket3;
901 hr = d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket3));
902 Q_ASSERT_SUCCEEDED(hr);
903
904 ComPtr<IAsyncAction> action;
905 hr = socket3->CancelIOAsync(&action);
906 Q_ASSERT_SUCCEEDED(hr);
907 hr = QWinRTFunctions::await(action, QWinRTFunctions::YieldThread, 5000);
908 // If there is no pending IO (no read established before) the function will fail with
909 // "function was called at an unexpected time" which is fine.
910 // Timeout is fine as well. The result will be the socket being hard reset instead of
911 // being closed gracefully
912 if (hr != E_ILLEGAL_METHOD_CALL && hr != ERROR_TIMEOUT)
913 Q_ASSERT_SUCCEEDED(hr);
914 return S_OK;
915 });
916 Q_ASSERT_SUCCEEDED(hr);
917 }
918
919 if (d->socketDescriptor != -1) {
920 ComPtr<IClosable> socket;
921 if (d->socketType == QAbstractSocket::TcpSocket) {
922 hr = d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
923 Q_ASSERT_SUCCEEDED(hr);
924 hr = d->tcpSocket()->Release();
925 Q_ASSERT_SUCCEEDED(hr);
926 } else if (d->socketType == QAbstractSocket::UdpSocket) {
927 hr = d->udpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
928 Q_ASSERT_SUCCEEDED(hr);
929 hr = d->udpSocket()->Release();
930 Q_ASSERT_SUCCEEDED(hr);
931 }
932
933 if (socket) {
934 hr = socket->Close();
935 Q_ASSERT_SUCCEEDED(hr);
936 }
937 d->socketDescriptor = -1;
938 }
939 d->socketState = QAbstractSocket::UnconnectedState;
940 d->hasSetSocketError = false;
941 d->localPort = 0;
942 d->localAddress.clear();
943 d->peerPort = 0;
944 d->peerAddress.clear();
945 d->inboundStreamCount = d->outboundStreamCount = 0;
946 }
947
joinMulticastGroup(const QHostAddress & groupAddress,const QNetworkInterface & iface)948 bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
949 {
950 Q_D(QNativeSocketEngine);
951 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false);
952 Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false);
953 Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false);
954 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << groupAddress << iface;
955 Q_UNIMPLEMENTED();
956 return false;
957 }
958
leaveMulticastGroup(const QHostAddress & groupAddress,const QNetworkInterface & iface)959 bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
960 {
961 Q_D(QNativeSocketEngine);
962 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::leaveMulticastGroup(), false);
963 Q_CHECK_STATE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false);
964 Q_CHECK_TYPE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false);
965 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << groupAddress << iface;
966 Q_UNIMPLEMENTED();
967 return false;
968 }
969
multicastInterface() const970 QNetworkInterface QNativeSocketEngine::multicastInterface() const
971 {
972 Q_D(const QNativeSocketEngine);
973 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::multicastInterface(), QNetworkInterface());
974 Q_CHECK_TYPE(QNativeSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface());
975 Q_UNIMPLEMENTED();
976 return QNetworkInterface();
977 }
978
setMulticastInterface(const QNetworkInterface & iface)979 bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
980 {
981 Q_D(QNativeSocketEngine);
982 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setMulticastInterface(), false);
983 Q_CHECK_TYPE(QNativeSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false);
984 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << iface;
985 Q_UNIMPLEMENTED();
986 return false;
987 }
988
bytesAvailable() const989 qint64 QNativeSocketEngine::bytesAvailable() const
990 {
991 Q_D(const QNativeSocketEngine);
992 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bytesAvailable(), -1);
993 Q_CHECK_NOT_STATE(QNativeSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, -1);
994 if (d->socketType != QAbstractSocket::TcpSocket)
995 return -1;
996
997 QMutexLocker locker(&d->worker->mutex);
998 const qint64 bytesAvailable = d->worker->pendingData.length();
999
1000 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << bytesAvailable;
1001 return bytesAvailable;
1002 }
1003
read(char * data,qint64 maxlen)1004 qint64 QNativeSocketEngine::read(char *data, qint64 maxlen)
1005 {
1006 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << maxlen;
1007 Q_D(QNativeSocketEngine);
1008 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::read(), -1);
1009 Q_CHECK_STATES(QNativeSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1);
1010 if (d->socketType != QAbstractSocket::TcpSocket)
1011 return -1;
1012
1013 // There will be a read notification when the socket was closed by the remote host. If that
1014 // happens and there isn't anything left in the buffer, we have to return -1 in order to signal
1015 // the closing of the socket.
1016 QMutexLocker mutexLocker(&d->worker->mutex);
1017 if (d->worker->pendingData.isEmpty() && d->socketState != QAbstractSocket::ConnectedState) {
1018 close();
1019 return -1;
1020 }
1021
1022 QByteArray readData;
1023 const int copyLength = qMin(maxlen, qint64(d->worker->pendingData.length()));
1024 if (maxlen >= d->worker->pendingData.length()) {
1025 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << "Reading full buffer";
1026 readData = d->worker->pendingData;
1027 d->worker->pendingData.clear();
1028 d->emitReadReady = true;
1029 } else {
1030 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << "Reading part of the buffer ("
1031 << copyLength << "of" << d->worker->pendingData.length() << "bytes";
1032 readData = d->worker->pendingData.left(maxlen);
1033 d->worker->pendingData.remove(0, maxlen);
1034 if (d->notifyOnRead) {
1035 d->pendingReadNotification = true;
1036 emit readReady();
1037 }
1038 }
1039 mutexLocker.unlock();
1040
1041 memcpy(data, readData, copyLength);
1042 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << "Read" << copyLength << "bytes";
1043 return copyLength;
1044 }
1045
write(const char * data,qint64 len)1046 qint64 QNativeSocketEngine::write(const char *data, qint64 len)
1047 {
1048 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << data << len;
1049 Q_D(QNativeSocketEngine);
1050 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::write(), -1);
1051 Q_CHECK_STATE(QNativeSocketEngine::write(), QAbstractSocket::ConnectedState, -1);
1052
1053 HRESULT hr = E_FAIL;
1054 ComPtr<IOutputStream> stream;
1055 if (d->socketType == QAbstractSocket::TcpSocket)
1056 hr = d->tcpSocket()->get_OutputStream(&stream);
1057 else if (d->socketType == QAbstractSocket::UdpSocket)
1058 hr = d->udpSocket()->get_OutputStream(&stream);
1059 Q_ASSERT_SUCCEEDED(hr);
1060
1061 qint64 bytesWritten = writeIOStream(stream, data, len);
1062 if (bytesWritten < 0)
1063 d->setError(QAbstractSocket::SocketAccessError, WinRTSocketEngine::AccessErrorString);
1064 else if (bytesWritten > 0 && d->notifyOnWrite)
1065 emit writeReady();
1066
1067 return bytesWritten;
1068 }
1069
readDatagram(char * data,qint64 maxlen,QIpPacketHeader * header,PacketHeaderOptions)1070 qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header,
1071 PacketHeaderOptions)
1072 {
1073 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << maxlen;
1074 #ifndef QT_NO_UDPSOCKET
1075 Q_D(QNativeSocketEngine);
1076 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
1077 Q_CHECK_STATES(QNativeSocketEngine::readDatagram(), QAbstractSocket::BoundState,
1078 QAbstractSocket::ConnectedState, -1);
1079
1080 QMutexLocker locker(&d->worker->mutex);
1081 if (d->socketType != QAbstractSocket::UdpSocket || d->worker->pendingDatagrams.isEmpty()) {
1082 if (header)
1083 header->clear();
1084 return -1;
1085 }
1086
1087 WinRtDatagram datagram = d->worker->pendingDatagrams.takeFirst();
1088 if (header)
1089 *header = datagram.header;
1090
1091 QByteArray readOrigin;
1092 if (maxlen < datagram.data.length())
1093 readOrigin = datagram.data.left(maxlen);
1094 else
1095 readOrigin = datagram.data;
1096 if (d->worker->pendingDatagrams.isEmpty()) {
1097 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << "That's all folks";
1098 d->worker->emitDataReceived = true;
1099 d->emitReadReady = true;
1100 }
1101
1102 locker.unlock();
1103 memcpy(data, readOrigin, qMin(maxlen, qint64(datagram.data.length())));
1104 return readOrigin.length();
1105 #else
1106 Q_UNUSED(data)
1107 Q_UNUSED(maxlen)
1108 Q_UNUSED(header)
1109 return -1;
1110 #endif // QT_NO_UDPSOCKET
1111 }
1112
writeDatagram(const char * data,qint64 len,const QIpPacketHeader & header)1113 qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
1114 {
1115 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << data << len;
1116 #ifndef QT_NO_UDPSOCKET
1117 Q_D(QNativeSocketEngine);
1118 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
1119 Q_CHECK_STATES(QNativeSocketEngine::writeDatagram(), QAbstractSocket::BoundState,
1120 QAbstractSocket::ConnectedState, -1);
1121
1122 if (d->socketType != QAbstractSocket::UdpSocket)
1123 return -1;
1124
1125 ComPtr<IHostName> remoteHost;
1126 ComPtr<IHostNameFactory> hostNameFactory;
1127
1128 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
1129 &hostNameFactory);
1130 Q_ASSERT_SUCCEEDED(hr);
1131 const QString addressString = header.destinationAddress.toString();
1132 HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
1133 hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
1134 RETURN_IF_FAILED("QNativeSocketEngine::writeDatagram: Could not create hostname.", return -1);
1135
1136 ComPtr<IAsyncOperation<IOutputStream *>> streamOperation;
1137 ComPtr<IOutputStream> stream;
1138 const QString portString = QString::number(header.destinationPort);
1139 HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16()));
1140 hr = d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation);
1141 Q_ASSERT_SUCCEEDED(hr);
1142
1143 hr = QWinRTFunctions::await(streamOperation, stream.GetAddressOf());
1144 Q_ASSERT_SUCCEEDED(hr);
1145
1146 return writeIOStream(stream, data, len);
1147 #else
1148 Q_UNUSED(data)
1149 Q_UNUSED(len)
1150 Q_UNUSED(header)
1151 return -1;
1152 #endif // QT_NO_UDPSOCKET
1153 }
1154
hasPendingDatagrams() const1155 bool QNativeSocketEngine::hasPendingDatagrams() const
1156 {
1157 Q_D(const QNativeSocketEngine);
1158 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::hasPendingDatagrams(), false);
1159 Q_CHECK_NOT_STATE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false);
1160 Q_CHECK_TYPE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
1161
1162 QMutexLocker locker(&d->worker->mutex);
1163 return d->worker->pendingDatagrams.length() > 0;
1164 }
1165
pendingDatagramSize() const1166 qint64 QNativeSocketEngine::pendingDatagramSize() const
1167 {
1168 Q_D(const QNativeSocketEngine);
1169 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::pendingDatagramSize(), -1);
1170 Q_CHECK_TYPE(QNativeSocketEngine::pendingDatagramSize(), QAbstractSocket::UdpSocket, -1);
1171
1172 QMutexLocker locker(&d->worker->mutex);
1173 if (d->worker->pendingDatagrams.isEmpty())
1174 return -1;
1175
1176 return d->worker->pendingDatagrams.at(0).data.length();
1177 }
1178
bytesToWrite() const1179 qint64 QNativeSocketEngine::bytesToWrite() const
1180 {
1181 return 0;
1182 }
1183
receiveBufferSize() const1184 qint64 QNativeSocketEngine::receiveBufferSize() const
1185 {
1186 Q_D(const QNativeSocketEngine);
1187 return d->option(QAbstractSocketEngine::ReceiveBufferSocketOption);
1188 }
1189
setReceiveBufferSize(qint64 bufferSize)1190 void QNativeSocketEngine::setReceiveBufferSize(qint64 bufferSize)
1191 {
1192 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << bufferSize;
1193 Q_D(QNativeSocketEngine);
1194 d->setOption(QAbstractSocketEngine::ReceiveBufferSocketOption, bufferSize);
1195 }
1196
sendBufferSize() const1197 qint64 QNativeSocketEngine::sendBufferSize() const
1198 {
1199 Q_D(const QNativeSocketEngine);
1200 return d->option(QAbstractSocketEngine::SendBufferSocketOption);
1201 }
1202
setSendBufferSize(qint64 bufferSize)1203 void QNativeSocketEngine::setSendBufferSize(qint64 bufferSize)
1204 {
1205 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << bufferSize;
1206 Q_D(QNativeSocketEngine);
1207 d->setOption(QAbstractSocketEngine::SendBufferSocketOption, bufferSize);
1208 }
1209
option(QAbstractSocketEngine::SocketOption option) const1210 int QNativeSocketEngine::option(QAbstractSocketEngine::SocketOption option) const
1211 {
1212 Q_D(const QNativeSocketEngine);
1213 return d->option(option);
1214 }
1215
setOption(QAbstractSocketEngine::SocketOption option,int value)1216 bool QNativeSocketEngine::setOption(QAbstractSocketEngine::SocketOption option, int value)
1217 {
1218 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << option << value;
1219 Q_D(QNativeSocketEngine);
1220 return d->setOption(option, value);
1221 }
1222
waitForRead(int msecs,bool * timedOut)1223 bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
1224 {
1225 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << msecs;
1226 Q_D(QNativeSocketEngine);
1227 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
1228 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForRead(),
1229 QAbstractSocket::UnconnectedState, false);
1230
1231 if (timedOut)
1232 *timedOut = false;
1233
1234 QElapsedTimer timer;
1235 timer.start();
1236 while (msecs > timer.elapsed()) {
1237 // Servers with active connections are ready for reading
1238 if (!d->currentConnections.isEmpty())
1239 return true;
1240
1241 // If we are a client, we are ready to read if our buffer has data
1242 QMutexLocker locker(&d->worker->mutex);
1243 if (!d->worker->pendingData.isEmpty())
1244 return true;
1245
1246 // Nothing to do, wait for more events
1247 d->eventLoop.processEvents();
1248 }
1249
1250 d->setError(QAbstractSocket::SocketTimeoutError,
1251 WinRTSocketEngine::TimeOutErrorString);
1252
1253 if (timedOut)
1254 *timedOut = true;
1255 return false;
1256 }
1257
waitForWrite(int msecs,bool * timedOut)1258 bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
1259 {
1260 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << msecs;
1261 Q_UNUSED(timedOut);
1262 Q_D(QNativeSocketEngine);
1263 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
1264 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForWrite(),
1265 QAbstractSocket::UnconnectedState, false);
1266
1267 if (d->socketState == QAbstractSocket::ConnectingState) {
1268 HRESULT hr = QWinRTFunctions::await(d->worker->connectOp, QWinRTFunctions::ProcessMainThreadEvents);
1269 if (SUCCEEDED(hr)) {
1270 handleConnectOpFinished(true, QAbstractSocket::UnknownSocketError, WinRTSocketEngine::UnknownSocketErrorString);
1271 return true;
1272 }
1273 }
1274 return false;
1275 }
1276
waitForReadOrWrite(bool * readyToRead,bool * readyToWrite,bool checkRead,bool checkWrite,int msecs,bool * timedOut)1277 bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, int msecs, bool *timedOut)
1278 {
1279 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << checkRead << checkWrite << msecs;
1280 Q_D(QNativeSocketEngine);
1281 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false);
1282 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
1283 QAbstractSocket::UnconnectedState, false);
1284
1285 Q_UNUSED(readyToRead);
1286 Q_UNUSED(readyToWrite);
1287 Q_UNUSED(timedOut);
1288 return false;
1289 }
1290
isReadNotificationEnabled() const1291 bool QNativeSocketEngine::isReadNotificationEnabled() const
1292 {
1293 Q_D(const QNativeSocketEngine);
1294 return d->notifyOnRead;
1295 }
1296
setReadNotificationEnabled(bool enable)1297 void QNativeSocketEngine::setReadNotificationEnabled(bool enable)
1298 {
1299 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << enable;
1300 Q_D(QNativeSocketEngine);
1301 d->notifyOnRead = enable;
1302 }
1303
isWriteNotificationEnabled() const1304 bool QNativeSocketEngine::isWriteNotificationEnabled() const
1305 {
1306 Q_D(const QNativeSocketEngine);
1307 return d->notifyOnWrite;
1308 }
1309
setWriteNotificationEnabled(bool enable)1310 void QNativeSocketEngine::setWriteNotificationEnabled(bool enable)
1311 {
1312 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << enable;
1313 Q_D(QNativeSocketEngine);
1314 d->notifyOnWrite = enable;
1315 if (enable && d->socketState == QAbstractSocket::ConnectedState) {
1316 if (bytesToWrite())
1317 return; // will be emitted as a result of bytes written
1318 writeNotification();
1319 }
1320 }
1321
isExceptionNotificationEnabled() const1322 bool QNativeSocketEngine::isExceptionNotificationEnabled() const
1323 {
1324 Q_D(const QNativeSocketEngine);
1325 return d->notifyOnException;
1326 }
1327
setExceptionNotificationEnabled(bool enable)1328 void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
1329 {
1330 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << enable;
1331 Q_D(QNativeSocketEngine);
1332 d->notifyOnException = enable;
1333 }
1334
establishRead()1335 void QNativeSocketEngine::establishRead()
1336 {
1337 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
1338 Q_D(QNativeSocketEngine);
1339
1340 HRESULT hr;
1341 hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
1342 d->worker->setTcpSocket(d->tcpSocket());
1343 d->worker->startReading();
1344 return S_OK;
1345 });
1346 Q_ASSERT_SUCCEEDED(hr);
1347 }
1348
handleConnectOpFinished(bool success,QAbstractSocket::SocketError error,WinRTSocketEngine::ErrorString errorString)1349 void QNativeSocketEngine::handleConnectOpFinished(bool success, QAbstractSocket::SocketError error, WinRTSocketEngine::ErrorString errorString)
1350 {
1351 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << success << error << errorString;
1352 Q_D(QNativeSocketEngine);
1353 disconnect(d->worker, &SocketEngineWorker::connectOpFinished,
1354 this, &QNativeSocketEngine::handleConnectOpFinished);
1355 if (!success) {
1356 d->setError(error, errorString);
1357 d->socketState = QAbstractSocket::UnconnectedState;
1358 close();
1359 return;
1360 }
1361
1362 d->socketState = QAbstractSocket::ConnectedState;
1363 d->fetchConnectionParameters();
1364 emit connectionReady();
1365
1366 if (d->socketType != QAbstractSocket::TcpSocket)
1367 return;
1368
1369 #ifndef QT_NO_SSL
1370 // Delay the reader so that the SSL socket can upgrade
1371 if (d->sslSocket)
1372 QObject::connect(qobject_cast<QSslSocket *>(d->sslSocket), &QSslSocket::encrypted, this, &QNativeSocketEngine::establishRead);
1373 else
1374 #endif
1375 establishRead();
1376 }
1377
handleNewData()1378 void QNativeSocketEngine::handleNewData()
1379 {
1380 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO;
1381 Q_D(QNativeSocketEngine);
1382
1383 if (d->notifyOnRead && d->emitReadReady) {
1384 if (d->socketType == QAbstractSocket::UdpSocket && !d->worker->emitDataReceived)
1385 return;
1386 qCDebug(lcNetworkSocketVerbose) << this << Q_FUNC_INFO << "Emitting readReady";
1387 d->pendingReadNotification = true;
1388 emit readReady();
1389 d->worker->emitDataReceived = false;
1390 d->emitReadReady = false;
1391 }
1392 }
1393
handleTcpError(QAbstractSocket::SocketError error)1394 void QNativeSocketEngine::handleTcpError(QAbstractSocket::SocketError error)
1395 {
1396 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << error;
1397 Q_D(QNativeSocketEngine);
1398 WinRTSocketEngine::ErrorString errorString;
1399 switch (error) {
1400 case QAbstractSocket::RemoteHostClosedError:
1401 errorString = WinRTSocketEngine::RemoteHostClosedErrorString;
1402 break;
1403 default:
1404 errorString = WinRTSocketEngine::UnknownSocketErrorString;
1405 }
1406
1407 d->setError(error, errorString);
1408 close();
1409 }
1410
processReadReady()1411 void QNativeSocketEngine::processReadReady()
1412 {
1413 Q_D(QNativeSocketEngine);
1414 if (d->closingDown)
1415 return;
1416
1417 d->pendingReadNotification = false;
1418 readNotification();
1419 }
1420
createNewSocket(QAbstractSocket::SocketType socketType,QAbstractSocket::NetworkLayerProtocol & socketProtocol)1421 bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
1422 {
1423 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << socketType << socketProtocol;
1424 Q_UNUSED(socketProtocol);
1425 HRESULT hr;
1426
1427 switch (socketType) {
1428 case QAbstractSocket::TcpSocket: {
1429 ComPtr<IStreamSocket> socket;
1430 hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &socket);
1431 RETURN_FALSE_IF_FAILED("createNewSocket: Could not create socket instance");
1432 socketDescriptor = qintptr(socket.Detach());
1433 break;
1434 }
1435 case QAbstractSocket::UdpSocket: {
1436 ComPtr<IDatagramSocket> socket;
1437 hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &socket);
1438 RETURN_FALSE_IF_FAILED("createNewSocket: Could not create socket instance");
1439 socketDescriptor = qintptr(socket.Detach());
1440 QEventDispatcherWinRT::runOnXamlThread([&hr, this]() {
1441 hr = udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(worker, &SocketEngineWorker::OnNewDatagramReceived).Get(), &connectionToken);
1442 if (FAILED(hr)) {
1443 qErrnoWarning(hr, "createNewSocket: Could not add \"message received\" callback");
1444 return hr;
1445 }
1446 return S_OK;
1447 });
1448 if (FAILED(hr))
1449 return false;
1450 break;
1451 }
1452 default:
1453 qWarning("Invalid socket type");
1454 return false;
1455 }
1456
1457 this->socketType = socketType;
1458
1459 // Make the socket nonblocking.
1460 if (!setOption(QAbstractSocketEngine::NonBlockingSocketOption, 1)) {
1461 setError(QAbstractSocket::UnsupportedSocketOperationError, WinRTSocketEngine::NonBlockingInitFailedErrorString);
1462 q_func()->close();
1463 return false;
1464 }
1465
1466 return true;
1467 }
1468
QNativeSocketEnginePrivate()1469 QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
1470 : QAbstractSocketEnginePrivate()
1471 , notifyOnRead(true)
1472 , notifyOnWrite(true)
1473 , notifyOnException(false)
1474 , closingDown(false)
1475 , socketDescriptor(-1)
1476 , worker(new SocketEngineWorker(this))
1477 , sslSocket(nullptr)
1478 , connectionToken( { -1 } )
1479 {
1480 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
1481 }
1482
~QNativeSocketEnginePrivate()1483 QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
1484 {
1485 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
1486 if (socketDescriptor == -1 || connectionToken.value == -1)
1487 return;
1488
1489 HRESULT hr;
1490 if (socketType == QAbstractSocket::UdpSocket)
1491 hr = udpSocket()->remove_MessageReceived(connectionToken);
1492 else if (socketType == QAbstractSocket::TcpSocket)
1493 hr = tcpListener->remove_ConnectionReceived(connectionToken);
1494 Q_ASSERT_SUCCEEDED(hr);
1495
1496 worker->deleteLater();
1497 }
1498
setError(QAbstractSocket::SocketError error,WinRTSocketEngine::ErrorString errorString) const1499 void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, WinRTSocketEngine::ErrorString errorString) const
1500 {
1501 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << error << errorString;
1502 if (hasSetSocketError) {
1503 // Only set socket errors once for one engine; expect the
1504 // socket to recreate its engine after an error. Note: There's
1505 // one exception: SocketError(11) bypasses this as it's purely
1506 // a temporary internal error condition.
1507 // Another exception is the way the waitFor*() functions set
1508 // an error when a timeout occurs. After the call to setError()
1509 // they reset the hasSetSocketError to false
1510 return;
1511 }
1512 if (error != QAbstractSocket::SocketError(11))
1513 hasSetSocketError = true;
1514
1515 socketError = error;
1516
1517 switch (errorString) {
1518 case WinRTSocketEngine::NonBlockingInitFailedErrorString:
1519 socketErrorString = QNativeSocketEngine::tr("Unable to initialize non-blocking socket");
1520 break;
1521 case WinRTSocketEngine::BroadcastingInitFailedErrorString:
1522 socketErrorString = QNativeSocketEngine::tr("Unable to initialize broadcast socket");
1523 break;
1524 // should not happen anymore
1525 case WinRTSocketEngine::NoIpV6ErrorString:
1526 socketErrorString = QNativeSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support");
1527 break;
1528 case WinRTSocketEngine::RemoteHostClosedErrorString:
1529 socketErrorString = QNativeSocketEngine::tr("The remote host closed the connection");
1530 break;
1531 case WinRTSocketEngine::TimeOutErrorString:
1532 socketErrorString = QNativeSocketEngine::tr("Network operation timed out");
1533 break;
1534 case WinRTSocketEngine::ResourceErrorString:
1535 socketErrorString = QNativeSocketEngine::tr("Out of resources");
1536 break;
1537 case WinRTSocketEngine::OperationUnsupportedErrorString:
1538 socketErrorString = QNativeSocketEngine::tr("Unsupported socket operation");
1539 break;
1540 case WinRTSocketEngine::ProtocolUnsupportedErrorString:
1541 socketErrorString = QNativeSocketEngine::tr("Protocol type not supported");
1542 break;
1543 case WinRTSocketEngine::InvalidSocketErrorString:
1544 socketErrorString = QNativeSocketEngine::tr("Invalid socket descriptor");
1545 break;
1546 case WinRTSocketEngine::HostUnreachableErrorString:
1547 socketErrorString = QNativeSocketEngine::tr("Host unreachable");
1548 break;
1549 case WinRTSocketEngine::NetworkUnreachableErrorString:
1550 socketErrorString = QNativeSocketEngine::tr("Network unreachable");
1551 break;
1552 case WinRTSocketEngine::AccessErrorString:
1553 socketErrorString = QNativeSocketEngine::tr("Permission denied");
1554 break;
1555 case WinRTSocketEngine::ConnectionTimeOutErrorString:
1556 socketErrorString = QNativeSocketEngine::tr("Connection timed out");
1557 break;
1558 case WinRTSocketEngine::ConnectionRefusedErrorString:
1559 socketErrorString = QNativeSocketEngine::tr("Connection refused");
1560 break;
1561 case WinRTSocketEngine::AddressInuseErrorString:
1562 socketErrorString = QNativeSocketEngine::tr("The bound address is already in use");
1563 break;
1564 case WinRTSocketEngine::AddressNotAvailableErrorString:
1565 socketErrorString = QNativeSocketEngine::tr("The address is not available");
1566 break;
1567 case WinRTSocketEngine::AddressProtectedErrorString:
1568 socketErrorString = QNativeSocketEngine::tr("The address is protected");
1569 break;
1570 case WinRTSocketEngine::DatagramTooLargeErrorString:
1571 socketErrorString = QNativeSocketEngine::tr("Datagram was too large to send");
1572 break;
1573 case WinRTSocketEngine::SendDatagramErrorString:
1574 socketErrorString = QNativeSocketEngine::tr("Unable to send a message");
1575 break;
1576 case WinRTSocketEngine::ReceiveDatagramErrorString:
1577 socketErrorString = QNativeSocketEngine::tr("Unable to receive a message");
1578 break;
1579 case WinRTSocketEngine::WriteErrorString:
1580 socketErrorString = QNativeSocketEngine::tr("Unable to write");
1581 break;
1582 case WinRTSocketEngine::ReadErrorString:
1583 socketErrorString = QNativeSocketEngine::tr("Network error");
1584 break;
1585 case WinRTSocketEngine::PortInuseErrorString:
1586 socketErrorString = QNativeSocketEngine::tr("Another socket is already listening on the same port");
1587 break;
1588 case WinRTSocketEngine::NotSocketErrorString:
1589 socketErrorString = QNativeSocketEngine::tr("Operation on non-socket");
1590 break;
1591 case WinRTSocketEngine::InvalidProxyTypeString:
1592 socketErrorString = QNativeSocketEngine::tr("The proxy type is invalid for this operation");
1593 break;
1594 case WinRTSocketEngine::TemporaryErrorString:
1595 socketErrorString = QNativeSocketEngine::tr("Temporary error");
1596 break;
1597 case WinRTSocketEngine::UnknownSocketErrorString:
1598 socketErrorString = QNativeSocketEngine::tr("Unknown error");
1599 break;
1600 }
1601 }
1602
option(QAbstractSocketEngine::SocketOption opt) const1603 int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) const
1604 {
1605 ComPtr<IStreamSocketControl> control;
1606 if (socketType == QAbstractSocket::TcpSocket) {
1607 if (FAILED(tcpSocket()->get_Control(&control))) {
1608 qWarning("QNativeSocketEnginePrivate::option: Could not obtain socket control");
1609 return -1;
1610 }
1611 }
1612 switch (opt) {
1613 case QAbstractSocketEngine::NonBlockingSocketOption:
1614 case QAbstractSocketEngine::BroadcastSocketOption:
1615 case QAbstractSocketEngine::ReceiveOutOfBandData:
1616 return 1;
1617 case QAbstractSocketEngine::SendBufferSocketOption:
1618 if (socketType == QAbstractSocket::UdpSocket)
1619 return -1;
1620
1621 UINT32 bufferSize;
1622 if (FAILED(control->get_OutboundBufferSizeInBytes(&bufferSize))) {
1623 qWarning("Could not obtain OutboundBufferSizeInBytes information vom socket control");
1624 return -1;
1625 }
1626 return bufferSize;
1627 case QAbstractSocketEngine::LowDelayOption:
1628 if (socketType == QAbstractSocket::UdpSocket)
1629 return -1;
1630
1631 boolean noDelay;
1632 if (FAILED(control->get_NoDelay(&noDelay))) {
1633 qWarning("Could not obtain NoDelay information from socket control");
1634 return -1;
1635 }
1636 return noDelay;
1637 case QAbstractSocketEngine::KeepAliveOption:
1638 if (socketType == QAbstractSocket::UdpSocket)
1639 return -1;
1640
1641 boolean keepAlive;
1642 if (FAILED(control->get_KeepAlive(&keepAlive))) {
1643 qWarning("Could not obtain KeepAlive information from socket control");
1644 return -1;
1645 }
1646 return keepAlive;
1647 case QAbstractSocketEngine::ReceiveBufferSocketOption:
1648 case QAbstractSocketEngine::AddressReusable:
1649 case QAbstractSocketEngine::BindExclusively:
1650 case QAbstractSocketEngine::MulticastTtlOption:
1651 case QAbstractSocketEngine::MulticastLoopbackOption:
1652 case QAbstractSocketEngine::TypeOfServiceOption:
1653 case QAbstractSocketEngine::MaxStreamsSocketOption:
1654 case QAbstractSocketEngine::PathMtuInformation:
1655 default:
1656 return -1;
1657 }
1658 return -1;
1659 }
1660
setOption(QAbstractSocketEngine::SocketOption opt,int v)1661 bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption opt, int v)
1662 {
1663 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO << opt << v;
1664 ComPtr<IStreamSocketControl> control;
1665 if (socketType == QAbstractSocket::TcpSocket) {
1666 if (FAILED(tcpSocket()->get_Control(&control))) {
1667 qWarning("QNativeSocketEnginePrivate::setOption: Could not obtain socket control");
1668 return false;
1669 }
1670 }
1671 switch (opt) {
1672 case QAbstractSocketEngine::NonBlockingSocketOption:
1673 case QAbstractSocketEngine::BroadcastSocketOption:
1674 case QAbstractSocketEngine::ReceiveOutOfBandData:
1675 return v != 0;
1676 case QAbstractSocketEngine::SendBufferSocketOption:
1677 if (socketType == QAbstractSocket::UdpSocket)
1678 return false;
1679
1680 if (FAILED(control->put_OutboundBufferSizeInBytes(v))) {
1681 qWarning("Could not set OutboundBufferSizeInBytes");
1682 return false;
1683 }
1684 return true;
1685 case QAbstractSocketEngine::LowDelayOption: {
1686 if (socketType == QAbstractSocket::UdpSocket)
1687 return false;
1688
1689 boolean noDelay = v;
1690 if (FAILED(control->put_NoDelay(noDelay))) {
1691 qWarning("Could not obtain NoDelay information from socket control");
1692 return false;
1693 }
1694 return true;
1695 }
1696 case QAbstractSocketEngine::KeepAliveOption: {
1697 if (socketType == QAbstractSocket::UdpSocket
1698 || socketState != QAbstractSocket::UnconnectedState)
1699 return false;
1700
1701 boolean keepAlive = v;
1702 if (FAILED(control->put_KeepAlive(keepAlive))) {
1703 qWarning("Could not set KeepAlive value");
1704 return false;
1705 }
1706 return true;
1707 }
1708 case QAbstractSocketEngine::ReceiveBufferSocketOption:
1709 case QAbstractSocketEngine::AddressReusable:
1710 case QAbstractSocketEngine::BindExclusively:
1711 case QAbstractSocketEngine::MulticastTtlOption:
1712 case QAbstractSocketEngine::MulticastLoopbackOption:
1713 case QAbstractSocketEngine::TypeOfServiceOption:
1714 case QAbstractSocketEngine::MaxStreamsSocketOption:
1715 case QAbstractSocketEngine::PathMtuInformation:
1716 default:
1717 return false;
1718 }
1719 return false;
1720 }
1721
fetchConnectionParameters()1722 bool QNativeSocketEnginePrivate::fetchConnectionParameters()
1723 {
1724 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
1725 localPort = 0;
1726 localAddress.clear();
1727 peerPort = 0;
1728 peerAddress.clear();
1729 inboundStreamCount = outboundStreamCount = 0;
1730
1731 HRESULT hr;
1732 if (socketType == QAbstractSocket::TcpSocket) {
1733 ComPtr<IHostName> hostName;
1734 HString tmpHString;
1735 ComPtr<IStreamSocketInformation> info;
1736 hr = tcpSocket()->get_Information(&info);
1737 Q_ASSERT_SUCCEEDED(hr);
1738 hr = info->get_LocalAddress(&hostName);
1739 Q_ASSERT_SUCCEEDED(hr);
1740 if (hostName) {
1741 hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
1742 Q_ASSERT_SUCCEEDED(hr);
1743 localAddress.setAddress(qt_QStringFromHString(tmpHString));
1744 hr = info->get_LocalPort(tmpHString.GetAddressOf());
1745 Q_ASSERT_SUCCEEDED(hr);
1746 localPort = qt_QStringFromHString(tmpHString).toInt();
1747 }
1748 if (!localPort && tcpListener) {
1749 ComPtr<IStreamSocketListenerInformation> listenerInfo = 0;
1750 hr = tcpListener->get_Information(&listenerInfo);
1751 Q_ASSERT_SUCCEEDED(hr);
1752 hr = listenerInfo->get_LocalPort(tmpHString.GetAddressOf());
1753 Q_ASSERT_SUCCEEDED(hr);
1754 localPort = qt_QStringFromHString(tmpHString).toInt();
1755 localAddress = QHostAddress::Any;
1756 }
1757 info->get_RemoteAddress(&hostName);
1758 if (hostName) {
1759 hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
1760 Q_ASSERT_SUCCEEDED(hr);
1761 peerAddress.setAddress(qt_QStringFromHString(tmpHString));
1762 hr = info->get_RemotePort(tmpHString.GetAddressOf());
1763 Q_ASSERT_SUCCEEDED(hr);
1764 peerPort = qt_QStringFromHString(tmpHString).toInt();
1765 inboundStreamCount = outboundStreamCount = 1;
1766 }
1767 } else if (socketType == QAbstractSocket::UdpSocket) {
1768 ComPtr<IHostName> hostName;
1769 HString tmpHString;
1770 ComPtr<IDatagramSocketInformation> info;
1771 hr = udpSocket()->get_Information(&info);
1772 Q_ASSERT_SUCCEEDED(hr);
1773 hr = info->get_LocalAddress(&hostName);
1774 Q_ASSERT_SUCCEEDED(hr);
1775 if (hostName) {
1776 hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
1777 Q_ASSERT_SUCCEEDED(hr);
1778 localAddress.setAddress(qt_QStringFromHString(tmpHString));
1779 hr = info->get_LocalPort(tmpHString.GetAddressOf());
1780 Q_ASSERT_SUCCEEDED(hr);
1781 localPort = qt_QStringFromHString(tmpHString).toInt();
1782 }
1783
1784 hr = info->get_RemoteAddress(&hostName);
1785 Q_ASSERT_SUCCEEDED(hr);
1786 if (hostName) {
1787 hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
1788 Q_ASSERT_SUCCEEDED(hr);
1789 peerAddress.setAddress(qt_QStringFromHString(tmpHString));
1790 hr = info->get_RemotePort(tmpHString.GetAddressOf());
1791 Q_ASSERT_SUCCEEDED(hr);
1792 peerPort = qt_QStringFromHString(tmpHString).toInt();
1793 inboundStreamCount = outboundStreamCount = 1;
1794 }
1795 }
1796 return true;
1797 }
1798
handleClientConnection(IStreamSocketListener * listener,IStreamSocketListenerConnectionReceivedEventArgs * args)1799 HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener *listener, IStreamSocketListenerConnectionReceivedEventArgs *args)
1800 {
1801 qCDebug(lcNetworkSocket) << this << Q_FUNC_INFO;
1802 Q_Q(QNativeSocketEngine);
1803 Q_UNUSED(listener)
1804 IStreamSocket *socket;
1805 args->get_Socket(&socket);
1806 pendingConnections.append(socket);
1807 emit q->connectionReady();
1808 if (notifyOnRead)
1809 emit q->readReady();
1810 return S_OK;
1811 }
1812
1813 QT_END_NAMESPACE
1814
1815 #include "qnativesocketengine_winrt.moc"
1816