1 #include "ace/Handle_Set.h"
2 #include "ace/Log_Category.h"
3 #include "ace/Countdown_Time.h"
4 #include "ace/OS_NS_string.h"
5 #include "ace/OS_NS_sys_select.h"
6 #include "ace/OS_Memory.h"
8 #include <openssl/err.h>
10 #include "SSL_SOCK_Stream.h"
12 #if !defined (__ACE_INLINE__)
13 #include "SSL_SOCK_Stream.inl"
14 #endif /* __ACE_INLINE__ */
16 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
18 ACE_ALLOC_HOOK_DEFINE(ACE_SSL_SOCK_Stream
)
20 ACE_SSL_SOCK_Stream::ACE_SSL_SOCK_Stream (ACE_SSL_Context
*context
)
24 ACE_TRACE ("ACE_SSL_SOCK_Stream::ACE_SSL_SOCK_Stream");
26 ACE_SSL_Context
* ctx
=
27 (context
== 0 ? ACE_SSL_Context::instance () : context
);
29 this->ssl_
= ::SSL_new (ctx
->context ());
33 ACELIB_ERROR ((LM_ERROR
,
34 "(%P|%t) ACE_SSL_SOCK_Stream "
35 "- cannot allocate new SSL structure %p\n",
40 ACE_SSL_SOCK_Stream::~ACE_SSL_SOCK_Stream ()
42 ACE_TRACE ("ACE_SSL_SOCK_Stream::~ACE_SSL_SOCK_Stream");
44 ::SSL_free (this->ssl_
);
46 // @@ Question: should we reference count the Context object or
47 // leave that to the application developer? We do not reference
48 // count reactors (for example) and following some simple rules
49 // seems to work fine!
53 ACE_SSL_SOCK_Stream::sendv (const iovec iov
[],
55 const ACE_Time_Value
*max_wait_time
) const
57 ACE_TRACE ("ACE_SSL_SOCK_Stream::sendv");
59 // There is subtle problem in this method that occurs when using
60 // non-blocking IO. The semantics of a non-blocking scatter write
61 // (sendv()) are not possible to retain with the emulation in this
64 ssize_t bytes_sent
= 0;
67 ACE_Time_Value
*timeout
= const_cast<ACE_Time_Value
*> (max_wait_time
);
69 if (max_wait_time
!= 0)
71 // Make a copy since ACE_Countdown_Time modifies the
77 // Take into account the time between each send.
78 ACE_Countdown_Time
countdown (timeout
);
80 for (size_t i
= 0; i
< n
; ++i
)
82 ssize_t
const result
= this->send (iov
[i
].iov_base
,
88 // There is a subtle difference in behaviour depending on
89 // whether or not any data was sent. If no data was sent,
90 // then always return -1. Otherwise return bytes_sent.
91 // This gives the caller an opportunity to keep track of
101 // Do not continue on to the next loop iteration if the
102 // amount of data sent was less than the amount data given.
103 // This avoids a subtle problem where "holes" in the data
104 // stream would occur if partial sends of a given buffer in
105 // the iovec array occurred.
106 if (static_cast<size_t> (result
) < static_cast<size_t> (iov
[i
].iov_len
))
110 (void) countdown
.update ();
117 ACE_SSL_SOCK_Stream::recvv (iovec
*io_vec
,
118 const ACE_Time_Value
*timeout
) const
120 ACE_TRACE ("ACE_SSL_SOCK_Stream::recvv");
122 // From ACE_SOCK_IO::recvv().
123 #if defined (FIONREAD)
124 ACE_Handle_Set handle_set
;
126 handle_set
.set_bit (this->get_handle ());
128 io_vec
->iov_base
= 0;
130 // Check the status of the current socket.
132 ACE_OS::select (int (this->get_handle ()) + 1,
146 // Goes fine, fallthrough to get data
152 if (ACE_OS::ioctl (this->get_handle (),
158 ACE_NEW_RETURN (io_vec
->iov_base
,
161 io_vec
->iov_len
= this->recv (io_vec
->iov_base
,
163 return io_vec
->iov_len
;
168 ACE_UNUSED_ARG (io_vec
);
169 ACE_UNUSED_ARG (timeout
);
170 ACE_NOTSUP_RETURN (-1);
171 #endif /* FIONREAD */
175 ACE_SSL_SOCK_Stream::send (const void *buf
,
178 const ACE_Time_Value
*timeout
) const
180 ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
182 // If SSL has data in the buffer, i.e. SSL_pending() returns a
183 // non-zero value, then don't block on select().
184 if (timeout
== 0 || ::SSL_pending (this->ssl_
))
185 return this->send (buf
, len
, flags
);
188 if (ACE::enter_send_timedwait (this->get_handle (),
193 ssize_t
const bytes_transferred
= this->send (buf
, len
, flags
);
195 ACE::restore_non_blocking_mode (this->get_handle (), val
);
197 return bytes_transferred
;
201 ACE_SSL_SOCK_Stream::recv (void *buf
,
204 const ACE_Time_Value
*timeout
) const
206 ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
208 return this->recv_i (buf
, n
, flags
, timeout
);
213 ACE_SSL_SOCK_Stream::send (size_t n
, ...) const
215 ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
217 size_t const total_tuples
= n
/ 2;
222 ssize_t bytes_sent
= 0;
224 // NOTE: This method used to fill an IO vector (e.g. iovec) and then
225 // send it using a scatter write (sendv()). However, it is
226 // not possible to emulate a non-blocking scatter write over
227 // SSL. As such, there is no point in attempting to use
228 // scatter writes over SSL.
229 for (size_t i
= 0; i
< total_tuples
; ++i
)
231 ssize_t
const data_len
= va_arg (argp
, ssize_t
);
232 ssize_t
const result
= this->send (va_arg (argp
, char *), data_len
);
236 // There is a subtle difference in behaviour depending on
237 // whether or not any data was sent. If no data was sent,
238 // then always return -1. Otherwise return bytes_sent.
239 // This gives the caller an opportunity to keep track of
240 // which data was actually sent.
251 bytes_sent
+= result
;
253 // Do not continue on to the next loop iteration if the
254 // amount of data sent was less than the amount of data
255 // given. This avoids a subtle problem where "holes" in the
256 // data stream would occur if partial sends of a given
257 // buffer in the varargs occurred.
258 if (result
< data_len
)
269 ACE_SSL_SOCK_Stream::recv (size_t n
, ...) const
271 ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
273 size_t const total_tuples
= n
/ 2;
278 ssize_t bytes_recv
= 0;
280 for (size_t i
= 0; i
< total_tuples
; ++i
)
282 ssize_t
const data_len
= va_arg (argp
, ssize_t
);
283 ssize_t
const result
= this->recv (va_arg (argp
, char *), data_len
);
287 // There is a subtle difference in behaviour depending on
288 // whether or not any data was received. If no data was
289 // received, then always return -1. Otherwise return
290 // bytes_received. This gives the caller an opportunity to
291 // keep track of which data was actually received.
304 bytes_recv
+= result
;
306 // Do not continue on to the next loop iteration if the
307 // amount of data received was less than the amount of data
308 // desired. This avoids a subtle problem where "holes" in
309 // the data stream would occur if partial receives of a
310 // given buffer in the varargs occurred.
311 if (result
< data_len
)
324 ACE_SSL_SOCK_Stream::send_n (const void *buf
,
327 const ACE_Time_Value
*timeout
,
330 ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
332 // No support for send flags in SSL.
335 ACE_NOTSUP_RETURN (-1);
338 /* This code mimics ACE::send_n */
339 // Total number of bytes written.
341 size_t &bytes_transferred
= ((bt
== 0) ? temp
: *bt
);
343 // Actual number of bytes written in each <send> attempt
346 for (bytes_transferred
= 0;
347 bytes_transferred
< len
;
348 bytes_transferred
+= n
)
350 n
= this->send ((const char*) buf
+ bytes_transferred
,
351 len
- bytes_transferred
,
357 if (errno
== EWOULDBLOCK
)
359 // If blocked, try again.
374 return ACE_Utils::truncate_cast
<ssize_t
> (bytes_transferred
);
378 ACE_SSL_SOCK_Stream::recv_n (void *buf
,
381 const ACE_Time_Value
*timeout
,
384 ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
388 if ((flags
| MSG_PEEK
) != MSG_PEEK
)
390 ACE_NOTSUP_RETURN (-1);
395 size_t &bytes_transferred
= ((bt
== 0) ? temp
: *bt
);
399 for (bytes_transferred
= 0;
400 bytes_transferred
< len
;
401 bytes_transferred
+= n
)
403 n
= this->recv ((char*) buf
+ bytes_transferred
,
404 len
- bytes_transferred
,
414 return ACE_Utils::truncate_cast
<ssize_t
> (bytes_transferred
);
418 ACE_SSL_SOCK_Stream::recv_n (void *buf
, int len
, int flags
) const
420 ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
424 if ((flags
| MSG_PEEK
) != MSG_PEEK
)
426 ACE_NOTSUP_RETURN (-1);
430 ssize_t bytes_transferred
= 0;
433 for (bytes_transferred
= 0;
434 bytes_transferred
< len
;
435 bytes_transferred
+= n
)
437 n
= this->recv ((char*) buf
+ bytes_transferred
,
438 len
- bytes_transferred
,
447 return ACE_Utils::truncate_cast
<ssize_t
> (bytes_transferred
);
451 ACE_SSL_SOCK_Stream::send_n (const void *buf
, int len
, int flags
) const
453 ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
455 // Send flags are unsupported in SSL
458 ACE_NOTSUP_RETURN (-1);
461 /* The following code mimics <ACE::send_n> */
462 size_t bytes_transferred
= 0;
465 for (bytes_transferred
= 0;
466 bytes_transferred
< (size_t) len
;
467 bytes_transferred
+= n
)
469 n
= this->send ((const char*) buf
+ bytes_transferred
,
470 len
- bytes_transferred
,
478 return ACE_Utils::truncate_cast
<ssize_t
> (bytes_transferred
);
482 ACE_SSL_SOCK_Stream::sendv_n (const iovec iov
[], size_t iovcnt
) const
484 ACE_TRACE ("ACE_SSL_SOCK_Stream::sendv_n");
486 ssize_t bytes_sent
= 0;
488 for (size_t i
= 0; i
< iovcnt
; ++i
)
490 ssize_t result
= this->send_n (iov
[i
].iov_base
,
496 // There is a subtle difference in behaviour depending on
497 // whether or not any data was sent. If no data was sent,
498 // then always return -1. Otherwise return bytes_sent.
499 // This gives the caller an opportunity to keep track of
500 // which data was actually sent.
512 bytes_sent
+= result
;
520 ACE_SSL_SOCK_Stream::recvv_n (iovec iov
[], size_t iovcnt
) const
522 ACE_TRACE ("ACE_SSL_SOCK_Stream::recvv_n");
524 ssize_t bytes_read
= 0;
526 for (size_t i
= 0; i
< iovcnt
; ++i
)
528 ssize_t
const result
= this->recv_n (iov
[i
].iov_base
,
533 // There is a subtle difference in behaviour depending on
534 // whether or not any data was read. If no data was read,
535 // then always return -1. Otherwise return bytes_read.
536 // This gives the caller an opportunity to keep track of
537 // which data was actually read.
549 bytes_read
+= result
;
557 ACE_SSL_SOCK_Stream::get_remote_addr (ACE_Addr
&addr
) const
559 // Some applications use get_remote_addr() as a way of determining
560 // whether or not a connection has been established. In SSL's case,
561 // the remote addr will be available once the TCP handshake has been
562 // complete. Despite that fact, the SSL connection may not have
563 // been completed. In such a case, a successful return from
564 // get_remote_addr() would be misleading.
565 if (SSL_is_init_finished (this->ssl_
))
567 return this->ACE_SSL_SOCK::get_remote_addr (addr
);
570 if (this->get_handle () == ACE_INVALID_HANDLE
)
582 ACE_END_VERSIONED_NAMESPACE_DECL