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: 2022-06-18 10:10:36 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          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             : // 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 :     snapdev::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 :     snapdev::NOT_USED(file, line);
     120             : 
     121           0 :     if(g_locks == nullptr)
     122             :     {
     123           0 :         throw 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 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 OPENSSL_VERSION_NUMBER < 0x1010100fL
     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             : #if OPENSSL_VERSION_NUMBER < 0x30000020L
     257             :     // this function is not necessary in newer versions of OpenSSL
     258             :     //
     259           0 :     ERR_load_SSL_strings();
     260             : #endif
     261           0 :     SSL_load_error_strings();
     262             : 
     263             :     // TODO: define a way to only define safe algorithms?
     264             :     //       (it looks like we can force TLSv1.2 below at least)
     265             :     //
     266           0 :     OpenSSL_add_all_algorithms();
     267             : 
     268             :     // TBD: need a PRNG seeding before creating a new SSL context?
     269             : 
     270             :     // then initialize the library so it works in a multithreaded
     271             :     // environment
     272             :     //
     273           0 :     crypto_thread_setup();
     274             : }
     275             : 
     276             : 
     277             : /** \brief Clean up the BIO environment.
     278             :  *
     279             :  * This function cleans up the BIO environment.
     280             :  *
     281             :  * \note
     282             :  * This function is here mainly for documentation rather than to get called.
     283             :  * Whenever you exit a process that uses the BIO calls it will leak
     284             :  * a few things. To make the process really spanking clean, you want
     285             :  * to call this function before exit(3). You have to make sure that
     286             :  * you call this function only after every single BIO object was
     287             :  * closed and none must be opened after this call.
     288             :  */
     289           0 : void bio_cleanup()
     290             : {
     291             : #if OPENSSL_VERSION_NUMBER < 0x1010100fL
     292             :     // this function is not necessary in newer versions of OpenSSL
     293             :     //
     294             :     ERR_remove_state(0);
     295             : #endif
     296             : 
     297             :     EVP_cleanup();
     298             :     CRYPTO_cleanup_all_ex_data();
     299             :     ERR_free_strings();
     300           0 : }
     301             : 
     302             : 
     303             : /** \brief Get all the error messages and output them in our logs.
     304             :  *
     305             :  * This function reads all existing errors from the OpenSSL library
     306             :  * and send them to our logs.
     307             :  *
     308             :  * \return The number of errors that the function found.
     309             :  */
     310           0 : int bio_log_errors()
     311             : {
     312             :     // allow for up to 5 errors in one go, but we have a HUGE problem
     313             :     // at this time as in some cases the same error is repeated forever
     314             :     //
     315           0 :     for(int count(0);; ++count)
     316             :     {
     317           0 :         char const * filename(nullptr);
     318           0 :         int line(0);
     319           0 :         char const * data(nullptr);
     320           0 :         int flags(0);
     321           0 :         char const * func_name(nullptr);
     322             : #if OPENSSL_VERSION_NUMBER < 0x30000020L
     323           0 :         unsigned long bio_errno(ERR_get_error_line_data(&filename, &line, &data, &flags));
     324             : #else
     325             :         unsigned long bio_errno(ERR_get_error_all(&filename, &line, &func_name, &data, &flags));
     326             : #endif
     327           0 :         if(bio_errno == 0)
     328             :         {
     329             :             // no more errors
     330             :             //
     331           0 :             return count;
     332             :         }
     333             : 
     334             :         // get corresponding messages too
     335             :         //
     336             :         // Note: current OpenSSL documentation on Ubuntu says errmsg[]
     337             :         //       should be at least 120 characters BUT the code actually
     338             :         //       use a limit of 256...
     339             :         //
     340           0 :         char errmsg[256];
     341           0 :         ERR_error_string_n(bio_errno, errmsg, sizeof(errmsg) / sizeof(errmsg[0]));
     342             :         // WARNING: the ERR_error_string() function is NOT multi-thread safe
     343             : 
     344             : #pragma GCC diagnostic push
     345             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     346           0 :         int const lib_num(ERR_GET_LIB(bio_errno));
     347             : #if OPENSSL_VERSION_NUMBER < 0x30000020L
     348           0 :         int const func_num(ERR_GET_FUNC(bio_errno));
     349             : #endif
     350             : #pragma GCC diagnostic pop
     351           0 :         char const * lib_name(ERR_lib_error_string(lib_num));
     352             : #if OPENSSL_VERSION_NUMBER < 0x30000020L
     353           0 :         func_name = ERR_func_error_string(func_num);
     354             : #endif
     355           0 :         int const reason_num(ERR_GET_REASON(bio_errno));
     356           0 :         char const * reason(ERR_reason_error_string(reason_num));
     357             : 
     358           0 :         if(lib_name == nullptr)
     359             :         {
     360           0 :             lib_name = "<no libname>";
     361             :         }
     362           0 :         if(func_name == nullptr)
     363             :         {
     364           0 :             func_name = "<no funcname>";
     365             :         }
     366           0 :         if(reason == nullptr)
     367             :         {
     368           0 :             reason = "<no reason>";
     369             :         }
     370             : 
     371             :         // the format used by the OpenSSL library is as follow:
     372             :         //
     373             :         //     [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]
     374             :         //
     375             :         // we do not duplicate the [pid] and "error" but include all the
     376             :         // other fields
     377             :         //
     378           0 :         SNAP_LOG_ERROR
     379           0 :             << "OpenSSL: ["
     380           0 :             << bio_errno // should be shown in hex...
     381           0 :             << "/"
     382             :             << lib_num
     383           0 :             << "|"
     384             :             << reason_num
     385             :             << "]:["
     386             :             << lib_name
     387             :             << "]:["
     388             :             << func_name
     389             :             << "]:["
     390             :             << reason
     391             :             << "]:["
     392             :             << filename
     393           0 :             << "]:["
     394             :             << line
     395             :             << "]:["
     396           0 :             << ((flags & ERR_TXT_STRING) != 0 && data != nullptr ? data : "(no details)")
     397             :             << "]"
     398             :             << SNAP_LOG_SEND;
     399           0 :     }
     400             : }
     401             : 
     402             : 
     403             : /** \brief Free a BIO object.
     404             :  *
     405             :  * This deleter is used to make sure that the BIO object gets freed
     406             :  * whenever the object holding it gets destroyed.
     407             :  *
     408             :  * Note that deleting a BIO connection calls shutdown() and close()
     409             :  * on the socket. In other words, it hangs up.
     410             :  *
     411             :  * \param[in] bio  The BIO object to be freed.
     412             :  */
     413           0 : void bio_deleter(BIO * bio)
     414             : {
     415             :     // IMPORTANT NOTE:
     416             :     //
     417             :     //   The BIO_free_all() calls shutdown() on the socket. This is not
     418             :     //   acceptable in a normal Unix application that makes use of fork().
     419             :     //   So... instead we ask the BIO interface to not close the socket,
     420             :     //   and instead we close it ourselves. This means the shutdown()
     421             :     //   never gets called.
     422             :     //
     423           0 :     BIO_set_close(bio, BIO_NOCLOSE);
     424             : 
     425           0 :     int c;
     426             : #pragma GCC diagnostic push
     427             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     428           0 :     BIO_get_fd(bio, &c);
     429             : #pragma GCC diagnostic pop
     430           0 :     if(c != -1)
     431             :     {
     432           0 :         close(c);
     433             :     }
     434             : 
     435           0 :     BIO_free_all(bio);
     436           0 : }
     437             : 
     438             : 
     439             : /** \brief Free an SSL_CTX object.
     440             :  *
     441             :  * This deleter is used to make sure that the SSL_CTX object gets
     442             :  * freed whenever the object holding it gets destroyed.
     443             :  *
     444             :  * \param[in] ssl_ctx  The SSL context to delete.
     445             :  */
     446           0 : void ssl_ctx_deleter(SSL_CTX * ssl_ctx)
     447             : {
     448           0 :     SSL_CTX_free(ssl_ctx);
     449           0 : }
     450             : 
     451             : 
     452             : }
     453             : // namespace detail
     454             : 
     455             : 
     456             : 
     457             : 
     458             : 
     459             : 
     460             : 
     461             : 
     462             : 
     463             : 
     464             : 
     465             : 
     466             : 
     467             : 
     468             : } // namespace ed
     469             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13