Line data Source code
1 : // Copyright (c) 2012-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Event dispatch class.
22 : *
23 : * Class used to handle events.
24 : */
25 :
26 : // make sure we use OpenSSL with multi-thread support
27 : // (TODO: move to .cpp once we have the impl!)
28 : #define OPENSSL_THREAD_DEFINES
29 :
30 : #define USE_KLUDGE 1
31 :
32 : // self
33 : //
34 : #include "eventdispatcher/tcp_bio_server.h"
35 :
36 : #include "eventdispatcher/exception.h"
37 : #include "eventdispatcher/tcp_private.h"
38 :
39 :
40 : // snaplogger
41 : //
42 : #include <snaplogger/message.h>
43 :
44 :
45 : // snapdev
46 : //
47 : #include <snapdev/not_used.h>
48 :
49 :
50 : // C++
51 : //
52 : #include <algorithm>
53 :
54 :
55 : // OpenSSL
56 : //
57 : #include <openssl/ssl.h>
58 :
59 :
60 : // C
61 : //
62 : #include <fcntl.h>
63 :
64 :
65 : // last include
66 : //
67 : #include <snapdev/poison.h>
68 :
69 :
70 :
71 :
72 : #ifndef OPENSSL_THREADS
73 : #error "OPENSSL_THREADS is not defined. Snap! requires support for multiple threads in OpenSSL."
74 : #endif
75 :
76 : namespace ed
77 : {
78 :
79 :
80 : namespace detail
81 : {
82 :
83 :
84 0 : class tcp_bio_server_impl
85 : {
86 : public:
87 : int f_max_connections = MAX_CONNECTIONS;
88 : std::shared_ptr<SSL_CTX> f_ssl_ctx = std::shared_ptr<SSL_CTX>();
89 : std::shared_ptr<BIO> f_listen = std::shared_ptr<BIO>();
90 : bool f_keepalive = true;
91 : bool f_close_on_exec = false;
92 : };
93 :
94 :
95 : }
96 :
97 :
98 : /** \class tcp_bio_server
99 : * \brief Create a BIO server, bind it, and listen for connections.
100 : *
101 : * This class is a server socket implementation used to listen for
102 : * connections that are to use TLS encryptions.
103 : *
104 : * The bind address must be available for the server initialization
105 : * to succeed.
106 : *
107 : * The BIO extension is from the OpenSSL library and it allows the server
108 : * to allow connections using SSL (TLS really now a day). The server
109 : * expects to be given information about a certificate and a private
110 : * key to function. You may also use the server in a non-secure manner
111 : * (without the TLS layer) so you do not need to implement two instances
112 : * of your server, one with tcp_bio_server and one with tcp_server.
113 : */
114 :
115 :
116 :
117 :
118 : /** \brief Construct a tcp_bio_server object.
119 : *
120 : * The tcp_bio_server constructor initializes a BIO server and listens
121 : * for connections from the specified address and port.
122 : *
123 : * The \p certificate and \p private_key filenames are expected to point
124 : * to a PEM file (.pem extension) that include the encryption information.
125 : *
126 : * The certificate file may include a chain in which case the whole chain
127 : * will be taken in account.
128 : *
129 : * \warning
130 : * Currently the max_connections parameter is pretty much ignored since
131 : * there is no way to pass that parameter down to the BIO interface. In
132 : * that code they use the SOMAXCONN definition which under Linux is
133 : * defined at 128 (Ubuntu 16.04.1). See:
134 : * /usr/include/x86_64-linux-gnu/bits/socket.h
135 : *
136 : * \param[in] address The address and port defined in an addr object.
137 : * \param[in] max_connections The number of connections to keep in the listen queue.
138 : * \param[in] reuse_addr Whether to mark the socket with the SO_REUSEADDR flag.
139 : * \param[in] certificate The server certificate filename (PEM).
140 : * \param[in] private_key The server private key filename (PEM).
141 : * \param[in] mode The mode used to create the listening socket.
142 : */
143 0 : tcp_bio_server::tcp_bio_server(
144 : addr::addr const & address
145 : , int max_connections
146 : , bool reuse_addr
147 : , std::string const & certificate
148 : , std::string const & private_key
149 0 : , mode_t mode)
150 0 : : f_impl(std::make_shared<detail::tcp_bio_server_impl>())
151 : {
152 0 : f_impl->f_max_connections = std::clamp(max_connections <= 0 ? MAX_CONNECTIONS : max_connections, 5, 1000);
153 :
154 0 : detail::bio_initialize();
155 :
156 0 : switch(mode)
157 : {
158 0 : case mode_t::MODE_ALWAYS_SECURE:
159 : case mode_t::MODE_SECURE:
160 : {
161 : // the following code is based on the example shown in the man page
162 : //
163 : // man BIO_f_ssl
164 : //
165 0 : if(certificate.empty()
166 0 : || private_key.empty())
167 : {
168 0 : throw initialization_error("with MODE_SECURE you must specify a certificate and a private_key filename");
169 : }
170 :
171 0 : std::shared_ptr<SSL_CTX> ssl_ctx; // use reset(), see SNAP-507
172 0 : ssl_ctx.reset(SSL_CTX_new(SSLv23_server_method()), detail::ssl_ctx_deleter);
173 0 : if(!ssl_ctx)
174 : {
175 0 : detail::bio_log_errors();
176 0 : throw initialization_error("failed creating an SSL_CTX server object");
177 : }
178 :
179 0 : SSL_CTX_set_cipher_list(ssl_ctx.get(), "ALL");//"HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
180 :
181 : // Assign the certificate to the SSL context
182 : //
183 : // TBD: we may want to use SSL_CTX_use_certificate_file() instead
184 : // (i.e. not the "chained" version)
185 : //
186 0 : if(!SSL_CTX_use_certificate_chain_file(ssl_ctx.get(), certificate.c_str()))
187 : {
188 0 : detail::bio_log_errors();
189 0 : throw initialization_error("failed initializing an SSL_CTX server object certificate");
190 : }
191 :
192 : // Assign the private key to the SSL context
193 : //
194 0 : if(!SSL_CTX_use_PrivateKey_file(ssl_ctx.get(), private_key.c_str(), SSL_FILETYPE_PEM))
195 : {
196 : // on failure, try again again with the RSA version, just in case
197 : // (probably useless?)
198 : //
199 : #if OPENSSL_VERSION_NUMBER < 0x30000020L
200 0 : if(!SSL_CTX_use_RSAPrivateKey_file(ssl_ctx.get(), private_key.c_str(), SSL_FILETYPE_PEM))
201 : {
202 : #endif
203 0 : detail::bio_log_errors();
204 0 : throw initialization_error("failed initializing an SSL_CTX server object private key");
205 : #if OPENSSL_VERSION_NUMBER < 0x30000020L
206 : }
207 : #endif
208 : }
209 :
210 : // Verify that the private key and certificate are a match
211 : //
212 0 : if(!SSL_CTX_check_private_key(ssl_ctx.get()))
213 : {
214 0 : detail::bio_log_errors();
215 0 : throw initialization_error("failed initializing an SSL_CTX server object private key");
216 : }
217 :
218 : // create a BIO connection with SSL
219 : //
220 0 : std::unique_ptr<BIO, void (*)(BIO *)> bio(BIO_new_ssl(ssl_ctx.get(), 0), detail::bio_deleter);
221 0 : if(bio == nullptr)
222 : {
223 0 : detail::bio_log_errors();
224 0 : throw initialization_error("failed initializing a BIO server object");
225 : }
226 :
227 : // get the SSL pointer, which generally means that the BIO
228 : // allocate succeeded fully, so we can set auto-retry
229 : //
230 0 : SSL * ssl(nullptr);
231 : #pragma GCC diagnostic push
232 : #pragma GCC diagnostic ignored "-Wold-style-cast"
233 0 : BIO_get_ssl(bio.get(), &ssl);
234 : #pragma GCC diagnostic pop
235 0 : if(ssl == nullptr)
236 : {
237 : // TBD: does this mean we would have a plain connection?
238 0 : detail::bio_log_errors();
239 0 : throw initialization_error("failed connecting BIO object with SSL_CTX object");
240 : }
241 :
242 : // allow automatic retries in case the connection somehow needs
243 : // an SSL renegotiation (maybe we should turn that off for cases
244 : // where we connect to a secure payment gateway?)
245 : //
246 0 : SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
247 :
248 : // create a listening connection
249 : //
250 0 : std::shared_ptr<BIO> listen; // use reset(), see SNAP-507
251 0 : listen.reset(BIO_new_accept(address.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT).c_str()), detail::bio_deleter);
252 0 : if(!listen)
253 : {
254 0 : detail::bio_log_errors();
255 0 : throw initialization_error("failed initializing a BIO server object");
256 : }
257 :
258 0 : BIO_set_bind_mode(listen.get(), reuse_addr ? BIO_BIND_REUSEADDR : BIO_BIND_NORMAL);
259 :
260 : // Attach the SSL bio to the listening BIO, this means whenever
261 : // a new connection is accepted, it automatically attaches it to
262 : // an SSL connection
263 : //
264 : #pragma GCC diagnostic push
265 : #pragma GCC diagnostic ignored "-Wold-style-cast"
266 0 : BIO_set_accept_bios(listen.get(), bio.get());
267 : #pragma GCC diagnostic pop
268 :
269 : // WARNING: the listen object takes ownership of the `bio`
270 : // pointer and thus we have to make sure that we
271 : // do not keep it in our unique_ptr<>().
272 : //
273 0 : snapdev::NOT_USED(bio.release());
274 :
275 : // Actually call bind() and listen() on the socket
276 : //
277 : // I called BIO_do_accept() before, but this looks cleaner
278 : // (although both calls do the same thing)
279 : //
280 0 : int const r(BIO_do_connect(listen.get()));
281 0 : if(r <= 0)
282 : {
283 0 : detail::bio_log_errors();
284 0 : throw initialization_error("failed initializing the BIO server socket to listen for client connections");
285 : }
286 :
287 : #if USE_KLUDGE
288 : // HUGE KLUDGE!
289 : //
290 : // the BIO_do_connect() does not correctly report errors in
291 : // case the IP address is not valid for the bind() call
292 : // (i.e. the address is 1.2.3.4 and none of your interfaces
293 : // support that IP address) our KLUDGE checks that the socket
294 : // is valid because at least the library closes it on failure
295 : //
296 : // newer versions of the library have a fix since Thu Apr 9 12:36:37 2020 +0100
297 : // (it should be in there for 1.1.2 or so)
298 : //
299 0 : int c(-1);
300 : #pragma GCC diagnostic push
301 : #pragma GCC diagnostic ignored "-Wold-style-cast"
302 0 : BIO_get_fd(listen.get(), &c);
303 : #pragma GCC diagnostic pop
304 0 : if(c < 0)
305 : {
306 0 : std::stringstream ss;
307 : ss << "bind() failed to connect to "
308 0 : << address;
309 0 : throw initialization_error(ss.str());
310 : }
311 0 : int error_code(0);
312 0 : socklen_t error_code_size = sizeof(error_code);
313 0 : int const g(getsockopt(c, SOL_SOCKET, SO_ERROR, reinterpret_cast<void *>(&error_code), &error_code_size));
314 0 : if(g != 0)
315 : {
316 0 : error_code = errno;
317 : }
318 0 : if(error_code != 0)
319 : {
320 0 : std::stringstream ss;
321 : ss << "bind() failed to connect to "
322 : << address
323 0 : << " and reported error #"
324 : << error_code
325 : << ", "
326 0 : << strerror(error_code);
327 0 : throw initialization_error(ss.str());
328 : }
329 : #endif
330 :
331 : // it worked, save the results
332 0 : f_impl->f_ssl_ctx.swap(ssl_ctx);
333 0 : f_impl->f_listen.swap(listen);
334 :
335 : // secure connection ready
336 : }
337 0 : break;
338 :
339 0 : case mode_t::MODE_PLAIN:
340 : {
341 0 : std::shared_ptr<BIO> listen; // use reset(), see SNAP-507
342 0 : listen.reset(BIO_new_accept(address.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT).c_str()), detail::bio_deleter);
343 0 : if(listen == nullptr)
344 : {
345 0 : detail::bio_log_errors();
346 0 : throw initialization_error("failed initializing a BIO server object");
347 : }
348 :
349 0 : BIO_set_bind_mode(listen.get(), BIO_BIND_REUSEADDR);
350 :
351 : // Call bind() and listen() on the socket
352 : //
353 : // I called BIO_do_accept() before, but this looks cleaner
354 : // (although both calls do the same thing)
355 : //
356 0 : int const r(BIO_do_connect(listen.get()));
357 0 : if(r <= 0)
358 : {
359 0 : detail::bio_log_errors();
360 0 : throw initialization_error("failed initializing the BIO server socket to listen for client connections");
361 : }
362 :
363 : #if USE_KLUDGE
364 : // HUGE KLUDGE!
365 : //
366 : // the BIO_do_connect() does not correctly report errors in
367 : // case the IP address is not valid for the bind() call
368 : // (i.e. the address is 1.2.3.4 and none of your interfaces
369 : // support that IP address) our KLUDGE checks that the socket
370 : // is valid because at least the library closes it on failure
371 : //
372 : // newer versions of the library have a fix since Thu Apr 9 12:36:37 2020 +0100
373 : // (it should be in there for 1.1.2 or so)
374 : //
375 0 : int c(-1);
376 : #pragma GCC diagnostic push
377 : #pragma GCC diagnostic ignored "-Wold-style-cast"
378 0 : BIO_get_fd(listen.get(), &c);
379 : #pragma GCC diagnostic pop
380 0 : if(c < 0)
381 : {
382 0 : std::stringstream ss;
383 : ss << "bind() failed to connect to "
384 0 : << address;
385 0 : throw initialization_error(ss.str());
386 : }
387 0 : int error_code(ENOTCONN);
388 0 : socklen_t error_code_size = sizeof(error_code);
389 0 : int const g(getsockopt(c, SOL_SOCKET, SO_ERROR, reinterpret_cast<void *>(&error_code), &error_code_size));
390 0 : if(g != 0)
391 : {
392 0 : error_code = errno;
393 : }
394 0 : if(error_code != 0)
395 : {
396 0 : std::stringstream ss;
397 : ss << "bind() failed to connect to "
398 : << address
399 0 : << " and reported error #"
400 : << error_code
401 : << ", "
402 0 : << strerror(error_code);
403 0 : throw initialization_error(ss.str());
404 : }
405 : #endif
406 :
407 : // it worked, save the results
408 : //
409 0 : f_impl->f_listen.swap(listen);
410 : }
411 0 : break;
412 :
413 : }
414 0 : }
415 :
416 :
417 : /** \brief Clean up the TCP Bio Server object.
418 : *
419 : * This function cleans up the object on destruction.
420 : */
421 0 : tcp_bio_server::~tcp_bio_server()
422 : {
423 0 : }
424 :
425 :
426 : /** \brief Return the current status of the keepalive flag.
427 : *
428 : * This function returns the current status of the keepalive flag. This
429 : * flag is set to true by default (in the constructor.) It can be
430 : * changed with the set_keepalive() function.
431 : *
432 : * The flag is used to mark new connections with the SO_KEEPALIVE flag.
433 : * This is used whenever a service may take a little to long to answer
434 : * and avoid losing the TCP connection before the answer is sent to
435 : * the client.
436 : *
437 : * \warning
438 : * It is very likely that the BIO interface forces the keepalive flag
439 : * automatically so even if false here, it is very likely that your
440 : * connection will either way be marked as keepalive.
441 : *
442 : * \return The current status of the keepalive flag.
443 : */
444 0 : bool tcp_bio_server::get_keepalive() const
445 : {
446 0 : return f_impl->f_keepalive;
447 : }
448 :
449 :
450 : /** \brief Set the keepalive flag.
451 : *
452 : * This function sets the keepalive flag to either true (i.e. mark connection
453 : * sockets with the SO_KEEPALIVE flag) or false. The default is true (as set
454 : * in the constructor,) because in most cases this is a feature people want.
455 : *
456 : * \warning
457 : * The keepalive flag is likely force within the BIO interface, so setting it
458 : * to true here (which is the default anyway) probably has no real effect
459 : * (i.e. the fact is set a second time).
460 : *
461 : * \param[in] yes Whether to keep new connections alive even when no traffic
462 : * goes through.
463 : */
464 0 : void tcp_bio_server::set_keepalive(bool yes)
465 : {
466 0 : f_impl->f_keepalive = yes;
467 0 : }
468 :
469 :
470 : /** \brief Return the current status of the close_on_exec flag.
471 : *
472 : * This function returns the current status of the close_on_exec flag. This
473 : * flag is set to false by default (in the constructor.) It can be
474 : * changed with the set_close_on_exec() function.
475 : *
476 : * The flag is used to atomically mark new connections with the FD_CLOEXEC
477 : * flag. This prevents child processes from inheriting the socket (i.e. if
478 : * you use the system() function, for example, that process would inherit
479 : * your socket).
480 : *
481 : * \return The current status of the close_on_exec flag.
482 : */
483 0 : bool tcp_bio_server::get_close_on_exec() const
484 : {
485 0 : return f_impl->f_close_on_exec;
486 : }
487 :
488 :
489 : /** \brief Set the close_on_exec flag.
490 : *
491 : * This function sets the close_on_exec flag to either true (i.e. mark connection
492 : * sockets with the FD_CLOEXEC flag) or false. The default is false (as set
493 : * in the constructor,) because in our legacy code, the flag is not expected
494 : * to be set.
495 : *
496 : * \note
497 : * When set to true, the FD_CLOEXEC is also set on the listening socket so
498 : * the child can't snatch connections from under our feet.
499 : *
500 : * \warning
501 : * This is not thread safe. The BIO_do_accept() implementation uses the
502 : * accept() function which then returns and we set the FD_CLOEXEC flag
503 : * on the socket. This means it's not secure if you use exec() in a
504 : * separate thread (i.e. it may share the socket anyway unless your accept
505 : * is protected from such things). If you need to have a separate process,
506 : * look into using a fork() instead of force close the sockets in the
507 : * child process.
508 : *
509 : * \param[in] yes Whether to close on exec() or not.
510 : */
511 0 : void tcp_bio_server::set_close_on_exec(bool yes)
512 : {
513 0 : f_impl->f_close_on_exec = yes;
514 :
515 0 : if(yes)
516 : {
517 : // retrieve the socket (we do not yet have a bio_client object
518 : // so we cannot call a get_socket() function...)
519 : //
520 0 : int socket(-1);
521 : #pragma GCC diagnostic push
522 : #pragma GCC diagnostic ignored "-Wold-style-cast"
523 0 : BIO_get_fd(f_impl->f_listen.get(), &socket);
524 : #pragma GCC diagnostic pop
525 0 : if(socket >= 0)
526 : {
527 : // if this call fails, we ignore the error, but still log the event
528 : //
529 0 : if(fcntl(socket, F_SETFD, FD_CLOEXEC) != 0)
530 : {
531 0 : int const e(errno);
532 0 : SNAP_LOG_WARNING
533 : << "tcp_bio_server::set_close_on_exec(): an error occurred trying"
534 0 : " to mark accepted socket with FD_CLOEXEC ("
535 : << e
536 : << ", "
537 0 : << strerror(e)
538 : << ")."
539 : << SNAP_LOG_SEND;
540 : }
541 : }
542 : }
543 0 : }
544 :
545 :
546 : /** \brief Tell you whether the server uses a secure BIO or not.
547 : *
548 : * This function checks whether the BIO is using encryption (true)
549 : * or is a plain connection (false).
550 : *
551 : * \return true if the BIO was created in secure mode.
552 : */
553 0 : bool tcp_bio_server::is_secure() const
554 : {
555 0 : return f_impl->f_ssl_ctx != nullptr;
556 : }
557 :
558 :
559 : /** \brief Get the listening socket.
560 : *
561 : * This function returns the file descriptor of the listening socket.
562 : * By default the socket is in blocking mode.
563 : *
564 : * \return The listening socket file descriptor.
565 : */
566 0 : int tcp_bio_server::get_socket() const
567 : {
568 0 : if(f_impl->f_listen)
569 : {
570 0 : int c(-1);
571 : #pragma GCC diagnostic push
572 : #pragma GCC diagnostic ignored "-Wold-style-cast"
573 0 : BIO_get_fd(f_impl->f_listen.get(), &c);
574 : #pragma GCC diagnostic pop
575 0 : return c;
576 : }
577 :
578 0 : return -1;
579 : }
580 :
581 :
582 : /** \brief Retrieve one new connection.
583 : *
584 : * This function will wait until a new connection arrives and returns a
585 : * new bio_client object for each new connection.
586 : *
587 : * If the socket is made non-blocking then the function may return without
588 : * a bio_client object (i.e. a null pointer instead.)
589 : *
590 : * \return A shared pointer to a newly allocated bio_client object.
591 : */
592 0 : tcp_bio_client::pointer_t tcp_bio_server::accept()
593 : {
594 : // TBD: does one call to BIO_do_accept() accept at most one connection
595 : // at a time or could it be that 'r' will be set to 2, 3, 4...
596 : // as more connections get accepted?
597 : //
598 0 : int const r(BIO_do_accept(f_impl->f_listen.get()));
599 0 : if(r <= 0)
600 : {
601 : // TBD: should we instead return an empty shared pointer in this case?
602 : //
603 0 : detail::bio_log_errors();
604 0 : throw runtime_error("failed accepting a new BIO client");
605 : }
606 :
607 : // retrieve the new connection by "popping it"
608 : //
609 0 : std::shared_ptr<BIO> bio; // use reset(), see SNAP-507
610 0 : bio.reset(BIO_pop(f_impl->f_listen.get()), detail::bio_deleter);
611 0 : if(bio == nullptr)
612 : {
613 0 : detail::bio_log_errors();
614 0 : throw runtime_error("failed retrieving the accepted BIO");
615 : }
616 :
617 : // mark the new connection with the SO_KEEPALIVE flag
618 : //
619 : // note that it is likely that the BIO implementation already does that
620 : // automatically once the accept() succeeded.
621 : //
622 0 : if(f_impl->f_keepalive)
623 : {
624 : // retrieve the socket (we do not yet have a bio_client object
625 : // so we cannot call a get_socket() function...)
626 : //
627 0 : int socket(-1);
628 : #pragma GCC diagnostic push
629 : #pragma GCC diagnostic ignored "-Wold-style-cast"
630 0 : BIO_get_fd(bio.get(), &socket);
631 : #pragma GCC diagnostic pop
632 0 : if(socket >= 0)
633 : {
634 : // if this call fails, we ignore the error, but still log the event
635 : //
636 0 : int optval(1);
637 0 : socklen_t const optlen(sizeof(optval));
638 0 : if(setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) != 0)
639 : {
640 0 : SNAP_LOG_WARNING
641 : << "tcp_bio_server::accept(): an error occurred trying"
642 : " to mark accepted socket with SO_KEEPALIVE."
643 : << SNAP_LOG_SEND;
644 : }
645 : }
646 : }
647 :
648 : // force a close on exec() to avoid sharing the socket in child processes
649 0 : if(f_impl->f_close_on_exec)
650 : {
651 : // retrieve the socket (we do not yet have a bio_client object
652 : // so we cannot call a get_socket() function...)
653 : //
654 0 : int socket(-1);
655 : #pragma GCC diagnostic push
656 : #pragma GCC diagnostic ignored "-Wold-style-cast"
657 0 : BIO_get_fd(bio.get(), &socket);
658 : #pragma GCC diagnostic pop
659 0 : if(socket >= 0)
660 : {
661 : // if this call fails, we ignore the error, but still log the event
662 : //
663 0 : if(fcntl(socket, F_SETFD, FD_CLOEXEC) != 0)
664 : {
665 0 : SNAP_LOG_WARNING
666 : << "tcp_bio_server::accept(): an error occurred trying"
667 : " to mark accepted socket with FD_CLOEXEC."
668 : << SNAP_LOG_SEND;
669 : }
670 : }
671 : }
672 :
673 : // tcp_bio_client is private so we can't use the std::make_shared<>
674 : //
675 0 : tcp_bio_client::pointer_t client(new tcp_bio_client);
676 :
677 0 : client->f_impl->f_bio = bio;
678 :
679 : // TODO: somehow this does not seem to give us any information
680 : // about the cipher and other details...
681 : //
682 : // this is because it is (way) too early, we did not even
683 : // receive the HELLO yet!
684 : //
685 0 : SSL * ssl(nullptr);
686 : #pragma GCC diagnostic push
687 : #pragma GCC diagnostic ignored "-Wold-style-cast"
688 0 : BIO_get_ssl(bio.get(), &ssl);
689 : #pragma GCC diagnostic pop
690 0 : if(ssl != nullptr)
691 : {
692 0 : char const * cipher_name(SSL_get_cipher(ssl));
693 0 : int cipher_bits(0);
694 0 : SSL_get_cipher_bits(ssl, &cipher_bits);
695 0 : SNAP_LOG_DEBUG
696 : << "accepted BIO client with SSL cipher \""
697 : << cipher_name
698 0 : << "\" representing "
699 : << cipher_bits
700 : << " bits of encryption."
701 : << SNAP_LOG_SEND;
702 : }
703 :
704 0 : return client;
705 : }
706 :
707 :
708 :
709 6 : } // namespace ed
710 : // vim: ts=4 sw=4 et
|