summaryrefslogtreecommitdiff
path: root/ACE/ace/SSL/SSL_SOCK_Stream.inl
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/SSL/SSL_SOCK_Stream.inl')
-rw-r--r--ACE/ace/SSL/SSL_SOCK_Stream.inl369
1 files changed, 369 insertions, 0 deletions
diff --git a/ACE/ace/SSL/SSL_SOCK_Stream.inl b/ACE/ace/SSL/SSL_SOCK_Stream.inl
new file mode 100644
index 00000000000..a720f07ebc6
--- /dev/null
+++ b/ACE/ace/SSL/SSL_SOCK_Stream.inl
@@ -0,0 +1,369 @@
+// -*- C++ -*-
+//
+// $Id$
+
+#include "ace/OS_NS_errno.h"
+#include "ace/Truncate.h"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+ACE_INLINE void
+ACE_SSL_SOCK_Stream::set_handle (ACE_HANDLE fd)
+{
+ if (this->ssl_ == 0 || fd == ACE_INVALID_HANDLE)
+ {
+ this->ACE_SSL_SOCK::set_handle (ACE_INVALID_HANDLE);
+ return;
+ }
+ else
+ {
+ (void) ::SSL_set_fd (this->ssl_, (int) fd);
+ this->ACE_SSL_SOCK::set_handle (fd);
+ this->stream_.set_handle (fd);
+ }
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::send_i (const void *buf,
+ size_t n,
+ int flags) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::send_i");
+
+ // NOTE: Caller must provide thread-synchronization.
+
+ // No send flags are supported in SSL.
+ if (flags != 0)
+ {
+ ACE_NOTSUP_RETURN (-1);
+ }
+
+ int const bytes_sent = ::SSL_write (this->ssl_,
+ static_cast<const char *> (buf),
+ ACE_Utils::truncate_cast<int> (n));
+
+ switch (::SSL_get_error (this->ssl_, bytes_sent))
+ {
+ case SSL_ERROR_NONE:
+ return bytes_sent;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ errno = EWOULDBLOCK;
+
+ return -1;
+
+ case SSL_ERROR_ZERO_RETURN:
+ // The peer has notified us that it is shutting down via the SSL
+ // "close_notify" message so we need to shutdown, too.
+ (void) ::SSL_shutdown (this->ssl_);
+
+ return bytes_sent;
+
+ case SSL_ERROR_SYSCALL:
+ if (bytes_sent == 0)
+ // An EOF occured but the SSL "close_notify" message was not
+ // sent. This is a protocol error, but we ignore it.
+ return 0;
+
+ // If not an EOF, then fall through to "default" case.
+
+ // On some platforms (e.g. MS Windows) OpenSSL does not store
+ // the last error in errno so explicitly do so.
+ ACE_OS::set_errno_to_last_error ();
+
+ break;
+
+ default:
+ // Reset errno to prevent previous values (e.g. EWOULDBLOCK)
+ // from being associated with fatal SSL errors.
+ errno = 0;
+
+ ACE_SSL_Context::report_error ();
+
+ break;
+ }
+
+ return -1;
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::send (const void *buf,
+ size_t n,
+ int flags) const
+{
+ return this->send_i (buf, n, flags);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::recv_i (void *buf,
+ size_t n,
+ int flags,
+ const ACE_Time_Value *timeout) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_i");
+
+ // NOTE: Caller must provide thread-synchronization.
+
+ int bytes_read = 0;
+ ACE_HANDLE const handle = this->get_handle ();
+
+ // Value for current I/O mode (blocking/non-blocking)
+ int val = 0;
+
+ if (timeout != 0)
+ ACE::record_and_set_non_blocking_mode (handle,
+ val);
+
+ // Only block to wait for I/O ready with a timeout if all on-hand data
+ // has been consumed. If there is remaining data in the SSL buffers
+ // the socket won't "select" even though SSL_read would complete.
+ // See "SSL and TLS" by Rescorla section 8.9 for more info.
+ bool peeking = false;
+ bool retry = false;
+ if (flags)
+ {
+ if (ACE_BIT_ENABLED (flags, MSG_PEEK))
+ {
+ peeking = true;
+ }
+ else
+ {
+ ACE_NOTSUP_RETURN (-1);
+ }
+ }
+
+ do
+ {
+ retry = false;
+ if (peeking)
+ {
+ bytes_read = ::SSL_peek (this->ssl_,
+ static_cast<char *> (buf),
+ ACE_Utils::truncate_cast<int> (n));
+ }
+ else
+ {
+ bytes_read = ::SSL_read (this->ssl_,
+ static_cast<char *> (buf),
+ ACE_Utils::truncate_cast<int> (n));
+ }
+
+ int const status = ::SSL_get_error (this->ssl_, bytes_read);
+ int substat = 0;
+ switch (status)
+ {
+ case SSL_ERROR_NONE:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if (timeout == 0)
+ {
+ errno = EWOULDBLOCK;
+ bytes_read = -1;
+ break;
+ }
+ substat = ACE::handle_ready (handle,
+ timeout,
+ status == SSL_ERROR_WANT_READ,
+ status == SSL_ERROR_WANT_WRITE,
+ 0);
+ if (substat == 1) // Now ready to proceed
+ {
+ retry = true;
+ break;
+ }
+ bytes_read = -1;
+ if (substat == 0)
+ errno = ETIME;
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ bytes_read = 0;
+
+ // The peer has notified us that it is shutting down via the SSL
+ // "close_notify" message so we need to shutdown, too.
+ (void) ::SSL_shutdown (this->ssl_);
+
+ break;
+
+ case SSL_ERROR_SYSCALL:
+ if (bytes_read == 0)
+ // An EOF occured but the SSL "close_notify" message was not
+ // sent. This is a protocol error, but we ignore it.
+ break;
+
+ // If not an EOF, then fall through to "default" case.
+
+ // On some platforms (e.g. MS Windows) OpenSSL does not store
+ // the last error in errno so explicitly do so.
+ ACE_OS::set_errno_to_last_error ();
+
+ break;
+
+ default:
+ // Reset errno to prevent previous values (e.g. EWOULDBLOCK)
+ // from being associated with a fatal SSL error.
+ bytes_read = -1;
+ errno = 0;
+
+ ACE_SSL_Context::report_error ();
+
+ break;
+ }
+ } while (retry);
+
+ if (timeout != 0)
+ ACE::restore_non_blocking_mode (handle, val);
+ return bytes_read;
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::recv (void *buf,
+ size_t n,
+ int flags) const
+{
+ return this->recv_i (buf, n, flags, 0);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::send (const void *buf,
+ size_t n) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
+
+ return this->send_i (buf, n, 0);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::recv (void *buf,
+ size_t n) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
+
+ return this->recv_i (buf, n, 0, 0);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::send (const void *buf,
+ size_t len,
+ const ACE_Time_Value *timeout) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
+ return this->send (buf, len, 0, timeout);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::recv (void *buf,
+ size_t n,
+ const ACE_Time_Value *timeout) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
+ return this->recv (buf, n, 0, timeout);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::recv_n (void *buf, int buf_size) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
+ return this->recv_n (buf, buf_size, 0);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::recv_n (void *buf,
+ size_t len,
+ const ACE_Time_Value *timeout,
+ size_t *bytes_transferred) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
+ return this->recv_n (buf, len, 0, timeout, bytes_transferred);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::send_n (const void *buf, int len) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
+ return this->send_n (buf, len, 0);
+}
+
+ACE_INLINE ssize_t
+ACE_SSL_SOCK_Stream::send_n (const void *buf,
+ size_t len,
+ const ACE_Time_Value *timeout,
+ size_t *bytes_transferred) const
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
+ return this->send_n (buf, len, 0, timeout, bytes_transferred);
+}
+
+ACE_INLINE int
+ACE_SSL_SOCK_Stream::close_reader (void)
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::close_reader");
+ return this->stream_.close_reader ();
+}
+
+ACE_INLINE int
+ACE_SSL_SOCK_Stream::close_writer (void)
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::close_writer");
+ return this->stream_.close_writer ();
+}
+
+ACE_INLINE int
+ACE_SSL_SOCK_Stream::close (void)
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::close");
+
+ if (this->ssl_ == 0 || this->get_handle () == ACE_INVALID_HANDLE)
+ return 0; // SSL_SOCK_Stream was never opened.
+
+ // SSL_shutdown() returns 1 on successful shutdown of the SSL
+ // connection, not 0.
+ int const status = ::SSL_shutdown (this->ssl_);
+
+ switch (::SSL_get_error (this->ssl_, status))
+ {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_SYSCALL: // Ignore this error condition.
+
+ // Reset the SSL object to allow another connection to be made
+ // using this ACE_SSL_SOCK_Stream instance. This prevents the
+ // previous SSL session state from being associated with the new
+ // SSL session/connection.
+ (void) ::SSL_clear (this->ssl_);
+ this->set_handle (ACE_INVALID_HANDLE);
+ return this->stream_.close ();
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ errno = EWOULDBLOCK;
+ break;
+
+ default:
+ ACE_SSL_Context::report_error ();
+
+ ACE_Errno_Guard error (errno); // Save/restore errno
+ (void) this->stream_.close ();
+
+ return -1;
+ }
+
+ return -1;
+}
+
+ACE_INLINE ACE_SOCK_Stream &
+ACE_SSL_SOCK_Stream::peer (void)
+{
+ ACE_TRACE ("ACE_SSL_SOCK_Stream::peer");
+ return this->stream_;
+}
+
+ACE_INLINE SSL *
+ACE_SSL_SOCK_Stream::ssl (void) const
+{
+ return this->ssl_;
+}
+
+ACE_END_VERSIONED_NAMESPACE_DECL