summaryrefslogtreecommitdiff
path: root/trunk/ACE/ace/SSL/SSL_SOCK_Stream.inl
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/ACE/ace/SSL/SSL_SOCK_Stream.inl')
-rw-r--r--trunk/ACE/ace/SSL/SSL_SOCK_Stream.inl323
1 files changed, 323 insertions, 0 deletions
diff --git a/trunk/ACE/ace/SSL/SSL_SOCK_Stream.inl b/trunk/ACE/ace/SSL/SSL_SOCK_Stream.inl
new file mode 100644
index 00000000000..352aca04b3e
--- /dev/null
+++ b/trunk/ACE/ace/SSL/SSL_SOCK_Stream.inl
@@ -0,0 +1,323 @@
+// -*- C++ -*-
+//
+// $Id$
+
+#include "ace/OS_NS_errno.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);
+
+ const int bytes_sent = ::SSL_write (this->ssl_,
+ static_cast<const char *> (buf),
+ 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;
+ const ACE_HANDLE 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 on select() with a timeout if no data in the
+ // internal OpenSSL buffer is pending read completion for
+ // the same reasons stated above, i.e. all data must be read
+ // before blocking on select().
+ if (timeout != 0
+ && !::SSL_pending (this->ssl_))
+ {
+ if (ACE::enter_recv_timedwait (handle,
+ timeout,
+ val) == -1)
+ return -1;
+ }
+
+ if (flags)
+ {
+ if (ACE_BIT_ENABLED (flags, MSG_PEEK))
+ bytes_read = ::SSL_peek (this->ssl_,
+ static_cast<char *> (buf),
+ n);
+ else
+ ACE_NOTSUP_RETURN (-1);
+ }
+ else
+ {
+ bytes_read = ::SSL_read (this->ssl_,
+ static_cast<char *> (buf),
+ n);
+ }
+
+ const int status = ::SSL_get_error (this->ssl_, bytes_read);
+ switch (status)
+ {
+ case SSL_ERROR_NONE:
+ if (timeout != 0)
+ ACE::restore_non_blocking_mode (handle, val);
+
+ return bytes_read;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ errno = EWOULDBLOCK;
+
+ return -1;
+
+ case SSL_ERROR_ZERO_RETURN:
+ if (timeout != 0)
+ ACE::restore_non_blocking_mode (handle, val);
+
+ // 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_read;
+
+ 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.
+ 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 a fatal SSL error.
+ errno = 0;
+
+ ACE_SSL_Context::report_error ();
+
+ break;
+ }
+
+ return -1;
+}
+
+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::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 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.
+ const int 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