/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "qpid/client/TCPConnector.h" #include "config.h" #include "qpid/Msg.h" #include "qpid/client/ConnectionImpl.h" #include "qpid/client/ConnectionSettings.h" #include "qpid/log/Statement.h" #include "qpid/sys/Dispatcher.h" #include "qpid/sys/Poller.h" #include "qpid/sys/Time.h" #include "qpid/sys/windows/check.h" #include "qpid/sys/windows/SslAsynchIO.h" #include #include #include #include // security.h needs to see this to distinguish from kernel use. #define SECURITY_WIN32 #include #include #undef SECURITY_WIN32 #include namespace qpid { namespace client { namespace windows { using namespace qpid::sys; using boost::format; using boost::str; class SslConnector : public qpid::client::TCPConnector { qpid::sys::windows::ClientSslAsynchIO *shim; boost::shared_ptr poller; std::string brokerHost; SCHANNEL_CRED cred; CredHandle credHandle; TimeStamp credExpiry; virtual ~SslConnector(); void negotiationDone(SECURITY_STATUS status); // A number of AsynchIO callbacks go right through to TCPConnector, but // we can't boost::bind to a protected ancestor, so these methods redirect // to those TCPConnector methods. void redirectReadbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*); void redirectWritebuff(qpid::sys::AsynchIO&); void redirectEof(qpid::sys::AsynchIO&); void redirectDisconnect(qpid::sys::AsynchIO&); void redirectSocketClosed(qpid::sys::AsynchIO&, const qpid::sys::Socket&); public: SslConnector(boost::shared_ptr, framing::ProtocolVersion pVersion, const ConnectionSettings&, ConnectionImpl*); virtual void connect(const std::string& host, const std::string& port); virtual void connected(const Socket&); }; // Static constructor which registers connector here namespace { Connector* create(boost::shared_ptr p, framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) { return new SslConnector(p, v, s, c); } struct StaticInit { StaticInit() { try { Connector::registerFactory("ssl", &create); } catch (const std::exception& e) { QPID_LOG(error, "Failed to initialise SSL connector: " << e.what()); } }; ~StaticInit() { } } init; } void SslConnector::negotiationDone(SECURITY_STATUS status) { if (status == SEC_E_OK) initAmqp(); else connectFailed(QPID_MSG(qpid::sys::strError(status))); } void SslConnector::redirectReadbuff(qpid::sys::AsynchIO& a, qpid::sys::AsynchIOBufferBase* b) { readbuff(a, b); } void SslConnector::redirectWritebuff(qpid::sys::AsynchIO& a) { writebuff(a); } void SslConnector::redirectEof(qpid::sys::AsynchIO& a) { eof(a); } void SslConnector::redirectDisconnect(qpid::sys::AsynchIO& a) { disconnected(a); } void SslConnector::redirectSocketClosed(qpid::sys::AsynchIO& a, const qpid::sys::Socket& s) { socketClosed(a, s); } SslConnector::SslConnector(boost::shared_ptr p, framing::ProtocolVersion ver, const ConnectionSettings& settings, ConnectionImpl* cimpl) : TCPConnector(p, ver, settings, cimpl), shim(0), poller(p) { memset(&cred, 0, sizeof(cred)); cred.dwVersion = SCHANNEL_CRED_VERSION; SECURITY_STATUS status = ::AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &credHandle, &credExpiry); if (status != SEC_E_OK) throw QPID_WINDOWS_ERROR(status); QPID_LOG(debug, "SslConnector created for " << ver.toString()); } SslConnector::~SslConnector() { ::FreeCredentialsHandle(&credHandle); } // Will this get reach via virtual method via boost::bind???? void SslConnector::connect(const std::string& host, const std::string& port) { brokerHost = host; TCPConnector::connect(host, port); } void SslConnector::connected(const Socket& s) { shim = new qpid::sys::windows::ClientSslAsynchIO(brokerHost, s, credHandle, boost::bind(&SslConnector::redirectReadbuff, this, _1, _2), boost::bind(&SslConnector::redirectEof, this, _1), boost::bind(&SslConnector::redirectDisconnect, this, _1), boost::bind(&SslConnector::redirectSocketClosed, this, _1, _2), 0, // nobuffs boost::bind(&SslConnector::redirectWritebuff, this, _1), boost::bind(&SslConnector::negotiationDone, this, _1)); start(shim); shim->start(poller); } }}} // namespace qpid::client::windows