Merge pull request #2301 from sonndinh/remove-dup-reactor-functions
[ACE_TAO.git] / ACE / ace / SSL / SSL_SOCK_Connector.cpp
blob7d8a46232278476a499fd22c5d4db48358ec9d4d
1 // -*- C++ -*-
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");
26 int
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 ();
31 if (ssl == 0)
32 return -1;
34 if (SSL_is_init_finished (ssl))
35 return 0;
37 // Check if a connection is already pending for the given SSL
38 // structure.
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
46 // it fails.
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;
53 if (timeout != 0)
55 reset_blocking_mode = ACE_BIT_DISABLED (ACE::get_flags (handle),
56 ACE_NONBLOCK);
57 // Set the handle into non-blocking mode if it's not already
58 // in it.
59 if (reset_blocking_mode
60 && ACE::set_flags (handle,
61 ACE_NONBLOCK) == -1)
62 return -1;
65 ACE_Time_Value t;
66 if (timeout != 0)
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));
72 int status;
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))
84 case SSL_ERROR_NONE:
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
88 break; // Done
90 case SSL_ERROR_WANT_WRITE:
91 wr_handle.set_bit (handle);
92 status = 1; // Wait for more activity
93 break;
95 case SSL_ERROR_WANT_READ:
96 rd_handle.set_bit (handle);
97 status = 1; // Wait for more activity
98 break;
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
103 // shutdown, too.
104 status = -1;
105 break;
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 &&
117 status == -1)
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);
131 else
133 status = -1; // Doesn't want anything - bail out
136 else
138 status = -1;
141 break;
143 default:
144 ACE_SSL_Context::report_error ();
145 status = -1;
146 break;
149 if (status == 1)
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,
156 &rd_handle,
157 &wr_handle,
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.
166 if (status >= 1)
168 status = 1;
170 else // Timeout or socket failure
172 status = -1;
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,
192 int reuse_addr,
193 int flags,
194 int perms)
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);
202 if (timeout != 0)
204 time_copy += *timeout;
205 countdown.start ();
208 int result =
209 this->connector_.connect (new_stream.peer (),
210 remote_sap,
211 timeout,
212 local_sap,
213 reuse_addr,
214 flags,
215 perms);
217 int error = 0;
218 if (result == -1)
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
227 && (result == 0
228 || (result == -1 && (error == EWOULDBLOCK
229 || error == EINPROGRESS))))
230 new_stream.set_handle (new_stream.peer ().get_handle ());
232 if (result == -1)
233 return result;
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.
238 if (timeout != 0)
240 countdown.update ();
241 timeout = &time_copy;
244 result = this->ssl_connect (new_stream, timeout);
246 if (result == -1)
247 new_stream.close ();
249 return result;
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,
259 ACE_SOCK_GROUP g,
260 u_long flags,
261 int reuse_addr,
262 int perms)
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);
270 if (timeout != 0)
272 time_copy += *timeout;
273 countdown.start ();
276 int result = this->connector_.connect (new_stream.peer (),
277 remote_sap,
278 qos_params,
279 timeout,
280 local_sap,
281 protocolinfo,
283 flags,
284 reuse_addr,
285 perms);
287 int error = 0;
288 if (result == -1)
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
297 && (result == 0
298 || (result == -1 && (error == EWOULDBLOCK
299 || error == EINPROGRESS))))
300 new_stream.set_handle (new_stream.peer ().get_handle ());
302 if (result == -1)
303 return result;
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.
308 if (timeout != 0)
310 countdown.update ();
311 timeout = &time_copy;
314 result = this->ssl_connect (new_stream, timeout);
316 if (result == -1)
317 new_stream.close ();
319 return result;
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);
335 if (tv != 0)
337 time_copy += *tv;
338 countdown.start ();
341 // Only attempt to complete the TCP connection if it that hasn't
342 // already been done.
343 ACE_INET_Addr raddr;
344 if (new_stream.peer ().get_remote_addr (raddr) != 0
345 && this->connector_.complete (new_stream.peer (),
346 remote_sap,
347 tv) == -1)
348 return -1;
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.
356 if (tv != 0)
358 countdown.update ();
359 tv = &time_copy;
362 if (this->ssl_connect (new_stream, tv) == -1)
364 new_stream.close ();
365 return -1;
368 return 0;
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,
377 int reuse_addr,
378 int flags,
379 int perms)
380 : connector_ ()
382 ACE_TRACE ("ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector");
383 this->connect (new_stream,
384 remote_sap,
385 timeout,
386 local_sap,
387 reuse_addr,
388 flags,
389 perms);
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,
399 ACE_SOCK_GROUP g,
400 u_long flags,
401 int reuse_addr,
402 int perms)
403 : connector_ ()
405 ACE_TRACE ("ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector");
407 this->connect (new_stream,
408 remote_sap,
409 qos_params,
410 timeout,
411 local_sap,
412 protocolinfo,
414 flags,
415 reuse_addr,
416 perms);
419 ACE_END_VERSIONED_NAMESPACE_DECL