Merge pull request #2216 from jwillemsen/jwi-cxxversionchecks
[ACE_TAO.git] / ACE / protocols / ace / INet / SSL_Proxy_Connector.cpp
blob91e42445763b2b876ba6893f52c915b8ae9e0a28
1 #include "ace/INet/SSL_Proxy_Connector.h"
2 #include "ace/INet/INet_Log.h"
4 #include "ace/OS_NS_errno.h"
5 #include "ace/Handle_Set.h"
6 #include "ace/Log_Msg.h"
7 #include "ace/Countdown_Time.h"
8 #include "ace/Truncate.h"
10 #include <openssl/err.h>
12 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
14 namespace ACE
16 namespace INet
18 SSL_Proxy_Connector::SSL_Proxy_Connector () {}
20 SSL_Proxy_Connector::~SSL_Proxy_Connector () {}
23 * This code is copied from ace/SSL/SSL_SOCK_Connector.cpp
25 int
26 SSL_Proxy_Connector::ssl_connect (ACE_SSL_SOCK_Stream &new_stream,
27 const ACE_Time_Value *timeout)
29 SSL *ssl = new_stream.ssl ();
31 if (SSL_is_init_finished (ssl))
32 return 0;
34 // Check if a connection is already pending for the given SSL
35 // structure.
36 if (!SSL_in_connect_init (ssl))
37 ::SSL_set_connect_state (ssl);
39 ACE_HANDLE handle = new_stream.get_handle ();
41 // We're going to call SSL_connect, optionally doing ACE::select and
42 // retrying the SSL_connect, until the SSL handshake is done or
43 // it fails.
44 // To get the timeout affect, set the socket to nonblocking mode
45 // before beginning if there is a timeout specified. If the timeout
46 // is 0 (wait as long as it takes) then don't worry about the blocking
47 // status; we'll block in SSL_connect if the socket is blocking, and
48 // block in ACE::select if not.
49 int reset_blocking_mode = 0;
50 if (timeout != 0)
52 reset_blocking_mode = ACE_BIT_DISABLED (ACE::get_flags (handle),
53 ACE_NONBLOCK);
54 // Set the handle into non-blocking mode if it's not already
55 // in it.
56 if (reset_blocking_mode
57 && ACE::set_flags (handle,
58 ACE_NONBLOCK) == -1)
59 return -1;
62 ACE_Time_Value t;
63 if (timeout != 0)
64 t = *timeout; // Need a non-const copy.
66 // Take into account the time between each select() call below.
67 ACE_Countdown_Time countdown ((timeout == 0 ? 0 : &t));
69 int status;
73 // These handle sets are used to set up for whatever SSL_connect
74 // says it wants next. They're reset on each pass around the loop.
75 ACE_Handle_Set rd_handle;
76 ACE_Handle_Set wr_handle;
78 status = ::SSL_connect (ssl);
79 switch (::SSL_get_error (ssl, status))
81 case SSL_ERROR_NONE:
82 // Start out with non-blocking disabled on the SSL stream.
83 new_stream.disable (ACE_NONBLOCK);
84 status = 0; // To tell caller about success
85 break; // Done
87 case SSL_ERROR_WANT_WRITE:
88 wr_handle.set_bit (handle);
89 status = 1; // Wait for more activity
90 break;
92 case SSL_ERROR_WANT_READ:
93 rd_handle.set_bit (handle);
94 status = 1; // Wait for more activity
95 break;
97 case SSL_ERROR_ZERO_RETURN:
98 // The peer has notified us that it is shutting down via
99 // the SSL "close_notify" message so we need to
100 // shutdown, too.
101 status = -1;
102 break;
104 case SSL_ERROR_SYSCALL:
105 // On some platforms (e.g. MS Windows) OpenSSL does not
106 // store the last error in errno so explicitly do so.
108 // Explicitly check for EWOULDBLOCK since it doesn't get
109 // converted to an SSL_ERROR_WANT_{READ,WRITE} on some
110 // platforms. If SSL_connect failed outright, though, don't
111 // bother checking more. This can happen if the socket gets
112 // closed during the handshake.
113 if (ACE_OS::set_errno_to_last_error () == EWOULDBLOCK &&
114 status == -1)
116 // Although the SSL_ERROR_WANT_READ/WRITE isn't getting
117 // set correctly, the read/write state should be valid.
118 // Use that to decide what to do.
119 status = 1; // Wait for more activity
120 if (SSL_want_write (ssl))
122 wr_handle.set_bit (handle);
124 else if (SSL_want_read (ssl))
126 rd_handle.set_bit (handle);
128 else
130 status = -1; // Doesn't want anything - bail out
133 else
135 status = -1;
137 break;
139 default:
140 ACE_SSL_Context::report_error ();
141 status = -1;
142 break;
145 if (status == 1)
147 // Must have at least one handle to wait for at this point.
148 ACE_ASSERT (rd_handle.num_set () == 1 || wr_handle.num_set () == 1);
150 // Block indefinitely if timeout pointer is zero.
151 status = ACE::select (int (handle) + 1,
152 &rd_handle,
153 &wr_handle,
155 (timeout == 0 ? 0 : &t));
157 (void) countdown.update ();
159 // 0 is timeout, so we're done.
160 // -1 is error, so we're done.
161 // Could be both handles set (same handle in both masks) so set to 1.
162 if (status >= 1)
164 status = 1;
166 else // Timeout or socket failure
168 status = -1;
172 } while (status == 1 && !SSL_is_init_finished (ssl));
174 if (reset_blocking_mode)
176 ACE_Errno_Guard eguard (errno);
177 ACE::clr_flags (handle, ACE_NONBLOCK);
180 return (status == -1 ? -1 : 0);
184 SSL_Proxy_Connector::connect (ACE_SSL_SOCK_Stream &new_stream,
185 ACE_HANDLE proxy_handle,
186 const ACE_Time_Value *timeout)
188 INET_TRACE ("SSL_Proxy_Connector::connect");
190 if (new_stream.get_handle () != ACE_INVALID_HANDLE)
191 return -1; // SSL already connected, somebody made a mistake here
193 // Set the handle from the established proxy connection in the
194 // SSL_SOCK_Stream.
195 new_stream.set_handle (proxy_handle);
197 // Finalize the connection by performing the SSL handshake
198 int result = this->ssl_connect (new_stream, timeout);
200 if (result == -1)
201 new_stream.close ();
203 return result;
209 ACE_END_VERSIONED_NAMESPACE_DECL