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:
parent
51b19c0d86
commit
b91389fef0
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user