winrt: Clean up QNativeSocketEngine

WinRT/Windows Phone "coding guidelines" are now used for the native
socket engine as well.
    - Whenever an operation is expected to succeed
      Q_ASSERT_SUCCEEDED is used.
    - QWinRTFunctions::await is used for waiting for async operations
    - Improved error handling

Change-Id: I6c8d64731da5c94b911a5190231c7c8f68d9c261
Reviewed-by: Andrew Knight <andrew.knight@intopalo.com>
This commit is contained in:
Oliver Wolff 2015-11-10 08:48:57 +01:00
parent 51b19c0d86
commit b91389fef0

View File

@ -150,16 +150,10 @@ static AsyncStatus opStatus(const ComPtr<T> &op)
{ {
ComPtr<IAsyncInfo> info; ComPtr<IAsyncInfo> info;
HRESULT hr = op.As(&info); HRESULT hr = op.As(&info);
if (FAILED(hr)) { Q_ASSERT_SUCCEEDED(hr);
qErrnoWarning(hr, "Failed to cast op to IAsyncInfo.");
return Error;
}
AsyncStatus status; AsyncStatus status;
hr = info->get_Status(&status); hr = info->get_Status(&status);
if (FAILED(hr)) { Q_ASSERT_SUCCEEDED(hr);
qErrnoWarning(hr, "Failed to get AsyncStatus.");
return Error;
}
return status; return status;
} }
@ -265,25 +259,26 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
Q_D(QNativeSocketEngine); Q_D(QNativeSocketEngine);
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(name.utf16())); HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(name.utf16()));
ComPtr<IHostNameFactory> hostNameFactory; ComPtr<IHostNameFactory> hostNameFactory;
GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory); &hostNameFactory);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IHostName> remoteHost; ComPtr<IHostName> remoteHost;
if (FAILED(hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost))) { hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not create hostname"); RETURN_FALSE_IF_FAILED("QNativeSocketEngine::connectToHostByName: Could not create hostname.");
return false;
}
const QString portString = QString::number(port); const QString portString = QString::number(port);
HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16())); HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
HRESULT hr = E_FAIL;
if (d->socketType == QAbstractSocket::TcpSocket) if (d->socketType == QAbstractSocket::TcpSocket)
hr = d->tcpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp); hr = d->tcpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
else if (d->socketType == QAbstractSocket::UdpSocket) else if (d->socketType == QAbstractSocket::UdpSocket)
hr = d->udpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp); hr = d->udpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
if (FAILED(hr)) { if (hr == E_ACCESSDENIED) {
qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not obtain connect action"); qErrnoWarning(hr, "QNativeSocketEngine::connectToHostByName: Unable to connect to host. \
Please check your manifest capabilities.");
return false; return false;
} }
Q_ASSERT_SUCCEEDED(hr);
d->socketState = QAbstractSocket::ConnectingState; d->socketState = QAbstractSocket::ConnectingState;
hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>( hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
d, &QNativeSocketEnginePrivate::handleConnectToHost).Get()); d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
@ -295,68 +290,52 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port) bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
{ {
Q_D(QNativeSocketEngine); Q_D(QNativeSocketEngine);
HRESULT hr;
ComPtr<IHostName> hostAddress; ComPtr<IHostName> hostAddress;
if (address != QHostAddress::Any && address != QHostAddress::AnyIPv4 && address != QHostAddress::AnyIPv6) { if (address != QHostAddress::Any && address != QHostAddress::AnyIPv4 && address != QHostAddress::AnyIPv6) {
ComPtr<IHostNameFactory> hostNameFactory; ComPtr<IHostNameFactory> hostNameFactory;
GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory); &hostNameFactory);
Q_ASSERT_SUCCEEDED(hr);
const QString addressString = address.toString(); const QString addressString = address.toString();
HStringReference addressRef(reinterpret_cast<LPCWSTR>(addressString.utf16())); HStringReference addressRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
hostNameFactory->CreateHostName(addressRef.Get(), &hostAddress); hr = hostNameFactory->CreateHostName(addressRef.Get(), &hostAddress);
RETURN_FALSE_IF_FAILED("QNativeSocketEngine::bind: Could not create hostname.");
} }
HRESULT hr;
QString portQString = port ? QString::number(port) : QString(); QString portQString = port ? QString::number(port) : QString();
HStringReference portString(reinterpret_cast<LPCWSTR>(portQString.utf16())); HStringReference portString(reinterpret_cast<LPCWSTR>(portQString.utf16()));
ComPtr<IAsyncAction> op; ComPtr<IAsyncAction> op;
if (d->socketType == QAbstractSocket::TcpSocket) { if (d->socketType == QAbstractSocket::TcpSocket) {
if (!d->tcpListener if (!d->tcpListener) {
&& FAILED(RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(), hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
&d->tcpListener))) { &d->tcpListener);
qWarning("Failed to create listener"); Q_ASSERT_SUCCEEDED(hr);
return false;
} }
d->tcpListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(), &d->connectionToken); hr = d->tcpListener->add_ConnectionReceived(
Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(),
&d->connectionToken);
Q_ASSERT_SUCCEEDED(hr);
hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op); hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message
return false;
}
} else if (d->socketType == QAbstractSocket::UdpSocket) { } else if (d->socketType == QAbstractSocket::UdpSocket) {
hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op); hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message
return false;
}
hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(d, &QNativeSocketEnginePrivate::handleBindCompleted).Get());
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to set bind callback.");
return false;
}
} }
if (hr == E_ACCESSDENIED) {
if (op) { qErrnoWarning(hr, "Unable to bind socket. Please check your manifest capabilities.");
while (opStatus(op) == Started) return false;
d->eventLoop.processEvents();
AsyncStatus status = opStatus(op);
if (status == Error || status == Canceled)
return false;
hr = op->GetResults();
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to bind socket");
return false;
}
d->socketState = QAbstractSocket::BoundState;
d->fetchConnectionParameters();
return true;
} }
Q_ASSERT_SUCCEEDED(hr);
return false; hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(d, &QNativeSocketEnginePrivate::handleBindCompleted).Get());
Q_ASSERT_SUCCEEDED(hr);
hr = QWinRTFunctions::await(op);
Q_ASSERT_SUCCEEDED(hr);
d->socketState = QAbstractSocket::BoundState;
return d->fetchConnectionParameters();
} }
bool QNativeSocketEngine::listen() bool QNativeSocketEngine::listen()
@ -430,27 +409,36 @@ void QNativeSocketEngine::close()
d->notifyOnWrite = false; d->notifyOnWrite = false;
d->notifyOnException = false; d->notifyOnException = false;
HRESULT hr;
if (d->connectOp) { if (d->connectOp) {
ComPtr<IAsyncInfo> info; ComPtr<IAsyncInfo> info;
d->connectOp.As(&info); hr = d->connectOp.As(&info);
Q_ASSERT_SUCCEEDED(hr);
if (info) { if (info) {
info->Cancel(); hr = info->Cancel();
info->Close(); Q_ASSERT_SUCCEEDED(hr);
hr = info->Close();
Q_ASSERT_SUCCEEDED(hr);
} }
} }
if (d->socketDescriptor != -1) { if (d->socketDescriptor != -1) {
ComPtr<IClosable> socket; ComPtr<IClosable> socket;
if (d->socketType == QAbstractSocket::TcpSocket) { if (d->socketType == QAbstractSocket::TcpSocket) {
d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket)); hr = d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
d->tcpSocket()->Release(); Q_ASSERT_SUCCEEDED(hr);
hr = d->tcpSocket()->Release();
Q_ASSERT_SUCCEEDED(hr);
} else if (d->socketType == QAbstractSocket::UdpSocket) { } else if (d->socketType == QAbstractSocket::UdpSocket) {
d->udpSocket()->QueryInterface(IID_PPV_ARGS(&socket)); hr = d->udpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
d->udpSocket()->Release(); Q_ASSERT_SUCCEEDED(hr);
hr = d->udpSocket()->Release();
Q_ASSERT_SUCCEEDED(hr);
} }
if (socket) { if (socket) {
socket->Close(); hr = socket->Close();
Q_ASSERT_SUCCEEDED(hr);
d->socketDescriptor = -1; d->socketDescriptor = -1;
} }
d->socketDescriptor = -1; d->socketDescriptor = -1;
@ -531,7 +519,7 @@ qint64 QNativeSocketEngine::write(const char *data, qint64 len)
hr = d->tcpSocket()->get_OutputStream(&stream); hr = d->tcpSocket()->get_OutputStream(&stream);
else if (d->socketType == QAbstractSocket::UdpSocket) else if (d->socketType == QAbstractSocket::UdpSocket)
hr = d->udpSocket()->get_OutputStream(&stream); hr = d->udpSocket()->get_OutputStream(&stream);
RETURN_IF_FAILED("Failed to get output stream to socket", return -1); Q_ASSERT_SUCCEEDED(hr);
qint64 bytesWritten = writeIOStream(stream, data, len); qint64 bytesWritten = writeIOStream(stream, data, len);
if (bytesWritten < 0) if (bytesWritten < 0)
@ -580,20 +568,21 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QI
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(), HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory); &hostNameFactory);
RETURN_IF_FAILED("Could not obtain hostname factory", return -1); Q_ASSERT_SUCCEEDED(hr);
const QString addressString = header.destinationAddress.toString(); const QString addressString = header.destinationAddress.toString();
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16())); HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost); hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
RETURN_IF_FAILED("QNativeSocketEngine::writeDatagram: Could not create hostname.", return -1);
ComPtr<IAsyncOperation<IOutputStream *>> streamOperation; ComPtr<IAsyncOperation<IOutputStream *>> streamOperation;
ComPtr<IOutputStream> stream; ComPtr<IOutputStream> stream;
const QString portString = QString::number(header.destinationPort); const QString portString = QString::number(header.destinationPort);
HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16())); HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16()));
hr = d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation); hr = d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation);
RETURN_IF_FAILED("Failed to get output stream to socket", return -1); Q_ASSERT_SUCCEEDED(hr);
hr = QWinRTFunctions::await(streamOperation, stream.GetAddressOf()); hr = QWinRTFunctions::await(streamOperation, stream.GetAddressOf());
RETURN_IF_FAILED("Failed to get output stream to socket", return -1); Q_ASSERT_SUCCEEDED(hr);
return writeIOStream(stream, data, len); return writeIOStream(stream, data, len);
} }
@ -778,26 +767,23 @@ void QNativeSocketEngine::establishRead()
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol) bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{ {
Q_UNUSED(socketProtocol); Q_UNUSED(socketProtocol);
HRESULT hr;
switch (socketType) { switch (socketType) {
case QAbstractSocket::TcpSocket: { case QAbstractSocket::TcpSocket: {
ComPtr<IStreamSocket> socket; ComPtr<IStreamSocket> socket;
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &socket); hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &socket);
if (FAILED(hr)) { Q_ASSERT_SUCCEEDED(hr);
qWarning("Failed to create StreamSocket instance");
return false;
}
socketDescriptor = qintptr(socket.Detach()); socketDescriptor = qintptr(socket.Detach());
break; break;
} }
case QAbstractSocket::UdpSocket: { case QAbstractSocket::UdpSocket: {
ComPtr<IDatagramSocket> socket; ComPtr<IDatagramSocket> socket;
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &socket); hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &socket);
if (FAILED(hr)) { Q_ASSERT_SUCCEEDED(hr);
qWarning("Failed to create stream socket");
return false;
}
socketDescriptor = qintptr(socket.Detach()); socketDescriptor = qintptr(socket.Detach());
udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &connectionToken); hr = udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &connectionToken);
Q_ASSERT_SUCCEEDED(hr);
break; break;
} }
default: default:
@ -834,10 +820,12 @@ QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
if (socketDescriptor == -1 || connectionToken.value == -1) if (socketDescriptor == -1 || connectionToken.value == -1)
return; return;
HRESULT hr;
if (socketType == QAbstractSocket::UdpSocket) if (socketType == QAbstractSocket::UdpSocket)
udpSocket()->remove_MessageReceived(connectionToken); hr = udpSocket()->remove_MessageReceived(connectionToken);
else if (socketType == QAbstractSocket::TcpSocket) else if (socketType == QAbstractSocket::TcpSocket)
tcpListener->remove_ConnectionReceived(connectionToken); hr = tcpListener->remove_ConnectionReceived(connectionToken);
Q_ASSERT_SUCCEEDED(hr);
} }
void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const
@ -1064,56 +1052,66 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
peerPort = 0; peerPort = 0;
peerAddress.clear(); peerAddress.clear();
HRESULT hr;
if (socketType == QAbstractSocket::TcpSocket) { if (socketType == QAbstractSocket::TcpSocket) {
ComPtr<IHostName> hostName; ComPtr<IHostName> hostName;
HString tmpHString; HString tmpHString;
ComPtr<IStreamSocketInformation> info; ComPtr<IStreamSocketInformation> info;
if (FAILED(tcpSocket()->get_Information(&info))) { hr = tcpSocket()->get_Information(&info);
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket info"); Q_ASSERT_SUCCEEDED(hr);
return false; hr = info->get_LocalAddress(&hostName);
} Q_ASSERT_SUCCEEDED(hr);
info->get_LocalAddress(&hostName);
if (hostName) { if (hostName) {
hostName->get_CanonicalName(tmpHString.GetAddressOf()); hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
localAddress.setAddress(qt_QStringFromHString(tmpHString)); localAddress.setAddress(qt_QStringFromHString(tmpHString));
info->get_LocalPort(tmpHString.GetAddressOf()); hr = info->get_LocalPort(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
localPort = qt_QStringFromHString(tmpHString).toInt(); localPort = qt_QStringFromHString(tmpHString).toInt();
} }
if (!localPort && tcpListener) { if (!localPort && tcpListener) {
ComPtr<IStreamSocketListenerInformation> listenerInfo = 0; ComPtr<IStreamSocketListenerInformation> listenerInfo = 0;
tcpListener->get_Information(&listenerInfo); hr = tcpListener->get_Information(&listenerInfo);
listenerInfo->get_LocalPort(tmpHString.GetAddressOf()); Q_ASSERT_SUCCEEDED(hr);
hr = listenerInfo->get_LocalPort(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
localPort = qt_QStringFromHString(tmpHString).toInt(); localPort = qt_QStringFromHString(tmpHString).toInt();
localAddress == QHostAddress::Any; localAddress = QHostAddress::Any;
} }
info->get_RemoteAddress(&hostName); info->get_RemoteAddress(&hostName);
if (hostName) { if (hostName) {
hostName->get_CanonicalName(tmpHString.GetAddressOf()); hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
peerAddress.setAddress(qt_QStringFromHString(tmpHString)); peerAddress.setAddress(qt_QStringFromHString(tmpHString));
info->get_RemotePort(tmpHString.GetAddressOf()); hr = info->get_RemotePort(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
peerPort = qt_QStringFromHString(tmpHString).toInt(); peerPort = qt_QStringFromHString(tmpHString).toInt();
} }
} else if (socketType == QAbstractSocket::UdpSocket) { } else if (socketType == QAbstractSocket::UdpSocket) {
ComPtr<IHostName> hostName; ComPtr<IHostName> hostName;
HString tmpHString; HString tmpHString;
ComPtr<IDatagramSocketInformation> info; ComPtr<IDatagramSocketInformation> info;
if (FAILED(udpSocket()->get_Information(&info))) { hr = udpSocket()->get_Information(&info);
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket information"); Q_ASSERT_SUCCEEDED(hr);
return false; hr = info->get_LocalAddress(&hostName);
} Q_ASSERT_SUCCEEDED(hr);
info->get_LocalAddress(&hostName);
if (hostName) { if (hostName) {
hostName->get_CanonicalName(tmpHString.GetAddressOf()); hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
localAddress.setAddress(qt_QStringFromHString(tmpHString)); localAddress.setAddress(qt_QStringFromHString(tmpHString));
info->get_LocalPort(tmpHString.GetAddressOf()); hr = info->get_LocalPort(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
localPort = qt_QStringFromHString(tmpHString).toInt(); localPort = qt_QStringFromHString(tmpHString).toInt();
} }
info->get_RemoteAddress(&hostName); hr = info->get_RemoteAddress(&hostName);
Q_ASSERT_SUCCEEDED(hr);
if (hostName) { if (hostName) {
hostName->get_CanonicalName(tmpHString.GetAddressOf()); hr = hostName->get_CanonicalName(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
peerAddress.setAddress(qt_QStringFromHString(tmpHString)); peerAddress.setAddress(qt_QStringFromHString(tmpHString));
info->get_RemotePort(tmpHString.GetAddressOf()); hr = info->get_RemotePort(tmpHString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
peerPort = qt_QStringFromHString(tmpHString).toInt(); peerPort = qt_QStringFromHString(tmpHString).toInt();
} }
} }
@ -1174,12 +1172,16 @@ void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *actio
// The callback might be triggered several times if we do not cancel/reset it here // The callback might be triggered several times if we do not cancel/reset it here
if (connectOp) { if (connectOp) {
ComPtr<IAsyncInfo> info; ComPtr<IAsyncInfo> info;
connectOp.As(&info); hr = connectOp.As(&info);
Q_ASSERT_SUCCEEDED(hr);
if (info) { if (info) {
info->Cancel(); hr = info->Cancel();
info->Close(); Q_ASSERT_SUCCEEDED(hr);
hr = info->Close();
Q_ASSERT_SUCCEEDED(hr);
} }
connectOp.Reset(); hr = connectOp.Reset();
Q_ASSERT_SUCCEEDED(hr);
} }
socketState = QAbstractSocket::ConnectedState; socketState = QAbstractSocket::ConnectedState;