GitHub Actions: Try MSVC builds with /std:c++17 and 20
[ACE_TAO.git] / ACE / ace / SSL / SSL_SOCK_Stream.inl
blob558be3e6628c77c82630a4698a7effc8a2b3dcf3
1 // -*- C++ -*-
2 #include "ace/OS_NS_errno.h"
3 #include "ace/Truncate.h"
5 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
7 ACE_INLINE void
8 ACE_SSL_SOCK_Stream::set_handle (ACE_HANDLE fd)
10   if (this->ssl_ == 0 || fd == ACE_INVALID_HANDLE)
11     {
12       this->ACE_SSL_SOCK::set_handle (ACE_INVALID_HANDLE);
13       return;
14     }
15   else
16     {
17       (void) ::SSL_set_fd (this->ssl_, (int) fd);
18       this->ACE_SSL_SOCK::set_handle (fd);
19       this->stream_.set_handle (fd);
20     }
23 ACE_INLINE ssize_t
24 ACE_SSL_SOCK_Stream::send_i (const void *buf,
25                              size_t n,
26                              int flags) const
28   ACE_TRACE ("ACE_SSL_SOCK_Stream::send_i");
30   // NOTE: Caller must provide thread-synchronization.
32   // No send flags are supported in SSL.
33   if (flags != 0)
34     {
35       ACE_NOTSUP_RETURN (-1);
36     }
38   int const bytes_sent = ::SSL_write (this->ssl_,
39                                       static_cast<const char *> (buf),
40                                       ACE_Utils::truncate_cast<int> (n));
42   switch (::SSL_get_error (this->ssl_, bytes_sent))
43     {
44     case SSL_ERROR_NONE:
45       return bytes_sent;
47     case SSL_ERROR_WANT_READ:
48     case SSL_ERROR_WANT_WRITE:
49       errno = EWOULDBLOCK;
51       return -1;
53     case SSL_ERROR_ZERO_RETURN:
54       // The peer has notified us that it is shutting down via the SSL
55       // "close_notify" message so we need to shutdown, too.
56       (void) ::SSL_shutdown (this->ssl_);
58       return bytes_sent;
60     case SSL_ERROR_SYSCALL:
61       if (bytes_sent == 0)
62         // An EOF occurred but the SSL "close_notify" message was not
63         // sent.  This is a protocol error, but we ignore it.
64         return 0;
66       // If not an EOF, then fall through to "default" case.
68       // On some platforms (e.g. MS Windows) OpenSSL does not store
69       // the last error in errno so explicitly do so.
70       ACE_OS::set_errno_to_last_error ();
72       break;
74     default:
75       // Reset errno to prevent previous values (e.g. EWOULDBLOCK)
76       // from being associated with fatal SSL errors.
77       errno = 0;
79       ACE_SSL_Context::report_error ();
81       break;
82     }
84   return -1;
87 ACE_INLINE ssize_t
88 ACE_SSL_SOCK_Stream::send (const void *buf,
89                            size_t n,
90                            int flags) const
92   return this->send_i (buf, n, flags);
95 ACE_INLINE ssize_t
96 ACE_SSL_SOCK_Stream::recv_i (void *buf,
97                              size_t n,
98                              int flags,
99                              const ACE_Time_Value *timeout) const
101   ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_i");
103   // NOTE: Caller must provide thread-synchronization.
104   int bytes_read = 0;
105   ACE_HANDLE const handle = this->get_handle ();
107   // Value for current I/O mode (blocking/non-blocking)
108   int val = 0;
110   if (timeout != 0)
111     ACE::record_and_set_non_blocking_mode (handle,
112                                            val);
114   // Only block to wait for I/O ready with a timeout if all on-hand data
115   // has been consumed. If there is remaining data in the SSL buffers
116   // the socket won't "select" even though SSL_read would complete.
117   // See "SSL and TLS" by Rescorla section 8.9 for more info.
118   bool peeking = false;
119   bool retry = false;
120   if (flags)
121     {
122       if (ACE_BIT_ENABLED (flags, MSG_PEEK))
123         {
124           peeking = true;
125         }
126       else
127         {
128           ACE_NOTSUP_RETURN (-1);
129         }
130     }
132   do
133     {
134       retry = false;
135       if (peeking)
136         {
137           bytes_read = ::SSL_peek (this->ssl_,
138                                    static_cast<char *> (buf),
139                                    ACE_Utils::truncate_cast<int> (n));
140         }
141       else
142         {
143           bytes_read = ::SSL_read (this->ssl_,
144                                    static_cast<char *> (buf),
145                                    ACE_Utils::truncate_cast<int> (n));
146         }
148       int const status = ::SSL_get_error (this->ssl_, bytes_read);
149       int substat = 0;
150       switch (status)
151         {
152         case SSL_ERROR_NONE:
153           break;
155         case SSL_ERROR_WANT_READ:
156         case SSL_ERROR_WANT_WRITE:
157           if (timeout == 0)
158             {
159               errno = EWOULDBLOCK;
160               bytes_read = -1;
161               break;
162             }
163           substat = ACE::handle_ready (handle,
164                                        timeout,
165                                        status == SSL_ERROR_WANT_READ,
166                                        status == SSL_ERROR_WANT_WRITE,
167                                        false);
168           if (substat == 1)   // Now ready to proceed
169             {
170               retry = true;
171               break;
172             }
173           bytes_read = -1;
174           if (substat == 0)
175             errno = ETIME;
176           break;
178         case SSL_ERROR_ZERO_RETURN:
179           bytes_read = 0;
181           // The peer has notified us that it is shutting down via the SSL
182           // "close_notify" message so we need to shutdown, too.
183           (void) ::SSL_shutdown (this->ssl_);
185           break;
187         case SSL_ERROR_SYSCALL:
188           if (bytes_read == 0)
189             // An EOF occurred but the SSL "close_notify" message was not
190             // sent.  This is a protocol error, but we ignore it.
191             break;
193           // On some platforms (e.g. MS Windows) OpenSSL does not store
194           // the last error in errno so explicitly do so.
195           ACE_OS::set_errno_to_last_error ();
197           break;
199         default:
200           // Reset errno to prevent previous values (e.g. EWOULDBLOCK)
201           // from being associated with a fatal SSL error.
202           bytes_read = -1;
203           errno = 0;
205           ACE_SSL_Context::report_error ();
207           break;
208         }
209     } while (retry);
211   if (timeout != 0)
212     ACE::restore_non_blocking_mode (handle, val);
213   return bytes_read;
216 ACE_INLINE ssize_t
217 ACE_SSL_SOCK_Stream::recv (void *buf,
218                            size_t n,
219                            int flags) const
221   return this->recv_i (buf, n, flags, 0);
224 ACE_INLINE ssize_t
225 ACE_SSL_SOCK_Stream::send (const void *buf,
226                            size_t n) const
228   ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
230   return this->send_i (buf, n, 0);
233 ACE_INLINE ssize_t
234 ACE_SSL_SOCK_Stream::recv (void *buf,
235                            size_t n) const
237   ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
239   return this->recv_i (buf, n, 0, 0);
242 ACE_INLINE ssize_t
243 ACE_SSL_SOCK_Stream::send (const void *buf,
244                            size_t len,
245                            const ACE_Time_Value *timeout) const
247   ACE_TRACE ("ACE_SSL_SOCK_Stream::send");
248   return this->send (buf, len, 0, timeout);
251 ACE_INLINE ssize_t
252 ACE_SSL_SOCK_Stream::recv (void *buf,
253                            size_t n,
254                            const ACE_Time_Value *timeout) const
256   ACE_TRACE ("ACE_SSL_SOCK_Stream::recv");
257   return this->recv (buf, n, 0, timeout);
260 ACE_INLINE ssize_t
261 ACE_SSL_SOCK_Stream::recv_n (void *buf, int buf_size) const
263   ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
264   return this->recv_n (buf, buf_size, 0);
267 ACE_INLINE ssize_t
268 ACE_SSL_SOCK_Stream::recv_n (void *buf,
269                              size_t len,
270                              const ACE_Time_Value *timeout,
271                              size_t *bytes_transferred) const
273   ACE_TRACE ("ACE_SSL_SOCK_Stream::recv_n");
274   return this->recv_n (buf, len, 0, timeout, bytes_transferred);
277 ACE_INLINE ssize_t
278 ACE_SSL_SOCK_Stream::send_n (const void *buf, int len) const
280   ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
281   return this->send_n (buf, len, 0);
284 ACE_INLINE ssize_t
285 ACE_SSL_SOCK_Stream::send_n (const void *buf,
286                              size_t len,
287                              const ACE_Time_Value *timeout,
288                              size_t *bytes_transferred) const
290   ACE_TRACE ("ACE_SSL_SOCK_Stream::send_n");
291   return this->send_n (buf, len, 0, timeout, bytes_transferred);
294 ACE_INLINE int
295 ACE_SSL_SOCK_Stream::close_reader (void)
297   ACE_TRACE ("ACE_SSL_SOCK_Stream::close_reader");
298   return this->stream_.close_reader ();
301 ACE_INLINE int
302 ACE_SSL_SOCK_Stream::close_writer (void)
304   ACE_TRACE ("ACE_SSL_SOCK_Stream::close_writer");
305   return this->stream_.close_writer ();
308 ACE_INLINE int
309 ACE_SSL_SOCK_Stream::close (void)
311   ACE_TRACE ("ACE_SSL_SOCK_Stream::close");
313   if (this->ssl_ == 0 || this->get_handle () == ACE_INVALID_HANDLE)
314     return 0;  // SSL_SOCK_Stream was never opened.
316   // SSL_shutdown() returns 1 on successful shutdown of the SSL
317   // connection, not 0.
318   int const status = ::SSL_shutdown (this->ssl_);
320   switch (::SSL_get_error (this->ssl_, status))
321     {
322     case SSL_ERROR_NONE:
323     case SSL_ERROR_SYSCALL:  // Ignore this error condition.
325       // Reset the SSL object to allow another connection to be made
326       // using this ACE_SSL_SOCK_Stream instance.  This prevents the
327       // previous SSL session state from being associated with the new
328       // SSL session/connection.
329       (void) ::SSL_clear (this->ssl_);
330       this->set_handle (ACE_INVALID_HANDLE);
331       return this->stream_.close ();
333     case SSL_ERROR_WANT_READ:
334     case SSL_ERROR_WANT_WRITE:
335       errno = EWOULDBLOCK;
336       break;
338     default:
339       ACE_SSL_Context::report_error ();
341       ACE_Errno_Guard error (errno);   // Save/restore errno
342       (void) this->stream_.close ();
344       return -1;
345     }
347   return -1;
350 ACE_INLINE ACE_SOCK_Stream &
351 ACE_SSL_SOCK_Stream::peer (void)
353   ACE_TRACE ("ACE_SSL_SOCK_Stream::peer");
354   return this->stream_;
357 ACE_INLINE SSL *
358 ACE_SSL_SOCK_Stream::ssl (void) const
360   return this->ssl_;
363 ACE_END_VERSIONED_NAMESPACE_DECL