summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOliver Wolff <oliver.wolff@qt.io>2016-06-03 10:39:46 +0200
committerOliver Wolff <oliver.wolff@qt.io>2016-06-13 06:13:07 +0000
commit0f6ededb157b3739b95c470f8dbf7b8bbb5a61cc (patch)
tree5332d5dc52c3e82b22f996feb5af710c921355d9 /src
parentd4e98a9a3856d60d52d54870af8dcefa907acf92 (diff)
WinRT: Proper error handling in socket engine's "bind"
runOnXamlThread should always return S_OK (causes exceptions otherwise) so we need another way of error reporting to the outside (hr reference). A failed hr is reported to the outside (of the lambda) and interpreted as an unknown error. Specific error cases like the given address not being a local address or the given address being in use already are handled inside the lambda. The specificErrorSet variable is necessary in these cases so that the error is not overwritten by unknownError. Change-Id: I198d66fe97726d5127bf31e50c7eff3363d5259c Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp47
1 files changed, 37 insertions, 10 deletions
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index 3a4ef4b400..b926583c46 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -342,19 +342,21 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
{
Q_D(QNativeSocketEngine);
HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([address, d, port, this]() {
- HRESULT hr;
+ // runOnXamlThread may only return S_OK (will assert otherwise) so no need to check its result.
+ // hr is set inside the lambda though. If an error occurred hr will point that out.
+ bool specificErrorSet = false;
+ QEventDispatcherWinRT::runOnXamlThread([address, d, &hr, port, &specificErrorSet, this]() {
ComPtr<IHostName> hostAddress;
if (address != QHostAddress::Any && address != QHostAddress::AnyIPv4 && address != QHostAddress::AnyIPv6) {
ComPtr<IHostNameFactory> hostNameFactory;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory);
- RETURN_HR_IF_FAILED("QNativeSocketEngine::bind: Could not obtain hostname factory");
+ RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not obtain hostname factory");
const QString addressString = address.toString();
HStringReference addressRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
hr = hostNameFactory->CreateHostName(addressRef.Get(), &hostAddress);
- RETURN_HR_IF_FAILED("QNativeSocketEngine::bind: Could not create hostname.");
+ RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not create hostname.");
}
QString portQString = port ? QString::number(port) : QString();
@@ -365,13 +367,13 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
if (!d->tcpListener) {
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
&d->tcpListener);
- RETURN_HR_IF_FAILED("QNativeSocketEngine::bind: Could not create tcp listener");
+ RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not create tcp listener");
}
hr = d->tcpListener->add_ConnectionReceived(
Callback<ClientConnectedHandler>(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(),
&d->connectionToken);
- RETURN_HR_IF_FAILED("QNativeSocketEngine::bind: Could not register client connection callback");
+ RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not register client connection callback");
hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
} else if (d->socketType == QAbstractSocket::UdpSocket) {
hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
@@ -379,15 +381,40 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
if (hr == E_ACCESSDENIED) {
qErrnoWarning(hr, "Unable to bind socket (%s:%hu/%s). Please check your manifest capabilities.",
qPrintable(address.toString()), port, socketDescription(this).constData());
- return hr;
+ d->setError(QAbstractSocket::SocketAccessError,
+ QNativeSocketEnginePrivate::AccessErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ specificErrorSet = true;
+ return S_OK;
}
- RETURN_HR_IF_FAILED("QNativeSocketEngine::bind: Unable to bind socket");
+ RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Unable to bind socket");
hr = QWinRTFunctions::await(op);
- RETURN_HR_IF_FAILED("QNativeSocketEngine::bind: Could not wait for bind to finish");
+ if (hr == 0x80072741) { // The requested address is not valid in its context
+ d->setError(QAbstractSocket::SocketAddressNotAvailableError,
+ QNativeSocketEnginePrivate::AddressNotAvailableErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ specificErrorSet = true;
+ return S_OK;
+ // Only one usage of each socket address (protocol/network address/port) is normally permitted
+ } else if (hr == 0x80072740) {
+ d->setError(QAbstractSocket::AddressInUseError,
+ QNativeSocketEnginePrivate::AddressInuseErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ specificErrorSet = true;
+ return S_OK;
+ }
+ RETURN_OK_IF_FAILED("QNativeSocketEngine::bind: Could not wait for bind to finish");
return S_OK;
});
- Q_ASSERT_SUCCEEDED(hr);
+ if (FAILED(hr)) {
+ if (!specificErrorSet) {
+ d->setError(QAbstractSocket::UnknownSocketError,
+ QNativeSocketEnginePrivate::UnknownSocketErrorString);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ }
+ return false;
+ }
d->socketState = QAbstractSocket::BoundState;
return d->fetchConnectionParameters();