Public Types | Public Member Functions | Public Attributes | Protected Member Functions | Protected Attributes | Private Member Functions

ACE_SSL_SOCK_Stream Class Reference

Defines methods in the ACE_SSL_SOCK_Stream abstraction. More...

#include <SSL_SOCK_Stream.h>

Inheritance diagram for ACE_SSL_SOCK_Stream:
Inheritance graph
[legend]
Collaboration diagram for ACE_SSL_SOCK_Stream:
Collaboration graph
[legend]

List of all members.

Public Types

typedef ACE_INET_Addr PEER_ADDR
 Meta-type info.

Public Member Functions

 ACE_SSL_SOCK_Stream (ACE_SSL_Context *context=ACE_SSL_Context::instance())
 Constructor.
 ~ACE_SSL_SOCK_Stream (void)
 Destructor.
ssize_t send (const void *buf, size_t n, int flags) const
ssize_t recv (void *buf, size_t n, int flags) const
ssize_t send (const void *buf, size_t n) const
ssize_t recv (void *buf, size_t n) const
ssize_t sendv (const iovec iov[], size_t n, const ACE_Time_Value *timeout=0) const
 Send an iovec of size n to the ssl socket.
ssize_t recvv (iovec *io_vec, const ACE_Time_Value *timeout=0) const
ssize_t send (const void *buf, size_t n, int flags, const ACE_Time_Value *timeout) const
ssize_t recv (void *buf, size_t n, int flags, const ACE_Time_Value *timeout) const
ssize_t send (const void *buf, size_t n, const ACE_Time_Value *timeout) const
ssize_t recv (void *buf, size_t n, const ACE_Time_Value *timeout) const
ssize_t send (size_t n,...) const
 Send n varargs messages to the connected ssl socket.
ssize_t recv (size_t n,...) const
 Recv n varargs messages to the connected ssl socket.
ssize_t send_n (const void *buf, int n) const
 Send n bytes, keep trying until n are sent.
ssize_t recv_n (void *buf, int n) const
 Recv n bytes, keep trying until n are received.
ssize_t sendv_n (const iovec iov[], size_t n) const
ssize_t recvv_n (iovec iov[], size_t n) const
 Receive an iovec of size n to the connected socket.
int close (void)
 Close down the socket.
void set_handle (ACE_HANDLE fd)
 Overridden set_handle() method.
SSL * ssl (void) const
 Return a pointer to the underlying SSL structure.
int get_remote_addr (ACE_Addr &) const
ACE_SOCK_Streampeer (void)
 Return the underlying ACE_SOCK_Stream which ACE_SSL runs atop of.

ssize_t send_n (const void *buf, int n, int flags) const
 Send n bytes, keep trying until n are sent.
ssize_t recv_n (void *buf, int n, int flags) const
 Recv n bytes, keep trying until n are sent.
ssize_t send_n (const void *buf, size_t len, int flags, const ACE_Time_Value *timeout, size_t *bytes_transferred=0) const
ssize_t send_n (const void *buf, size_t len, const ACE_Time_Value *timeout, size_t *bytes_transferred=0) const
ssize_t recv_n (void *buf, size_t len, int flags, const ACE_Time_Value *timeout, size_t *bytes_transferred=0) const
ssize_t recv_n (void *buf, size_t len, const ACE_Time_Value *timeout, size_t *bytes_transferred=0) const

int close_reader (void)
 Close down the reader.
int close_writer (void)
 Close down the writer.

Public Attributes

 ACE_ALLOC_HOOK_DECLARE
 Declare the dynamic allocation hooks.

Protected Member Functions

ssize_t send_i (const void *buf, size_t n, int flags) const
ssize_t recv_i (void *buf, size_t n, int flags, const ACE_Time_Value *timeout) const

Protected Attributes

SSL * ssl_
 The SSL session.
ACE_SOCK_Stream stream_
 The stream which works under the ssl connection.

Private Member Functions

void operator= (const ACE_SSL_SOCK_Stream &)
 ACE_SSL_SOCK_Stream (const ACE_SSL_SOCK_Stream &)

Detailed Description

Defines methods in the ACE_SSL_SOCK_Stream abstraction.

This class encapsulates the methods and functionality necessary to send and receive data over TLS/SSL.

Since SSL is record-oriented, some additional steps must be taken to make the ACE_SSL_SOCK_Stream interact properly with the Reactor (if one is used) when performing non-blocking IO. In particular, if SSL_pending (ssl), where "ssl" is a pointer to the SSL data structure returned from ACE_SSL_SOCK_Stream::ssl(), returns a non-zero value then the event handler that calls the IO methods in this class should return a value greater than zero to force the Reactor to invoke the event handler before polling for additional events (e.g. blocking on select()).
Note:
The user must currently ensure that only one thread services a given SSL session at any given time since underlying SSL implementations, such as OpenSSL, are not entirely thread-safe or reentrant.

Definition at line 62 of file SSL_SOCK_Stream.h.


Member Typedef Documentation

Meta-type info.

Definition at line 280 of file SSL_SOCK_Stream.h.


Constructor & Destructor Documentation

ACE_SSL_SOCK_Stream::ACE_SSL_SOCK_Stream ( ACE_SSL_Context context = ACE_SSL_Context::instance()  ) 

Constructor.

Parameters:
context Pointer to ACE_SSL_Context instance containing the OpenSSL SSL data structure to be associated with this ACE_SSL_SOCK_Stream. The SSL data structure will be copied to make it at least logically independent of the supplied context.
ACE_SSL_SOCK_Stream::~ACE_SSL_SOCK_Stream ( void   ) 

Destructor.

Definition at line 46 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::~ACE_SSL_SOCK_Stream");

  ::SSL_free (this->ssl_);

  // @@ Question: should we reference count the Context object or
  // leave that to the application developer? We do not reference
  // count reactors (for example) and following some simple rules
  // seems to work fine!
}

ACE_SSL_SOCK_Stream::ACE_SSL_SOCK_Stream ( const ACE_SSL_SOCK_Stream  )  [private]

Member Function Documentation

int ACE_SSL_SOCK_Stream::close ( void   ) 

Close down the socket.

Reimplemented from ACE_SOCK.

Definition at line 296 of file SSL_SOCK_Stream.inl.

{
  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;
}

int ACE_SSL_SOCK_Stream::close_reader ( void   ) 

Close down the reader.

Selectively close endpoints.

Definition at line 282 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::close_reader");
  return this->stream_.close_reader ();
}

int ACE_SSL_SOCK_Stream::close_writer ( void   ) 

Close down the writer.

Definition at line 289 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::close_writer");
  return this->stream_.close_writer ();
}

int ACE_SSL_SOCK_Stream::get_remote_addr ( ACE_Addr addr  )  const

Return the address of the remotely connected peer (if there is one), in the referenced <ACE_Addr>. Returns 0 if successful, else -1.

Note:
If the TCP connection has been completed but the SSL connection has not been completed yet, -1 will be returned.

Reimplemented from ACE_SOCK.

Definition at line 604 of file SSL_SOCK_Stream.cpp.

{
  // Some applications use get_remote_addr() as a way of determining
  // whether or not a connection has been established.  In SSL's case,
  // the remote addr will be available once the TCP handshake has been
  // complete.  Despite that fact, the SSL connection may not have
  // been completed.  In such a case, a successful return from
  // get_remote_addr() would be misleading.

  if (SSL_is_init_finished (this->ssl_))
    {
      return this->ACE_SSL_SOCK::get_remote_addr (addr);
    }

  if (this->get_handle () == ACE_INVALID_HANDLE)
    {
      errno = EBADF;
    }
  else
    {
      errno = ENOTCONN;
    }

  return -1;
}

void ACE_SSL_SOCK_Stream::operator= ( const ACE_SSL_SOCK_Stream  )  [private]
ACE_SOCK_Stream & ACE_SSL_SOCK_Stream::peer ( void   ) 

Return the underlying ACE_SOCK_Stream which ACE_SSL runs atop of.

Definition at line 338 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::peer");
  return this->stream_;
}

ssize_t ACE_SSL_SOCK_Stream::recv ( void *  buf,
size_t  n,
int  flags 
) const

Recv an n byte buffer from the ssl socket using the semantics of recv(3n). ACE_SSL supports MSG_PEEK, but no other flags at this time.

Definition at line 204 of file SSL_SOCK_Stream.inl.

{
  return this->recv_i (buf, n, flags, 0);
}

ssize_t ACE_SSL_SOCK_Stream::recv ( void *  buf,
size_t  n,
int  flags,
const ACE_Time_Value timeout 
) const

Wait up to timeout amount of time to receive up to n bytes into buf (uses the recv() call). If recv() times out -1 is returned with errno == ETIME. If it succeeds the number of bytes received is returned. MSG_PEEK is the only supported flag.

Definition at line 207 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");

  return this->recv_i (buf, n, flags, timeout);
}

ssize_t ACE_SSL_SOCK_Stream::recv ( void *  buf,
size_t  n 
) const

Recv an n byte buffer from the ssl socket using the semantics of read(2).

Definition at line 221 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");

  return this->recv_i (buf, n, 0, 0);
}

ssize_t ACE_SSL_SOCK_Stream::recv ( void *  buf,
size_t  n,
const ACE_Time_Value timeout 
) const

Wait up to timeout amount of time to receive up to n bytes into buf (uses the recv() call). If recv() times out a -1 is returned with errno == ETIME. If it succeeds the number of bytes received is returned.

Definition at line 239 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
  return this->recv (buf, n, 0, timeout);
}

ssize_t ACE_SSL_SOCK_Stream::recv ( size_t  n,
  ... 
) const

Recv n varargs messages to the connected ssl socket.

Definition at line 276 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");

  size_t const total_tuples = n / 2;

  va_list argp;
  va_start (argp, n);

  ssize_t bytes_recv = 0;

  for (size_t i = 0; i < total_tuples; ++i)
    {
      ssize_t const data_len = va_arg (argp, ssize_t);
      ssize_t const result = this->recv (va_arg (argp, char *), data_len);

      if (result == -1)
        {
          // There is a subtle difference in behaviour depending on
          // whether or not any data was received.  If no data was
          // received, then always return -1.  Otherwise return
          // bytes_received.  This gives the caller an opportunity to
          // keep track of which data was actually received.
          if (bytes_recv > 0)
            {
              break;
            }
          else
            {
              va_end (argp);
              return -1;
            }
        }
      else
        {
          bytes_recv += result;

          // Do not continue on to the next loop iteration if the
          // amount of data received was less than the amount of data
          // desired.  This avoids a subtle problem where "holes" in
          // the data stream would occur if partial receives of a
          // given buffer in the varargs occured.
          if (result < data_len)
            {
              break;
            }
        }
    }

  va_end (argp);

  return bytes_recv;
}

ssize_t ACE_SSL_SOCK_Stream::recv_i ( void *  buf,
size_t  n,
int  flags,
const ACE_Time_Value timeout 
) const [protected]

Underlying send() helper method common to all public send() methods.

Definition at line 99 of file SSL_SOCK_Stream.inl.

{
  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 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),
                                   ACE_Utils::truncate_cast<int> (n));
        }
      else
        {
          ACE_NOTSUP_RETURN (-1);
        }
    }
  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);
  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;
}

ssize_t ACE_SSL_SOCK_Stream::recv_n ( void *  buf,
int  n,
int  flags 
) const

Recv n bytes, keep trying until n are sent.

Definition at line 438 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");

  if (flags != 0)
    {
      if ((flags | MSG_PEEK) != MSG_PEEK)
        {
          ACE_NOTSUP_RETURN (-1);
        }
    }

  ssize_t bytes_transferred = 0;
  ssize_t n = 0;

  for (bytes_transferred = 0;
       bytes_transferred < len;
       bytes_transferred += n)
    {
      n = this->recv ((char*) buf + bytes_transferred,
                      len - bytes_transferred,
                      flags);

      if (n < 0)
        {
          if (errno == EWOULDBLOCK)
            {
              // If blocked, try again.
              n = 0;
              continue;
            }
          else
            {
              return -1;
            }
        }
      else if (n == 0)
        {
          break;
        }
    }

  return ACE_Utils::truncate_cast<ssize_t> (bytes_transferred);
}

ssize_t ACE_SSL_SOCK_Stream::recv_n ( void *  buf,
size_t  len,
int  flags,
const ACE_Time_Value timeout,
size_t *  bytes_transferred = 0 
) const

Try to receive exactly len bytes into buf (uses the recv() call). The ACE_Time_Value indicates how long to blocking trying to receive. If timeout == 0, the caller will block until action is possible, else will wait until the relative time specified in timeout elapses). If recv() blocks for longer than timeout the number of bytes actually read is returned with errno == ETIME. If a timeout does not occur, recv_n return len (i.e., the number of bytes requested to be read).

Definition at line 385 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");

  if (flags != 0)
    {
      if ((flags | MSG_PEEK) != MSG_PEEK)
        {
          ACE_NOTSUP_RETURN (-1);
        }
    }

  size_t temp = 0;
  size_t &bytes_transferred = ((bt == 0) ? temp : *bt);

  ssize_t n = 0;

  for (bytes_transferred = 0;
       bytes_transferred < len;
       bytes_transferred += n)
    {
      n = this->recv ((char*) buf + bytes_transferred,
                      len - bytes_transferred,
                      flags,
                      timeout);

      if (n < 0)
        {
          if (errno == EWOULDBLOCK)
            {
              // If blocked, try again.
              n = 0;
              continue;
            }
          else
            {
              return -1;
            }
        }
      else if (n == 0)
        {
          break;
        }
    }

  return ACE_Utils::truncate_cast<ssize_t> (bytes_transferred);
}

ssize_t ACE_SSL_SOCK_Stream::recv_n ( void *  buf,
size_t  len,
const ACE_Time_Value timeout,
size_t *  bytes_transferred = 0 
) const

Try to receive exactly len bytes into buf (uses the recv() call). The ACE_Time_Value indicates how long to blocking trying to receive. If timeout == 0, the caller will block until action is possible, else will wait until the relative time specified in timeout elapses). If recv() blocks for longer than timeout the number of bytes actually read is returned with errno == ETIME. If a timeout does not occur, recv_n return len (i.e., the number of bytes requested to be read).

Definition at line 255 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
  return this->recv_n (buf, len, 0, timeout, bytes_transferred);
}

ssize_t ACE_SSL_SOCK_Stream::recv_n ( void *  buf,
int  n 
) const

Recv n bytes, keep trying until n are received.

Definition at line 248 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
  return this->recv_n (buf, buf_size, 0);
}

ssize_t ACE_SSL_SOCK_Stream::recvv ( iovec *  io_vec,
const ACE_Time_Value timeout = 0 
) const

Allows a client to read from a socket without having to provide a buffer to read. This method determines how much data is in the socket, allocates a buffer of this size, reads in the data, and returns the number of bytes read. The caller is responsible for deleting the member in the iov_base field of io_vec using delete [] io_vec->iov_base.

Definition at line 123 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recvv");

  // From ACE_SOCK_IO::recvv().
#if defined (FIONREAD)
  ACE_Handle_Set handle_set;
  handle_set.reset ();
  handle_set.set_bit (this->get_handle ());

  io_vec->iov_base = 0;

  // Check the status of the current socket.
  switch (
    ACE_OS::select (int (this->get_handle ()) + 1,
                    handle_set,
                    0,
                    0,
                    timeout))
    {
    case -1:
      return -1;
      /* NOTREACHED */
    case 0:
      errno = ETIME;
      return -1;
      /* NOTREACHED */
    default:
      // Goes fine, fallthrough to get data
      break;
    }

  int inlen;

  if (ACE_OS::ioctl (this->get_handle (),
                     FIONREAD,
                     &inlen) == -1)
    return -1;
  else if (inlen > 0)
    {
      ACE_NEW_RETURN (io_vec->iov_base,
                      char[inlen],
                      -1);
      io_vec->iov_len = this->recv (io_vec->iov_base,
                                    inlen);
      return io_vec->iov_len;
    }
  else
    return 0;
#else
  ACE_UNUSED_ARG (io_vec);
  ACE_UNUSED_ARG (timeout);
  ACE_NOTSUP_RETURN (-1);
#endif /* FIONREAD */
}

ssize_t ACE_SSL_SOCK_Stream::recvv_n ( iovec  iov[],
size_t  n 
) const

Receive an iovec of size n to the connected socket.

Definition at line 567 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::recvv_n");

  ssize_t bytes_read = 0;

  for (size_t i = 0; i < iovcnt; ++i)
    {
      ssize_t const result = this->recv_n (iov[i].iov_base,
                                           iov[i].iov_len);

      if (result == -1)
        {
          // There is a subtle difference in behaviour depending on
          // whether or not any data was read.  If no data was read,
          // then always return -1.  Otherwise return bytes_read.
          // This gives the caller an opportunity to keep track of
          // which data was actually read.
          if (bytes_read > 0)
            {
              break;
            }
          else
            {
              return -1;
            }
        }
      else
        {
          bytes_read += result;
        }
    }

  return bytes_read;
}

ssize_t ACE_SSL_SOCK_Stream::send ( const void *  buf,
size_t  n 
) const

Send an n byte buffer to the ssl socket using the semantics of write(2).

Definition at line 212 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send");

  return this->send_i (buf, n, 0);
}

ssize_t ACE_SSL_SOCK_Stream::send ( const void *  buf,
size_t  n,
const ACE_Time_Value timeout 
) const

Wait to to timeout amount of time to send up to n bytes into buf (uses the send() call). If send() times out a -1 is returned with errno == ETIME. If it succeeds the number of bytes sent is returned.

Definition at line 230 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
  return this->send (buf, len, 0, timeout);
}

ssize_t ACE_SSL_SOCK_Stream::send ( const void *  buf,
size_t  n,
int  flags 
) const

Send an n byte buffer to the ssl socket using the semantics of send(3n). ACE_SSL supports no flags for sending at this time.

Definition at line 91 of file SSL_SOCK_Stream.inl.

{
  return this->send_i (buf, n, flags);
}

ssize_t ACE_SSL_SOCK_Stream::send ( const void *  buf,
size_t  n,
int  flags,
const ACE_Time_Value timeout 
) const

Wait to timeout amount of time to send up to n bytes into buf (uses the send() call). If send() times out -1 is returned with errno == ETIME. If it succeeds the number of bytes sent is returned. No flags are supported.

Definition at line 181 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send");

  // If SSL has data in the buffer, i.e. SSL_pending() returns a
  // non-zero value, then don't block on select().
  if (timeout == 0 || ::SSL_pending (this->ssl_))
    return this->send (buf, len, flags);

  int val = 0;
  if (ACE::enter_send_timedwait (this->get_handle (),
                                 timeout,
                                 val) == -1)
    return -1;

  ssize_t const bytes_transferred = this->send (buf, len, flags);

  ACE::restore_non_blocking_mode (this->get_handle (), val);

  return bytes_transferred;
}

ssize_t ACE_SSL_SOCK_Stream::send ( size_t  n,
  ... 
) const

Send n varargs messages to the connected ssl socket.

Definition at line 219 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send");

  size_t const total_tuples = n / 2;

  va_list argp;
  va_start (argp, n);

  ssize_t bytes_sent = 0;

  // NOTE: This method used to fill an IO vector (e.g. iovec) and then
  //       send it using a scatter write (sendv()).  However, it is
  //       not possible to emulate a non-blocking scatter write over
  //       SSL.  As such, there is no point in attempting to use
  //       scatter writes over SSL.
  for (size_t i = 0; i < total_tuples; ++i)
    {
      ssize_t const data_len = va_arg (argp, ssize_t);
      ssize_t const result = this->send (va_arg (argp, char *), data_len);

      if (result == -1)
        {
          // There is a subtle difference in behaviour depending on
          // whether or not any data was sent.  If no data was sent,
          // then always return -1.  Otherwise return bytes_sent.
          // This gives the caller an opportunity to keep track of
          // which data was actually sent.
          if (bytes_sent > 0)
            break;
          else
            {
              va_end (argp);
              return -1;
            }
        }
      else
        {
          bytes_sent += result;

          // Do not continue on to the next loop iteration if the
          // amount of data sent was less than the amount of data
          // given.  This avoids a subtle problem where "holes" in the
          // data stream would occur if partial sends of a given
          // buffer in the varargs occured.
          if (result < data_len)
            break;

        }
    }

  va_end (argp);

  return bytes_sent;
}

ssize_t ACE_SSL_SOCK_Stream::send_i ( const void *  buf,
size_t  n,
int  flags 
) const [protected]

Underlying send() helper method common to all public send() methods.

Definition at line 27 of file SSL_SOCK_Stream.inl.

{
  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;
}

ssize_t ACE_SSL_SOCK_Stream::send_n ( const void *  buf,
int  n 
) const

Send n bytes, keep trying until n are sent.

Definition at line 265 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
  return this->send_n (buf, len, 0);
}

ssize_t ACE_SSL_SOCK_Stream::send_n ( const void *  buf,
int  n,
int  flags 
) const

Send n bytes, keep trying until n are sent.

Note:
In the following four methods, only MSG_PEEK is supported for recv_n(), and no flags are supported for send_n().

Definition at line 484 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");

  // Send flags are unsupported in SSL
  if (flags != 0)
    {
      ACE_NOTSUP_RETURN (-1);
    }

  /*  The following code mimics <ACE::send_n> */
  size_t bytes_transferred = 0;
  ssize_t n = 0;

  for (bytes_transferred = 0;
       bytes_transferred < (size_t) len;
       bytes_transferred += n)
    {
      n = this->send ((const char*) buf + bytes_transferred,
                      len - bytes_transferred,
                      flags);

      if (n < 0)
        {
          if (errno == EWOULDBLOCK)
            {
              // If blocked, try again.
              n = 0;
              continue;
            }
          else
            {
              return -1;
            }
        }
      else if (n == 0)
        {
          break;
        }
    }

  return ACE_Utils::truncate_cast<ssize_t> (bytes_transferred);
}

ssize_t ACE_SSL_SOCK_Stream::send_n ( const void *  buf,
size_t  len,
const ACE_Time_Value timeout,
size_t *  bytes_transferred = 0 
) const

Try to send exactly len bytes into buf (uses the send() call). If send() blocks for longer than timeout the number of bytes actually sent is returned with errno == ETIME. If a timeout does not occur, send_n() return len (i.e., the number of bytes requested to be sent).

Definition at line 272 of file SSL_SOCK_Stream.inl.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
  return this->send_n (buf, len, 0, timeout, bytes_transferred);
}

ssize_t ACE_SSL_SOCK_Stream::send_n ( const void *  buf,
size_t  len,
int  flags,
const ACE_Time_Value timeout,
size_t *  bytes_transferred = 0 
) const

Try to send exactly len bytes into buf (uses the send() call). If send() blocks for longer than timeout the number of bytes actually sent is returned with errno == ETIME. If a timeout does not occur, send_n() return len (i.e., the number of bytes requested to be sent).

Definition at line 331 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");

  // No support for send flags in SSL.
  if (flags != 0)
    {
      ACE_NOTSUP_RETURN (-1);
    }

  /* This code mimics ACE::send_n */
  // Total number of bytes written.
  size_t temp = 0;
  size_t &bytes_transferred = ((bt == 0) ? temp : *bt);

  // Actual number of bytes written in each <send> attempt
  ssize_t n = 0;

  for (bytes_transferred = 0;
       bytes_transferred < len;
       bytes_transferred += n)
    {
      n = this->send ((const char*) buf + bytes_transferred,
                      len - bytes_transferred,
                      flags,
                      timeout);

      if (n < 0)
        {
          if (errno == EWOULDBLOCK)
            {
              // If blocked, try again.
              n = 0;
              continue;
            }
          else
            {
              return -1;
            }
        }
      else if (n == 0)
        {
          break;
        }
    }

  return ACE_Utils::truncate_cast<ssize_t> (bytes_transferred);
}

ssize_t ACE_SSL_SOCK_Stream::sendv ( const iovec  iov[],
size_t  n,
const ACE_Time_Value timeout = 0 
) const

Send an iovec of size n to the ssl socket.

Note that it is not possible to perform a "scattered" write with the underlying OpenSSL implementation. As such, the expected semantics are not fully reproduced with this implementation.

Definition at line 59 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::sendv");

  // There is subtle problem in this method that occurs when using
  // non-blocking IO.  The semantics of a non-blocking scatter write
  // (sendv()) are not possible to retain with the emulation in this
  // method.

  ssize_t bytes_sent = 0;

  ACE_Time_Value t;
  ACE_Time_Value *timeout = const_cast<ACE_Time_Value *> (max_wait_time);

  if (max_wait_time != 0)
    {
      // Make a copy since ACE_Countdown_Time modifies the
      // ACE_Time_Value.
      t = *max_wait_time;
      timeout = &t;
    }

  // Take into account the time between each send.
  ACE_Countdown_Time countdown (timeout);

  for (size_t i = 0; i < n; ++i)
    {
      ssize_t const result = this->send (iov[i].iov_base,
                                         iov[i].iov_len,
                                         timeout);

      if (result == -1)
        {
          // There is a subtle difference in behaviour depending on
          // whether or not any data was sent.  If no data was sent,
          // then always return -1.  Otherwise return bytes_sent.
          // This gives the caller an opportunity to keep track of
          if (bytes_sent > 0)
            break;
          else
            return -1;
        }
      else
        {
          bytes_sent += result;

          // Do not continue on to the next loop iteration if the
          // amount of data sent was less than the amount data given.
          // This avoids a subtle problem where "holes" in the data
          // stream would occur if partial sends of a given buffer in
          // the iovec array occured.
          if (static_cast<size_t> (result) < static_cast<size_t> (iov[i].iov_len))
            break;
        }

      (void) countdown.update ();
    }

  return bytes_sent;
}

ssize_t ACE_SSL_SOCK_Stream::sendv_n ( const iovec  iov[],
size_t  n 
) const

Send an iovec of size n to the connected socket. Will block until all bytes are sent or an error occurs.

Definition at line 529 of file SSL_SOCK_Stream.cpp.

{
  ACE_TRACE ("ACE_SSL_SOCK_Stream::sendv_n");

  ssize_t bytes_sent = 0;

  for (size_t i = 0; i < iovcnt; ++i)
    {
      ssize_t result = this->send_n (iov[i].iov_base,
                                     iov[i].iov_len);


      if (result == -1)
        {
          // There is a subtle difference in behaviour depending on
          // whether or not any data was sent.  If no data was sent,
          // then always return -1.  Otherwise return bytes_sent.
          // This gives the caller an opportunity to keep track of
          // which data was actually sent.
          if (bytes_sent > 0)
            {
              break;
            }
          else
            {
              return -1;
            }
        }
      else
        {
          bytes_sent += result;
        }
    }

  return bytes_sent;
}

void ACE_SSL_SOCK_Stream::set_handle ( ACE_HANDLE  fd  ) 

Overridden set_handle() method.

Only an ACE_SSL_SOCK_Acceptor or ACE_SSL_SOCK_Connector should access this method since some state in the underlying "ssl_" data structure is set during SSL connection establishment.

Reimplemented from ACE_SSL_SOCK.

Definition at line 11 of file SSL_SOCK_Stream.inl.

{
  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);
    }
}

SSL * ACE_SSL_SOCK_Stream::ssl ( void   )  const

Return a pointer to the underlying SSL structure.

Definition at line 345 of file SSL_SOCK_Stream.inl.

{
  return this->ssl_;
}


Member Data Documentation

Declare the dynamic allocation hooks.

Reimplemented from ACE_SOCK.

Definition at line 283 of file SSL_SOCK_Stream.h.

SSL* ACE_SSL_SOCK_Stream::ssl_ [protected]

The SSL session.

Definition at line 333 of file SSL_SOCK_Stream.h.

The stream which works under the ssl connection.

Definition at line 336 of file SSL_SOCK_Stream.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines