LCOV - code coverage report
Current view: top level - eventdispatcher - tcp_private.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 79 0.0 %
Date: 2021-09-19 09:06:58 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2021  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
      17             : // along with this program; if not, write to the Free Software
      18             : // Foundation, Inc., 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             : // self
      31             : //
      32             : #include    "eventdispatcher/tcp_private.h"
      33             : 
      34             : #include    "eventdispatcher/exception.h"
      35             : 
      36             : 
      37             : // cppthread lib
      38             : //
      39             : #include    <cppthread/guard.h>
      40             : #include    <cppthread/mutex.h>
      41             : #include    <cppthread/thread.h>
      42             : 
      43             : 
      44             : // snaplogger lib
      45             : //
      46             : #include    <snaplogger/message.h>
      47             : 
      48             : 
      49             : // snapdev lib
      50             : //
      51             : #include    <snapdev/not_used.h>
      52             : 
      53             : 
      54             : // OpenSSL lib
      55             : //
      56             : #include    <openssl/bio.h>
      57             : #include    <openssl/err.h>
      58             : #include    <openssl/ssl.h>
      59             : 
      60             : 
      61             : // last include
      62             : //
      63             : #include    <snapdev/poison.h>
      64             : 
      65             : 
      66             : 
      67             : 
      68             : #ifndef OPENSSL_THREADS
      69             : #error "OPENSSL_THREADS is not defined. Event Dispatcher requires OpenSSL to support multi-threading."
      70             : #endif
      71             : 
      72             : namespace ed
      73             : {
      74             : 
      75             : 
      76             : namespace detail
      77             : {
      78             : 
      79             : 
      80             : 
      81             : /** \brief The vector of locks.
      82             :  *
      83             :  * This function is initialized by the crypto_thread_setup().
      84             :  *
      85             :  * It is defined as a pointer in case someone was to try to access this
      86             :  * pointer before entering main().
      87             :  */
      88             : cppthread::mutex::direct_vector_t  *   g_locks = nullptr;
      89             : 
      90             : 
      91             : /** \brief Retrieve the system thread identifier.
      92             :  *
      93             :  * This function is used by the OpenSSL library to attach an internal thread
      94             :  * identifier (\p tid) to a system thread identifier.
      95             :  *
      96             :  * \param[in] tid  The crypto internal thread identifier.
      97             :  */
      98           0 : void pthreads_thread_id(CRYPTO_THREADID * tid)
      99             : {
     100             :     // on 19.04 the macro does not use tid
     101             :     //
     102           0 :     snap::NOT_USED(tid);
     103             : 
     104             :     CRYPTO_THREADID_set_numeric(tid, cppthread::gettid());
     105           0 : }
     106             : 
     107             : 
     108             : /** \brief Handle locks and unlocks.
     109             :  *
     110             :  * This function is a callback used to lock and unlock mutexes as required.
     111             :  *
     112             :  * \param[in] mode  Whether lock or unlock in read or write mode.
     113             :  * \param[in] type  The "type" of lock (i.e. the index).
     114             :  * \param[in] file  The filename of the source asking for a lock/unlock.
     115             :  * \param[in] line  The line number in file where the call was made.
     116             :  */
     117           0 : void pthreads_locking_callback(int mode, int type, char const * file, int line)
     118             : {
     119           0 :     snap::NOT_USED(file, line);
     120             : 
     121           0 :     if(g_locks == nullptr)
     122             :     {
     123           0 :         throw event_dispatcher_initialization_missing("g_locks was not initialized");
     124             :     }
     125             : 
     126             : /*
     127             : # ifdef undef
     128             :     BIO_printf(bio_err, "thread=%4d mode=%s lock=%s %s:%d\n",
     129             :                CRYPTO_thread_id(),
     130             :                (mode & CRYPTO_LOCK) ? "l" : "u",
     131             :                (type & CRYPTO_READ) ? "r" : "w", file, line);
     132             : # endif
     133             :     if (CRYPTO_LOCK_SSL_CERT == type)
     134             :             BIO_printf(bio_err,"(t,m,f,l) %ld %d %s %d\n",
     135             :                        CRYPTO_thread_id(),
     136             :                        mode,file,line);
     137             : */
     138             : 
     139             :     // Note: at this point we ignore READ | WRITE because we do not have
     140             :     //       such a concept with a simple mutex; we could take those in
     141             :     //       account with a semaphore though.
     142             :     //
     143           0 :     if((mode & CRYPTO_LOCK) != 0)
     144             :     {
     145           0 :         (*g_locks)[type].lock();
     146             :     }
     147             :     else
     148             :     {
     149           0 :         (*g_locks)[type].unlock();
     150             :     }
     151           0 : }
     152             : 
     153             : 
     154             : /** \brief This function is called once on initialization.
     155             :  *
     156             :  * This function is called when the bio_initialize() function. It is
     157             :  * expected that the bio_initialize() function is called once by the
     158             :  * main thread before any other thread has a chance to do so.
     159             :  */
     160           0 : void crypto_thread_setup()
     161             : {
     162           0 :     cppthread::guard g(*cppthread::g_system_mutex);
     163             : 
     164           0 :     if(g_locks != nullptr)
     165             :     {
     166             :         throw event_dispatcher_initialization_error(
     167             :                 "crypto_thread_setup() called for the second time."
     168             :                 " This usually means two threads are initializing"
     169           0 :                 " the BIO environment simultaneously.");
     170             :     }
     171             : 
     172           0 :     g_locks = new cppthread::mutex::direct_vector_t(CRYPTO_num_locks());
     173             : 
     174             :     CRYPTO_THREADID_set_callback(pthreads_thread_id);
     175             :     CRYPTO_set_locking_callback(pthreads_locking_callback);
     176           0 : }
     177             : 
     178             : 
     179             : /** \brief This function cleans up the thread setup.
     180             :  *
     181             :  * This function could be called to clean up the setup created to support
     182             :  * multiple threads running with the OpenSSL library.
     183             :  *
     184             :  * \note
     185             :  * At this time this function never gets called. So we have a small leak
     186             :  * but that's only on a quit.
     187             :  */
     188           0 : void thread_cleanup()
     189             : {
     190             :     CRYPTO_set_locking_callback(nullptr);
     191             : 
     192           0 :     delete g_locks;
     193           0 :     g_locks = nullptr;
     194           0 : }
     195             : 
     196             : 
     197             : /** \brief This function cleans up the error state of a thread.
     198             :  *
     199             :  * Whenever the OpenSSL system runs in a thread, it may create a
     200             :  * state to save various information, especially its error queue.
     201             :  *
     202             :  * \sa cleanup_on_thread_exit()
     203             :  */
     204           0 : void per_thread_cleanup()
     205             : {
     206             : #if __cplusplus < 201700
     207             :     // this function is not necessary in newer versions of OpenSSL
     208             :     //
     209             :     ERR_remove_thread_state(nullptr);
     210             : #endif
     211           0 : }
     212             : 
     213             : 
     214             : 
     215             : 
     216             : 
     217             : 
     218             : 
     219             : /** \brief Whether the bio_initialize() function was already called.
     220             :  *
     221             :  * This flag is used to know whether the bio_initialize() function was
     222             :  * already called. Only the bio_initialize() function is expected to
     223             :  * make use of this flag. Other functions should simply call the
     224             :  * bio_initialize() function (future versions may include addition
     225             :  * flags or use various bits in an integer instead.)
     226             :  */
     227             : bool g_bio_initialized = false;
     228             : 
     229             : 
     230             : /** \brief Initialize the BIO library.
     231             :  *
     232             :  * This function is called by the BIO implementations to initialize the
     233             :  * BIO library as required. It can be called any number of times. The
     234             :  * initialization will happen only once.
     235             :  */
     236           0 : void bio_initialize()
     237             : {
     238           0 :     cppthread::guard g(*cppthread::g_system_mutex);
     239             : 
     240             :     // already initialized?
     241             :     //
     242           0 :     if(g_bio_initialized)
     243             :     {
     244           0 :         return;
     245             :     }
     246           0 :     g_bio_initialized = true;
     247             : 
     248             :     // Make sure the SSL library gets initialized
     249             :     //
     250           0 :     SSL_library_init();
     251             : 
     252             :     // TBD: should we call the load string functions only when we
     253             :     //      are about to generate the first error?
     254             :     //
     255           0 :     ERR_load_crypto_strings();
     256           0 :     ERR_load_SSL_strings();
     257           0 :     SSL_load_error_strings();
     258             : 
     259             :     // TODO: define a way to only define safe algorithms?
     260             :     //       (it looks like we can force TLSv1.2 below at least)
     261             :     //
     262           0 :     OpenSSL_add_all_algorithms();
     263             : 
     264             :     // TBD: need a PRNG seeding before creating a new SSL context?
     265             : 
     266             :     // then initialize the library so it works in a multithreaded
     267             :     // environment
     268             :     //
     269           0 :     crypto_thread_setup();
     270             : }
     271             : 
     272             : 
     273             : /** \brief Clean up the BIO environment.
     274             :  *
     275             :  * This function cleans up the BIO environment.
     276             :  *
     277             :  * \note
     278             :  * This function is here mainly for documentation rather than to get called.
     279             :  * Whenever you exit a process that uses the BIO calls it will leak
     280             :  * a few things. To make the process really spanking clean, you want
     281             :  * to call this function before exit(3). You have to make sure that
     282             :  * you call this function only after every single BIO object was
     283             :  * closed and none must be opened after this call.
     284             :  */
     285           0 : void bio_cleanup()
     286             : {
     287             : #if __cplusplus < 201700
     288             :     // this function is not necessary in newer versions of OpenSSL
     289             :     //
     290             :     ERR_remove_state(0);
     291             : #endif
     292             : 
     293             :     EVP_cleanup();
     294             :     CRYPTO_cleanup_all_ex_data();
     295             :     ERR_free_strings();
     296           0 : }
     297             : 
     298             : 
     299             : /** \brief Get all the error messages and output them in our logs.
     300             :  *
     301             :  * This function reads all existing errors from the OpenSSL library
     302             :  * and send them to our logs.
     303             :  *
     304             :  * \param[in] sni  Whether SNI is ON (true) or OFF (false).
     305             :  */
     306           0 : int bio_log_errors()
     307             : {
     308             :     // allow for up to 5 errors in one go, but we have a HUGE problem
     309             :     // at this time as in some cases the same error is repeated forever
     310             :     //
     311           0 :     for(int i(0);; ++i)
     312             :     {
     313           0 :         char const * filename(nullptr);
     314           0 :         int line(0);
     315           0 :         char const * data(nullptr);
     316           0 :         int flags(0);
     317           0 :         unsigned long bio_errno(ERR_get_error_line_data(&filename, &line, &data, &flags));
     318           0 :         if(bio_errno == 0)
     319             :         {
     320             :             // no more errors
     321             :             //
     322           0 :             return i;
     323             :         }
     324             : 
     325             :         // get corresponding messages too
     326             :         //
     327             :         // Note: current OpenSSL documentation on Ubuntu says errmsg[]
     328             :         //       should be at least 120 characters BUT the code actually
     329             :         //       use a limit of 256...
     330             :         //
     331           0 :         char errmsg[256];
     332           0 :         ERR_error_string_n(bio_errno, errmsg, sizeof(errmsg) / sizeof(errmsg[0]));
     333             :         // WARNING: the ERR_error_string() function is NOT multi-thread safe
     334             : 
     335             : #pragma GCC diagnostic push
     336             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     337           0 :         int const lib_num(ERR_GET_LIB(bio_errno));
     338           0 :         int const func_num(ERR_GET_FUNC(bio_errno));
     339             : #pragma GCC diagnostic pop
     340           0 :         char const * lib_name(ERR_lib_error_string(lib_num));
     341           0 :         char const * func_name(ERR_func_error_string(func_num));
     342           0 :         int const reason_num(ERR_GET_REASON(bio_errno));
     343           0 :         char const * reason(ERR_reason_error_string(reason_num));
     344             : 
     345           0 :         if(lib_name == nullptr)
     346             :         {
     347           0 :             lib_name = "<no libname>";
     348             :         }
     349           0 :         if(func_name == nullptr)
     350             :         {
     351           0 :             func_name = "<no funcname>";
     352             :         }
     353           0 :         if(reason == nullptr)
     354             :         {
     355           0 :             reason = "<no reason>";
     356             :         }
     357             : 
     358             :         // the format used by the OpenSSL library is as follow:
     359             :         //
     360             :         //     [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]
     361             :         //
     362             :         // we do not duplicate the [pid] and "error" but include all the
     363             :         // other fields
     364             :         //
     365           0 :         SNAP_LOG_ERROR
     366           0 :             << "OpenSSL: ["
     367           0 :             << bio_errno // should be shown in hex...
     368           0 :             << "/"
     369             :             << lib_num
     370           0 :             << "|"
     371             :             << func_num
     372           0 :             << "|"
     373             :             << reason_num
     374             :             << "]:["
     375             :             << lib_name
     376             :             << "]:["
     377             :             << func_name
     378             :             << "]:["
     379             :             << reason
     380             :             << "]:["
     381             :             << filename
     382           0 :             << "]:["
     383             :             << line
     384             :             << "]:["
     385           0 :             << ((flags & ERR_TXT_STRING) != 0 && data != nullptr ? data : "(no details)")
     386             :             << "]"
     387             :             << SNAP_LOG_SEND;
     388           0 :     }
     389             : }
     390             : 
     391             : 
     392             : /** \brief Free a BIO object.
     393             :  *
     394             :  * This deleter is used to make sure that the BIO object gets freed
     395             :  * whenever the object holding it gets destroyed.
     396             :  *
     397             :  * Note that deleting a BIO connection calls shutdown() and close()
     398             :  * on the socket. In other words, it hangs up.
     399             :  *
     400             :  * \param[in] bio  The BIO object to be freed.
     401             :  */
     402           0 : void bio_deleter(BIO * bio)
     403             : {
     404             :     // IMPORTANT NOTE:
     405             :     //
     406             :     //   The BIO_free_all() calls shutdown() on the socket. This is not
     407             :     //   acceptable in a normal Unix application that makes use of fork().
     408             :     //   So... instead we ask the BIO interface to not close the socket,
     409             :     //   and instead we close it ourselves. This means the shutdown()
     410             :     //   never gets called.
     411             :     //
     412           0 :     BIO_set_close(bio, BIO_NOCLOSE);
     413             : 
     414           0 :     int c;
     415             : #pragma GCC diagnostic push
     416             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     417           0 :     BIO_get_fd(bio, &c);
     418             : #pragma GCC diagnostic pop
     419           0 :     if(c != -1)
     420             :     {
     421           0 :         close(c);
     422             :     }
     423             : 
     424           0 :     BIO_free_all(bio);
     425           0 : }
     426             : 
     427             : 
     428             : /** \brief Free an SSL_CTX object.
     429             :  *
     430             :  * This deleter is used to make sure that the SSL_CTX object gets
     431             :  * freed whenever the object holding it gets destroyed.
     432             :  */
     433           0 : void ssl_ctx_deleter(SSL_CTX * ssl_ctx)
     434             : {
     435           0 :     SSL_CTX_free(ssl_ctx);
     436           0 : }
     437             : 
     438             : 
     439             : }
     440             : // namespace detail
     441             : 
     442             : 
     443             : 
     444             : 
     445             : 
     446             : 
     447             : 
     448             : 
     449             : 
     450             : 
     451             : 
     452             : 
     453             : 
     454             : 
     455             : } // namespace ed
     456             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13