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