diff options
Diffstat (limited to 'cpp/src/IceSSL/OpenSSLTransceiverI.cpp')
-rw-r--r-- | cpp/src/IceSSL/OpenSSLTransceiverI.cpp | 318 |
1 files changed, 285 insertions, 33 deletions
diff --git a/cpp/src/IceSSL/OpenSSLTransceiverI.cpp b/cpp/src/IceSSL/OpenSSLTransceiverI.cpp index 0f8359f3638..ee10d229f81 100644 --- a/cpp/src/IceSSL/OpenSSLTransceiverI.cpp +++ b/cpp/src/IceSSL/OpenSSLTransceiverI.cpp @@ -8,6 +8,7 @@ // ********************************************************************** #include <IceSSL/OpenSSLTransceiverI.h> +#include <IceSSL/OpenSSLEngine.h> #include <IceUtil/Mutex.h> #include <IceUtil/MutexPtrLock.h> @@ -22,8 +23,7 @@ #include <Ice/LocalException.h> #include <Ice/Network.h> -#ifdef ICE_USE_OPENSSL - +#include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/bio.h> @@ -32,7 +32,7 @@ using namespace Ice; using namespace IceSSL; // -// BUGFIX: an openssl bug that affects OpensSSL < 1.0.0k +// BUGFIX: an openssl bug that affects OpenSSL < 1.0.0k // could cause a deadlock when decoding public keys. // // See: http://cvs.openssl.org/chngview?cn=22569 @@ -71,20 +71,20 @@ int IceSSL_opensslVerifyCallback(int ok, X509_STORE_CTX* ctx) { SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); - TransceiverI* p = reinterpret_cast<TransceiverI*>(SSL_get_ex_data(ssl, 0)); + OpenSSL::TransceiverI* p = reinterpret_cast<OpenSSL::TransceiverI*>(SSL_get_ex_data(ssl, 0)); return p->verifyCallback(ok, ctx); } } IceInternal::NativeInfoPtr -IceSSL::TransceiverI::getNativeInfo() +OpenSSL::TransceiverI::getNativeInfo() { return _delegate->getNativeInfo(); } IceInternal::SocketOperation -IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::Buffer& writeBuffer) +OpenSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::Buffer& writeBuffer) { if(!_connected) { @@ -108,7 +108,23 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B return IceInternal::SocketOperationRead; } +#ifdef ICE_USE_IOCP + _maxSendPacketSize = std::max(512, IceInternal::getSendBufferSize(fd)); + _maxRecvPacketSize = std::max(512, IceInternal::getRecvBufferSize(fd)); + BIO* bio; + _sentBytes = 0; + if(!BIO_new_bio_pair(&bio, _maxSendPacketSize, &_iocpBio, _maxRecvPacketSize)) + { + bio = 0; + _iocpBio = 0; + } +#else + // + // This static_cast is necessary due to 64bit windows. There SOCKET is a non-int type. + // BIO* bio = BIO_new_socket(static_cast<int>(fd), 0); +#endif + if(!bio) { SecurityException ex(__FILE__, __LINE__); @@ -120,6 +136,10 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B if(!_ssl) { BIO_free(bio); +#ifdef ICE_USE_IOCP + BIO_free(_iocpBio); + _iocpBio = 0; +#endif SecurityException ex(__FILE__, __LINE__); ex.reason = "openssl failure"; throw ex; @@ -182,7 +202,7 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B // // - // BUGFIX: an openssl bug that affects OpensSSL < 1.0.0k + // BUGFIX: an openssl bug that affects OpenSSL < 1.0.0k // could cause a deadlock when decoding public keys. // // See: http://cvs.openssl.org/chngview?cn=22569 @@ -196,6 +216,18 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x100000bfL && !defined(LIBRESSL_VERSION_NUMBER) sync.release(); #endif + +#ifdef ICE_USE_IOCP + if(BIO_ctrl_pending(_iocpBio)) + { + if(!send()) + { + return IceInternal::SocketOperationWrite; + } + continue; + } +#endif + if(ret <= 0) { switch(SSL_get_error(_ssl, ret)) @@ -213,14 +245,27 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B } case SSL_ERROR_WANT_READ: { +#ifdef ICE_USE_IOCP + if(receive()) + { + continue; + } +#endif return IceInternal::SocketOperationRead; } case SSL_ERROR_WANT_WRITE: { +#ifdef ICE_USE_IOCP + if(send()) + { + continue; + } +#endif return IceInternal::SocketOperationWrite; } case SSL_ERROR_SYSCALL: { +#ifndef ICE_USE_IOCP if(IceInternal::interrupted()) { break; @@ -246,12 +291,10 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B ex.error = IceInternal::getSocketErrno(); throw ex; } - else - { - SocketException ex(__FILE__, __LINE__); - ex.error = IceInternal::getSocketErrno(); - throw ex; - } +#endif + SocketException ex(__FILE__, __LINE__); + ex.error = IceInternal::getSocketErrno(); + throw ex; } case SSL_ERROR_SSL: { @@ -327,7 +370,7 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B } IceInternal::SocketOperation -IceSSL::TransceiverI::closing(bool initiator, const Ice::LocalException&) +OpenSSL::TransceiverI::closing(bool initiator, const Ice::LocalException&) { // If we are initiating the connection closure, wait for the peer // to close the TCP/IP connection. Otherwise, close immediately. @@ -335,7 +378,7 @@ IceSSL::TransceiverI::closing(bool initiator, const Ice::LocalException&) } void -IceSSL::TransceiverI::close() +OpenSSL::TransceiverI::close() { if(_ssl) { @@ -353,17 +396,35 @@ IceSSL::TransceiverI::close() _ssl = 0; } +#ifdef ICE_USE_IOCP + if(_iocpBio) + { + BIO_free(_iocpBio); + _iocpBio = 0; + } +#endif + _delegate->close(); } IceInternal::SocketOperation -IceSSL::TransceiverI::write(IceInternal::Buffer& buf) +OpenSSL::TransceiverI::write(IceInternal::Buffer& buf) { if(!_connected) { return _delegate->write(buf); } +#ifdef ICE_USE_IOCP + if(_writeBuffer.i != _writeBuffer.b.end()) + { + if(!send()) + { + return IceInternal::SocketOperationWrite; + } + } +#endif + if(buf.i == buf.b.end()) { return IceInternal::SocketOperationNone; @@ -372,11 +433,37 @@ IceSSL::TransceiverI::write(IceInternal::Buffer& buf) // // It's impossible for packetSize to be more than an Int. // - int packetSize = static_cast<int>(buf.b.end() - buf.i); + int packetSize = +#ifdef ICE_USE_IOCP + std::min(static_cast<int>(_maxSendPacketSize), static_cast<int>(buf.b.end() - buf.i)); +#else + static_cast<int>(buf.b.end() - buf.i); +#endif while(buf.i != buf.b.end()) { ERR_clear_error(); // Clear any spurious errors. +#ifdef ICE_USE_IOCP + int ret; + if(_sentBytes) + { + ret = _sentBytes; + _sentBytes = 0; + } + else + { + ret = SSL_write(_ssl, reinterpret_cast<const void*>(&*buf.i), packetSize); + if(ret > 0) + { + if(!send()) + { + _sentBytes = ret; + return IceInternal::SocketOperationWrite; + } + } + } +#else int ret = SSL_write(_ssl, reinterpret_cast<const void*>(&*buf.i), packetSize); +#endif if(ret <= 0) { switch(SSL_get_error(_ssl, ret)) @@ -397,10 +484,18 @@ IceSSL::TransceiverI::write(IceInternal::Buffer& buf) } case SSL_ERROR_WANT_WRITE: { +#ifdef ICE_USE_IOCP + if(send()) + { + continue; + } +#endif return IceInternal::SocketOperationWrite; } case SSL_ERROR_SYSCALL: { +#ifndef ICE_USE_IOCP + if(IceInternal::interrupted()) { continue; @@ -417,7 +512,7 @@ IceSSL::TransceiverI::write(IceInternal::Buffer& buf) assert(SSL_want_write(_ssl)); return IceInternal::SocketOperationWrite; } - +#endif if(IceInternal::connectionLost() || IceInternal::getSocketErrno() == 0) { ConnectionLostException ex(__FILE__, __LINE__); @@ -447,18 +542,27 @@ IceSSL::TransceiverI::write(IceInternal::Buffer& buf) packetSize = static_cast<int>(buf.b.end() - buf.i); } } - return IceInternal::SocketOperationNone; } IceInternal::SocketOperation -IceSSL::TransceiverI::read(IceInternal::Buffer& buf) +OpenSSL::TransceiverI::read(IceInternal::Buffer& buf) { if(!_connected) { return _delegate->read(buf); } +#ifdef ICE_USE_IOCP + if(_readBuffer.i != _readBuffer.b.end()) + { + if(!receive()) + { + return IceInternal::SocketOperationRead; + } + } +#endif + // // Note: We assume that OpenSSL doesn't read more SSL records than // necessary to fill the requested data and that the sender sends @@ -497,6 +601,12 @@ IceSSL::TransceiverI::read(IceInternal::Buffer& buf) } case SSL_ERROR_WANT_READ: { +#ifdef ICE_USE_IOCP + if(receive()) + { + continue; + } +#endif return IceInternal::SocketOperationRead; } case SSL_ERROR_WANT_WRITE: @@ -506,6 +616,7 @@ IceSSL::TransceiverI::read(IceInternal::Buffer& buf) } case SSL_ERROR_SYSCALL: { +#ifndef ICE_USE_IOCP if(IceInternal::interrupted()) { continue; @@ -522,7 +633,7 @@ IceSSL::TransceiverI::read(IceInternal::Buffer& buf) assert(SSL_want_read(_ssl)); return IceInternal::SocketOperationRead; } - +#endif if(IceInternal::connectionLost() || IceInternal::getSocketErrno() == 0) { ConnectionLostException ex(__FILE__, __LINE__); @@ -561,26 +672,108 @@ IceSSL::TransceiverI::read(IceInternal::Buffer& buf) return IceInternal::SocketOperationNone; } +#ifdef ICE_USE_IOCP + +bool +OpenSSL::TransceiverI::startWrite(IceInternal::Buffer& buffer) +{ + if(!_connected) + { + return _delegate->startWrite(buffer); + } + + assert(!_writeBuffer.b.empty() && _writeBuffer.i != _writeBuffer.b.end()); + return _delegate->startWrite(_writeBuffer) && buffer.i == buffer.b.end(); +} + +void +OpenSSL::TransceiverI::finishWrite(IceInternal::Buffer& buffer) +{ + if(!_connected) + { + _delegate->finishWrite(buffer); + return; + } + + _delegate->finishWrite(_writeBuffer); +} + +void +OpenSSL::TransceiverI::startRead(IceInternal::Buffer& buffer) +{ + if(!_connected) + { + _delegate->startRead(buffer); + return; + } + + if(_readBuffer.i == _readBuffer.b.end()) + { + assert(!buffer.b.empty() && buffer.i != buffer.b.end()); + assert(!BIO_ctrl_get_read_request(_iocpBio)); + + ERR_clear_error(); // Clear any spurious errors. +#ifndef NDEBUG + int ret = +#endif + SSL_read(_ssl, reinterpret_cast<void*>(&*buffer.i), static_cast<int>(buffer.b.end() - buffer.i)); + assert(ret <= 0 && SSL_get_error(_ssl, ret) == SSL_ERROR_WANT_READ); + + assert(BIO_ctrl_get_read_request(_iocpBio)); + _readBuffer.b.resize(BIO_ctrl_get_read_request(_iocpBio)); + _readBuffer.i = _readBuffer.b.begin(); + } + + assert(!_readBuffer.b.empty() && _readBuffer.i != _readBuffer.b.end()); + + _delegate->startRead(_readBuffer); +} + +void +OpenSSL::TransceiverI::finishRead(IceInternal::Buffer& buffer) +{ + if(!_connected) + { + _delegate->finishRead(buffer); + return; + } + + _delegate->finishRead(_readBuffer); + if(_iocpBio && _readBuffer.i == _readBuffer.b.end()) + { + assert(_readBuffer.i == _readBuffer.b.end()); + int n = BIO_write(_iocpBio, _readBuffer.b.begin(), static_cast<int>(_readBuffer.b.size())); + if(n < 0) // Expected if the transceiver was closed. + { + SecurityException ex(__FILE__, __LINE__); + ex.reason = "SSL bio write failed"; + throw ex; + } + assert(n == static_cast<int>(_readBuffer.b.size())); + } +} +#endif + string -IceSSL::TransceiverI::protocol() const +OpenSSL::TransceiverI::protocol() const { return _instance->protocol(); } string -IceSSL::TransceiverI::toString() const +OpenSSL::TransceiverI::toString() const { return _delegate->toString(); } string -IceSSL::TransceiverI::toDetailedString() const +OpenSSL::TransceiverI::toDetailedString() const { return toString(); } Ice::ConnectionInfoPtr -IceSSL::TransceiverI::getInfo() const +OpenSSL::TransceiverI::getInfo() const { NativeConnectionInfoPtr info = ICE_MAKE_SHARED(NativeConnectionInfo); info->underlying = _delegate->getInfo(); @@ -594,18 +787,18 @@ IceSSL::TransceiverI::getInfo() const } void -IceSSL::TransceiverI::checkSendSize(const IceInternal::Buffer&) +OpenSSL::TransceiverI::checkSendSize(const IceInternal::Buffer&) { } void -IceSSL::TransceiverI::setBufferSize(int rcvSize, int sndSize) +OpenSSL::TransceiverI::setBufferSize(int rcvSize, int sndSize) { _delegate->setBufferSize(rcvSize, sndSize); } int -IceSSL::TransceiverI::verifyCallback(int ok, X509_STORE_CTX* c) +OpenSSL::TransceiverI::verifyCallback(int ok, X509_STORE_CTX* c) { if(!ok && _engine->securityTraceLevel() >= 1) { @@ -636,7 +829,7 @@ IceSSL::TransceiverI::verifyCallback(int ok, X509_STORE_CTX* c) _certs.clear(); for(int i = 0; i < sk_X509_num(chain); ++i) { - CertificatePtr cert = ICE_MAKE_SHARED(Certificate, X509_dup(sk_X509_value(chain, i))); + CertificatePtr cert = OpenSSL::Certificate::create(X509_dup(sk_X509_value(chain, i))); _nativeCerts.push_back(cert); _certs.push_back(cert->encode()); } @@ -652,10 +845,12 @@ IceSSL::TransceiverI::verifyCallback(int ok, X509_STORE_CTX* c) return 1; } -IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, const IceInternal::TransceiverPtr& delegate, - const string& hostOrAdapterName, bool incoming) : +OpenSSL::TransceiverI::TransceiverI(const InstancePtr& instance, + const IceInternal::TransceiverPtr& delegate, + const string& hostOrAdapterName, + bool incoming) : _instance(instance), - _engine(OpenSSLEnginePtr::dynamicCast(instance->engine())), + _engine(OpenSSL::SSLEnginePtr::dynamicCast(instance->engine())), _host(incoming ? "" : hostOrAdapterName), _adapterName(incoming ? hostOrAdapterName : ""), _incoming(incoming), @@ -663,11 +858,68 @@ IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, const IceInterna _connected(false), _verified(false), _ssl(0) +#ifdef ICE_USE_IOCP + , _iocpBio(0), + _sentBytes(0), + _maxSendPacketSize(0), + _maxRecvPacketSize(0) +#endif { } -IceSSL::TransceiverI::~TransceiverI() +OpenSSL::TransceiverI::~TransceiverI() { } +#ifdef ICE_USE_IOCP +bool +OpenSSL::TransceiverI::receive() +{ + if(_readBuffer.i == _readBuffer.b.end()) + { + assert(BIO_ctrl_get_read_request(_iocpBio)); + _readBuffer.b.resize(BIO_ctrl_get_read_request(_iocpBio)); + _readBuffer.i = _readBuffer.b.begin(); + } + + while(_readBuffer.i != _readBuffer.b.end()) + { + if(_delegate->read(_readBuffer) != IceInternal::SocketOperationNone) + { + return false; + } + } + + assert(_readBuffer.i == _readBuffer.b.end()); + +#ifndef NDEBUG + int n = +#endif + BIO_write(_iocpBio, &_readBuffer.b[0], static_cast<int>(_readBuffer.b.end() - _readBuffer.b.begin())); + + assert(n == static_cast<int>(_readBuffer.b.end() - _readBuffer.b.begin())); + + return true; +} + +bool +OpenSSL::TransceiverI::send() +{ + if(_writeBuffer.i == _writeBuffer.b.end()) + { + assert(BIO_ctrl_pending(_iocpBio)); + _writeBuffer.b.resize( BIO_ctrl_pending(_iocpBio)); + _writeBuffer.i = _writeBuffer.b.begin(); + BIO_read(_iocpBio, _writeBuffer.i, static_cast<int>(_writeBuffer.b.size())); + } + + if(_writeBuffer.i != _writeBuffer.b.end()) + { + if(_delegate->write(_writeBuffer) != IceInternal::SocketOperationNone) + { + return false; + } + } + return _writeBuffer.i == _writeBuffer.b.end(); +} #endif |