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