winrt: Add support for Windows Information Protection

Windows Information Protection is used for splitting corporate and
personal data, requiring connections to be established in a different
way instantiating ThreadNetworkContext.

Usage is enabled via the QT_WINRT_USE_THREAD_NETWORK_CONTEXT environment
variable.

Change-Id: I3aaa097b66fc616d42cd05a1e20bbcb004f6e467
Reviewed-by: James Tong
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
Maurice Kalinowski 2016-11-04 13:46:36 +01:00
parent 20017d0b1b
commit e9fa435652
2 changed files with 76 additions and 5 deletions

View File

@ -1113,10 +1113,15 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
// Tries to connect to the address. If it succeeds immediately
// (localhost address on BSD or any UDP connect), emit
// connected() and return.
if (socketEngine->connectToHost(host, port)) {
//_q_testConnection();
fetchConnectionParameters();
return;
if (
#if defined(Q_OS_WINRT) && _MSC_VER >= 1900
!qEnvironmentVariableIsEmpty("QT_WINRT_USE_THREAD_NETWORK_CONTEXT") ?
socketEngine->connectToHostByName(hostName, port) :
#endif
socketEngine->connectToHost(host, port)) {
//_q_testConnection();
fetchConnectionParameters();
return;
}
// Check that we're in delayed connection state. If not, try

View File

@ -75,6 +75,9 @@ using namespace ABI::Windows::Storage::Streams;
using namespace ABI::Windows::Networking;
using namespace ABI::Windows::Networking::Connectivity;
using namespace ABI::Windows::Networking::Sockets;
#if _MSC_VER >= 1900
using namespace ABI::Windows::Security::EnterpriseData;
#endif
typedef ITypedEventHandler<StreamSocketListener *, StreamSocketListenerConnectionReceivedEventArgs *> ClientConnectedHandler;
typedef ITypedEventHandler<DatagramSocket *, DatagramSocketMessageReceivedEventArgs *> DatagramReceivedHandler;
@ -84,6 +87,45 @@ typedef IAsyncOperationWithProgress<IBuffer *, UINT32> IAsyncBufferOperation;
QT_BEGIN_NAMESPACE
#if _MSC_VER >= 1900
static HRESULT qt_winrt_try_create_thread_network_context(QString host, ComPtr<IThreadNetworkContext> &context)
{
HRESULT hr;
ComPtr<IProtectionPolicyManagerStatics> protectionPolicyManager;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(),
&protectionPolicyManager);
RETURN_HR_IF_FAILED("Could not access ProtectionPolicyManager statics.");
ComPtr<IHostNameFactory> hostNameFactory;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory);
RETURN_HR_IF_FAILED("Could not access HostName factory.");
ComPtr<IHostName> hostName;
HStringReference hostRef(reinterpret_cast<LPCWSTR>(host.utf16()), host.length());
hr = hostNameFactory->CreateHostName(hostRef.Get(), &hostName);
RETURN_HR_IF_FAILED("Could not create hostname.");
ComPtr<IAsyncOperation<HSTRING>> op;
hr = protectionPolicyManager->GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName.Get(), &op);
RETURN_HR_IF_FAILED("Could not get identity operation.");
HSTRING hIdentity;
hr = QWinRTFunctions::await(op, &hIdentity);
RETURN_HR_IF_FAILED("Could not wait for identity operation.");
// Implies there is no need for a network context for this address
if (hIdentity == nullptr)
return S_OK;
hr = protectionPolicyManager->CreateCurrentThreadNetworkContext(hIdentity, &context);
RETURN_HR_IF_FAILED("Could not create thread network context");
return S_OK;
}
#endif // _MSC_VER >= 1900
static inline QString qt_QStringFromHString(const HString &string)
{
UINT32 length;
@ -367,9 +409,23 @@ bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 por
bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
{
Q_D(QNativeSocketEngine);
HRESULT hr;
#if _MSC_VER >= 1900
ComPtr<IThreadNetworkContext> networkContext;
if (!qEnvironmentVariableIsEmpty("QT_WINRT_USE_THREAD_NETWORK_CONTEXT")) {
hr = qt_winrt_try_create_thread_network_context(name, networkContext);
if (FAILED(hr)) {
setError(QAbstractSocket::ConnectionRefusedError, QLatin1String("Could not create thread network context."));
d->socketState = QAbstractSocket::ConnectedState;
return true;
}
}
#endif // _MSC_VER >= 1900
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(name.utf16()));
ComPtr<IHostNameFactory> hostNameFactory;
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IHostName> remoteHost;
@ -390,6 +446,16 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
}
Q_ASSERT_SUCCEEDED(hr);
#if _MSC_VER >= 1900
if (networkContext != nullptr) {
ComPtr<IClosable> networkContextCloser;
hr = networkContext.As(&networkContextCloser);
Q_ASSERT_SUCCEEDED(hr);
hr = networkContextCloser->Close();
Q_ASSERT_SUCCEEDED(hr);
}
#endif // _MSC_VER >= 1900
d->socketState = QAbstractSocket::ConnectingState;
QEventDispatcherWinRT::runOnXamlThread([d, &hr]() {
hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(