2 #include "SSL_SOCK_Connector.h"
4 #include "ace/OS_NS_errno.h"
5 #include "ace/Handle_Set.h"
6 #include "ace/INET_Addr.h"
7 #include "ace/Log_Category.h"
8 #include "ace/Countdown_Time.h"
9 #include "ace/Truncate.h"
11 #include <openssl/err.h>
13 #if !defined (__ACE_INLINE__)
14 #include "SSL_SOCK_Connector.inl"
15 #endif /* __ACE_INLINE__ */
17 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
19 ACE_ALLOC_HOOK_DEFINE(ACE_SSL_SOCK_Connector
)
21 ACE_SSL_SOCK_Connector::~ACE_SSL_SOCK_Connector ()
23 ACE_TRACE ("ACE_SSL_SOCK_Connector::~ACE_SSL_SOCK_Connector");
27 ACE_SSL_SOCK_Connector::ssl_connect (ACE_SSL_SOCK_Stream
&new_stream
,
28 const ACE_Time_Value
*timeout
)
30 SSL
*ssl
= new_stream
.ssl ();
34 if (SSL_is_init_finished (ssl
))
37 // Check if a connection is already pending for the given SSL
39 if (!SSL_in_connect_init (ssl
))
40 ::SSL_set_connect_state (ssl
);
42 ACE_HANDLE handle
= new_stream
.get_handle ();
44 // We're going to call SSL_connect, optionally doing ACE::select and
45 // retrying the SSL_connect, until the SSL handshake is done or
47 // To get the timeout affect, set the socket to nonblocking mode
48 // before beginning if there is a timeout specified. If the timeout
49 // is 0 (wait as long as it takes) then don't worry about the blocking
50 // status; we'll block in SSL_connect if the socket is blocking, and
51 // block in ACE::select if not.
52 int reset_blocking_mode
= 0;
55 reset_blocking_mode
= ACE_BIT_DISABLED (ACE::get_flags (handle
),
57 // Set the handle into non-blocking mode if it's not already
59 if (reset_blocking_mode
60 && ACE::set_flags (handle
,
67 t
= *timeout
; // Need a non-const copy.
69 // Take into account the time between each select() call below.
70 ACE_Countdown_Time
countdown ((timeout
== 0 ? 0 : &t
));
76 // These handle sets are used to set up for whatever SSL_connect
77 // says it wants next. They're reset on each pass around the loop.
78 ACE_Handle_Set rd_handle
;
79 ACE_Handle_Set wr_handle
;
81 status
= ::SSL_connect (ssl
);
82 switch (::SSL_get_error (ssl
, status
))
85 // Start out with non-blocking disabled on the SSL stream.
86 new_stream
.disable (ACE_NONBLOCK
);
87 status
= 0; // To tell caller about success
90 case SSL_ERROR_WANT_WRITE
:
91 wr_handle
.set_bit (handle
);
92 status
= 1; // Wait for more activity
95 case SSL_ERROR_WANT_READ
:
96 rd_handle
.set_bit (handle
);
97 status
= 1; // Wait for more activity
100 case SSL_ERROR_ZERO_RETURN
:
101 // The peer has notified us that it is shutting down via
102 // the SSL "close_notify" message so we need to
107 case SSL_ERROR_SYSCALL
:
108 // On some platforms (e.g. MS Windows) OpenSSL does not
109 // store the last error in errno so explicitly do so.
111 // Explicitly check for EWOULDBLOCK since it doesn't get
112 // converted to an SSL_ERROR_WANT_{READ,WRITE} on some
113 // platforms. If SSL_connect failed outright, though, don't
114 // bother checking more. This can happen if the socket gets
115 // closed during the handshake.
116 if (ACE_OS::set_errno_to_last_error () == EWOULDBLOCK
&&
119 // Although the SSL_ERROR_WANT_READ/WRITE isn't getting
120 // set correctly, the read/write state should be valid.
121 // Use that to decide what to do.
122 status
= 1; // Wait for more activity
123 if (SSL_want_write (ssl
))
125 wr_handle
.set_bit (handle
);
127 else if (SSL_want_read (ssl
))
129 rd_handle
.set_bit (handle
);
133 status
= -1; // Doesn't want anything - bail out
144 ACE_SSL_Context::report_error ();
151 // Must have at least one handle to wait for at this point.
152 ACE_ASSERT (rd_handle
.num_set () == 1 || wr_handle
.num_set () == 1);
154 // Block indefinitely if timeout pointer is zero.
155 status
= ACE::select (int (handle
) + 1,
159 (timeout
== 0 ? 0 : &t
));
161 (void) countdown
.update ();
163 // 0 is timeout, so we're done.
164 // -1 is error, so we're done.
165 // Could be both handles set (same handle in both masks) so set to 1.
170 else // Timeout or socket failure
176 } while (status
== 1 && !SSL_is_init_finished (ssl
));
178 if (reset_blocking_mode
)
180 ACE_Errno_Guard
eguard (errno
);
181 ACE::clr_flags (handle
, ACE_NONBLOCK
);
184 return (status
== -1 ? -1 : 0);
188 ACE_SSL_SOCK_Connector::connect (ACE_SSL_SOCK_Stream
&new_stream
,
189 const ACE_Addr
&remote_sap
,
190 const ACE_Time_Value
*timeout
,
191 const ACE_Addr
&local_sap
,
196 ACE_TRACE ("ACE_SSL_SOCK_Connector::connect");
198 // Take into account the time to complete the basic TCP handshake
199 // and the SSL handshake.
200 ACE_Time_Value time_copy
;
201 ACE_Countdown_Time
countdown (&time_copy
);
204 time_copy
+= *timeout
;
209 this->connector_
.connect (new_stream
.peer (),
219 error
= errno
; // Save us some TSS accesses.
221 // Obtain the handle from the underlying SOCK_Stream and set it in
222 // the SSL_SOCK_Stream. Note that the case where a connection is in
223 // progress is also handled. In that case, the handle must also be
224 // set in the SSL_SOCK_Stream so that the correct handle is returned
225 // when performing non-blocking connect()s.
226 if (new_stream
.get_handle () == ACE_INVALID_HANDLE
228 || (result
== -1 && (error
== EWOULDBLOCK
229 || error
== EINPROGRESS
))))
230 new_stream
.set_handle (new_stream
.peer ().get_handle ());
235 // If using a timeout, update the countdown timer to reflect the time
236 // spent on the connect itself, then pass the remaining time to
237 // ssl_connect to bound the time on the handshake.
241 timeout
= &time_copy
;
244 result
= this->ssl_connect (new_stream
, timeout
);
253 ACE_SSL_SOCK_Connector::connect (ACE_SSL_SOCK_Stream
&new_stream
,
254 const ACE_Addr
&remote_sap
,
255 ACE_QoS_Params qos_params
,
256 const ACE_Time_Value
*timeout
,
257 const ACE_Addr
&local_sap
,
258 ACE_Protocol_Info
*protocolinfo
,
264 ACE_TRACE ("ACE_SSL_SOCK_Connector::connect");
266 // Take into account the time to complete the basic TCP handshake
267 // and the SSL handshake.
268 ACE_Time_Value time_copy
;
269 ACE_Countdown_Time
countdown (&time_copy
);
272 time_copy
+= *timeout
;
276 int result
= this->connector_
.connect (new_stream
.peer (),
289 error
= errno
; // Save us some TSS accesses.
291 // Obtain the handle from the underlying SOCK_Stream and set it in
292 // the SSL_SOCK_Stream. Note that the case where a connection is in
293 // progress is also handled. In that case, the handle must also be
294 // set in the SSL_SOCK_Stream so that the correct handle is returned
295 // when performing non-blocking connect()s.
296 if (new_stream
.get_handle () == ACE_INVALID_HANDLE
298 || (result
== -1 && (error
== EWOULDBLOCK
299 || error
== EINPROGRESS
))))
300 new_stream
.set_handle (new_stream
.peer ().get_handle ());
305 // If using a timeout, update the countdown timer to reflect the time
306 // spent on the connect itself, then pass the remaining time to
307 // ssl_connect to bound the time on the handshake.
311 timeout
= &time_copy
;
314 result
= this->ssl_connect (new_stream
, timeout
);
322 // Try to complete a non-blocking connection.
325 ACE_SSL_SOCK_Connector::complete (ACE_SSL_SOCK_Stream
&new_stream
,
326 ACE_Addr
*remote_sap
,
327 const ACE_Time_Value
*tv
)
329 ACE_TRACE ("ACE_SSL_SOCK_Connector::complete");
331 // Take into account the time to complete the basic TCP handshake
332 // and the SSL handshake.
333 ACE_Time_Value time_copy
;
334 ACE_Countdown_Time
countdown (&time_copy
);
341 // Only attempt to complete the TCP connection if it that hasn't
342 // already been done.
344 if (new_stream
.peer ().get_remote_addr (raddr
) != 0
345 && this->connector_
.complete (new_stream
.peer (),
350 // The handle in the SSL_SOCK_Stream should have already been set in
351 // the connect() method.
353 // If using a timeout, update the countdown timer to reflect the time
354 // spent on the connect itself, then pass the remaining time to
355 // ssl_connect to bound the time on the handshake.
362 if (this->ssl_connect (new_stream
, tv
) == -1)
372 ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector (
373 ACE_SSL_SOCK_Stream
&new_stream
,
374 const ACE_Addr
&remote_sap
,
375 const ACE_Time_Value
*timeout
,
376 const ACE_Addr
&local_sap
,
382 ACE_TRACE ("ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector");
383 this->connect (new_stream
,
392 ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector (
393 ACE_SSL_SOCK_Stream
&new_stream
,
394 const ACE_Addr
&remote_sap
,
395 ACE_QoS_Params qos_params
,
396 const ACE_Time_Value
*timeout
,
397 const ACE_Addr
&local_sap
,
398 ACE_Protocol_Info
*protocolinfo
,
405 ACE_TRACE ("ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector");
407 this->connect (new_stream
,
419 ACE_END_VERSIONED_NAMESPACE_DECL