LCOV - code coverage report
Current view: top level - eventdispatcher - tcp_private.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 99 0.0 %
Date: 2019-08-10 01:48:51 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12