Document return values
[ACE_TAO.git] / ACE / ace / SSL / SSL_SOCK_Acceptor.cpp
blob2fcd75c2c9513134f6b1f4f9e493fc48181ce699
1 // -*- C++ -*-
3 #include "SSL_SOCK_Acceptor.h"
5 #include "ace/Handle_Set.h"
6 #include "ace/OS_Errno.h"
7 #include "ace/OS_NS_errno.h"
8 #include "ace/Log_Category.h"
9 #include "ace/Time_Value.h"
10 #include "ace/Countdown_Time.h"
11 #include "ace/Truncate.h"
13 #if !defined (__ACE_INLINE__)
14 #include "SSL_SOCK_Acceptor.inl"
15 #endif /* __ACE_INLINE__ */
17 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
19 ACE_ALLOC_HOOK_DEFINE(ACE_SSL_SOCK_Acceptor)
21 ACE_SSL_SOCK_Acceptor::~ACE_SSL_SOCK_Acceptor ()
23 ACE_TRACE ("ACE_SSL_SOCK_Acceptor::~ACE_SSL_SOCK_Acceptor");
26 int
27 ACE_SSL_SOCK_Acceptor::ssl_accept (ACE_SSL_SOCK_Stream &new_stream,
28 ACE_Time_Value *timeout) const
30 SSL *ssl = new_stream.ssl ();
32 if (SSL_is_init_finished (ssl))
33 return 0;
35 if (!SSL_in_accept_init (ssl))
36 ::SSL_set_accept_state (ssl);
38 ACE_HANDLE handle = new_stream.get_handle ();
40 // We're going to call SSL_accept, optionally doing ACE::select and
41 // retrying the SSL_accept, until the SSL handshake is done or
42 // it fails.
43 // To get the timeout affect, set the socket to nonblocking mode
44 // before beginning if there is a timeout specified. If the timeout
45 // is 0 (wait as long as it takes) then don't worry about the blocking
46 // status; we'll block in SSL_accept if the socket is blocking, and
47 // block in ACE::select if not.
48 int reset_blocking_mode = 0;
49 if (timeout != 0)
51 reset_blocking_mode = ACE_BIT_DISABLED (ACE::get_flags (handle),
52 ACE_NONBLOCK);
53 // Set the handle into non-blocking mode if it's not already
54 // in it.
55 if (reset_blocking_mode
56 && ACE::set_flags (handle,
57 ACE_NONBLOCK) == -1)
58 return -1;
61 // Take into account the time between each select() call below.
62 ACE_Countdown_Time countdown (timeout);
64 int status;
67 // These handle sets are used to set up for whatever SSL_accept
68 // says it wants next. They're reset on each pass around the loop.
69 ACE_Handle_Set rd_handle;
70 ACE_Handle_Set wr_handle;
72 status = ::SSL_accept (ssl);
73 switch (::SSL_get_error (ssl, status))
75 case SSL_ERROR_NONE:
76 status = 0; // To tell caller about success
77 break; // Done
79 case SSL_ERROR_WANT_WRITE:
80 wr_handle.set_bit (handle);
81 status = 1; // Wait for more activity
82 break;
84 case SSL_ERROR_WANT_READ:
85 rd_handle.set_bit (handle);
86 status = 1; // Wait for more activity
87 break;
89 case SSL_ERROR_ZERO_RETURN:
90 // The peer has notified us that it is shutting down via
91 // the SSL "close_notify" message so we need to
92 // shutdown, too.
93 status = -1;
94 break;
96 case SSL_ERROR_SYSCALL:
97 // On some platforms (e.g. MS Windows) OpenSSL does not
98 // store the last error in errno so explicitly do so.
100 // Explicitly check for EWOULDBLOCK since it doesn't get
101 // converted to an SSL_ERROR_WANT_{READ,WRITE} on some
102 // platforms. If SSL_accept failed outright, though, don't
103 // bother checking more. This can happen if the socket gets
104 // closed during the handshake.
105 if (ACE_OS::set_errno_to_last_error () == EWOULDBLOCK &&
106 status == -1)
108 // Although the SSL_ERROR_WANT_READ/WRITE isn't getting
109 // set correctly, the read/write state should be valid.
110 // Use that to decide what to do.
111 status = 1; // Wait for more activity
112 if (SSL_want_write (ssl))
113 wr_handle.set_bit (handle);
114 else if (SSL_want_read (ssl))
115 rd_handle.set_bit (handle);
116 else
117 status = -1; // Doesn't want anything - bail out
119 else
120 status = -1;
121 break;
123 default:
124 ACE_SSL_Context::report_error ();
125 status = -1;
126 break;
129 if (status == 1)
131 // Must have at least one handle to wait for at this point.
132 ACE_ASSERT (rd_handle.num_set() == 1 || wr_handle.num_set () == 1);
133 status = ACE::select (int (handle) + 1,
134 &rd_handle,
135 &wr_handle,
137 timeout);
139 (void) countdown.update ();
141 // 0 is timeout, so we're done.
142 // -1 is error, so we're done.
143 // Could be both handles set (same handle in both masks) so
144 // set to 1.
145 if (status >= 1)
146 status = 1;
147 else // Timeout or failure
148 status = -1;
151 } while (status == 1 && !SSL_is_init_finished (ssl));
153 if (reset_blocking_mode)
155 ACE_Errno_Guard eguard (errno);
156 ACE::clr_flags (handle, ACE_NONBLOCK);
159 return (status == -1 ? -1 : 0);
162 // General purpose routine for accepting new connections.
163 // Since our underlying acceptor is of the plain old ACE_SOCK_Acceptor
164 // variety, get the basic socket setup done with it, then take care of
165 // the SSL handshake if the socket is accepted.
167 ACE_SSL_SOCK_Acceptor::accept (ACE_SSL_SOCK_Stream &new_stream,
168 ACE_Addr *remote_addr,
169 ACE_Time_Value *timeout,
170 bool restart,
171 bool reset_new_handle) const
173 ACE_TRACE ("ACE_SSL_SOCK_Acceptor::accept");
175 // Take into account the time to complete the basic TCP handshake
176 // and the SSL handshake.
177 ACE_Countdown_Time countdown (timeout);
179 ACE_SOCK_Stream temp_stream;
180 if (-1 == this->acceptor_.accept (temp_stream,
181 remote_addr,
182 timeout,
183 restart,
184 reset_new_handle))
185 return -1;
187 (void) countdown.update ();
189 new_stream.set_handle (temp_stream.get_handle ());
190 temp_stream.set_handle (ACE_INVALID_HANDLE);
192 if (this->ssl_accept (new_stream, timeout) == -1)
194 new_stream.close ();
195 new_stream.set_handle (ACE_INVALID_HANDLE);
196 return -1;
199 return 0;
203 ACE_SSL_SOCK_Acceptor::accept (ACE_SSL_SOCK_Stream &new_stream,
204 ACE_Accept_QoS_Params qos_params,
205 ACE_Addr *remote_addr,
206 ACE_Time_Value *timeout,
207 bool restart,
208 bool reset_new_handle) const
210 ACE_TRACE ("ACE_SSL_SOCK_Acceptor::accept");
212 // Take into account the time to complete the basic TCP handshake
213 // and the SSL handshake.
214 ACE_Countdown_Time countdown (timeout);
216 ACE_SOCK_Stream temp_stream;
217 if (-1 == this->acceptor_.accept (temp_stream,
218 qos_params,
219 remote_addr,
220 timeout,
221 restart,
222 reset_new_handle))
223 return -1;
225 (void) countdown.update ();
227 new_stream.set_handle (temp_stream.get_handle ());
228 temp_stream.set_handle (ACE_INVALID_HANDLE);
230 if (this->ssl_accept (new_stream, timeout) == -1)
232 new_stream.close ();
233 new_stream.set_handle (ACE_INVALID_HANDLE);
234 return -1;
237 return 0;
240 ACE_END_VERSIONED_NAMESPACE_DECL