LCOV - code coverage report
Current view: top level - snapwebsites - snapwebsites.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 3 876 0.3 %
Date: 2019-12-15 17:13:15 Functions: 2 85 2.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Server -- snap websites server
       2             : // Copyright (c) 2011-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // https://snapwebsites.org/
       5             : // contact@m2osw.com
       6             : //
       7             : // This program is free software; you can redistribute it and/or modify
       8             : // it under the terms of the GNU General Public License as published by
       9             : // the Free Software Foundation; either version 2 of the License, or
      10             : // (at your option) any later version.
      11             : //
      12             : // This program is distributed in the hope that it will be useful,
      13             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             : // GNU General Public License for more details.
      16             : //
      17             : // You should have received a copy of the GNU General Public License
      18             : // along with this program; if not, write to the Free Software
      19             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      20             : 
      21             : 
      22             : // self
      23             : //
      24             : #include "snapwebsites/snapwebsites.h"
      25             : 
      26             : 
      27             : // snapwebsites lib
      28             : //
      29             : #include "snapwebsites/log.h"
      30             : #include "snapwebsites/snap_backend.h"
      31             : #include "snapwebsites/snap_cassandra.h"
      32             : #include "snapwebsites/snap_lock.h"
      33             : #include "snapwebsites/snap_tables.h"
      34             : 
      35             : 
      36             : // snapdev lib
      37             : //
      38             : #include <snapdev/not_used.h>
      39             : 
      40             : 
      41             : // Qt lib
      42             : //
      43             : #include <QFile>
      44             : #include <QDirIterator>
      45             : #include <QHostAddress>
      46             : #include <QCoreApplication>
      47             : #include <QTextCodec>
      48             : 
      49             : 
      50             : // C++ lib
      51             : //
      52             : #include <sstream>
      53             : 
      54             : 
      55             : // C lib
      56             : //
      57             : #include <errno.h>
      58             : #include <signal.h>
      59             : #include <syslog.h>
      60             : #include <sys/resource.h>
      61             : #include <sys/stat.h>
      62             : #include <sys/types.h>
      63             : 
      64             : 
      65             : // last include
      66             : //
      67             : #include <snapdev/poison.h>
      68             : 
      69             : 
      70             : 
      71             : 
      72             : 
      73             : /** \file
      74             :  * \brief This file represents the Snap! Server.
      75             :  *
      76             :  * The snapwebsites.cpp and corresponding header file represents the Snap!
      77             :  * Server. When you create a server object, its code is available here.
      78             :  * The server can listen for client connections or run backend processes.
      79             :  */
      80             : 
      81             : 
      82             : /** \mainpage
      83             :  * \brief Snap! C++ Documentation
      84             :  *
      85             :  * \section introduction Introduction
      86             :  *
      87             :  * The Snap! C++ environment includes a library, plugins, tools, and
      88             :  * the necessary executables to run the snap server: a fast C++
      89             :  * CMS (Content Management System).
      90             :  *
      91             :  * \section database The Database Environment in Snap! C++
      92             :  *
      93             :  * The database makes use of a Cassandra cluster. It is accessed using
      94             :  * the libQtCassandra class.
      95             :  *
      96             :  * \section todo_xxx_tbd Usage of TODO, XXX, and TBD
      97             :  *
      98             :  * The TODO mark within the code is used to talk about things that are
      99             :  * necessary but not yet implemented. The further we progress the less
     100             :  * of these we should see as we implement each one of them as required.
     101             :  *
     102             :  * The XXX mark within the code are things that should be done, although
     103             :  * it is most generally linked with a question: is it really necessary?
     104             :  * It can also be a question about the hard coded value (is 5 minutes
     105             :  * the right amount of time to wait between random session changes?)
     106             :  * In most cases these should disappear as we get the answer to the
     107             :  * questions. In effect they are between the TODO and the TBD.
     108             :  *
     109             :  * The TBD mark is a pure question: Is that code valid? A TBD does not
     110             :  * mean that the code needs change just that we cannot really decide,
     111             :  * at the time it get written, whether it is correct or not. With time
     112             :  * (especially in terms of usage) we should be able to answer the
     113             :  * question and transform the question in a comment explaining why
     114             :  * the code is one way or the other. Of course, if proven wrong, the
     115             :  * code is to be changed to better fit the needs.
     116             :  */
     117             : 
     118             : 
     119             : /** \brief The snap namespace.
     120             :  *
     121             :  * The snap namespace is used throughout all the snap objects: libraries,
     122             :  * plugins, tools.
     123             :  *
     124             :  * Plugins make use of a sub-namespace within the snap namespace.
     125             :  */
     126             : namespace snap
     127             : {
     128             : 
     129             : 
     130             : /** \brief Get a fixed name.
     131             :  *
     132             :  * The Snap! Server makes use of a certain number of fixed names
     133             :  * which instead of being defined in macros are defined here as
     134             :  * static strings. To retrieve one of the strings, call the function
     135             :  * with the appropriate index.
     136             :  *
     137             :  * \param[in] name  The name to retrieve.
     138             :  *
     139             :  * \return A pointer to the name.
     140             :  */
     141           0 : char const * get_name(name_t name)
     142             : {
     143           0 :     switch(name)
     144             :     {
     145             :     // Names that are really considered low level
     146           0 :     case name_t::SNAP_NAME_SERVER:
     147           0 :         return "Snap! Server";
     148             : 
     149           0 :     case name_t::SNAP_NAME_CONTEXT:
     150           0 :         return "snap_websites";
     151             : 
     152           0 :     case name_t::SNAP_NAME_INDEX: // name used for the domains and websites indexes
     153           0 :         return "*index*"; // this is a row name inside the domains/websites tables
     154             : 
     155           0 :     case name_t::SNAP_NAME_DOMAINS: // domain/sub-domain canonicalization
     156           0 :         return "domains";
     157             : 
     158           0 :     case name_t::SNAP_NAME_WEBSITES: // remaining of URL canonicalization
     159           0 :         return "websites";
     160             : 
     161           0 :     case name_t::SNAP_NAME_SITES: // website global settings
     162           0 :         return "sites";
     163             : 
     164           0 :     case name_t::SNAP_NAME_BACKEND: // backend progress
     165           0 :         return "backend";
     166             : 
     167           0 :     case name_t::SNAP_NAME_MX: // backend progress
     168           0 :         return "mx";
     169             : 
     170             :     // names used by CORE (server and snap_child)
     171           0 :     case name_t::SNAP_NAME_CORE_ADMINISTRATOR_EMAIL:
     172           0 :         return "core::administrator_email";
     173             : 
     174           0 :     case name_t::SNAP_NAME_CORE_CANONICAL_DOMAIN:  // this is only for test websites so search engines know to search on the real site instead
     175           0 :         return "core::canonical_domain";
     176             : 
     177           0 :     case name_t::SNAP_NAME_CORE_CONTENT_DISPOSITION:
     178           0 :         return "Content-Disposition";
     179             : 
     180           0 :     case name_t::SNAP_NAME_CORE_CONTENT_LANGUAGE:
     181           0 :         return "Content-Language";
     182             : 
     183           0 :     case name_t::SNAP_NAME_CORE_CONTENT_TYPE_HEADER:
     184           0 :         return "Content-Type";
     185             : 
     186           0 :     case name_t::SNAP_NAME_CORE_COOKIE_DOMAIN:
     187           0 :         return "core::cookie_domain";
     188             : 
     189           0 :     case name_t::SNAP_NAME_CORE_DATA_PATH:
     190           0 :         return "data_path";
     191             : 
     192           0 :     case name_t::SNAP_NAME_CORE_DATE:
     193           0 :         return "Date";
     194             : 
     195           0 :     case name_t::SNAP_NAME_CORE_EMAIL_CONTENT_ENCODING_QUOTED_PRINTABLE:
     196           0 :         return "quoted-printable";
     197             : 
     198           0 :     case name_t::SNAP_NAME_CORE_EMAIL_CONTENT_TRANSFER_ENCODING:
     199           0 :         return "Content-Transfer-Encoding";
     200             : 
     201           0 :     case name_t::SNAP_NAME_CORE_EMAIL_FROM:
     202           0 :         return "From";
     203             : 
     204           0 :     case name_t::SNAP_NAME_CORE_EMAIL_IMPORTANCE:
     205           0 :         return "Importance";
     206             : 
     207           0 :     case name_t::SNAP_NAME_CORE_EMAIL_LIST_UNSUBSCRIBE:
     208           0 :         return "List-Unsubscribe";
     209             : 
     210           0 :     case name_t::SNAP_NAME_CORE_EMAIL_MESSAGE_ID:
     211           0 :         return "Message-ID";
     212             : 
     213           0 :     case name_t::SNAP_NAME_CORE_EMAIL_MIME_VERSION:
     214           0 :         return "MIME-Version";
     215             : 
     216           0 :     case name_t::SNAP_NAME_CORE_EMAIL_PRECEDENCE:
     217           0 :         return "Precedence";
     218             : 
     219           0 :     case name_t::SNAP_NAME_CORE_EMAIL_PRIORITY_BULK:
     220           0 :         return "Bulk";
     221             : 
     222           0 :     case name_t::SNAP_NAME_CORE_EMAIL_PRIORITY_HIGH:
     223           0 :         return "High";
     224             : 
     225           0 :     case name_t::SNAP_NAME_CORE_EMAIL_PRIORITY_LOW:
     226           0 :         return "Low";
     227             : 
     228           0 :     case name_t::SNAP_NAME_CORE_EMAIL_PRIORITY_NORMAL:
     229           0 :         return "Normal";
     230             : 
     231           0 :     case name_t::SNAP_NAME_CORE_EMAIL_PRIORITY_URGENT:
     232           0 :         return "Urgent";
     233             : 
     234           0 :     case name_t::SNAP_NAME_CORE_EMAIL_REPLY_TO:
     235           0 :         return "Reply-To";
     236             : 
     237           0 :     case name_t::SNAP_NAME_CORE_EMAIL_SUBJECT:
     238           0 :         return "Subject";
     239             : 
     240           0 :     case name_t::SNAP_NAME_CORE_EMAIL_TO:
     241           0 :         return "To";
     242             : 
     243           0 :     case name_t::SNAP_NAME_CORE_EMAIL_X_PRIORITY:
     244           0 :         return "X-Priority";
     245             : 
     246           0 :     case name_t::SNAP_NAME_CORE_EMAIL_X_MSMAIL_PRIORITY:
     247           0 :         return "X-MSMail-Priority";
     248             : 
     249           0 :     case name_t::SNAP_NAME_CORE_HTTP_LINK_HEADER:
     250           0 :         return "Link";
     251             : 
     252           0 :     case name_t::SNAP_NAME_CORE_HTTP_ACCEPT_LANGUAGE:
     253           0 :         return "HTTP_ACCEPT_LANGUAGE";
     254             : 
     255           0 :     case name_t::SNAP_NAME_CORE_HTTP_USER_AGENT:
     256           0 :         return "HTTP_USER_AGENT";
     257             : 
     258           0 :     case name_t::SNAP_NAME_CORE_LAST_DYNAMIC_UPDATE:
     259           0 :         return "core::last_dynamic_update";
     260             : 
     261           0 :     case name_t::SNAP_NAME_CORE_LAST_UPDATED:
     262           0 :         return "core::last_updated";
     263             : 
     264           0 :     case name_t::SNAP_NAME_CORE_LIST_DATA_PATH:
     265           0 :         return "list_data_path";
     266             : 
     267           0 :     case name_t::SNAP_NAME_CORE_LIST_DB_PATH: // sub-path to access the database handled by the pagelist backend ($list_data_path + "/" + "db")
     268           0 :         return "db";
     269             : 
     270           0 :     case name_t::SNAP_NAME_CORE_LIST_JOURNAL_PATH: // sub-path to access the journal generated by the list plugin ($list_data_path + "/" + "journal")
     271           0 :         return "journal";
     272             : 
     273           0 :     case name_t::SNAP_NAME_CORE_LOCATION_HEADER:
     274           0 :         return "Location";
     275             : 
     276           0 :     case name_t::SNAP_NAME_CORE_MX_LAST_CHECKED:
     277           0 :         return "core::mx_last_checked";
     278             : 
     279           0 :     case name_t::SNAP_NAME_CORE_MX_RESULT:
     280           0 :         return "core::mx_result";
     281             : 
     282           0 :     case name_t::SNAP_NAME_CORE_ORIGINAL_RULES:
     283           0 :         return "core::original_rules";
     284             : 
     285           0 :     case name_t::SNAP_NAME_CORE_PARAM_DEFAULT_PLUGINS:
     286           0 :         return "default_plugins";
     287             : 
     288           0 :     case name_t::SNAP_NAME_CORE_PARAM_PLUGINS:
     289           0 :         return "plugins";
     290             : 
     291           0 :     case name_t::SNAP_NAME_CORE_PARAM_PLUGINS_PATH:
     292           0 :         return "plugins_path";
     293             : 
     294           0 :     case name_t::SNAP_NAME_CORE_PARAM_TABLE_SCHEMA_PATH:
     295           0 :         return "table_schema_path";
     296             : 
     297           0 :     case name_t::SNAP_NAME_CORE_PLUGINS:
     298           0 :         return "core::plugins";
     299             : 
     300           0 :     case name_t::SNAP_NAME_CORE_PLUGIN_THRESHOLD:
     301           0 :         return "core::plugin_threshold";
     302             : 
     303           0 :     case name_t::SNAP_NAME_CORE_REDIRECT:
     304           0 :         return "core::redirect";
     305             : 
     306           0 :     case name_t::SNAP_NAME_CORE_REMOTE_ADDR:
     307           0 :         return "REMOTE_ADDR";
     308             : 
     309           0 :     case name_t::SNAP_NAME_CORE_REQUEST_METHOD:
     310           0 :         return "REQUEST_METHOD";
     311             : 
     312           0 :     case name_t::SNAP_NAME_CORE_REQUEST_URI:
     313           0 :         return "REQUEST_URI";
     314             : 
     315           0 :     case name_t::SNAP_NAME_CORE_RETRY_AFTER_HEADER:
     316           0 :         return "Retry-After";
     317             : 
     318           0 :     case name_t::SNAP_NAME_CORE_RULES:
     319           0 :         return "core::rules";
     320             : 
     321           0 :     case name_t::SNAP_NAME_CORE_SERVER_PROTOCOL:
     322           0 :         return "SERVER_PROTOCOL";
     323             : 
     324           0 :     case name_t::SNAP_NAME_CORE_SITE_LONG_NAME:
     325           0 :         return "core::site_long_name";
     326             : 
     327           0 :     case name_t::SNAP_NAME_CORE_SITE_NAME:
     328           0 :         return "core::site_name";
     329             : 
     330           0 :     case name_t::SNAP_NAME_CORE_SITE_READY:
     331           0 :         return "core::site_ready";
     332             : 
     333           0 :     case name_t::SNAP_NAME_CORE_SITE_SECURE:
     334           0 :         return "core::site_secure";
     335             : 
     336           0 :     case name_t::SNAP_NAME_CORE_SITE_SHORT_NAME:
     337           0 :         return "core::site_short_name";
     338             : 
     339           0 :     case name_t::SNAP_NAME_CORE_SITE_STATE:
     340           0 :         return "core::site_state";
     341             : 
     342           0 :     case name_t::SNAP_NAME_CORE_SNAPBACKEND:
     343           0 :         return "snapbackend";
     344             : 
     345           0 :     case name_t::SNAP_NAME_CORE_STATUS_HEADER:
     346           0 :         return "Status";
     347             : 
     348           0 :     case name_t::SNAP_NAME_CORE_TEST_SITE:
     349           0 :         return "core::test_site";
     350             : 
     351           0 :     case name_t::SNAP_NAME_CORE_USER_COOKIE_NAME:
     352           0 :         return "core::user_cookie_name";
     353             : 
     354           0 :     case name_t::SNAP_NAME_CORE_X_POWERED_BY_HEADER:
     355           0 :         return "X-Powered-By";
     356             : 
     357           0 :     default:
     358             :         // invalid index
     359           0 :         throw snap_logic_exception(QString("invalid name_t::SNAP_NAME_CORE_... (%1)").arg(static_cast<int>(name)));
     360             : 
     361             :     }
     362             :     NOTREACHED();
     363             : }
     364             : 
     365             : 
     366             : // definitions from the plugins so we can define the name and filename of
     367             : // the server plugin
     368             : namespace plugins
     369             : {
     370             : extern QString g_next_register_name;
     371             : extern QString g_next_register_filename;
     372             : }
     373             : 
     374             : 
     375             : /** \brief Hidden Snap! Server namespace.
     376             :  *
     377             :  * This namespace encompasses global variables only available to the
     378             :  * server code.
     379             :  */
     380             : namespace
     381             : {
     382             : 
     383             : 
     384             : /** \brief Command line options.
     385             :  *
     386             :  * This table includes all the options supported by the server.
     387             :  */
     388             : advgetopt::option const g_snapserver_options[] =
     389             : {
     390             :     advgetopt::define_option(
     391             :           advgetopt::Name("action")
     392             :         , advgetopt::ShortName('a')
     393             :         , advgetopt::Flags(advgetopt::any_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     394             :                                               , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
     395             :                                               , advgetopt::GETOPT_FLAG_REQUIRED>())
     396             :         , advgetopt::Help("Specify a server action.")
     397             :     ),
     398             :     advgetopt::define_option(
     399             :           advgetopt::Name("background")
     400             :         , advgetopt::ShortName('b')
     401             :         , advgetopt::Flags(advgetopt::option_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     402             :                                                  , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE>())
     403             :         , advgetopt::Help("Detaches the server to the background (default is stay in the foreground.)")
     404             :     ),
     405             :     advgetopt::define_option(
     406             :           advgetopt::Name("config")
     407             :         , advgetopt::ShortName('c')
     408             :         , advgetopt::Flags(advgetopt::any_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     409             :                                               , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
     410             :                                               , advgetopt::GETOPT_FLAG_REQUIRED
     411             :                                               , advgetopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR>())
     412             :         , advgetopt::Help("Specify the configuration file to load at startup.")
     413             :     ),
     414             :     advgetopt::define_option(
     415             :           advgetopt::Name("cron-action")
     416             :         , advgetopt::Flags(advgetopt::any_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     417             :                                               , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
     418             :                                               , advgetopt::GETOPT_FLAG_REQUIRED>())
     419             :         , advgetopt::Help("Specify a server CRON action.")
     420             :     ),
     421             : #ifdef SNAP_NO_FORK
     422             :     advgetopt::define_option(
     423             :           advgetopt::Name("nofork")
     424             :         , advgetopt::ShortName('k')
     425             :         , advgetopt::Flags(advgetopt::option_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     426             :                                                  , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE>())
     427             :         , advgetopt::Help("If set, this switch causes the server not to fork when a child is launched. This should never be use for a production server!")
     428             :     ),
     429             : #endif
     430             :     advgetopt::define_option(
     431             :           advgetopt::Name("param")
     432             :         , advgetopt::ShortName('p')
     433             :         , advgetopt::Flags(advgetopt::any_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     434             :                                               , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
     435             :                                               , advgetopt::GETOPT_FLAG_REQUIRED
     436             :                                               , advgetopt::GETOPT_FLAG_MULTIPLE>())
     437             :         , advgetopt::Help("Define one or more server parameters on the command line (-p name=value).")
     438             :     ),
     439             :     advgetopt::define_option(
     440             :           advgetopt::Name("filename")
     441             :         , advgetopt::Flags(advgetopt::command_flags<advgetopt::GETOPT_FLAG_DEFAULT_OPTION
     442             :                                                   , advgetopt::GETOPT_FLAG_REQUIRED
     443             :                                                   , advgetopt::GETOPT_FLAG_MULTIPLE>())
     444             :     ),
     445             : 
     446             :     // LOG SPECIFIC (moving to snaplogger soon)
     447             :     //
     448             :     advgetopt::define_option(
     449             :           advgetopt::Name("debug")
     450             :         , advgetopt::ShortName('d')
     451             :         , advgetopt::Flags(advgetopt::option_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     452             :                                                  , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE>())
     453             :         , advgetopt::Help("Outputs debug logs. Perform additional checks in various places.")
     454             :     ),
     455             :     advgetopt::define_option(
     456             :           advgetopt::Name("logfile")
     457             :         , advgetopt::ShortName('f')
     458             :         , advgetopt::Flags(advgetopt::any_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     459             :                                               , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
     460             :                                               , advgetopt::GETOPT_FLAG_REQUIRED>())
     461             :         , advgetopt::Help("Output log file to write to. Overrides the setting in the configuration file.")
     462             :     ),
     463             :     advgetopt::define_option(
     464             :           advgetopt::Name("logconf")
     465             :         , advgetopt::ShortName('l')
     466             :         , advgetopt::Flags(advgetopt::any_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     467             :                                               , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE
     468             :                                               , advgetopt::GETOPT_FLAG_REQUIRED>())
     469             :         , advgetopt::Help("Log configuration file to read from. Overrides log_config in the configuration file.")
     470             :     ),
     471             :     advgetopt::define_option(
     472             :           advgetopt::Name("no-log")
     473             :         , advgetopt::ShortName('n')
     474             :         , advgetopt::Flags(advgetopt::option_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE
     475             :                                                  , advgetopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE>())
     476             :         , advgetopt::Help("Don't create a logfile, just output to the console.")
     477             :     ),
     478             :     advgetopt::define_option(
     479             :           advgetopt::Name("no-messenger-logging")
     480             :         , advgetopt::Flags(advgetopt::option_flags<advgetopt::GETOPT_FLAG_COMMAND_LINE>())
     481             :         , advgetopt::Help("Turn off the automatic logging through snapcommunicator.")
     482             :     ),
     483             : 
     484             :     advgetopt::end_options()
     485             : };
     486             : 
     487             : 
     488             : #pragma GCC diagnostic push
     489             : #pragma GCC diagnostic ignored "-Wpedantic"
     490             : advgetopt::options_environment g_snapserver_options_environment =
     491             : {
     492             :     .f_project_name = "snapwebsites",       // this does NOT vary depending on your program, all writable files are under snapwebsites.d/...
     493             :     .f_options = g_snapserver_options,
     494             :     .f_options_files_directory = nullptr,
     495             :     .f_environment_variable_name = "SNAPSERVER_OPTIONS",
     496             :     .f_configuration_files = nullptr,
     497             :     .f_configuration_filename = nullptr,
     498             :     .f_configuration_directories = nullptr,
     499             :     .f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS,
     500             :     .f_help_header = "Usage: %p [-<opt>]\n"
     501             :                      "where -<opt> is one or more of:",
     502             :     .f_help_footer = "Configuration files:\n"       // TODO: fix the snapserver::usage() function so this works as expected
     503             :                      "%*f\n"
     504             :                      "Environment variable: %e\n"
     505             :                      "%p v%v from %a\n"
     506             :                      "Built on %t\n"
     507             :                      "See also http://www.snapwebsites.org/project",
     508             :     .f_version = SNAPWEBSITES_VERSION_STRING,
     509             :     .f_license = "This software is licenced under the GPL v2 and LGPL v2",
     510             :     .f_copyright = "Copyright (c) 2011-" BOOST_PP_STRINGIZE(UTC_BUILD_YEAR) " by Made to Order Software Corporation",
     511             :     //.f_build_date = UTC_BUILD_DATE,
     512             :     //.f_build_time = UTC_BUILD_TIME
     513             : };
     514             : #pragma GCC diagnostic pop
     515             : 
     516           0 : struct connection_t
     517             : {
     518             :     snap_communicator::pointer_t                    f_communicator = snap_communicator::pointer_t();
     519             :     snap_communicator::snap_connection::pointer_t   f_interrupt = snap_communicator::snap_connection::pointer_t();
     520             :     snap_communicator::snap_connection::pointer_t   f_listener = snap_communicator::snap_connection::pointer_t();
     521             :     snap_communicator::snap_connection::pointer_t   f_child_death_listener = snap_communicator::snap_connection::pointer_t();
     522             :     snap_communicator::snap_connection::pointer_t   f_messenger = snap_communicator::snap_connection::pointer_t();
     523             :     snap_communicator::snap_connection::pointer_t   f_cassandra_check_timer = snap_communicator::snap_connection::pointer_t(); // timer in case an error occurs that will not generate a CASSANDRAREADY
     524             : };
     525             : 
     526             : /** \brief The pointers to communicator elements.
     527             :  *
     528             :  * The communicator we use to run the server events.
     529             :  *
     530             :  * \todo
     531             :  * At some point we need to look into whether it would be possible
     532             :  * for us to use a shared pointer. At this point the g_connection
     533             :  * gets allocated and never deleted (not a big deal since it is
     534             :  * ONE instance for the entire time the process is running.)
     535             :  */
     536             : connection_t *          g_connection = nullptr;
     537             : 
     538             : 
     539             : }
     540             : //namespace
     541             : 
     542             : 
     543             : //#pragma message "Why do we even have this? Adding a smart pointer causes a crash when the server detaches, so commented out."
     544             : // Note: We need the argc/argv when we create the application and those are
     545             : //       not available when we create the server (they are not passed along)
     546             : //       but I suppose the server could be ameliorated for that purpose...
     547           2 : QPointer<QCoreApplication> g_application;
     548             : 
     549             : 
     550             : /** \brief Server instance.
     551             :  *
     552             :  * The g_instance variable holds the current server instance.
     553             :  */
     554           2 : std::shared_ptr<server> server::g_instance;
     555             : 
     556             : 
     557             : /** \brief Return the server version.
     558             :  *
     559             :  * This function can be used to verify that the server version is
     560             :  * compatible with your plugin or to display the version.
     561             :  *
     562             :  * To compare versions, however, it is suggested that you make
     563             :  * use of the version_major(), version_minor(), and version_patch()
     564             :  * instead.
     565             :  *
     566             :  * \return A pointer to a constant string representing the server version.
     567             :  */
     568           0 : char const * server::version()
     569             : {
     570           0 :     return SNAPWEBSITES_VERSION_STRING;
     571             : }
     572             : 
     573             : 
     574             : /** \brief Return the server major version.
     575             :  *
     576             :  * This function returns the major version of the server. This can be used
     577             :  * to verify that you have the correct version of the server to run your
     578             :  * plugin.
     579             :  *
     580             :  * This is a positive number.
     581             :  *
     582             :  * \return The server major version as an integer.
     583             :  */
     584           0 : int server::version_major()
     585             : {
     586           0 :     return SNAPWEBSITES_VERSION_MAJOR;
     587             : }
     588             : 
     589             : 
     590             : /** \brief Return the server minor version.
     591             :  *
     592             :  * This function returns the minor version of the server. This can be used
     593             :  * to verify that you have the correct version of the server to run your
     594             :  * plugin.
     595             :  *
     596             :  * This is a positive number.
     597             :  *
     598             :  * \return The server minor version as an integer.
     599             :  */
     600           0 : int server::version_minor()
     601             : {
     602           0 :     return SNAPWEBSITES_VERSION_MINOR;
     603             : }
     604             : 
     605             : 
     606             : /** \brief Return the server patch version.
     607             :  *
     608             :  * This function returns the patch version of the server. This can be used
     609             :  * to verify that you have the correct version of the server to run your
     610             :  * plugin.
     611             :  *
     612             :  * This is a positive number.
     613             :  *
     614             :  * \return The server patch version as an integer.
     615             :  */
     616           0 : int server::version_patch()
     617             : {
     618           0 :     return SNAPWEBSITES_VERSION_PATCH;
     619             : }
     620             : 
     621             : 
     622             : /** \brief Get the server instance.
     623             :  *
     624             :  * The main central hub is the server object.
     625             :  *
     626             :  * Like all the plugins, there can be only one server instance.
     627             :  * Because of that, it is made a singleton which means whichever
     628             :  * plugin that first needs the server can get a pointer to it at
     629             :  * any time.
     630             :  *
     631             :  * \note
     632             :  * This function is not thread safe.
     633             :  *
     634             :  * \return A pointer to the server.
     635             :  */
     636           0 : server::pointer_t server::instance()
     637             : {
     638           0 :     if( !g_instance )
     639             :     {
     640             :         // plugins registration make use of those two variables
     641           0 :         plugins::g_next_register_name = "server";
     642           0 :         plugins::g_next_register_filename = __FILE__;
     643             : 
     644           0 :         g_instance.reset( new server );
     645             : 
     646           0 :         plugins::g_next_register_name.clear();
     647           0 :         plugins::g_next_register_filename.clear();
     648             :     }
     649           0 :     return g_instance;
     650             : }
     651             : 
     652             : 
     653             : /** \brief Return the current server pointer.
     654             :  *
     655             :  * When deriving from the snap server, you cannot put the pointer in
     656             :  * another variable than the g_instance pointer. However, you cannot
     657             :  * allocate the right type of server if you call the instance()
     658             :  * function because it does not use a factory model that allows you
     659             :  * to create any type of server.
     660             :  *
     661             :  * Instead, you call this get_instance() function and if it returns
     662             :  * a pointer, you create your own server and save its pointer in
     663             :  * the g_instance variable using the set_instance() function.
     664             :  *
     665             :  * \code
     666             :  *      pointer_t my_server(get_instance());
     667             :  *      if(!my_server)
     668             :  *      {
     669             :  *          ...
     670             :  *          set_instance(new my_server_class);
     671             :  *          ...
     672             :  *      }
     673             :  * \endcode
     674             :  *
     675             :  * \return The server instance if defined, may return a null pointer.
     676             :  */
     677           0 : server::pointer_t server::get_instance()
     678             : {
     679           0 :     return g_instance;
     680             : }
     681             : 
     682             : 
     683             : /** \brief When creating a server using a different factory.
     684             :  *
     685             :  * This function is used when one create a server using a different
     686             :  * factory than the main Snap Server factor (i.e. the
     687             :  * server::instance() function.) For example, the watchdog_server
     688             :  * uses this function to save a pointer of itself here.
     689             :  *
     690             :  * Note that the other server must be derived from the snap::server
     691             :  * class, obviously.
     692             :  *
     693             :  * See the get_instance() for more information about how to allocate
     694             :  * a new server. As an example, check out the lib/snapwatchdog.cpp file.
     695             :  *
     696             :  * \param[in] other_server  The other type of server to save in this instance.
     697             :  *
     698             :  * \return A pointer to the new instance of the server.
     699             :  */
     700           0 : server::pointer_t server::set_instance(pointer_t other_server)
     701             : {
     702           0 :     if(g_instance)
     703             :     {
     704           0 :         throw snap_logic_exception("server::set_instance() cannot be called more than once.");
     705             :     }
     706             : 
     707           0 :     return g_instance = other_server;
     708             : }
     709             : 
     710             : 
     711             : /** \brief A path or URI to a logo for this plugin.
     712             :  *
     713             :  * This function returns a 64x64 icons representing this plugin.
     714             :  *
     715             :  * \return A path to the logo.
     716             :  */
     717           0 : QString server::icon() const
     718             : {
     719           0 :     return "/images/snap/snap-logo-64x64.png";
     720             : }
     721             : 
     722             : 
     723             : /** \brief Return the description of this plugin.
     724             :  *
     725             :  * This function returns the English description of this plugin.
     726             :  * The system presents that description when the user is offered to
     727             :  * install or uninstall a plugin on his website. Translation may be
     728             :  * available in the database.
     729             :  *
     730             :  * \return The description in a QString.
     731             :  */
     732           0 : QString server::description() const
     733             : {
     734             :     return "The server plugin is hard coded in the base of the system."
     735             :         " It handles the incoming and outgoing network connections."
     736           0 :         " The server handles a number of messages that are global.";
     737             : }
     738             : 
     739             : 
     740             : /** \brief Return our dependencies.
     741             :  *
     742             :  * The server has no dependencies so this function returns an empty string.
     743             :  *
     744             :  * \return An empty string.
     745             :  */
     746           0 : QString server::dependencies() const
     747             : {
     748           0 :     return QString();
     749             : }
     750             : 
     751             : 
     752             : /** \brief Required bootstrap definition.
     753             :  *
     754             :  * This function does nothing as the server object is already properly
     755             :  * initialized by the time this function gets called.
     756             :  *
     757             :  * However, since it is a pure virtual function, we suppose that it
     758             :  * is required.
     759             :  */
     760           0 : void server::bootstrap(snap_child * snap)
     761             : {
     762             :     // virtual function stub
     763           0 :     NOTUSED(snap);
     764           0 : }
     765             : 
     766             : 
     767             : /** \brief Update the server, the function is mandatory.
     768             :  *
     769             :  * This function is here because it is a pure virtual in the plug in. At this
     770             :  * time it does nothing and it probably will never have actual updates.
     771             :  *
     772             :  * \param[in] last_updated  The UTC Unix date when this plugin was last updated (in micro seconds).
     773             :  *
     774             :  * \return The UTC Unix date of the last update of this plugin.
     775             :  */
     776           0 : int64_t server::do_update(int64_t last_updated)
     777             : {
     778           0 :     NOTUSED(last_updated);
     779             : 
     780           0 :     SNAP_PLUGIN_UPDATE_INIT();
     781           0 :     SNAP_PLUGIN_UPDATE_EXIT();
     782             : }
     783             : 
     784             : 
     785             : /** \brief Initialize the server.
     786             :  *
     787             :  * This function initializes the server.
     788             :  *
     789             :  * \note
     790             :  * The server is also a plugin. This is useful for having support for
     791             :  * signals in the server.
     792             :  */
     793           0 : server::server()
     794             :     : f_parameters("snapserver")
     795           0 :     , f_translator()        // forced to include because of -Weffc++
     796             : {
     797             :     // set the plugin version
     798           0 :     set_version(SNAPWEBSITES_VERSION_MAJOR, SNAPWEBSITES_VERSION_MINOR);
     799           0 : }
     800             : 
     801             : 
     802             : /** \brief Clean up the server.
     803             :  *
     804             :  * Since the server is a singleon, it never gets deleted while running.
     805             :  * Since we use a bare pointer, it should never go out of scope, thus
     806             :  * this function should never be called.
     807             :  */
     808           0 : server::~server()
     809             : {
     810           0 :     for( auto const & child : f_children_waiting )
     811             :     {
     812           0 :         delete child;
     813             :     }
     814           0 :     f_children_waiting.clear();
     815             :     //
     816           0 :     for( auto const & child : f_children_running )
     817             :     {
     818           0 :         if( child )
     819             :         {
     820           0 :             child->kill();
     821             :         }
     822             :         //
     823           0 :         delete child;
     824             :     }
     825           0 :     f_children_running.clear();
     826             : 
     827             :     // Destroy the QApplication instance.
     828             :     //
     829           0 :     g_application = nullptr;
     830           0 : }
     831             : 
     832             : 
     833             : /** \brief Exit the server.
     834             :  *
     835             :  * This function exists the program by calling the exit(3) function from
     836             :  * the C library. Before doing so, though, it will first make sure that
     837             :  * the server is cleaned up as required.
     838             :  *
     839             :  * \param[in] code  The exit code, generally 0 or 1.
     840             :  */
     841           0 : void server::exit( int const code )
     842             : {
     843             :     // Destroy the snapwebsites server instance.
     844             :     //
     845           0 :     g_instance.reset();
     846           0 :     g_application = nullptr;    // Make sure the QApplication instance is really deleted.
     847             : 
     848             :     // Call the C exit(3) function.
     849             :     //
     850           0 :     ::exit(code);
     851             : 
     852             :     // Sanity check!
     853             :     //
     854             :     NOTREACHED();
     855             : }
     856             : 
     857             : 
     858             : /** \brief Print out usage information to start the server.
     859             :  *
     860             :  * This function prints out a usage message that describes the arguments
     861             :  * that the server accepts on the command line.
     862             :  *
     863             :  * The function calls exit(1) and never returns.
     864             :  */
     865           0 : void server::usage()
     866             : {
     867             :     // TODO: switch to the config. from advgetopt and then we can just
     868             :     //       use a %<flag> such as %f, %*g, etc.
     869             :     //
     870           0 :     std::stringstream ss_footer;
     871             :     ss_footer << "Configuration File: \""
     872           0 :               << f_parameters.get_configuration_path()
     873             :               << "/"
     874           0 :               << f_parameters.get_configuration_filename()
     875           0 :               << ".conf\""
     876           0 :               << std::endl;
     877           0 :     std::string footer(ss_footer.str());
     878           0 :     g_snapserver_options_environment.f_help_footer = footer.c_str();
     879             : 
     880           0 :     std::cout << f_opt->usage();
     881             : 
     882           0 :     g_snapserver_options_environment.f_help_footer = nullptr;
     883             : 
     884           0 :     exit(1);
     885             : }
     886             : 
     887             : 
     888             : /** \brief Change the configuration filename.
     889             :  *
     890             :  * The various daemons that make use of the server will generally want to
     891             :  * use a different .conf filename (i.e. snapwatchdog uses snapwatchdog.conf
     892             :  * instead of snapserver.conf). This function is used for that purpose
     893             :  * right after the server was created, call it with the name of your
     894             :  * configuration file.
     895             :  *
     896             :  * The path is not set here. The default is "/etc/snapwebsites". It can
     897             :  * be changed using the --config command line option.
     898             :  *
     899             :  * \param[in] filename  The name of the configuration file.
     900             :  */
     901           0 : void server::set_config_filename(std::string const & filename)
     902             : {
     903           0 :     f_parameters.set_configuration_filename(filename);
     904           0 : }
     905             : 
     906             : 
     907             : /** \brief Mark the server object as a backend tool instead.
     908             :  *
     909             :  * This function is called by the backend tool to mark the server
     910             :  * as a command line tool rather than a server. In general, this
     911             :  * is ignored, but there are a few cases where it is checked to
     912             :  * make sure that everything works as expected.
     913             :  *
     914             :  * The function can be called as many times as necessary.
     915             :  */
     916           0 : void server::setup_as_backend()
     917             : {
     918           0 :     f_backend = true;
     919           0 : }
     920             : 
     921             : 
     922             : /** \fn server::is_backend() const;
     923             :  * \brief Check whether the server is setup as a backend.
     924             :  *
     925             :  * This function returns false unless the setup_as_backend()
     926             :  * funciton was called.
     927             :  *
     928             :  * \return true if this is a server, false if this is used as a command line tool
     929             :  */
     930             : 
     931             : 
     932             : /** \brief Print the version string to stdout.
     933             :  *
     934             :  * This function prints out the version string of this server to the standard
     935             :  * output stream.
     936             :  *
     937             :  * This is a virtual function so that way servers and daemons that derive
     938             :  * from snap::server have a chance to show their own version.
     939             :  */
     940           0 : void server::show_version()
     941             : {
     942           0 :     std::cout << SNAPWEBSITES_VERSION_STRING << std::endl;
     943           0 : }
     944             : 
     945             : 
     946             : /** \brief Configure the server.
     947             :  *
     948             :  * This function parses the command line arguments and reads the
     949             :  * configuration file.
     950             :  *
     951             :  * By default, the configuration file is defined as:
     952             :  *
     953             :  * \code
     954             :  * /etc/snapwebsites/snapserver.conf
     955             :  * \endcode
     956             :  *
     957             :  * The user may use the --config argument to use a different file.
     958             :  *
     959             :  * The function does not return if any of the arguments generate an
     960             :  * error or if the configuration file has an invalid parameter.
     961             :  *
     962             :  * \note
     963             :  * In this function we still use syslog() to log errors because the
     964             :  * logger is initialized at the end of the function once we got
     965             :  * all the necessary information to initialize the logger. Later we
     966             :  * may want to record the configuration file errors and log them
     967             :  * if we can still properly initialize the logger.
     968             :  *
     969             :  * \param[in] argc  The number of arguments in argv.
     970             :  * \param[in] argv  The array of argument strings.
     971             :  */
     972           0 : void server::config(int argc, char * argv[])
     973             : {
     974             :     // Stop on these signals, log them, then terminate.
     975             :     //
     976           0 :     signal( SIGSEGV, sighandler );
     977           0 :     signal( SIGBUS,  sighandler );
     978           0 :     signal( SIGFPE,  sighandler );
     979           0 :     signal( SIGILL,  sighandler );
     980           0 :     signal( SIGTERM, sighandler );
     981           0 :     signal( SIGINT,  sighandler );
     982           0 :     signal( SIGQUIT, sighandler );
     983           0 :     signal( SIGALRM, sighandler );
     984           0 :     signal( SIGABRT, sighandler );  // although we can't really return from this one, having the stack trace is useful
     985             : 
     986             :     // we want to ignore SIGPIPE, but having a log is really useful so
     987             :     // we use a signal handler that logs the info and returns,
     988             :     // letting the daemon continue
     989             :     //
     990           0 :     signal( SIGPIPE,  sigloghandler );
     991             : 
     992             :     // ignore console signals
     993             :     //
     994           0 :     signal( SIGTSTP,  SIG_IGN );
     995           0 :     signal( SIGTTIN,  SIG_IGN );
     996           0 :     signal( SIGTTOU,  SIG_IGN );
     997             : 
     998             :     // Force timezone to UTC/GMT so it does not vary between installations
     999             :     // (i.e. you could have Snap servers all over the world!)
    1000             :     //
    1001           0 :     setenv("TZ", "", 1);  // default is UTC
    1002           0 :     tzset();
    1003             : 
    1004             :     // Force the locale to "C" so we do not get too many surprises.
    1005             :     // Users may change their locale settings so a child may change
    1006             :     // the locale for display formatting needs.
    1007             :     //
    1008           0 :     char const * default_locale(std::setlocale(LC_ALL, "C.UTF-8"));
    1009           0 :     if(default_locale == nullptr)
    1010             :     {
    1011           0 :         std::locale const & loc(std::locale("C"));
    1012           0 :         std::locale::global(loc);  // default depends on LC_... vars
    1013           0 :         std::cin.imbue(loc);
    1014           0 :         std::cout.imbue(loc);
    1015           0 :         std::cerr.imbue(loc);
    1016             :     }
    1017             :     else
    1018             :     {
    1019             :         // if we can use UTF-8, do so rather than just plain C
    1020           0 :         std::locale const & loc(std::locale("C.UTF-8"));
    1021           0 :         std::locale::global(loc);  // default depends on LC_... vars
    1022           0 :         std::cin.imbue(loc);
    1023           0 :         std::cout.imbue(loc);
    1024           0 :         std::cerr.imbue(loc);
    1025             :     }
    1026             :     // TBD: we initialize the Qt library later, I do not think it will
    1027             :     //      change the locale on us, but this is a TBD until otherwise
    1028             :     //      proven to be safe... (see QLocale) -- and that could change
    1029             :     //      when we start using Qt 5.x
    1030             : 
    1031             :     // Parse command-line options...
    1032             :     //
    1033             : 
    1034           0 :     f_opt = std::make_shared<advgetopt::getopt>( g_snapserver_options_environment, argc, argv );
    1035             : 
    1036           0 :     if(f_opt->is_defined("version"))
    1037             :     {
    1038           0 :         show_version();
    1039           0 :         exit(0);
    1040             :         NOTREACHED();
    1041             :     }
    1042             : 
    1043             :     // We want the servername for later.
    1044             :     //
    1045             :     // TODO: this f_servername is the name of the daemon binary, not
    1046             :     //       the name of the computer; we want to change that variable
    1047             :     //       name and rename the corresponding functions too at some point
    1048             :     //
    1049           0 :     f_servername = f_opt->get_program_name();
    1050             : 
    1051           0 :     if(f_service_name.empty())
    1052             :     {
    1053           0 :         f_service_name = f_servername;
    1054             :     }
    1055             : 
    1056             :     // Keep the server in the foreground?
    1057             :     //
    1058           0 :     f_foreground = !f_opt->is_defined( "background" );
    1059             : 
    1060             :     // initialize the syslog() interface
    1061           0 :     openlog(f_servername.c_str(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
    1062             : 
    1063           0 :     bool help(false);
    1064             : 
    1065             :     // handle configuration file
    1066             :     //
    1067             :     // One can change the path with "--config <new path>", but not the
    1068             :     // filename of the configuration file.
    1069             :     //
    1070           0 :     if(f_opt->is_defined("config"))
    1071             :     {
    1072           0 :         f_parameters.set_configuration_path(f_opt->get_string("config"));
    1073             :     }
    1074             : 
    1075             :     // default parameters -- we may want to have a separate function and
    1076             :     //                       maybe some clear separate variables?
    1077           0 :     f_parameters.set_parameter_default("listen", "127.0.0.1:4004");
    1078           0 :     f_parameters.set_parameter_default(get_name(name_t::SNAP_NAME_CORE_PARAM_PLUGINS_PATH), "/usr/lib/snapwebsites/plugins");
    1079           0 :     f_parameters.set_parameter_default(get_name(name_t::SNAP_NAME_CORE_PARAM_TABLE_SCHEMA_PATH), "/usr/lib/snapwebsites/tables");
    1080           0 :     f_parameters.set_parameter_default("qs_action", "a");
    1081           0 :     f_parameters.set_parameter_default("qs_hit", "hit");
    1082             : 
    1083             :     // Output log to stdout. Implies foreground mode.
    1084             :     //
    1085           0 :     f_debug = f_opt->is_defined( "debug" )
    1086           0 :            || f_parameters.has_parameter("debug");
    1087             : 
    1088           0 :     if(f_opt->is_defined("param"))
    1089             :     {
    1090           0 :         int const max_params(f_opt->size("param"));
    1091           0 :         for(int idx(0); idx < max_params; ++idx)
    1092             :         {
    1093           0 :             QString const param(QString::fromUtf8(f_opt->get_string("param", idx).c_str()));
    1094           0 :             int const p(param.indexOf('='));
    1095           0 :             if(p == -1)
    1096             :             {
    1097           0 :                 SNAP_LOG_FATAL("unexpected parameter \"--param ")(f_opt->get_string("param", idx))("\". No '=' found in the parameter definition. (in server::config())");
    1098           0 :                 syslog(LOG_CRIT, "unexpected parameter \"--param %s\". No '=' found in the parameter definition. (in server::config())", f_opt->get_string("param", idx).c_str());
    1099           0 :                 help = true;
    1100             :             }
    1101             :             else
    1102             :             {
    1103             :                 // got a user defined parameter
    1104           0 :                 QString const name(param.left(p));
    1105           0 :                 f_parameters[name] = param.mid(p + 1);
    1106             :             }
    1107             :         }
    1108             :     }
    1109             : 
    1110           0 :     if( f_opt->is_defined( "filename" ) )
    1111             :     {
    1112           0 :         std::string const filename(f_opt->get_string("filename"));
    1113           0 :         if( f_backend )
    1114             :         {
    1115           0 :             f_parameters["__BACKEND_URI"] = filename.c_str();
    1116             :         }
    1117             :         else
    1118             :         {
    1119             :             // If not backend, "--filename" is not currently useful.
    1120             :             //
    1121           0 :             SNAP_LOG_FATAL("unexpected standalone parameter \"")(filename)("\", server not started. (in server::config())");
    1122           0 :             syslog( LOG_CRIT, "unexpected standalone parameter \"%s\", server not started. (in server::config())", filename.c_str() );
    1123           0 :             help = true;
    1124             :         }
    1125             :     }
    1126             : 
    1127           0 :     if( f_opt->is_defined( "action" ) )
    1128             :     {
    1129           0 :         std::string const action(f_opt->get_string("action"));
    1130           0 :         if( f_backend )
    1131             :         {
    1132           0 :             f_parameters["__BACKEND_ACTION"] = action.c_str();
    1133             :         }
    1134             :         else
    1135             :         {
    1136             :             // If not backend, "--action" does not make sense.
    1137             :             //
    1138           0 :             SNAP_LOG_FATAL("unexpected command line option \"--action ")(action)("\", server not started as backend. (in server::config())");
    1139           0 :             syslog( LOG_CRIT, "unexpected command line option \"--action %s\", server not started as backend. (in server::config())", action.c_str() );
    1140           0 :             help = true;
    1141             :         }
    1142           0 :         if( f_opt->is_defined( "cron-action" ) )
    1143             :         {
    1144             :             // --action and --cron-action are mutually exclusive
    1145             :             //
    1146           0 :             SNAP_LOG_FATAL("command line options \"--action\" and \"--cron-action\" are mutually exclusive, server not started as backend. (in server::config())");
    1147           0 :             syslog( LOG_CRIT, "command line options \"--action\" and \"--cron-action\" are mutually exclusive, server not started as backend. (in server::config())" );
    1148           0 :             help = true;
    1149             :         }
    1150             :     }
    1151             : 
    1152           0 :     if( f_opt->is_defined( "cron-action" ) )
    1153             :     {
    1154           0 :         std::string const cron_action(f_opt->get_string("cron-action"));
    1155           0 :         if( f_backend )
    1156             :         {
    1157           0 :             f_parameters["__BACKEND_CRON_ACTION"] = cron_action.c_str();
    1158             :         }
    1159             :         else
    1160             :         {
    1161             :             // If not backend, "--cron-action" does not make sense.
    1162             :             //
    1163           0 :             SNAP_LOG_FATAL("unexpected command line option \"--cron-action ")(cron_action)("\", server not started as backend. (in server::config())");
    1164           0 :             syslog( LOG_CRIT, "unexpected command line option \"--cron-action %s\", server not started as backend. (in server::config())", cron_action.c_str() );
    1165           0 :             help = true;
    1166             :         }
    1167             :     }
    1168             : 
    1169           0 :     if( help || f_opt->is_defined( "help" ) )
    1170             :     {
    1171           0 :         usage();
    1172             :         exit(1);
    1173             :     }
    1174             : 
    1175             :     // Finally we can initialize the log system
    1176             :     //
    1177           0 :     logging::set_progname(f_servername);
    1178           0 :     if( f_opt->is_defined( "no-log" ) )
    1179             :     {
    1180             :         // Override log_config and output only to the console
    1181             :         //
    1182           0 :         logging::configure_console();
    1183             :     }
    1184           0 :     else if( f_opt->is_defined("logfile") )
    1185             :     {
    1186             :         // Override the output logfile specified in the configuration file.
    1187             :         //
    1188           0 :         logging::configure_logfile( f_opt->get_string( "logfile" ).c_str() );
    1189             :     }
    1190           0 :     else if( f_opt->is_defined("logconf") )
    1191             :     {
    1192           0 :         logging::configure_conffile( f_opt->get_string( "logconf" ).c_str() );
    1193             :     }
    1194             :     else
    1195             :     {
    1196             :         // Read the log configuration file and use it to specify the appenders
    1197             :         // and log level. If a server version exists and the server is
    1198             :         // available then use the loggging server.
    1199             :         //
    1200           0 :         QString const log_config( f_parameters["log_config"] );
    1201           0 :         if( log_config.isEmpty() )
    1202             :         {
    1203             :             // Fall back to output to the console
    1204             :             //
    1205           0 :             logging::configure_console();
    1206             :         }
    1207             :         else
    1208             :         {
    1209             :             // Configure the logging system according to the log configuration.
    1210             :             //
    1211           0 :             logging::configure_conffile( log_config );
    1212             :         }
    1213             :     }
    1214             : 
    1215             : #ifdef SNAP_NO_FORK
    1216             :     SNAP_LOG_WARNING("SNAP_NO_FORK is defined! This is NOT a production-ready build!");
    1217             :     if( f_opt->is_defined("nofork") )
    1218             :     {
    1219             :         SNAP_LOG_INFO("--nofork specified: snap_child will not fork and server will terminate.");
    1220             :         f_nofork = true;
    1221             :     }
    1222             : #endif
    1223             : 
    1224           0 :     if( f_debug )
    1225             :     {
    1226             :         // Force the logger level to DEBUG
    1227             :         // If the current level is already lower, leave it as is
    1228             :         //
    1229           0 :         logging::reduce_log_output_level( logging::log_level_t::LOG_LEVEL_DEBUG );
    1230             :     }
    1231             : 
    1232           0 :     QString const lock_obtension_duration( f_parameters["lock_obtension_duration"] );
    1233           0 :     if( !lock_obtension_duration.isEmpty() )
    1234             :     {
    1235           0 :         bool ok(false);
    1236           0 :         int const lock_obtension(lock_obtension_duration.toInt(&ok, 10));
    1237           0 :         if(ok)
    1238             :         {
    1239           0 :             snap_lock::initialize_lock_obtention_timeout(lock_obtension);
    1240             :         }
    1241             :     }
    1242             : 
    1243             :     // determine the name of the server
    1244             :     //
    1245           0 :     get_server_name();
    1246             : 
    1247             :     // determine whether the snapfirewall daemon is active
    1248             :     // (if so we want to wait for the FIREWALLUP message)
    1249             :     //
    1250           0 :     f_firewall_is_active = system("systemctl is-active -q snapfirewall") == 0;
    1251           0 : }
    1252             : 
    1253             : 
    1254             : /** \brief Define the service name.
    1255             :  *
    1256             :  * This function sets the service name to the specified parameter. By
    1257             :  * default the service name is set to the process name. So for example
    1258             :  * the snapserver service name is "snapserver".
    1259             :  *
    1260             :  * This function is useful to change the service name of processes such
    1261             :  * as the snapbackend processes which all use the same process but perform
    1262             :  * different services.
    1263             :  *
    1264             :  * \param[in] service_name  The name of the service using the server class.
    1265             :  */
    1266           0 : void server::set_service_name(std::string const & service_name)
    1267             : {
    1268           0 :     f_service_name = service_name;
    1269           0 : }
    1270             : 
    1271             : 
    1272             : /** \brief Retrieve the service name.
    1273             :  *
    1274             :  * This function returns the service name. This is most often the same
    1275             :  * as the servername() parameter only sometimes the service name gets
    1276             :  * changed to avoid confusion. For example, snapbackend is used for
    1277             :  * several different services such as "list::pagelist" and "images::images".
    1278             :  *
    1279             :  * \note
    1280             :  * The service names should not include colons in their names. The
    1281             :  * snapbackend will transform the action name to use underscores
    1282             :  * instead (i.e. "list__pagelist" or "images__images".)
    1283             :  *
    1284             :  * \note
    1285             :  * This name is used as the PID filename. It is important for us to be
    1286             :  * able to distinguish between various snapbackend processes since each
    1287             :  * PID file needs a distinct filename.
    1288             :  *
    1289             :  * \return A reference to the service name.
    1290             :  */
    1291           0 : std::string const & server::get_service_name() const
    1292             : {
    1293           0 :     return f_service_name;
    1294             : }
    1295             : 
    1296             : 
    1297             : /** \brief Get the server name.
    1298             :  *
    1299             :  * This function retrieves the name of the server. If it is defined in
    1300             :  * the snapcommunicator.conf file, then that name is returned. If not
    1301             :  * defined there, then the hostname() function is used to retrieve
    1302             :  * the name of the computer.
    1303             :  *
    1304             :  * The name will be verified and reformatted to be compatible with
    1305             :  * the snapcommunicator messaging system. This means '-' are replaced
    1306             :  * with '_', A to Z are replaced by a to z, and names cannot start
    1307             :  * with a digit or be empty.
    1308             :  *
    1309             :  * \note
    1310             :  * The function caches the name so it does not have to recalculate
    1311             :  * it over and over again. This also means that a change of the hostname
    1312             :  * will not be seen by one of our daemons until it gets restarted.
    1313             :  *
    1314             :  * \return A copy of the server name.
    1315             :  */
    1316           0 : std::string server::get_server_name()
    1317             : {
    1318             :     // if called more than once, returned the same name each time after that
    1319             :     //
    1320           0 :     static std::string saved_server_name;
    1321           0 :     if(saved_server_name.empty())
    1322             :     {
    1323             :         // WARNING: we create a separate version of the parameters variable,
    1324             :         //          but remember that all the configurations accessible
    1325             :         //          through that interface which saves them in a global, so
    1326             :         //          yes, it is a separate parameter, but really the same
    1327             :         //          configuration variables
    1328             :         //
    1329             :         //          we expect server_name to only be defined in the
    1330             :         //          snapcommunicator.conf file because it needs it
    1331             :         //          and it gets started first.
    1332             :         //
    1333             :         // Note: We create this separate variable because this is a static
    1334             :         //       function and thus we do not have access to f_parameters.
    1335             :         //
    1336           0 :         snap_config parameters("snapcommunicator");
    1337             : 
    1338           0 :         snap_config::snap_config_parameter_ref server_name(parameters["server_name"]);
    1339             : 
    1340             :         // if the parameter was not defined in the configuration file,
    1341             :         // read the system hostname
    1342             :         //
    1343           0 :         if(server_name.empty())
    1344             :         {
    1345             :             // use hostname by default if undefined in configuration file
    1346             :             //
    1347             :             char host[HOST_NAME_MAX + 1];
    1348           0 :             host[HOST_NAME_MAX] = '\0';
    1349           0 :             if(gethostname(host, sizeof(host)) != 0
    1350           0 :             || strlen(host) == 0)
    1351             :             {
    1352           0 :                 throw snapwebsites_exception_parameter_not_available("snapwebsites.cpp: server::get_server_name() could not determine the name of this server.");
    1353             :             }
    1354             :             // TODO: add code to verify that we like that name (i.e. if the
    1355             :             //       name includes periods we will reject it when sending
    1356             :             //       messages to/from snapcommunicator)
    1357             :             //
    1358           0 :             server_name = host;
    1359             :         }
    1360             : 
    1361           0 :         saved_server_name = server_name;
    1362             : 
    1363           0 :         verify_server_name(saved_server_name);
    1364             :     }
    1365             : 
    1366           0 :     return saved_server_name;
    1367             : }
    1368             : 
    1369             : 
    1370             : /** \brief Verify a name that is expected to be used as a server name.
    1371             :  *
    1372             :  * This function is used to check a \p server_name string. The function
    1373             :  * fixes up the name (replace the '-' with '_', removed any characters
    1374             :  * after the first '.', and force characters to lowercase.)
    1375             :  *
    1376             :  * The name cannot be empty nor larger than 63 characters. Note that
    1377             :  * a name that starts with a period looks like it is empty.
    1378             :  *
    1379             :  * \param[in,out] server_name  The name to be checked.
    1380             :  */
    1381           0 : void server::verify_server_name(std::string & server_name)
    1382             : {
    1383           0 :     std::string name;
    1384           0 :     std::string const original(server_name);
    1385           0 :     char const * s(original.c_str());
    1386           0 :     while(*s != '\0' && *s != '.')
    1387             :     {
    1388           0 :         if(*s == '-')
    1389             :         {
    1390             :             // the dash is not acceptable in our server name
    1391             :             // replace it with an underscore
    1392             :             //
    1393           0 :             SNAP_LOG_WARNING("Hostname \"")
    1394           0 :                             (std::string(server_name))
    1395           0 :                             ("\" includes a dash character (-) which is not supported by snap."
    1396             :                              " Replacing with an underscore (_). If that is not what you expect,"
    1397             :                              " edit \"/etc/snapwebsites/snapwebsites.d/snapcommunicator.conf\""
    1398             :                              " and set the name as you want it in \"server_name=...\"");
    1399           0 :             name += '_';
    1400             :         }
    1401           0 :         else if(*s >= 'A' && *s <= 'Z')
    1402             :         {
    1403             :             // force lowercase -- hostnames are expected to be in
    1404             :             // lowercase although they are case insensitive so we
    1405             :             // certainly want them to be in lowercase anyway
    1406             :             //
    1407             :             // note: we do not support UTF-8 servernames so really only
    1408             :             //       ASCII will be taken in account here
    1409             :             //
    1410           0 :             name += *s | 0x20;
    1411             :         }
    1412           0 :         else if((*s >= 'a' && *s <= 'z')
    1413           0 :              || (*s >= '0' && *s <= '9')
    1414           0 :              || *s == '_')
    1415             :         {
    1416           0 :             name += *s;
    1417             :         }
    1418             :         else
    1419             :         {
    1420           0 :             throw snapwebsites_exception_invalid_parameters("snapwebsites.cpp: server::get_server_name() found invalid characters in your server_name parameter.");
    1421             :         }
    1422             : 
    1423           0 :         ++s;
    1424             :     }
    1425           0 :     if(*s == '.')
    1426             :     {
    1427             :         // according to the hostname documentation, the FQDN is
    1428             :         // the name before the first dot; this means if you have
    1429             :         // more than two dots, the sub-sub-sub...sub-domain is
    1430             :         // the FQDN
    1431             :         //
    1432           0 :         SNAP_LOG_WARNING("Hostname \"")(std::string(server_name))("\" includes a dot character (.) which is not supported by snap. We assume that indicates the end of the name. If that is not what you expect, edit snapcommunicator.conf and set the name as you want it in server_name=...");
    1433             :     }
    1434             : 
    1435             : 
    1436             :     // TBD: We could further prevent the name from starting/ending with '_'?
    1437             :     //
    1438           0 :     if(server_name != name)
    1439             :     {
    1440             :         // warning about changing the name (not that in the above loop
    1441             :         // we do not warn about changing the name to lowercase)
    1442             :         //
    1443           0 :         SNAP_LOG_WARNING("Your server_name parameter \"")(std::string(server_name))("\" was transformed to \"")(name)("\" to be compatible with Snap!");
    1444           0 :         server_name = name;
    1445             :     }
    1446             : 
    1447             :     // make sure the computer name is no more than 63 characters
    1448             :     //
    1449           0 :     if(server_name.empty()
    1450           0 :     || server_name.length() > 63)
    1451             :     {
    1452           0 :         throw snapwebsites_exception_invalid_parameters("snapwebsites.cpp: server::get_server_name(): your server_name parameter is empty or too long. The maximum length is 63 characters.");
    1453             :     }
    1454             : 
    1455             :     // make sure we can use that name to send messages between computers
    1456             :     //
    1457           0 :     snap::snap_communicator_message::verify_name(QString::fromUtf8(server_name.c_str()), false, true);
    1458           0 : }
    1459             : 
    1460             : 
    1461             : /** \brief Retrieve the number of threads in this process.
    1462             :  *
    1463             :  * This function counts the total number of threads that this process is
    1464             :  * currently running with.
    1465             :  *
    1466             :  * \todo
    1467             :  * We should make sure that the count is 1 before any call to fork().
    1468             :  *
    1469             :  * \return The number of running threads in this process.
    1470             :  */
    1471           0 : size_t server::thread_count()
    1472             : {
    1473             :     struct stat task;
    1474             : 
    1475           0 :     if(stat("/proc/self/task", &task) != 0)
    1476             :     {
    1477           0 :         return -1;
    1478             :     }
    1479             : 
    1480           0 :     return task.st_nlink - 2;
    1481             : }
    1482             : 
    1483             : 
    1484             : /** \brief Retrieve one of the configuration file parameters.
    1485             :  *
    1486             :  * This function returns the value of a named parameter. The
    1487             :  * parameter is defined in the configuration file, it may also
    1488             :  * be given a default value when the server is initialized.
    1489             :  *
    1490             :  * The following are the parameters currently supported by
    1491             :  * the core system. Additional parameters may be defined by
    1492             :  * plugins. Remember that parameters defined in the
    1493             :  * configuration file are common to ALL the websites and at
    1494             :  * this point plugins do not have direct access to the
    1495             :  * get_parameter() function (look at the get_site_parameter()
    1496             :  * function in the snap_child class as a better alternative
    1497             :  * for plugins.)
    1498             :  *
    1499             :  * \li backend_nice -- the nice value to use with backends; if undefined, keep
    1500             :  *     the default nice value (i.e. 0)
    1501             :  * \li cassandra_host -- the IP address or server name to Cassandra; default is localhost
    1502             :  * \li cassandra_port -- the port to use to connect to Cassandra; default is 9042
    1503             :  * \li data_path -- path to the directory holding the system data (images, js, css, counters, etc.)
    1504             :  * \li default_plugins -- list of default plugins to initialize a new website
    1505             :  * \li listen -- address:port to listen to (default 0.0.0.0:4004)
    1506             :  * \li plugins -- path to the list of plugins
    1507             :  * \li qs_action -- the variable holding the action over this path ("view" if not specified)
    1508             :  * \li max_pending_connections -- the number of connections that can wait in
    1509             :  *     the server queue, there is Snap default (i.e. the Qt TCP server default
    1510             :  *     is used if undefined, which in most cases means the system of 5.)
    1511             :  * \li server_name -- the name of the server, defaults to gethostname()
    1512             :  * \li timeout_wait_children -- the amount of time to wait before checking on
    1513             :  *     the existing children; cannot be less than 100ms; defaults to 5,000ms
    1514             :  *
    1515             :  * \param[in] param_name  The name of the parameter to retrieve.
    1516             :  *
    1517             :  * \sa set_parameter()
    1518             :  *
    1519             :  * \return The value of the specified parameter.
    1520             :  */
    1521           0 : QString server::get_parameter(QString const & param_name) const
    1522             : {
    1523           0 :     return f_parameters[param_name];
    1524             : }
    1525             : 
    1526             : 
    1527             : /** \brief Set one of the configuration file parameters.
    1528             :  *
    1529             :  * \param[in] param_name  The name of the parameter to retrieve.
    1530             :  * \param[in] value       The value to put into the parameter.
    1531             :  *
    1532             :  * \sa get_parameter()
    1533             :  */
    1534           0 : void server::set_parameter( const QString& param_name, const QString& value )
    1535             : {
    1536           0 :     f_parameters[param_name] = value;
    1537           0 : }
    1538             : 
    1539             : 
    1540             : /** \brief Set up the Qt4 application instance.
    1541             :  *
    1542             :  * This function creates the Qt4 application instance for application-wide use.
    1543             :  *
    1544             :  * \note This is code moved from config() above, since initializing and trying to delete
    1545             :  * on detach caused a crash.
    1546             :  */
    1547           0 : void server::prepare_qtapp( int argc, char *argv[] )
    1548             : {
    1549             :     // make sure the Qt Locale is UTF-8
    1550           0 :     QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
    1551             : 
    1552           0 :     if(!g_application)
    1553             :     {
    1554             :         // We install a translator early, but language files are only
    1555             :         // loaded if the user is logged in or a website specified a
    1556             :         // locale which is not "en" or "en_US".
    1557             :         //
    1558           0 :         g_application = QPointer<QCoreApplication>( new QCoreApplication(argc, argv) );
    1559           0 :         g_application->installTranslator(&f_translator);
    1560             :     }
    1561           0 : }
    1562             : 
    1563             : 
    1564             : /** \brief Change the current translation.
    1565             :  *
    1566             :  * This function is called whenever a new translation becomes available.
    1567             :  * In most cases this happens whenever a user is logged in the system.
    1568             :  *
    1569             :  * At some point we may want to provide a translation capability from
    1570             :  * the server settings so one can have most error messages translated
    1571             :  * in their main country language instead of the default English.
    1572             :  *
    1573             :  * The \p xml_data buffer is XML as output by Qt Linguist. We actually
    1574             :  * make use of our own translation tool in Snap! and have a backend
    1575             :  * process which gathers all the translations and generates one XML
    1576             :  * file for each given language.
    1577             :  *
    1578             :  * \param[in] xml_data  The XML data representing the translation as
    1579             :  *                      expected by QTranslator.
    1580             :  */
    1581           0 : void server::set_translation(QString const xml_data)
    1582             : {
    1583             :     // WARNING: the translation must not disappear when installed from
    1584             :     //          using the load(char const *, int) overload function so
    1585             :     //          we keep a copy in f_translation_xml
    1586             :     //
    1587           0 :     f_translation_xml = xml_data.toUtf8();
    1588             : 
    1589             :     // we use a cast because .data() returns a 'char *'
    1590           0 :     f_translator.load(reinterpret_cast<uchar const *>(f_translation_xml.data()), f_translation_xml.size());
    1591           0 : }
    1592             : 
    1593             : 
    1594             : /** \brief Prepare the Cassandra database.
    1595             :  *
    1596             :  * This function ensures that the Cassandra database includes the default
    1597             :  * context and tables (domain, website, contents--although we only test
    1598             :  * for one single table.)
    1599             :  *
    1600             :  * This is called once each time the server is started. It does not matter
    1601             :  * too much as it is quite fast. Only one mandatory table gets checked. We
    1602             :  * may later provide a way for plugins to create different contexts but at
    1603             :  * this point we expect all of them to only make use of the Core provided
    1604             :  * context (a.k.a. "snap_websites").
    1605             :  *
    1606             :  * \todo
    1607             :  * If this function does not get called, the f_snapdbproxy_addr and
    1608             :  * f_snapdbproxy_port do not get defined. This is a problem that should
    1609             :  * be addressed at some point, even if the call is considered mandatory.
    1610             :  *
    1611             :  * \todo
    1612             :  * This function only checks for one table. Unfortunately, if all tables
    1613             :  * are not created before we accept connections, things will not work
    1614             :  * right. This will NOT be fixed here, however. Instead, we will change
    1615             :  * the snapdbproxy implementation to start in three steps: (1) connect
    1616             :  * to Cassandra, (2) make sure the snap_websites context exists, and
    1617             :  * (3) make sure all the known tables exist. Once all of these steps
    1618             :  * complete successfully, then snapdbproxy sends the CASSANDRAREADY.
    1619             :  *
    1620             :  * \param[in] mandatory_table  A table that we expect to exist to go on.
    1621             :  * \param[out] timer_required  Whether the caller should setup a timer to
    1622             :  *             poll availability (true) or another CASSANDRAREADY message
    1623             :  *             will be sent later (i.e. no context/tables when true.)
    1624             :  *
    1625             :  * \return true if Cassandra is considered valid (up/running/initialized).
    1626             :  */
    1627           0 : bool server::check_cassandra(QString const & mandatory_table, bool & timer_required)
    1628             : {
    1629           0 :     timer_required = false;
    1630             : 
    1631             :     try
    1632             :     {
    1633           0 :         snap_cassandra cassandra;
    1634             : 
    1635             :         // attempt a connection, this may throw if the connection fails
    1636             :         //
    1637           0 :         cassandra.connect();
    1638             : 
    1639             :         // make sure we have the "snap_websites" context
    1640             :         //
    1641           0 :         libdbproxy::context::pointer_t context( cassandra.get_snap_context() );
    1642           0 :         if( !context )
    1643             :         {
    1644             :             // CASSANDRAREADY will be sent to use again once the tables are
    1645             :             // created (which implies that the context exists)
    1646             :             //
    1647           0 :             SNAP_LOG_WARNING("snap_websites context does not exist! snapserver is going to sleep.");
    1648           0 :             return false;
    1649             :         }
    1650             : 
    1651             :         // make sure a certain table is ready so this daemon can run as
    1652             :         // expected; if not present, exit immediately
    1653             :         //
    1654             :         // XXX: The get_table() function throws if the table is not available
    1655             :         //      and that triggers the cassandra_check_timer instead of just
    1656             :         //      waiting for a new CASSANDRAREADY message. At some point we
    1657             :         //      may want to look into a way to not throw if the table is
    1658             :         //      not there, only throw if an actual error occurs.
    1659             :         //
    1660           0 :         if(!cassandra.get_table(mandatory_table))
    1661             :         {
    1662             :             // the table does not exist yet...
    1663             :             //
    1664             :             // tables are expected to be created from the *-tables.xml files
    1665             :             // (see snapdbproxy/tools/snapcreatetables for details.)
    1666             :             //
    1667             :             // CASSANDRAREADY will be sent to us again once the tables are
    1668             :             // created (which implies that the context exists)
    1669             :             //
    1670           0 :             SNAP_LOG_WARNING("\"")
    1671           0 :                             (mandatory_table)
    1672           0 :                             ("\" table does not exist! snapserver is going to sleep.");
    1673           0 :             return false;
    1674             :         }
    1675             : 
    1676             :         // save the snapdbproxy address and port so the children can quickly
    1677             :         // get that information
    1678             :         //
    1679           0 :         f_snapdbproxy_addr = cassandra.get_snapdbproxy_addr();
    1680           0 :         f_snapdbproxy_port = cassandra.get_snapdbproxy_port();
    1681             : 
    1682           0 :         return true;
    1683             :     }
    1684           0 :     catch(std::runtime_error const & e)
    1685             :     {
    1686           0 :         SNAP_LOG_WARNING("could not connect to the \"snapdbproxy\" daemon, context was not created, or table \"")
    1687           0 :                         (mandatory_table)
    1688           0 :                         ("\" is missing. Error: ")
    1689           0 :                         (e.what());
    1690             : 
    1691             :         // In this case we are not going to ever receive another message
    1692             :         // to wake us up, so we want to use a timer and try again later
    1693             :         //
    1694           0 :         timer_required = true;
    1695           0 :         return false;
    1696             :     }
    1697             : }
    1698             : 
    1699             : 
    1700             : /** \brief Detach the server unless in foreground mode.
    1701             :  *
    1702             :  * This function detaches the server unless it is in foreground mode.
    1703             :  *
    1704             :  * \warning
    1705             :  * It is very important that you call the server_loop_ready() function
    1706             :  * after having called the detach() function. We expect that other
    1707             :  * function to be called just before you enter the server loop.
    1708             :  * In our case that generally means before calling the
    1709             :  * snap_communicator->run() function. That way, if anything in the
    1710             :  * initialization process fails and the loop is never enetered, we
    1711             :  * never signal systemd about being successful which is exactly what
    1712             :  * we want.
    1713             :  */
    1714           0 : void server::detach()
    1715             : {
    1716           0 :     if(f_foreground)
    1717             :     {
    1718           0 :         return;
    1719             :     }
    1720             : 
    1721             :     // create a new PID file, this gets a pipe ready for communication
    1722             :     // (i.e. the parent wants to wait for the child to be ready and
    1723             :     // have had time to create the PID file, something that can only
    1724             :     // happen after we called fork() unfortunately...)
    1725             :     //
    1726           0 :     f_pid_file.reset(new snap_pid(f_service_name));
    1727             : 
    1728             :     // detaching using fork()
    1729             :     //
    1730           0 :     pid_t const child_pid(fork());
    1731           0 :     if(child_pid == 0)
    1732             :     {
    1733             :         // this is the child, make sure we keep the log alive
    1734             :         //
    1735           0 :         logging::reconfigure();
    1736             : 
    1737             :         // at some point we want to save our PID in the PID file,
    1738             :         // this means we're ready (as far as systemd is concerned)
    1739             :         // but we want to do that just before entering the server
    1740             :         // loop because if anything fails before that happens we
    1741             :         // do not want to tell systemd that we succeessfully started
    1742             :         //
    1743           0 :         return;
    1744             :     }
    1745             : 
    1746           0 :     if(child_pid == -1)
    1747             :     {
    1748           0 :         logging::reconfigure();
    1749           0 :         SNAP_LOG_FATAL("the server could not fork() a child process to detach itself from your console.");
    1750           0 :         exit(1);
    1751             :     }
    1752             : 
    1753           0 :     int const code(f_pid_file->wait_signal() ? 0 : 1);
    1754             : 
    1755           0 :     exit(code);
    1756             : }
    1757             : 
    1758             : 
    1759             : /** \brief The server is ready to enter the server loop.
    1760             :  *
    1761             :  * If you use the detach() function, this function must be called just
    1762             :  * before you enter the server loop itself. In most cases, our server
    1763             :  * loop starts at the time we call the snap_communicator::run() function.
    1764             :  *
    1765             :  * This function finishes up the PID file initialization by creating the
    1766             :  * actual file and sending a signal to the parent process (through the
    1767             :  * pipe created for this purpose.)
    1768             :  *
    1769             :  * It is very important that this function gets called because otherwise
    1770             :  * the parent stays stuck waiting for its signal and instead of returning
    1771             :  * as expected, it will linger. This means systemd will not understand
    1772             :  * what the process status is.
    1773             :  */
    1774           0 : void server::server_loop_ready()
    1775             : {
    1776           0 :     if(f_pid_file != nullptr)
    1777             :     {
    1778           0 :         f_pid_file->create_pid_file();
    1779             :     }
    1780           0 : }
    1781             : 
    1782             : 
    1783             : /** \brief Send a PING message to the specified UDP server.
    1784             :  *
    1785             :  * This function sends a PING message (4 bytes) to the specified
    1786             :  * UDP server. This is used after you saved data in the Cassandra
    1787             :  * cluster to wake up a background process which can then "slowly"
    1788             :  * process the data further.
    1789             :  *
    1790             :  * Remember that UDP is not reliable so we do not in any way
    1791             :  * guarantee that this goes anywhere. The function returns no
    1792             :  * feedback at all. We do not wait for a reply since at the time
    1793             :  * we send the message the listening server may be busy. The
    1794             :  * idea of this ping is just to make sure that if the server is
    1795             :  * sleeping at that time, it wakes up sooner rather than later
    1796             :  * so it can immediately start processing the data we just added
    1797             :  * to Cassandra.
    1798             :  *
    1799             :  * The \p message is expected to be a NUL terminated string. The
    1800             :  * NUL is not sent across. At this point most of our servers
    1801             :  * accept a PING message to wake up and start working on new
    1802             :  * data.
    1803             :  *
    1804             :  * The \p upd_addr_port parameter is an IP address (IPv4 or IPv6)
    1805             :  * which must be followed by a colon and a port number.
    1806             :  *
    1807             :  * \warning
    1808             :  * The URI is expected to NOT include any port, path, query string
    1809             :  * options, anchor information. Only the protocol and full domain
    1810             :  * name ended by a slash.
    1811             :  *
    1812             :  * \param[in] service  The name of the service to ping.
    1813             :  * \param[in] uri  The website generating the ping.
    1814             :  */
    1815           0 : void server::udp_ping_server( QString const & service, QString const & uri )
    1816             : {
    1817           0 :     snap::snap_communicator_message ping;
    1818           0 :     ping.set_command("PING");
    1819           0 :     ping.set_service(service);
    1820           0 :     ping.add_parameter("uri", uri);
    1821             : 
    1822             :     // TBD: we may want to cache that information in case we call
    1823             :     //      this function more than once
    1824             :     //
    1825           0 :     QString addr("127.0.0.1");
    1826           0 :     int port(4041);
    1827           0 :     QString const communicator_addr_port( f_parameters(QString("snapcommunicator"), "signal") );
    1828           0 :     tcp_client_server::get_addr_port(communicator_addr_port, addr, port, "udp");
    1829             : 
    1830           0 :     snap_communicator::snap_udp_server_message_connection::send_message(
    1831           0 :                   addr.toUtf8().data()
    1832             :                 , port
    1833             :                 , ping
    1834           0 :                 , f_parameters(QString("snapcommunicator"), "signal_secret").toUtf8().data());
    1835           0 : }
    1836             : 
    1837             : 
    1838             : /** \brief Send message to snapcomminucator about usage statistics.
    1839             :  *
    1840             :  * When a process ends, you may call this function in order to send
    1841             :  * its own statistics to the snapcommunicator. Any service can
    1842             :  * listen for the message to react to it in various ways.
    1843             :  *
    1844             :  * \param[in] process_name  The name of the process dying.
    1845             :  */
    1846           0 : void server::udp_rusage(QString const & process_name)
    1847             : {
    1848             :     // retrieve the current usage information
    1849             :     //
    1850             :     struct rusage usage;
    1851           0 :     getrusage(RUSAGE_SELF, &usage);
    1852             : 
    1853             :     // log some basic information
    1854             :     //
    1855           0 :     SNAP_LOG_DEBUG("snap_child: used ")
    1856           0 :                   (usage.ru_maxrss)
    1857           0 :                   (" pages, ")
    1858           0 :                   (usage.ru_utime.tv_sec) // TODO: add ".xxx"
    1859           0 :                   (" seconds (user), and ")
    1860           0 :                   (usage.ru_stime.tv_sec) // TODO: add ".xxx"
    1861           0 :                   (" seconds (system).");
    1862             : 
    1863             :     // prepare a message to send to the snapwatchdog (via the snapcommunicator)
    1864             :     //
    1865             :     // TODO: make sure we get actual values, it looks like linux may not be
    1866             :     //       defining much in the rusage structure... see:
    1867             :     //       http://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-run-time-in-c
    1868             :     //
    1869           0 :     snap::snap_communicator_message rusage_message;
    1870           0 :     rusage_message.set_command("RUSAGE");
    1871           0 :     rusage_message.set_server(get_server_name().c_str());
    1872           0 :     rusage_message.set_service("snapwatchdog");
    1873           0 :     rusage_message.add_parameter("cache", "ttl=10");  // cache for at most 10 seconds
    1874           0 :     rusage_message.add_parameter("process_name", process_name);
    1875           0 :     rusage_message.add_parameter("pid", getpid());
    1876           0 :     rusage_message.add_parameter("user_time", QString("%1.%2").arg(usage.ru_utime.tv_sec).arg(usage.ru_utime.tv_usec, 6, 10, QChar('0')));
    1877           0 :     rusage_message.add_parameter("system_time", QString("%1.%2").arg(usage.ru_stime.tv_sec).arg(usage.ru_stime.tv_usec, 6, 10, QChar('0')));
    1878           0 :     rusage_message.add_parameter("maxrss", QString("%1").arg(usage.ru_maxrss));
    1879           0 :     rusage_message.add_parameter("minor_page_fault", QString("%1").arg(usage.ru_minflt));
    1880           0 :     rusage_message.add_parameter("major_page_fault", QString("%1").arg(usage.ru_majflt));
    1881           0 :     rusage_message.add_parameter("in_block", QString("%1").arg(usage.ru_inblock));
    1882           0 :     rusage_message.add_parameter("out_block", QString("%1").arg(usage.ru_oublock));
    1883           0 :     rusage_message.add_parameter("volontary_context_switches", QString("%1").arg(usage.ru_nvcsw));
    1884           0 :     rusage_message.add_parameter("involontary_context_switches", QString("%1").arg(usage.ru_nivcsw));
    1885             : 
    1886             :     // TBD: we may want to cache that information in case we call
    1887             :     //      this function more than once
    1888             :     //
    1889           0 :     QString addr("127.0.0.1");
    1890           0 :     int port(4041);
    1891           0 :     QString const communicator_addr_port( f_parameters(QString("snapcommunicator"), "signal") );
    1892           0 :     tcp_client_server::get_addr_port(communicator_addr_port, addr, port, "udp");
    1893             : 
    1894           0 :     snap_communicator::snap_udp_server_message_connection::send_message(
    1895           0 :                       addr.toUtf8().data()
    1896             :                     , port
    1897             :                     , rusage_message
    1898           0 :                     , f_parameters(QString("snapcommunicator"), "signal_secret").toUtf8().data());
    1899           0 : }
    1900             : 
    1901             : 
    1902             : /** \brief Block an IP address at the firewall level.
    1903             :  *
    1904             :  * This function sends a BLOCK message to the snapfirewall service in
    1905             :  * order to have the IP from the specified \p uri blocked for the
    1906             :  * specified \p period.
    1907             :  *
    1908             :  * The \p uri can include a scheme which represents the name of a protocol
    1909             :  * that needs to be blocked. At this time, we accept "http" and "smtp".
    1910             :  * Please use "http" for "https" since both ports will get blocked anyway.
    1911             :  *
    1912             :  * This function does not verify the name of the scheme. However, the
    1913             :  * snapfirewall will do so before using it.
    1914             :  *
    1915             :  * If the scheme is not defined, then the default, which is "http",
    1916             :  * is used.
    1917             :  *
    1918             :  * Supported schemes are defined under /etc/iplock/schemes and
    1919             :  * /etc/iplock/schemes/schemes.d for user defined schemes and
    1920             :  * modifications of system defined schemes.
    1921             :  *
    1922             :  * The \p period parameter is not required. If not specified, the default
    1923             :  * will apply. At this time, the snapfirewall tool uses "day" as its default.
    1924             :  * The supported periods are:
    1925             :  *
    1926             :  * \li "5min" -- this is mainly for test purposes, blocks the IP for 5 minutes.
    1927             :  * \li "hour" -- block the IP address for one hour.
    1928             :  * \li "day" -- block the IP address for 24h. (default)
    1929             :  * \li "week" -- block the IP address for 7 days.
    1930             :  * \li "month" -- block the IP address for 31 days.
    1931             :  * \li "year" -- block the IP address for 366 days.
    1932             :  * \li "forever" -- block the IP address for 5 years.
    1933             :  *
    1934             :  * \param[in] uri  The IP address of to ban.
    1935             :  * \param[in] period  The duration for which the ban applies.
    1936             :  * \param[in] reason  A description for why the block is being requested.
    1937             :  */
    1938           0 : void server::block_ip( QString const & uri, QString const & period, QString const & reason )
    1939             : {
    1940             :     // create a server object (we are a static function!)
    1941             :     //
    1942           0 :     snap::server::pointer_t s( snap::server::instance() );
    1943             : 
    1944             :     // retrieve the IP and port to the snapcommunicator
    1945             :     //
    1946           0 :     QString addr("127.0.0.1");
    1947           0 :     int port(4041);
    1948           0 :     snap_config config("snapcommunicator");
    1949           0 :     tcp_client_server::get_addr_port(config["signal"], addr, port, "udp");
    1950             : 
    1951             :     // create a BLOCK message
    1952             :     //
    1953           0 :     snap::snap_communicator_message message;
    1954           0 :     message.set_command("BLOCK");
    1955           0 :     message.set_service("*");           // broadcast to all snapfirewall anywhere in our mesh
    1956             : 
    1957           0 :     message.add_parameter("uri", uri);
    1958             : 
    1959           0 :     if(!period.isEmpty())
    1960             :     {
    1961           0 :         message.add_parameter("period", period);
    1962             :     }
    1963             :     //else -- snapfirewall will use "day" by default
    1964             : 
    1965           0 :     if(!reason.isEmpty())
    1966             :     {
    1967           0 :         message.add_parameter("reason", reason);
    1968             :     }
    1969             : 
    1970             :     // send the message using a UDP signal
    1971             :     //
    1972           0 :     snap::snap_communicator::snap_udp_server_message_connection::send_message(
    1973           0 :                       addr.toUtf8().data()
    1974             :                     , port
    1975             :                     , message
    1976             :                     , config["signal_secret"]);
    1977           0 : }
    1978             : 
    1979             : 
    1980           0 : const snap_config&  server::get_parameters() const
    1981             : {
    1982           0 :     return f_parameters;
    1983             : }
    1984             : 
    1985             : 
    1986             : #ifdef SNAP_NO_FORK
    1987             : /** \brief Don't fork the snap child if true.
    1988             :  *
    1989             :  * This is set via the command line. If set, the snap_child object will not fork.
    1990             :  *
    1991             :  * \note This is debug-only code, which should never be in production.
    1992             :  */
    1993             : bool server::nofork() const
    1994             : {
    1995             :     return f_nofork;
    1996             : }
    1997             : #endif
    1998             : 
    1999             : 
    2000             : 
    2001             : /** \brief Check which child died.
    2002             :  *
    2003             :  * This function is used to find children that died and remove them
    2004             :  * from the list of zombies.
    2005             :  *
    2006             :  * \warning
    2007             :  * Although the signalfd() function returns a child PID, when you run
    2008             :  * parallel child processes and may get multiple SIGCHLD very quickly,
    2009             :  * you may miss a few with time. This means you could get zombies if
    2010             :  * you do not check all the children...
    2011             :  *
    2012             :  * \param[in] child_pid  The process identification of the child that died.
    2013             :  */
    2014           0 : void server::capture_zombies(pid_t child_pid)
    2015             : {
    2016             :     // unfortunately, we cannot just do a waidpid() on child_pid specifically...
    2017             :     //
    2018             :     // TODO:
    2019             :     // we probably want to change the algorithm to be able to
    2020             :     // use waitpid(-1, ...) instead of looping through the list of
    2021             :     // all the running children each time (it is probably more effective
    2022             :     // than calling waitpid(child_pid, ...) for each existing child),
    2023             :     // however, at this point the check_status() function makes that
    2024             :     // call so we cannot have it here too...
    2025             :     //
    2026           0 :     NOTUSED(child_pid);
    2027             : 
    2028             :     // capture zombies first
    2029           0 :     snap_child_vector_t::size_type max_children(f_children_running.size());
    2030           0 :     for(snap_child_vector_t::size_type idx(0); idx < max_children; ++idx)
    2031             :     {
    2032             :         // note that some children could become ready "at the same time"
    2033             :         // (i.e. some SIGCHLD can be lost because a process is not expected
    2034             :         // to stack more than one signal number at a time...)
    2035             :         //
    2036           0 :         if(f_children_running[idx]->check_status() == snap_child::status_t::SNAP_CHILD_STATUS_READY)
    2037             :         {
    2038             :             // it is ready, so it can be reused now
    2039           0 :             f_children_waiting.push_back(f_children_running[idx]);
    2040           0 :             f_children_running.erase(f_children_running.begin() + idx);
    2041             : 
    2042             :             // removed one child so decrement index:
    2043           0 :             --idx;
    2044           0 :             --max_children;
    2045             :         }
    2046             :     }
    2047           0 : }
    2048             : 
    2049             : 
    2050             : /** \brief Capture children death.
    2051             :  *
    2052             :  * This class used used to create a connection on startup that allows
    2053             :  * us to know when a child dies. Whenever that happens, we get a call
    2054             :  * to the process_signal() callback.
    2055             :  */
    2056             : class signal_child_death
    2057             :     : public snap_communicator::snap_signal
    2058             : {
    2059             : public:
    2060             :     typedef std::shared_ptr<signal_child_death>     pointer_t;
    2061             : 
    2062             :                             signal_child_death(server * s);
    2063             :                             signal_child_death(signal_child_death const & rhs) = delete;
    2064           0 :     virtual                 ~signal_child_death() override {}
    2065             : 
    2066             :     signal_child_death &    operator = (signal_child_death const & rhs) = delete;
    2067             : 
    2068             :     // snap_communicator::snap_signal implementation
    2069             :     virtual void            process_signal() override;
    2070             : 
    2071             : private:
    2072             :     // TBD: should this be a weak pointer?
    2073             :     server *                f_server = nullptr;
    2074             : };
    2075             : 
    2076             : 
    2077             : /** \brief Initialize the child death signal.
    2078             :  *
    2079             :  * The function initializes the snap_signal to listen on the SIGCHLD
    2080             :  * Unix signal. It also saves the pointer \p s to the server so
    2081             :  * it can be used to call various functions in the server whenever
    2082             :  * the signal occurs.
    2083             :  *
    2084             :  * \param[in] s  The server pointer.
    2085             :  */
    2086           0 : signal_child_death::signal_child_death(server * s)
    2087             :     : snap_signal(SIGCHLD)
    2088           0 :     , f_server(s)
    2089             : {
    2090           0 : }
    2091             : 
    2092             : 
    2093             : /** \brief Callback called each time the SIGCHLD signal occurs.
    2094             :  *
    2095             :  * This function gets called each time a child dies.
    2096             :  *
    2097             :  * The function checks all the children and removes zombies.
    2098             :  */
    2099           0 : void signal_child_death::process_signal()
    2100             : {
    2101             :     // check all our children and remove zombies
    2102             :     //
    2103           0 :     f_server->capture_zombies(get_child_pid());
    2104           0 : }
    2105             : 
    2106             : 
    2107             : 
    2108             : 
    2109             : /** \brief Timer to poll Cassandra's availability.
    2110             :  *
    2111             :  * This class is specifically used to pretend that we received a
    2112             :  * CASSANDRAREADY even when not sent to us. This is because when
    2113             :  * we check for the availability of Cassandra, it may not have the
    2114             :  * context and tables available yet. In that case, we would just
    2115             :  * fall asleep and do nothing more.
    2116             :  *
    2117             :  * This timer allows us to re-check for the Cassandra context and
    2118             :  * mandatory table as expected on a CASSANDRAREADY message.
    2119             :  */
    2120             : class cassandra_check_timer
    2121             :         : public snap_communicator::snap_timer
    2122             : {
    2123             : public:
    2124             :     typedef std::shared_ptr<cassandra_check_timer>  pointer_t;
    2125             : 
    2126             :                             cassandra_check_timer(server * s);
    2127             :                             cassandra_check_timer(cassandra_check_timer const & rhs) = delete;
    2128           0 :     virtual                 ~cassandra_check_timer() override {}
    2129             : 
    2130             :     cassandra_check_timer   operator = (cassandra_check_timer const & rhs) = delete;
    2131             : 
    2132             :     // snap_communicator::snap_connection implementation
    2133             :     virtual void            process_timeout() override;
    2134             : 
    2135             : private:
    2136             :     // TBD: should this be a weak pointer?
    2137             :     server *                f_server = nullptr;
    2138             : };
    2139             : 
    2140             : 
    2141             : /** \brief Initialize the timer as required.
    2142             :  *
    2143             :  * This disables the timer and sets up its ticks to send us a timeout
    2144             :  * event once per minute.
    2145             :  *
    2146             :  * So by default this timer does nothing.
    2147             :  *
    2148             :  * If the check_cassandra() function somehow fails in a way that means
    2149             :  * we would never get awaken again, then this timer gets turned on.
    2150             :  * It will be awaken be a timeout and send us a CASSANDRAREADY to
    2151             :  * simulate that something happened and we better recheck whether
    2152             :  * the Cassandra connection is now truly available.
    2153             :  *
    2154             :  * \param[in] s  The server pointer.
    2155             :  */
    2156           0 : cassandra_check_timer::cassandra_check_timer(server * s)
    2157             :     : snap_timer(60LL * 1000000LL)
    2158           0 :     , f_server(s)
    2159             : {
    2160           0 :     set_name("cassandra check timer");
    2161           0 :     set_priority(1);
    2162           0 :     set_enable(false);
    2163           0 : }
    2164             : 
    2165             : 
    2166             : /** \brief The timer ticked.
    2167             :  *
    2168             :  * This function gets called each time the timer ticks. This is once
    2169             :  * per minute for this timer (see constructor).
    2170             :  *
    2171             :  * The timer is turned off (disabled) by default. It is used only if
    2172             :  * there is an error while trying to get the snap_websites context or a
    2173             :  * mandatory table.
    2174             :  *
    2175             :  * The function simulate a CASSANDRAREADY message as if the snapdbproxy
    2176             :  * service had sent it to us.
    2177             :  */
    2178           0 : void cassandra_check_timer::process_timeout()
    2179             : {
    2180             :     // disable ourselves, if the Cassandra cluster is still not ready,
    2181             :     // then we will automatically be re-enabled
    2182             :     //
    2183           0 :     set_enable(false);
    2184             : 
    2185             :     // simulate a CASSANDRAREADY message
    2186             :     //
    2187           0 :     snap_communicator_message cassandra_ready;
    2188           0 :     cassandra_ready.set_command("CASSANDRAREADY");
    2189           0 :     f_server->process_message(cassandra_ready);
    2190           0 : }
    2191             : 
    2192             : 
    2193             : 
    2194             : 
    2195             : /** \brief Listen and send messages with other services.
    2196             :  *
    2197             :  * This class is used to listen for incoming messages from
    2198             :  * snapcommunicator and also to send messages
    2199             :  *
    2200             :  * \note
    2201             :  * At this time we only send to snapwatchdog statistics at the time we die...
    2202             :  * but we may want to send more statistics about the children such as the
    2203             :  * count and other similar statistics. (i.e. we have to think about the time
    2204             :  * when we create listening children and in that case we do not want to
    2205             :  * count those children until they get a new connection; before that they
    2206             :  * do not count.)
    2207             :  *
    2208             :  * Also, we default to *not* using a thread to connect, because we are defaulting
    2209             :  * to the server. When used in a snap_child instance, you must override the default
    2210             :  * and set the flag to *true*. Otherwise bad things will happen.
    2211             :  */
    2212             : class messenger
    2213             :         : public snap_communicator::snap_tcp_client_permanent_message_connection
    2214             : {
    2215             : public:
    2216             :     typedef std::shared_ptr<messenger>    pointer_t;
    2217             : 
    2218             :                         messenger(server * s, std::string const & addr, int port, bool const use_thread = false );
    2219             :                         messenger(messenger const & rhs) = delete;
    2220           0 :     virtual             ~messenger() override {}
    2221             : 
    2222             :     messenger &         operator = (messenger const & rhs) = delete;
    2223             : 
    2224             :     // snap_communicator::snap_tcp_client_permanent_message_connection implementation
    2225             :     virtual void        process_message(snap_communicator_message const & message) override;
    2226             :     virtual void        process_connected() override;
    2227             : 
    2228             : private:
    2229             :     server *            f_server = nullptr;
    2230             : };
    2231             : 
    2232             : 
    2233             : /** \brief Initialize the messenger connection.
    2234             :  *
    2235             :  * This function initializes the messenger connection. It saves
    2236             :  * a pointer to the main Snap! server so it can react appropriately
    2237             :  * whenever a message is received.
    2238             :  *
    2239             :  * \param[in] s           A pointer to the server so we can send messages there.
    2240             :  * \param[in] addr        The address of the snapcommunicator server.
    2241             :  * \param[in] port        The port of the snapcommunicator server.
    2242             :  * \param[in] use_thread  If set to true, a thread is being used to connect to the server.
    2243             :  */
    2244           0 : messenger::messenger(server * s, std::string const & addr, int port, bool const use_thread )
    2245             :     : snap_tcp_client_permanent_message_connection
    2246             :       (   addr
    2247             :         , port
    2248             :         , tcp_client_server::bio_client::mode_t::MODE_PLAIN
    2249             :         , snap_communicator::snap_tcp_client_permanent_message_connection::DEFAULT_PAUSE_BEFORE_RECONNECTING
    2250             :         , use_thread
    2251             :       )
    2252           0 :     , f_server(s)
    2253             : {
    2254           0 : }
    2255             : 
    2256             : 
    2257             : /** \brief Process a message we just received.
    2258             :  *
    2259             :  * This function is called whenever the snapcommunicator received and
    2260             :  * decided to forward a message to us.
    2261             :  *
    2262             :  * \param[in] message  The message we just received.
    2263             :  */
    2264           0 : void messenger::process_message(snap_communicator_message const & message)
    2265             : {
    2266           0 :     f_server->process_message(message);
    2267           0 : }
    2268             : 
    2269             : 
    2270             : /** \brief Process was just connected.
    2271             :  *
    2272             :  * This callback happens whenever a new connection is established.
    2273             :  * It sends a REGISTER command to the snapcommunicator. The READY
    2274             :  * reply will be received when process_message() gets called. At
    2275             :  * that point we are fully registered.
    2276             :  *
    2277             :  * This callback happens first so if we lose our connection to
    2278             :  * the snapcommunicator server, it will re-register the snapserver
    2279             :  * again as expected.
    2280             :  */
    2281           0 : void messenger::process_connected()
    2282             : {
    2283           0 :     snap_tcp_client_permanent_message_connection::process_connected();
    2284             : 
    2285           0 :     snap::snap_communicator_message register_snapserver;
    2286           0 :     register_snapserver.set_command("REGISTER");
    2287           0 :     register_snapserver.add_parameter("service", "snapserver");
    2288           0 :     register_snapserver.add_parameter("version", snap::snap_communicator::VERSION);
    2289           0 :     send_message(register_snapserver);
    2290           0 : }
    2291             : 
    2292             : 
    2293             : /** \brief Process a message received from Snap! Communicator.
    2294             :  *
    2295             :  * This function gets called whenever a message from snapcommunicator
    2296             :  * is received.
    2297             :  *
    2298             :  * The function reacts according to the message command:
    2299             :  *
    2300             :  * \li HELP -- reply with the COMMANDS message and the few commands we
    2301             :  *             understand
    2302             :  * \li LOG -- reset the log
    2303             :  * \li READY -- ignored, this means Snap Communicator acknowledge that we
    2304             :  *              registered with it
    2305             :  * \li STOP or QUITTING -- stop the server
    2306             :  * \li UNKNOWN -- ignored command, we log the fact that we sent an unknown
    2307             :  *                message to someone
    2308             :  *
    2309             :  * If another command is received, the function replies with the UNKNOWN
    2310             :  * command to make sure the sender is aware that the command was ignored.
    2311             :  *
    2312             :  * \todo
    2313             :  * Convert to using a dispatcher.
    2314             :  *
    2315             :  * \param[in] message  The message to process.
    2316             :  */
    2317           0 : void server::process_message(snap_communicator_message const & message)
    2318             : {
    2319           0 :     if(g_connection == nullptr
    2320           0 :     || g_connection->f_communicator == nullptr)
    2321             :     {
    2322           0 :         SNAP_LOG_WARNING("received message after the g_connection or g_connection->f_communicator variables were cleared.");
    2323           0 :         return;
    2324             :     }
    2325             : 
    2326           0 :     QString const command(message.get_command());
    2327             : 
    2328             :     // STATUS is sent too many times, so do not trace them all...
    2329           0 :     if(command != "STATUS")
    2330             :     {
    2331           0 :         SNAP_LOG_TRACE("received message [")(message.to_message())("] for server");
    2332             :     }
    2333             : 
    2334           0 :     if(command == "STOP")
    2335             :     {
    2336           0 :         stop(false);
    2337           0 :         return;
    2338             :     }
    2339           0 :     if(command == "QUITTING")  // QUITTING happens when we send a message to snapcommunicator after it received a STOP
    2340             :     {
    2341           0 :         stop(true);
    2342           0 :         return;
    2343             :     }
    2344             : 
    2345           0 :     if(command == "LOG")
    2346             :     {
    2347           0 :         SNAP_LOG_INFO("Logging reconfiguration.");
    2348           0 :         logging::reconfigure();
    2349           0 :         return;
    2350             :     }
    2351             : 
    2352           0 :     if(command == "READY")
    2353             :     {
    2354             :         // TBD: should we start the listener here instead?
    2355             :         //
    2356             :         //      the fact is... if we lose the connection to
    2357             :         //      snapcommunicator we would start the listener
    2358             :         //      at another time anyway
    2359             :         //
    2360             : 
    2361             :         // request snapdbproxy to send us a status signal about
    2362             :         // Cassandra, after that one call, we will receive the
    2363             :         // statuses just because we understand them.
    2364             :         //
    2365             :         {
    2366           0 :             snap::snap_communicator_message isdbready_message;
    2367           0 :             isdbready_message.set_command("CASSANDRASTATUS");
    2368           0 :             isdbready_message.set_service("snapdbproxy");
    2369           0 :             std::dynamic_pointer_cast<messenger>(g_connection->f_messenger)->send_message(isdbready_message);
    2370             :         }
    2371             : 
    2372             :         // request snapcommunicator to send us a STATUS message
    2373             :         // about the current status of the snaplock service
    2374             :         //
    2375             :         {
    2376             :             // TODO: we need to switch that to receiving the LOCKREADY
    2377             :             //       and NOLOCK messages instead (i.e. see LOCKSTATUS)
    2378             :             //
    2379           0 :             snap::snap_communicator_message islockready_message;
    2380           0 :             islockready_message.set_command("SERVICESTATUS");
    2381           0 :             islockready_message.add_parameter("service", "snaplock");
    2382           0 :             std::dynamic_pointer_cast<messenger>(g_connection->f_messenger)->send_message(islockready_message);
    2383             :         }
    2384             : 
    2385             :         // request snapfirewall to send us a FIREWALLUP
    2386             :         // or a FIREWALLDOWN message
    2387             :         //
    2388           0 :         if(f_firewall_is_active)
    2389             :         {
    2390           0 :             snap::snap_communicator_message isfirewallready_message;
    2391           0 :             isfirewallready_message.set_command("FIREWALLSTATUS");
    2392           0 :             isfirewallready_message.set_service("snapfirewall");
    2393           0 :             std::dynamic_pointer_cast<messenger>(g_connection->f_messenger)->send_message(isfirewallready_message);
    2394             :         }
    2395             :         else
    2396             :         {
    2397             :             // this is not automatically true, but we will not have a
    2398             :             // way to know any better
    2399             :             //
    2400           0 :             f_firewall_up = true;
    2401             :         }
    2402             : 
    2403           0 :         return;
    2404             :     }
    2405             : 
    2406           0 :     if(command == "NOCASSANDRA")
    2407             :     {
    2408             :         // we lost Cassandra, disconnect from snapdbproxy until we
    2409             :         // get CASSANDRAREADY again
    2410             :         //
    2411           0 :         f_snapdbproxy_addr.clear();
    2412           0 :         f_snapdbproxy_port = 0;
    2413             : 
    2414           0 :         return;
    2415             :     }
    2416             : 
    2417           0 :     if(command == "CASSANDRAREADY")
    2418             :     {
    2419             :         // connect to Cassandra and verify that a "domains" table
    2420             :         // exists; the function returns false if not
    2421             :         //
    2422           0 :         bool timer_required(false);
    2423           0 :         if(!check_cassandra(get_name(name_t::SNAP_NAME_DOMAINS), timer_required))
    2424             :         {
    2425           0 :             if(timer_required && g_connection->f_cassandra_check_timer != nullptr)
    2426             :             {
    2427           0 :                 g_connection->f_cassandra_check_timer->set_enable(true);
    2428             :             }
    2429             :         }
    2430           0 :         return;
    2431             :     }
    2432             : 
    2433           0 :     if(command == "FIREWALLUP")
    2434             :     {
    2435           0 :         f_firewall_up = true;
    2436           0 :         return;
    2437             :     }
    2438             : 
    2439           0 :     if(command == "FIREWALLDOWN")
    2440             :     {
    2441           0 :         f_firewall_up = false;
    2442           0 :         return;
    2443             :     }
    2444             : 
    2445           0 :     if(command == "STATUS")
    2446             :     {
    2447           0 :         if(message.get_parameter("service") == "snaplock")
    2448             :         {
    2449             :             // show the one STATUS that we manage here
    2450             :             //
    2451           0 :             SNAP_LOG_TRACE("received message [")(message.to_message())("]");
    2452             : 
    2453           0 :             f_snaplock = message.has_parameter("status")
    2454           0 :                       && message.get_parameter("status") == "up";
    2455             :         }
    2456             :         // else -- ignore all others
    2457             : 
    2458           0 :         return;
    2459             :     }
    2460             : 
    2461           0 :     if(command == "HELP")
    2462             :     {
    2463           0 :         snap::snap_communicator_message reply;
    2464           0 :         reply.set_command("COMMANDS");
    2465             : 
    2466             :         // list of commands understood by server
    2467           0 :         reply.add_parameter("list", "CASSANDRAREADY,FIREWALLUP,HELP,LOG,NOCASSANDRA,QUITTING,READY,RELOADCONFIG,STATUS,STOP,UNKNOWN");
    2468             : 
    2469           0 :         std::dynamic_pointer_cast<messenger>(g_connection->f_messenger)->send_message(reply);
    2470           0 :         return;
    2471             :     }
    2472             : 
    2473           0 :     if(command == "RELOADCONFIG")
    2474             :     {
    2475           0 :         f_force_restart = true;
    2476           0 :         stop(false);
    2477           0 :         return;
    2478             :     }
    2479             : 
    2480           0 :     if(command == "UNKNOWN")
    2481             :     {
    2482           0 :         SNAP_LOG_ERROR("we sent unknown command \"")(message.get_parameter("command"))("\" and probably did not get the expected result.");
    2483           0 :         return;
    2484             :     }
    2485             : 
    2486             :     // unknown command is reported and process goes on
    2487             :     //
    2488           0 :     SNAP_LOG_ERROR("unsupported command \"")(command)("\" was received on the TCP connection.");
    2489             :     {
    2490           0 :         snap::snap_communicator_message reply;
    2491           0 :         reply.set_command("UNKNOWN");
    2492           0 :         reply.add_parameter("command", command);
    2493           0 :         std::dynamic_pointer_cast<messenger>(g_connection->f_messenger)->send_message(reply);
    2494             :     }
    2495           0 :     return;
    2496             : }
    2497             : 
    2498             : 
    2499             : 
    2500             : /** \brief Do the necessary to stop the Snap! server.
    2501             :  *
    2502             :  * This function closes the connections which as a result will stop
    2503             :  * the snapserver daemon.
    2504             :  *
    2505             :  * \param[in] quitting  If true, the process received a QUITTING message.
    2506             :  */
    2507           0 : void server::stop(bool quitting)
    2508             : {
    2509           0 :     SNAP_LOG_INFO("Stopping server.");
    2510             : 
    2511           0 :     if(g_connection != nullptr
    2512           0 :     && g_connection->f_messenger != nullptr)
    2513             :     {
    2514           0 :         messenger::pointer_t msg(std::dynamic_pointer_cast<messenger>(g_connection->f_messenger));
    2515           0 :         if(quitting || (msg && !msg->is_connected()))
    2516             :         {
    2517             :             // turn off that connection now, we cannot UNREGISTER since
    2518             :             // we are not connected to snapcommunicator
    2519             :             //
    2520           0 :             g_connection->f_communicator->remove_connection(g_connection->f_messenger);
    2521           0 :             g_connection->f_messenger.reset();
    2522             :         }
    2523             :         else
    2524             :         {
    2525           0 :             if(msg)
    2526             :             {
    2527           0 :                 msg->mark_done();
    2528             :             }
    2529             : 
    2530             :             // snapcommunicator is not quitting, so we also want to unregister
    2531             :             // to make sure everything works as expected
    2532             :             //
    2533           0 :             snap::snap_communicator_message cmd;
    2534           0 :             cmd.set_command("UNREGISTER");
    2535           0 :             cmd.add_parameter("service", "snapserver");
    2536           0 :             std::static_pointer_cast<messenger>(g_connection->f_messenger)->send_message(cmd);
    2537             : 
    2538             :             // f_messenger is expected to HUP after this
    2539             :         }
    2540             :     }
    2541             : 
    2542             :     {
    2543           0 :         g_connection->f_communicator->remove_connection(g_connection->f_listener);
    2544           0 :         g_connection->f_communicator->remove_connection(g_connection->f_child_death_listener);
    2545           0 :         g_connection->f_communicator->remove_connection(g_connection->f_interrupt);
    2546           0 :         g_connection->f_interrupt.reset();
    2547           0 :         g_connection->f_communicator->remove_connection(g_connection->f_cassandra_check_timer);
    2548           0 :         g_connection->f_cassandra_check_timer.reset();
    2549             :     }
    2550           0 : }
    2551             : 
    2552             : 
    2553             : 
    2554             : 
    2555             : 
    2556             : 
    2557             : /** \brief Handle the SIGINT that is expected to stop the server.
    2558             :  *
    2559             :  * This class is an implementation of the snap_signal that listens
    2560             :  * on the SIGINT.
    2561             :  */
    2562             : class server_interrupt
    2563             :         : public snap::snap_communicator::snap_signal
    2564             : {
    2565             : public:
    2566             :     typedef std::shared_ptr<server_interrupt>     pointer_t;
    2567             : 
    2568             :                         server_interrupt(server * s);
    2569             :                         server_interrupt(server_interrupt const & rhs) = delete;
    2570           0 :     virtual             ~server_interrupt() override {}
    2571             : 
    2572             :     server_interrupt    operator = (server_interrupt const & rhs) = delete;
    2573             : 
    2574             :     // snap::snap_communicator::snap_signal implementation
    2575             :     virtual void        process_signal() override;
    2576             : 
    2577             : private:
    2578             :     server *            f_server = nullptr;
    2579             : };
    2580             : 
    2581             : 
    2582             : /** \brief The interrupt initialization.
    2583             :  *
    2584             :  * The interrupt uses the signalfd() function to obtain a way to listen on
    2585             :  * incoming Unix signals.
    2586             :  *
    2587             :  * Specifically, it listens on the SIGINT signal, which is the equivalent
    2588             :  * to the Ctrl-C.
    2589             :  *
    2590             :  * \param[in] s  The server we are listening for.
    2591             :  */
    2592           0 : server_interrupt::server_interrupt(server * s)
    2593             :     : snap_signal(SIGINT)
    2594           0 :     , f_server(s)
    2595             : {
    2596           0 :     unblock_signal_on_destruction();
    2597           0 :     set_name("server interrupt");
    2598           0 : }
    2599             : 
    2600             : 
    2601             : /** \brief Call the stop function of the snaplock object.
    2602             :  *
    2603             :  * When this function is called, the signal was received and thus we are
    2604             :  * asked to quit as soon as possible.
    2605             :  */
    2606           0 : void server_interrupt::process_signal()
    2607             : {
    2608             :     // we simulate the STOP, so pass 'false' (i.e. not quitting)
    2609             :     //
    2610           0 :     f_server->stop(false);
    2611           0 : }
    2612             : 
    2613             : 
    2614             : 
    2615             : 
    2616             : 
    2617             : /** \brief Handle new connections from clients.
    2618             :  *
    2619             :  * This function is an implementation of the snap server so we can
    2620             :  * handle new connections from various clients.
    2621             :  */
    2622             : class listener_impl
    2623             :         : public snap_communicator::snap_tcp_server_connection
    2624             : {
    2625             : public:
    2626             :                     listener_impl(server * s, std::string const & addr, int port, std::string const & certificate, std::string const & private_key, int max_connections, bool reuse_addr);
    2627             :                     listener_impl(listener_impl const & rhs) = delete;
    2628           0 :     virtual         ~listener_impl() override {}
    2629             : 
    2630             :     listener_impl   operator = (listener_impl const & rhs) = delete;
    2631             : 
    2632             :     // snap_communicator::snap_tcp_server_connection implementation
    2633             :     virtual void    process_accept() override;
    2634             : 
    2635             : private:
    2636             :     // this is owned by a server function so no need for a smart pointer
    2637             :     server *            f_server = nullptr;
    2638             : };
    2639             : 
    2640             : 
    2641             : 
    2642             : /** \brief The listener initialization.
    2643             :  *
    2644             :  * The listener receives a pointer back to the snap::server object and
    2645             :  * information on how to generate the new network connection to listen
    2646             :  * on incoming connections from clients.
    2647             :  *
    2648             :  * The server listens to two types of messages:
    2649             :  *
    2650             :  * \li accept() -- a new connection is accepted from a client
    2651             :  * \li recv() -- a UDP message was received
    2652             :  *
    2653             :  * \param[in] s  The server we are listening for.
    2654             :  * \param[in] addr  The address to listen on. Most often it is 0.0.0.0.
    2655             :  * \param[in] port  The port to listen on.
    2656             :  * \param[in] certificate  The filename to a PEM file with a certificate.
    2657             :  * \param[in] private_key  The filename to a PEM file with the private key.
    2658             :  * \param[in] max_connections  The maximum number of connections to keep
    2659             :  *            waiting; if more arrive, refuse them until we are done with
    2660             :  *            some existing connections.
    2661             :  * \param[in] reuse_addr  Whether to let the OS reuse that socket immediately.
    2662             :  */
    2663           0 : listener_impl::listener_impl(server * s, std::string const & addr, int port, std::string const & certificate, std::string const & private_key, int max_connections, bool reuse_addr)
    2664             :     : snap_tcp_server_connection(
    2665             :                       addr
    2666             :                     , port
    2667             :                     , certificate
    2668             :                     , private_key
    2669           0 :                     , (certificate.empty() && private_key.empty()) || addr == "127.0.0.1"
    2670             :                             ? tcp_client_server::bio_server::mode_t::MODE_PLAIN
    2671             :                             : tcp_client_server::bio_server::mode_t::MODE_SECURE
    2672             :                     , max_connections
    2673             :                     , reuse_addr)
    2674           0 :     , f_server(s)
    2675             : {
    2676           0 :     non_blocking();
    2677           0 : }
    2678             : 
    2679             : 
    2680             : /** \brief This callback is called whenever a client tries to connect.
    2681             :  *
    2682             :  * This callback function is called whenever a new client tries to connect
    2683             :  * to the server.
    2684             :  *
    2685             :  * The function retrieves the new connection socket, makes the socket
    2686             :  * "keep alive" and then calls the process_connection() function of
    2687             :  * the server.
    2688             :  */
    2689           0 : void listener_impl::process_accept()
    2690             : {
    2691             :     // a new client just connected
    2692             :     //
    2693           0 :     tcp_client_server::bio_client::pointer_t const new_client(accept());
    2694           0 :     if(!new_client)
    2695             :     {
    2696             :         // TBD: should we call process_error() instead? problem is this
    2697             :         //      listener would be removed from the list of connections...
    2698             :         //
    2699           0 :         int const e(errno);
    2700           0 :         SNAP_LOG_ERROR("accept() returned an error. (errno: ")(e)(" -- ")(strerror(e))("). No new connection will be created.");
    2701           0 :         return;
    2702             :     }
    2703             : 
    2704             :     // process the new connection, which means create a child process
    2705             :     // and run the necessary code to return an HTML page, a document,
    2706             :     // robots.txt, etc.
    2707             :     //
    2708           0 :     f_server->process_connection(new_client);
    2709             : }
    2710             : 
    2711             : 
    2712             : /** \brief Create the permanent messenger instance.
    2713             :  *
    2714             :  * This creates the messenger object, and hooks up the logger so we can send logs to
    2715             :  * snapcommunicator (and ultimately to snaplog).
    2716             :  *
    2717             :  * \param[in] use_thread    If set to true, this will create a thread. Set to false if you are going to fork()
    2718             :  */
    2719           0 : void server::create_messenger_instance( bool const use_thread )
    2720             : {
    2721           0 :     if(g_connection == nullptr
    2722           0 :     || g_connection->f_communicator == nullptr)
    2723             :     {
    2724           0 :         SNAP_LOG_WARNING("attempt to create messenger after the g_connection or g_connection->f_communicator variables were cleared.");
    2725           0 :         return;
    2726             :     }
    2727             : 
    2728             :     // Remove the old connection (ignored if not connected)
    2729             :     //
    2730           0 :     g_connection->f_communicator->remove_connection( g_connection->f_messenger );
    2731             : 
    2732             :     // Get the communicator address/port
    2733             :     //
    2734           0 :     QString communicator_addr("127.0.0.1");
    2735           0 :     int communicator_port(4040);
    2736             :     tcp_client_server::get_addr_port
    2737           0 :             ( QString::fromUtf8(f_parameters("snapcommunicator", "local_listen").c_str())
    2738             :             , communicator_addr
    2739             :             , communicator_port
    2740             :             , "tcp"
    2741             :             );
    2742             : 
    2743             :     // Create a new messenger object
    2744             :     //
    2745           0 :     g_connection->f_messenger.reset(new messenger(this, communicator_addr.toUtf8().data(), communicator_port, use_thread));
    2746           0 :     g_connection->f_messenger->set_name("messenger");
    2747           0 :     g_connection->f_messenger->set_priority(50);
    2748             : 
    2749             : 
    2750             :     // Add it into the instance list.
    2751             :     //
    2752           0 :     g_connection->f_communicator->add_connection( g_connection->f_messenger );
    2753             : 
    2754             :     // Add this to the logging facility so we can broadcast logs to snaplog via snapcommunicator.
    2755             :     //
    2756           0 :     configure_messenger_logging(
    2757           0 :         std::static_pointer_cast<snap_communicator::snap_tcp_client_permanent_message_connection>( g_connection->f_messenger )
    2758             :     );
    2759             : }
    2760             : 
    2761             : 
    2762             : /** \brief Listen to incoming connections.
    2763             :  *
    2764             :  * This function initializes various connections which get added to
    2765             :  * the snap_communicator object. These connections are:
    2766             :  *
    2767             :  * \li A listener, which opens a port to listen to new incoming connections.
    2768             :  * \li A signal handler, also via a connection, which listens to the SIGCHLD
    2769             :  *     Unix signal. This allows us to immediately manage zombie processes.
    2770             :  * \li A messenger, which is a permanent connection to the Snap Communicator
    2771             :  *     server. Permanent because if the connection is lost, it will be
    2772             :  *     reinstantiated as soon as possible.
    2773             :  *
    2774             :  * Our snap.cgi process is the one that connects to our listener, since at
    2775             :  * this time we do not directly listen to port 80 or 443.
    2776             :  *
    2777             :  * The messenger receives messages such as the STOP and LOG messages. The
    2778             :  * STOP message actually requests that this very function returns as soon
    2779             :  * as the server is done with anything it is currently doing.
    2780             :  *
    2781             :  * If the function finds an error in one of the parameters used from the
    2782             :  * configuration file, then it logs an error and calls exit(1).
    2783             :  *
    2784             :  * Other errors may occur in which case it is likely that the process
    2785             :  * will throw an error.
    2786             :  */
    2787           0 : void server::listen()
    2788             : {
    2789           0 :     SNAP_LOG_INFO("--------------------------------- snapserver started on ")(get_server_name());
    2790             : 
    2791             :     // offer the user to setup the maximum number of pending connections
    2792           0 :     long max_pending_connections(-1);
    2793             :     bool ok;
    2794           0 :     QString max_connections(f_parameters["max_pending_connections"]);
    2795           0 :     if(!max_connections.isEmpty())
    2796             :     {
    2797           0 :         max_pending_connections = max_connections.toLong(&ok);
    2798           0 :         if(!ok)
    2799             :         {
    2800           0 :             SNAP_LOG_FATAL("invalid max_pending_connections, a valid number was expected instead of \"")(max_connections)("\".");
    2801           0 :             exit(1);
    2802             :         }
    2803           0 :         if(max_pending_connections < 1)
    2804             :         {
    2805           0 :             SNAP_LOG_FATAL("max_pending_connections must be positive, \"")(max_connections)("\" is not valid.");
    2806           0 :             exit(1);
    2807             :         }
    2808             :     }
    2809             : 
    2810             :     // get the address/port info
    2811           0 :     QString addr("127.0.0.1");
    2812           0 :     int port(4004);
    2813           0 :     tcp_client_server::get_addr_port(f_parameters["listen"], addr, port, "tcp");
    2814             : 
    2815             :     // convert the address information
    2816           0 :     QHostAddress const a(addr);
    2817           0 :     if(a.isNull())
    2818             :     {
    2819           0 :         SNAP_LOG_FATAL("invalid address specification in \"")(addr)(":")(port)("\".");
    2820           0 :         exit(1);
    2821             :     }
    2822             : 
    2823             :     // get timeout time for wait when children exist
    2824           0 :     long timeout_wait_children(5000);
    2825           0 :     QString timeout_wait_children_param(f_parameters["timeout_wait_children"]);
    2826           0 :     if(!timeout_wait_children_param.isEmpty())
    2827             :     {
    2828           0 :         timeout_wait_children = timeout_wait_children_param.toLong(&ok);
    2829           0 :         if(!ok)
    2830             :         {
    2831           0 :             SNAP_LOG_FATAL("invalid timeout_wait_children, a valid number was expected instead of \"")(timeout_wait_children_param)("\".");
    2832           0 :             exit(1);
    2833             :         }
    2834           0 :         if(timeout_wait_children < 100)
    2835             :         {
    2836           0 :             SNAP_LOG_FATAL("timeout_wait_children must be at least 100, \"")(timeout_wait_children_param)("\" is not acceptable.");
    2837           0 :             exit(1);
    2838             :         }
    2839             :     }
    2840             : 
    2841             :     // get the SSL certificate and private key paths
    2842             :     //
    2843           0 :     std::string const certificate(f_parameters["ssl_certificate"]);
    2844           0 :     std::string const private_key(f_parameters["ssl_private_key"]);
    2845             : 
    2846             :     // get the snapcommunicator IP and port
    2847           0 :     QString communicator_addr("127.0.0.1");
    2848           0 :     int communicator_port(4040);
    2849           0 :     tcp_client_server::get_addr_port(QString::fromUtf8(f_parameters("snapcommunicator", "local_listen").c_str())
    2850             :                                    , communicator_addr
    2851             :                                    , communicator_port
    2852             :                                    , "tcp");
    2853             : 
    2854             :     // TBD: Would we need a lock sooner? if so, we are in trouble...
    2855             :     //      Initialize the snap communicator information in snap_lock
    2856             :     //      so locks work as expected.
    2857             :     //
    2858             :     // We keep the default timeout but various processes may change that to
    2859             :     // a different value as required.
    2860             :     //
    2861           0 :     snap::snap_lock::initialize_snapcommunicator(communicator_addr.toUtf8().data(), communicator_port);
    2862             : 
    2863             :     // create a communicator
    2864             :     //
    2865             :     // only we use a bare pointer because otherwise the child processes
    2866             :     // attempt to destroy these objects and that does not work right
    2867             :     //
    2868           0 :     g_connection = new connection_t;
    2869           0 :     g_connection->f_communicator = snap_communicator::instance();
    2870             : 
    2871             :     // capture Ctrl-C (SIGINT)
    2872             :     //
    2873           0 :     g_connection->f_interrupt.reset(new server_interrupt(this));
    2874           0 :     g_connection->f_communicator->add_connection(g_connection->f_interrupt);
    2875             : 
    2876             :     // create a listener, for new arriving client connections
    2877             :     //
    2878             :     // auto-close is set to false because the accept() is not directly used
    2879             :     // on the tcp_server object
    2880             :     //
    2881           0 :     g_connection->f_listener.reset(new listener_impl(this, addr.toUtf8().data(), port, certificate, private_key, max_pending_connections, true));
    2882           0 :     g_connection->f_listener->set_name("server listener");
    2883           0 :     g_connection->f_listener->set_priority(30);
    2884           0 :     g_connection->f_communicator->add_connection(g_connection->f_listener);
    2885             : 
    2886           0 :     g_connection->f_child_death_listener.reset(new signal_child_death(this));
    2887           0 :     g_connection->f_child_death_listener->set_name("child death listener");
    2888           0 :     g_connection->f_child_death_listener->set_priority(75);
    2889           0 :     g_connection->f_communicator->add_connection(g_connection->f_child_death_listener);
    2890             : 
    2891           0 :     g_connection->f_cassandra_check_timer.reset(new cassandra_check_timer(this));
    2892           0 :     g_connection->f_communicator->add_connection(g_connection->f_cassandra_check_timer);
    2893             : 
    2894           0 :     create_messenger_instance();
    2895             : 
    2896             :     // the server was successfully started
    2897           0 :     SNAP_LOG_INFO("Snap v" SNAPWEBSITES_VERSION_STRING " on \"")(get_server_name())("\" started.");
    2898             : 
    2899           0 :     server_loop_ready();
    2900             : 
    2901             :     // run until we get killed
    2902           0 :     g_connection->f_communicator->run();
    2903             : 
    2904             :     // if we are returning that is because the signals were removed from
    2905             :     // the communicator so we can now destroy the communicator
    2906           0 :     g_connection->f_communicator.reset();
    2907             : 
    2908           0 :     if(f_force_restart)
    2909             :     {
    2910           0 :         exit(1);
    2911             :     }
    2912           0 : }
    2913             : 
    2914             : 
    2915             : /** \brief Process an incoming connection.
    2916             :  *
    2917             :  * This function processes an incoming connection from a client.
    2918             :  * This connection is from the snap.cgi to the snapserver.
    2919             :  *
    2920             :  * \param[in] client  The client which represents the new connection.
    2921             :  */
    2922           0 : void server::process_connection(tcp_client_server::bio_client::pointer_t client)
    2923             : {
    2924             :     // we are handling one more connection, whether it works or
    2925             :     // not we increase our internal counter
    2926           0 :     ++f_connections_count;
    2927             : 
    2928             :     // make sure the database connection is ready, if not, we just
    2929             :     // reply with an instant error
    2930           0 :     if(f_snapdbproxy_addr.isEmpty())
    2931             :     {
    2932           0 :         if(!f_snaplock)
    2933             :         {
    2934           0 :             SNAP_LOG_DEBUG("snapserver contacted before cassandra and snaplock are ready.");
    2935             :         }
    2936             :         else
    2937             :         {
    2938           0 :             SNAP_LOG_DEBUG("snapserver contacted before cassandra is ready.");
    2939             :         }
    2940             :         std::string const err("Status: 503 Service Unavailable\n"
    2941             :                       "Expires: Sun, 19 Nov 1978 05:00:00 GMT\n"
    2942             :                       "Content-type: text/html\n"
    2943             :                       "Connection: close\n"
    2944             :                       "\n"
    2945             :                       "<h1>503 Service Unavailable</h1>\n"
    2946           0 :                       "<p>Snap cannot find <strong>Cassandra</strong> at the moment.</p>\n");
    2947           0 :         NOTUSED(client->write(err.c_str(), err.size()));
    2948             :     }
    2949           0 :     else if(!f_snaplock)
    2950             :     {
    2951           0 :         SNAP_LOG_DEBUG("snapserver contacted before snaplock is ready.");
    2952             :         std::string const err("Status: 503 Service Unavailable\n"
    2953             :                       "Expires: Sun, 19 Nov 1978 05:00:00 GMT\n"
    2954             :                       "Content-type: text/html\n"
    2955             :                       "Connection: close\n"
    2956             :                       "\n"
    2957             :                       "<h1>503 Service Unavailable</h1>\n"
    2958           0 :                       "<p>Cannot find <strong>Snap! Lock</strong> at the moment.</p>\n");
    2959           0 :         NOTUSED(client->write(err.c_str(), err.size()));
    2960             :     }
    2961           0 :     else if(!f_firewall_up)
    2962             :     {
    2963           0 :         SNAP_LOG_DEBUG("snapserver contacted before snapfirewall is ready.");
    2964             :         std::string const err("Status: 503 Service Unavailable\n"
    2965             :                       "Expires: Sun, 19 Nov 1978 05:00:00 GMT\n"
    2966             :                       "Content-type: text/html\n"
    2967             :                       "Connection: close\n"
    2968             :                       "\n"
    2969             :                       "<h1>503 Service Unavailable</h1>\n"
    2970           0 :                       "<p>Cannot find <strong>Snap! Firewall</strong> at the moment.</p>\n");
    2971           0 :         NOTUSED(client->write(err.c_str(), err.size()));
    2972             :     }
    2973             :     else
    2974             :     {
    2975           0 :         snap_child * child(nullptr);
    2976             : 
    2977           0 :         if(f_children_waiting.empty())
    2978             :         {
    2979           0 :             child = new snap_child(g_instance);
    2980             :         }
    2981             :         else
    2982             :         {
    2983           0 :             child = f_children_waiting.back();
    2984           0 :             f_children_waiting.pop_back();
    2985             :         }
    2986             : 
    2987           0 :         if(child->process(client))
    2988             :         {
    2989             :             // this child is now busy
    2990             :             //
    2991           0 :             f_children_running.push_back(child);
    2992             :         }
    2993             :         else
    2994             :         {
    2995             :             // it failed, we can keep that child as a waiting child
    2996             :             //
    2997           0 :             f_children_waiting.push_back(child);
    2998             : 
    2999             :             // and tell the user about a problem without telling much...
    3000             :             // (see the logs for more info.)
    3001             :             // TBD Translation?
    3002             :             //
    3003             :             std::string const err("Status: 503 Service Unavailable\n"
    3004             :                           "Expires: Sun, 19 Nov 1978 05:00:00 GMT\n"
    3005             :                           "Content-type: text/html\n"
    3006             :                           "Connection: close\n"
    3007             :                           "\n"
    3008             :                           "<h1>503 Service Unavailable</h1>\n"
    3009           0 :                           "<p>Server cannot start child process.</p>\n");
    3010           0 :             NOTUSED(client->write(err.c_str(), err.size()));
    3011             :         }
    3012             :     }
    3013           0 : }
    3014             : 
    3015             : 
    3016             : /** \brief Handle caught signals
    3017             :  *
    3018             :  * Catch the signal, then log the signal, then terminate with 1 status.
    3019             :  */
    3020           0 : void server::sighandler( int sig )
    3021             : {
    3022           0 :     std::string signame;
    3023           0 :     bool output_stack_trace(true);
    3024           0 :     switch( sig )
    3025             :     {
    3026           0 :         case SIGSEGV : signame = "SIGSEGV"; break;
    3027           0 :         case SIGBUS  : signame = "SIGBUS";  break;
    3028           0 :         case SIGFPE  : signame = "SIGFPE";  break;
    3029           0 :         case SIGILL  : signame = "SIGILL";  break;
    3030           0 :         case SIGTERM : signame = "SIGTERM"; output_stack_trace = false; break;
    3031           0 :         case SIGINT  : signame = "SIGINT";  output_stack_trace = false; break;
    3032           0 :         case SIGQUIT : signame = "SIGQUIT"; output_stack_trace = false; break;
    3033           0 :         case SIGALRM : signame = "SIGALRM"; break;
    3034           0 :         case SIGABRT : signame = "SIGABRT"; break;
    3035           0 :         default      : signame = "UNKNOWN"; break;
    3036             :     }
    3037             : 
    3038           0 :     SNAP_LOG_FATAL("POSIX signal caught: ")(signame);
    3039             : 
    3040           0 :     if( output_stack_trace )
    3041             :     {
    3042           0 :         snap_exception_base::output_stack_trace();
    3043             :     }
    3044             : 
    3045             :     // is server available?
    3046             :     //
    3047           0 :     if(g_instance)
    3048             :     {
    3049           0 :         g_instance->exit(1);
    3050             :     }
    3051             : 
    3052             :     // server not available, exit directly
    3053             :     //
    3054           0 :     ::exit(1);
    3055             : }
    3056             : 
    3057             : 
    3058             : /** \brief Capture POSIX signals, log that they happened, and continue.
    3059             :  *
    3060             :  * This function is a callback we use to capture certain signals that
    3061             :  * we want to know of but do not want to kill the process.
    3062             :  *
    3063             :  * The function logs the fact that the signal occurred and then returns.
    3064             :  * This means the software continues to run. The function that generated
    3065             :  * the signal should fail, in many cases, meaning that it returns -1 or
    3066             :  * some similar error code. errno should then be set to EINTR. It is
    3067             :  * the responsibility of the caller to properly handle such error codes.
    3068             :  *
    3069             :  * \note
    3070             :  * Signals such as SIGSEGV and SIGILL should never use this function
    3071             :  * since those signals are considered terminal.
    3072             :  *
    3073             :  * \param[in] sig  The signal that just generated an interrupt.
    3074             :  */
    3075           0 : void server::sigloghandler( int sig )
    3076             : {
    3077           0 :     std::string signame;
    3078             : 
    3079           0 :     switch( sig )
    3080             :     {
    3081           0 :     case SIGPIPE : signame = "SIGPIPE"; break;
    3082           0 :     default      : signame = "UNKNOWN"; break;
    3083             :     }
    3084             : 
    3085             :     // in most cases we do not want to waste time with the stack trace here
    3086             :     // but if you need it, just uncomment the next line, just try NOT commit
    3087             :     // it uncommented because that could then end up in a release version...
    3088             :     //
    3089             :     //snap_exception_base::output_stack_trace();
    3090             : 
    3091           0 :     SNAP_LOG_WARNING("POSIX signal caught: ")(signame);
    3092             : 
    3093             :     // in this case we return because we want the process to continue
    3094             :     //
    3095           0 :     return;
    3096             : }
    3097             : 
    3098             : 
    3099             : /** \brief Run the backend process.
    3100             :  *
    3101             :  * This function creates a child and runs its backend function.
    3102             :  *
    3103             :  * The function may first initialize some more things in the server.
    3104             :  *
    3105             :  * When the backend process ends, the function returns. Assuming everything
    3106             :  * works as expected, the function is exepcted to return cleanly.
    3107             :  */
    3108           0 : void server::backend()
    3109             : {
    3110           0 :     snap_backend the_backend(g_instance);
    3111           0 :     the_backend.run_backend();
    3112           0 : }
    3113             : 
    3114             : 
    3115             : /** \brief Return the number of connections received by the server.
    3116             :  *
    3117             :  * This function returns the connections counter. Note that this
    3118             :  * counter is just an in memory counter so once the server restarts
    3119             :  * it is reset to zero.
    3120             :  */
    3121           0 : unsigned long server::connections_count()
    3122             : {
    3123           0 :     return f_connections_count;
    3124             : }
    3125             : 
    3126             : 
    3127             : /** \brief Servername, taken from argv[0].
    3128             :  *
    3129             :  * This method returns the server name, taken from the first argument on the command line.
    3130             :  */
    3131           0 : std::string server::servername() const
    3132             : {
    3133           0 :     return f_servername;
    3134             : }
    3135             : 
    3136             : 
    3137           0 : void server::configure_messenger_logging( snap_communicator::snap_tcp_client_permanent_message_connection::pointer_t ptr )
    3138             : {
    3139           0 :     if( f_opt->is_defined("no-messenger-logging") )
    3140             :     {
    3141           0 :         return;
    3142             :     }
    3143             : 
    3144           0 :     logging::set_log_messenger( ptr );
    3145             : }
    3146             : 
    3147             : 
    3148             : /** \fn void server::init()
    3149             :  * \brief Initialize the Snap Websites server.
    3150             :  *
    3151             :  * This function readies the Init signal.
    3152             :  *
    3153             :  * At this time, it does nothing.
    3154             :  */
    3155             : 
    3156             : 
    3157             : /** \fn void server::update(int64_t last_updated)
    3158             :  * \brief Update the Snap Websites server.
    3159             :  *
    3160             :  * This signal ensures that the data managed by this plugin is up to date.
    3161             :  *
    3162             :  * \param[in] last_updated  The date and time when the website was last updated.
    3163             :  */
    3164             : 
    3165             : 
    3166             : /** \fn void server::process_cookies()
    3167             :  * \brief Process a cookies on an HTTP request.
    3168             :  *
    3169             :  * This signal is used to 
    3170             :  *
    3171             :  * At this time, it does nothing.
    3172             :  */
    3173             : 
    3174             : 
    3175             : /** \fn void server::attach_to_session()
    3176             :  * \brief Process the attach to session event.
    3177             :  *
    3178             :  * This signal gives plugins a chance to attach data to the session right
    3179             :  * before the process ends.
    3180             :  */
    3181             : 
    3182             : 
    3183             : /** \fn void server::detach_from_session()
    3184             :  * \brief Process the detach from session event.
    3185             :  *
    3186             :  * This signal gives plugins a chance to detach data that they attached to
    3187             :  * the sessions earlier. This signal happens early on after the process
    3188             :  * initialized the plugins.
    3189             :  */
    3190             : 
    3191             : 
    3192             : /** \fn void server::define_locales(http_strings::WeightedHttpString & locales)
    3193             :  * \brief Give plugins a chance to define the acceptable page locales.
    3194             :  *
    3195             :  * This signal is used to give a chance to plugins to define the user's
    3196             :  * locale. Note that the user locale is in second position. If the
    3197             :  * information was defined in the URI (query string, path, domain, or
    3198             :  * sub-domain...) then the URI locale gets used if it exists.
    3199             :  *
    3200             :  * In most cases, on the `users` plugin should deal with this signal.
    3201             :  * However, other plugins may also accept this signal and add to the
    3202             :  * list of locales.
    3203             :  *
    3204             :  * This signals passes a \p locales parameter which can be used to
    3205             :  * add more locales to the acceptable locales. In most cases, all
    3206             :  * you want to do is call the parse() function as in:
    3207             :  *
    3208             :  * \code
    3209             :  *      // add Spanish as a choice, albeit very low level
    3210             :  *      locales.parse("es;q=0.1");
    3211             :  * \endcode
    3212             :  *
    3213             :  * Other example of language strings:
    3214             :  *
    3215             :  * \code
    3216             :  *      # as is (spaces not required)
    3217             :  *      "de, fr"
    3218             :  *
    3219             :  *      # the same with weights (again, spaces not required)
    3220             :  *      "de; q=0.9, fr; q=0.3"
    3221             :  * \endcode
    3222             :  *
    3223             :  * If you already have the language, country, and level separated, you
    3224             :  * may instead create a part_t and push it on the vector. At this time
    3225             :  * you have to retrieve a reference to the vector to do the push.
    3226             :  *
    3227             :  * \code
    3228             :  *      http_strings::WeightedHttpString::part_t p;
    3229             :  *      p.set_language("es");
    3230             :  *      p.set_country("PE"); // optional
    3231             :  *      p.set_level(0.1);
    3232             :  *      locales.get_parts().push_back(p);
    3233             :  * \endcode
    3234             :  *
    3235             :  * You do not have to worry about the sort order, the caller will take
    3236             :  * care of it.
    3237             :  *
    3238             :  * \warning
    3239             :  * At this time the sort is executed after we are done with this function
    3240             :  * and that can mean that the order in which the final set of locales is
    3241             :  * given has nothing to do with the order in which the various signal
    3242             :  * implementations get called.
    3243             :  *
    3244             :  * \param[in,out] locales  The variable receiving the locales.
    3245             :  */
    3246             : 
    3247             : 
    3248             : /** \fn void server::process_post(QString const & url)
    3249             :  * \brief Process a POST request at the specified URL.
    3250             :  *
    3251             :  * This signal is sent when the server is called with a POST instead of a GET.
    3252             :  *
    3253             :  * \param[in] url  The URL to process a POST from.
    3254             :  */
    3255             : 
    3256             : 
    3257             : /** \fn void server::execute(QString const & url)
    3258             :  * \brief Execute the URL.
    3259             :  *
    3260             :  * This signal is called once the plugins were fully initialized. At this point
    3261             :  * only one plugin is expected to implement that signal: path.
    3262             :  *
    3263             :  * \param[in] url  The URL to execute.
    3264             :  */
    3265             : 
    3266             : 
    3267             : /** \fn void server::register_backend_cron(backend_action_set & actions)
    3268             :  * \brief Execute the specified backend action every 5 minutes.
    3269             :  *
    3270             :  * This signal is called when the backend server is asked to run a backend
    3271             :  * service as a CRON server. By default the service runs once every five
    3272             :  * minutes. It can also be awaken with a PING message and ended with a STOP
    3273             :  * message.
    3274             :  *
    3275             :  * Plugins that handle backend work that happens on a regular schedule and
    3276             :  * has to be available quickly through a PING are registered using this
    3277             :  * signal.
    3278             :  *
    3279             :  * If you are writing a one time signal process, use the
    3280             :  * register_backend_action() instead. And if you are writing a backend
    3281             :  * process that does not need to be quickly awaken via a PING, use the
    3282             :  * regular process_backend() signal.
    3283             :  *
    3284             :  * The actions are run through the on_backend_action() virtual function
    3285             :  * of the backend_action structure.
    3286             :  *
    3287             :  * \param[in,out] actions  A map where plugins can register the actions they support.
    3288             :  */
    3289             : 
    3290             : 
    3291             : /** \fn void server::register_backend_action(backend_action_set & actions)
    3292             :  * \brief Execute the specified backend action.
    3293             :  *
    3294             :  * This signal is called when the server is run as a backend service.
    3295             :  * Plugins that handle backend work can register when this signal is
    3296             :  * triggered.
    3297             :  *
    3298             :  * If you want to register a backend that executes every five minutes
    3299             :  * and can quickly be awaken using a PING event, then use the
    3300             :  * register_backend_cron() function instead. For actions that are to
    3301             :  * run over and over again instead of once in a while on an explicit
    3302             :  * call, implement the backend_process() instead.
    3303             :  *
    3304             :  * The actions are run through the on_backend_action() virtual function
    3305             :  * of the backend_action structure.
    3306             :  *
    3307             :  * \param[in,out] actions  A map where plugins can register the actions they support.
    3308             :  */
    3309             : 
    3310             : 
    3311             : /** \fn void server::backend_process()
    3312             :  * \brief Execute the backend processes.
    3313             :  *
    3314             :  * This signal runs backend processes that do not need to be run immediately
    3315             :  * when something changes in the database. For example, the RSS feeds are
    3316             :  * updated when this signal calls the feed on_backend_process()
    3317             :  * implementation.
    3318             :  *
    3319             :  * The signal is sent to all plugins that registered with the standard
    3320             :  * SNAP_LISTEN() macro. The function is expected to do some work and then
    3321             :  * return. The function should not take too long or it has to verify
    3322             :  * whether the STOP event was sent to the backend.
    3323             :  *
    3324             :  * This implementation is different from the backend actions which are
    3325             :  * either permanent (register_backend_cron) or a one time call
    3326             :  * (register_backend_action). The CRON actions stay and run forever and
    3327             :  * can be awaken by a PING event.
    3328             :  */
    3329             : 
    3330             : 
    3331             : /** \fn void server::save_content()
    3332             :  * \brief Request new content to be saved.
    3333             :  *
    3334             :  * This signal is sent after the update signal returns. This gives a chance
    3335             :  * to the content plugin to save the data. It is somewhat specialized at this
    3336             :  * point, unfortunately, but it has the advantage of working properly.
    3337             :  */
    3338             : 
    3339             : 
    3340             : /** \fn void server::xss_filter(QDomNode & node, QString const & acceptable_tags, QString const & acceptable_attributes)
    3341             :  * \brief Implementation of the XSS filter signal.
    3342             :  *
    3343             :  * This signal is used to clean any possible XSS potential problems in the specified
    3344             :  * \p node.
    3345             :  *
    3346             :  * \param[in,out] node  The HTML node to check with XSS filters.
    3347             :  * \param[in] acceptable_tags  The tags kept in the specified HTML.
    3348             :  *                             (i.e. "p a ul li")
    3349             :  * \param[in] acceptable_attributes  The list of (not) acceptable attributes
    3350             :  *                                   (i.e. "!styles")
    3351             :  *
    3352             :  * \return true if the signal has to be sent to other plugins.
    3353             :  */
    3354             : 
    3355             : 
    3356             : /** \fn permission_error_callback::on_error(snap_child::http_code_t const err_code, QString const& err_name, QString const& err_description, QString const& err_details, bool const err_by_mime_type)
    3357             :  * \brief Generate an error.
    3358             :  *
    3359             :  * This function is called if an error is generated. If so then the function
    3360             :  * should mark the permission as not available for that user.
    3361             :  *
    3362             :  * This function accepts the same parameters as the snap_child::die()
    3363             :  * function.
    3364             :  *
    3365             :  * This implementation of the function does not returned. However, it cannot
    3366             :  * expect that all implementations would not return (to the contrary!)
    3367             :  *
    3368             :  * \param[in] err_code  The error code such as 501 or 503.
    3369             :  * \param[in] err_name  The name of the error such as "Service Not Available".
    3370             :  * \param[in] err_description  HTML message about the problem.
    3371             :  * \param[in] err_details  Server side text message with details that are logged only.
    3372             :  * \param[in] err_by_mime_type  If returning an error, do not return HTML when this element MIME type is something else, instead send a file of that type, but still with the HTTP error code supplied.
    3373             :  */
    3374             : 
    3375             : 
    3376             : /** \fn permission_error_callback::on_redirect(QString const& err_name, QString const& err_description, QString const& err_details, bool err_security, QString const& path, snap_child::http_code_t const http_code)
    3377             :  * \brief Generate a message and redirect the user.
    3378             :  *
    3379             :  * This function is called if an error is generated, but an error that can
    3380             :  * be "fixed" (in most cases by having the user log in or enter his
    3381             :  * credentials for a higher level of security on the website.)
    3382             :  *
    3383             :  * This function accepts the same parameters as the message::set_error()
    3384             :  * function followed by the same parameters as the snap_child::redirect()
    3385             :  * function.
    3386             :  *
    3387             :  * This implementation of the function does not returned. However, it cannot
    3388             :  * expect that all implementations would not return (to the contrary!)
    3389             :  *
    3390             :  * \param[in] err_name  The name of the error such as "Value Too Small".
    3391             :  * \param[in] err_description  HTML message about the problem.
    3392             :  * \param[in] err_details  Server side text message with details that are logged only.
    3393             :  * \param[in] err_security  Whether this message is considered a security related message.
    3394             :  * \param[in] path  The path where the user is being redirected.
    3395             :  * \param[in] http_code  The code to use while redirecting the user.
    3396             :  */
    3397             : 
    3398             : 
    3399             : /** \fn void server::improve_signature(QString const& path, QString& signature)
    3400             :  * \brief Improve the die() signature to add at the bottom of pages.
    3401             :  *
    3402             :  * This function calls all the plugins that define the signature signal so
    3403             :  * they can append their own link or other information to the signature.
    3404             :  * The signature is a simple mechanism to get several plugins to link to
    3405             :  * a page where the user can go to continue his browsing on that website.
    3406             :  * In most cases it is never called because the site will have a
    3407             :  * page_not_found() call which is answered properly and thus a regular
    3408             :  * error page is shown.
    3409             :  *
    3410             :  * The signature parameter is passed to the plugins as an in/out parameter.
    3411             :  * The plugins are free to do whatever they want, including completely
    3412             :  * overwrite the content although keep in mind that you cannot ensure
    3413             :  * that a plugin is last in the last. In most cases you should limit
    3414             :  * yourself to doing something like this:
    3415             :  *
    3416             :  * \code
    3417             :  *   signature += " <a href=\"/search\">Search This Website</a>";
    3418             :  * \endcode
    3419             :  *
    3420             :  * This very function does nothing, just returthisns true.
    3421             :  *
    3422             :  * \param[in] path  The path that generated the error
    3423             :  * \param[in,out] signature  The signature as inline HTML code (i.e. no blocks!)
    3424             :  *
    3425             :  * \return true if the signal has to be sent to other plugins.
    3426             :  */
    3427             : 
    3428             : 
    3429             : /** \brief Load a file.
    3430             :  *
    3431             :  * This function is used to load a file. As additional plugins are added
    3432             :  * additional protocols can be supported.
    3433             :  *
    3434             :  * The file information defaults are kept as is as much as possible. If
    3435             :  * a plugin returns a file, though, it is advised that any information
    3436             :  * available to the plugin be set in the file object.
    3437             :  *
    3438             :  * The base load_file() function (i.e. this very function) supports the
    3439             :  * file system protocol (file:) and the Qt resources protocol (qrc:).
    3440             :  * Including the "file:" protocol is not required. Also, the Qt resources
    3441             :  * can be indicated simply by adding a colon at the beginning of the
    3442             :  * filename (":/such/as/this/name").
    3443             :  *
    3444             :  * \param[in,out] file  The file name and content.
    3445             :  * \param[in,out] found  Whether the file was found.
    3446             :  *
    3447             :  * \return true if the signal is to be propagated to all the plugins.
    3448             :  */
    3449           0 : bool server::load_file_impl(snap_child::post_file_t & file, bool & found)
    3450             : {
    3451           0 :     QString filename(file.get_filename());
    3452             : 
    3453           0 :     found = false;
    3454             : 
    3455           0 :     int const colon_pos(filename.indexOf(':'));
    3456           0 :     int const slash_pos(filename.indexOf('/'));
    3457           0 :     if(colon_pos <= 0                    // no protocol
    3458           0 :     || colon_pos > slash_pos            // no protocol
    3459           0 :     || filename.startsWith("file:")     // file protocol
    3460           0 :     || filename.startsWith("qrc:"))     // Qt resource protocol
    3461             :     {
    3462           0 :         if(filename.startsWith("file:"))
    3463             :         {
    3464             :             // remove the protocol
    3465           0 :             filename = filename.mid(5);
    3466             :         }
    3467           0 :         else if(filename.startsWith("qrc:"))
    3468             :         {
    3469             :             // remove the protocol, but keep the colon
    3470           0 :             filename = filename.mid(3);
    3471             :         }
    3472           0 :         QFile f(filename);
    3473           0 :         if(!f.open(QIODevice::ReadOnly))
    3474             :         {
    3475             :             // file not found...
    3476           0 :             SNAP_LOG_ERROR("error trying to read file \"")(filename)("\", system error: ")(f.errorString());
    3477           0 :             return false;
    3478             :         }
    3479           0 :         file.set_filename(filename);
    3480           0 :         file.set_data(f.readAll());
    3481           0 :         found = true;
    3482             :         // return false since we already "found" the file
    3483           0 :         return false;
    3484             :     }
    3485             : 
    3486           0 :     return true;
    3487             : }
    3488             : 
    3489             : 
    3490             : 
    3491             : /** \fn void server::table_is_accessible(QString const & table_name, accessible_flag_t & accessible)
    3492             :  * \brief Check whether a table can securily be used in a script.
    3493             :  *
    3494             :  * This signal is sent by the cell() function of snap_expr objects.
    3495             :  * The plugins receiving the signal can check the table name
    3496             :  * and mark it as accessible or secure.
    3497             :  *
    3498             :  * A table only marked as accessible can be accessed safely.
    3499             :  *
    3500             :  * \code
    3501             :  *   void my_plugin::on_table_isaccessible(QString const & table_name, accessible_flag_t & accessible)
    3502             :  *   {
    3503             :  *      if(table_name == get_name(name_t::SNAP_NAME_MYPLUGIN_TABLE_NAME))
    3504             :  *      {
    3505             :  *          accessible.mark_as_accessible();
    3506             :  *      }
    3507             :  *   }
    3508             :  * \endcode
    3509             :  *
    3510             :  * It is possible for a plugin to mark certain tables as not accessible,
    3511             :  * whether or not a plugin mark them as accessible. For example:
    3512             :  *
    3513             :  * \code
    3514             :  *   void content::on_table_isaccessible(QString const & table_name, accessible_flag_t & accessible)
    3515             :  *   {
    3516             :  *      if(table_name == get_name(name_t::SNAP_NAME_CONTENT_SECRET_TABLE))
    3517             :  *      {
    3518             :  *          // explicitly mark this table as a secure table
    3519             :  *          accessible.mark_as_secure();
    3520             :  *      }
    3521             :  *   }
    3522             :  * \endcode
    3523             :  *
    3524             :  * This is used, for example, to protect the users and secret tables.
    3525             :  * Even though passwords are encrypted, allowing an end user to get a copy
    3526             :  * of the encrypted password would dearly simplify the work of a hacker in
    3527             :  * finding the unencrypted password.
    3528             :  *
    3529             :  * The \p secure flag is used to mark the cell as secure. Simply call
    3530             :  * the mark_as_secure() function to do so. This means the table cannot
    3531             :  * be accessed and the cell() function fails.
    3532             :  *
    3533             :  * \param[in] table  The table being accessed.
    3534             :  * \param[in] accessible  Whether the cell is secure.
    3535             :  */
    3536             : 
    3537             : 
    3538             : /** \fn void server::add_snap_expr_functions(snap_expr::functions_t& functions)
    3539             :  * \brief Give a change to different plugins to add functions for snap_expr.
    3540             :  *
    3541             :  * This function gives a chance to any plugin listening to this signal
    3542             :  * to add functions that the snap_expr can then make use of.
    3543             :  *
    3544             :  * \return true in case the signal is to be broadcast.
    3545             :  */
    3546             : 
    3547             : 
    3548             : /** \fn void server::output_result(QString const& uri_path, QByteArray& result)
    3549             :  * \brief Implementation of the output_result signal.
    3550             :  *
    3551             :  * The output_result() signal offers the result buffer to all the plugins
    3552             :  * to look at. Since the buffer is passed as a reference, a plugin can
    3553             :  * modify it as required although it is not generally expected to happen.
    3554             :  *
    3555             :  * It may also be used to process the result and exit if a plugin thinks
    3556             :  * that the default processing is not going to be capable of handling
    3557             :  * the data appropriately. For example, the server_access plugin
    3558             :  * intercepts all results and transforms them to an AJAX response in
    3559             :  * case the request was an AJAX request.
    3560             :  *
    3561             :  * \param[in,out] result  The result buffer.
    3562             :  *
    3563             :  * \return true if the signal has to be sent to other plugins.
    3564             :  */
    3565             : 
    3566             : 
    3567             : 
    3568             : /** \brief Initializes a quiet error callback object.
    3569             :  *
    3570             :  * This function initializes an error callback object. It expects a pointer
    3571             :  * to the running snap_child.
    3572             :  *
    3573             :  * The \p log parameter is used to know whether the errors and redirects
    3574             :  * should be logged or not. In most cases it probably will be set to
    3575             :  * false to avoid large amounts of logs.
    3576             :  *
    3577             :  * \param[in,out] snap  The snap pointer.
    3578             :  * \param[in] log  The log flag, if true send all errors to the loggers.
    3579             :  */
    3580           0 : quiet_error_callback::quiet_error_callback(snap_child * snap, bool log)
    3581             :     : f_snap(snap)
    3582           0 :     , f_log(log)
    3583             :     //, f_error(false) -- auto-init
    3584             : {
    3585           0 : }
    3586             : 
    3587             : 
    3588             : /** \brief Generate an error.
    3589             :  *
    3590             :  * This function is called when the user is trying to view something that
    3591             :  * is not accessible. The system already checked to know whether the user
    3592             :  * could upgrade to a higher level of control and failed, so the user
    3593             :  * simply cannot access this page. Hence we do not try to redirect him to
    3594             :  * a log in screen, and instead generate an error.
    3595             :  *
    3596             :  * In this default implementation, we simply log the information (assuming
    3597             :  * the object was created with the log flag set to true) and mark the
    3598             :  * object as erroneous.
    3599             :  *
    3600             :  * \param[in] err_code  The HTTP code to be returned to the user.
    3601             :  * \param[in] err_name  The name of the error being generated.
    3602             :  * \param[in] err_description  A more complete description of the error.
    3603             :  * \param[in] err_details  The internal details about the error (for system administrators only).
    3604             :  * \param[in] err_by_mime_type  If returning an error, do not return HTML when this element MIME type is something else, instead send a file of that type, but still with the HTTP error code supplied.
    3605             :  */
    3606           0 : void quiet_error_callback::on_error(snap_child::http_code_t const err_code, QString const & err_name, QString const & err_description, QString const & err_details, bool const err_by_mime_type)
    3607             : {
    3608             :     // since we ignore the error here anyway we can ignore this flag...
    3609           0 :     NOTUSED(err_by_mime_type);
    3610             : 
    3611           0 :     f_error = true;
    3612             : 
    3613           0 :     if(f_log)
    3614             :     {
    3615             :         // log the error so administrators know something happened
    3616           0 :         SNAP_LOG_ERROR("error #")(static_cast<int>(err_code))(":")(err_name)(": ")(err_description)(" -- ")(err_details);
    3617             :     }
    3618           0 : }
    3619             : 
    3620             : 
    3621             : /** \brief Redirect the user so he can log in.
    3622             :  *
    3623             :  * In most cases this function is used to redirect the user to a log in page.
    3624             :  * It may be a log in screen to escalate the user to a new level so he can
    3625             :  * authorize changes requiring a higher level of control.
    3626             :  *
    3627             :  * In the base implementation, the error is logged (assuming the object was
    3628             :  * created with the log flag set to true) and the object is marked as
    3629             :  * erroneous, meaning that the object being checked will remain hidden.
    3630             :  * However, the user does not get redirected.
    3631             :  *
    3632             :  * \param[in] err_name  The name of the error being generated.
    3633             :  * \param[in] err_description  A more complete description of the error.
    3634             :  * \param[in] err_details  The internal details about the error (for system administrators only).
    3635             :  * \param[in] err_security  Whether the error is a security error (cannot be displayed to the end user).
    3636             :  * \param[in] path  The path that generated the error.
    3637             :  * \param[in] http_code  The HTTP code to be returned to the user.
    3638             :  */
    3639           0 : void quiet_error_callback::on_redirect(
    3640             :         /* message::set_error() */ QString const & err_name, QString const & err_description, QString const & err_details, bool err_security,
    3641             :         /* snap_child::page_redirect() */ QString const & path, snap_child::http_code_t const http_code)
    3642             : {
    3643           0 :     NOTUSED(err_security);
    3644             : 
    3645           0 :     f_error = true;
    3646           0 :     if(f_log)
    3647             :     {
    3648             :         // log the feat so administrators know something happened
    3649           0 :         SNAP_LOG_ERROR("error #")(static_cast<int>(http_code))(":")(err_name)(": ")(err_description)(" -- ")(err_details)(" (would redirect to: \"")(path)("\")");
    3650             :     }
    3651           0 : }
    3652             : 
    3653             : 
    3654             : /** \brief Clear the error.
    3655             :  *
    3656             :  * This function clear the error flag.
    3657             :  *
    3658             :  * This class is often used in a loop such as the one used to generate all
    3659             :  * the boxes on a page. The same object can be reused to check
    3660             :  * wehther a box is accessible or not, however, the object needs to clear
    3661             :  * its state before you test another box or all the boxes after the first
    3662             :  * that's currently forbidden would get hidden.
    3663             :  */
    3664           0 : void quiet_error_callback::clear_error()
    3665             : {
    3666           0 :     f_error = false;
    3667           0 : }
    3668             : 
    3669             : 
    3670             : /** \brief Check whether an error occurred.
    3671             :  *
    3672             :  * This function returns true if one of the on_redirect() or on_error()
    3673             :  * function were called during the process. If so, then the page is
    3674             :  * protected.
    3675             :  *
    3676             :  * In most cases the redirect is used to send the user to the log in screen.
    3677             :  * If the user is on a page that proves he cannot have an account or is
    3678             :  * already logged in and he cannot increase his rights, then the on_error()
    3679             :  * function is used. So in effect, either function represents the same
    3680             :  * thing: the user cannot access the specified page.
    3681             :  *
    3682             :  * \return true if an error occurred and thus the page is not accessible.
    3683             :  */
    3684           0 : bool quiet_error_callback::has_error() const
    3685             : {
    3686           0 :     return f_error;
    3687             : }
    3688             : 
    3689             : 
    3690             : /** \brief Add an action to the specified action set.
    3691             :  *
    3692             :  * This function adds an action to this action set.
    3693             :  *
    3694             :  * The action name must be unique within a plugin. The function
    3695             :  * forces the name of the plugin as a namespace so the name ends
    3696             :  * up looking something like this (for the "reset" action of
    3697             :  * the "list" plugin):
    3698             :  *
    3699             :  * \code
    3700             :  *      list::reset
    3701             :  * \endcode
    3702             :  *
    3703             :  * \exception snapwebsites_exception_invalid_parameters
    3704             :  * If the plugin does not implement the backend_action, then this
    3705             :  * exception is raised. It should happen rarely since without
    3706             :  * implementing that interface you end up never receiving the
    3707             :  * event. That being said, if you implement a function and forget
    3708             :  * to add the derivation, it will compile and raise this exception.
    3709             :  *
    3710             :  * \param[in] action  The action to be added.
    3711             :  * \param[in] p  The plugin that is registering this \p action.
    3712             :  */
    3713           0 : void server::backend_action_set::add_action(QString const & action, plugin * p)
    3714             : {
    3715             :     // make sure that this plugin implements the backend action
    3716             :     //
    3717           0 :     backend_action * ba(dynamic_cast<backend_action *>(p));
    3718           0 :     if(ba == nullptr)
    3719             :     {
    3720             :         throw snapwebsites_exception_invalid_parameters("snapwebsites.cpp:"
    3721           0 :                             " could not cast p to a backend_action pointer");
    3722             :     }
    3723             : 
    3724             :     // calculate the full name of this action
    3725             :     //
    3726           0 :     QString const name(QString("%1::%2").arg(p->get_plugin_name()).arg(action));
    3727             : 
    3728             :     // make sure we do not get duplicates
    3729             :     //
    3730           0 :     if(f_actions.contains(name))
    3731             :     {
    3732             :         throw snapwebsites_exception_invalid_parameters(
    3733           0 :                 QString("snapwebsites.cpp: server::backend_action_set::add_action()"
    3734           0 :                         " was called with \"%1\" twice.").arg(name));
    3735             :     }
    3736             : 
    3737           0 : SNAP_LOG_DEBUG("adding action \"")(name)("\".");
    3738           0 :     f_actions[name] = ba;
    3739           0 : }
    3740             : 
    3741             : 
    3742             : /** \brief Check whether a named action is defined in this set.
    3743             :  *
    3744             :  * Note that various websites may have various actions registered
    3745             :  * depending on which plugin is installed. This function is used
    3746             :  * to know whether an action is defined for that website.
    3747             :  *
    3748             :  * \note
    3749             :  * The backend processing function exits with an error when an
    3750             :  * action is not defined. This does not prevent the process from
    3751             :  * moving forward (since the same action is generally run against
    3752             :  * all the installed websites.)
    3753             :  *
    3754             :  * \param[in] action  The action to check the existance of.
    3755             :  *
    3756             :  * \return true if a plugin defines that specific action.
    3757             :  */
    3758           0 : bool server::backend_action_set::has_action(QString const & action) const
    3759             : {
    3760           0 :     return f_actions.contains(action);
    3761             : }
    3762             : 
    3763             : 
    3764             : /** \brief Actually call the backend action function.
    3765             :  *
    3766             :  * This function calls the plugin implementation of the on_backend_action()
    3767             :  * function.
    3768             :  *
    3769             :  * The function is passed the \p action parameter since the same function
    3770             :  * may get called for any number of actions (depending on how many where
    3771             :  * recorded.)
    3772             :  *
    3773             :  * \warning
    3774             :  * Note that CRON and non-CRON actions are both executed the same way.
    3775             :  * The plugin is aware of which action was registered as a CRON action
    3776             :  * and which was registered as a non-CRON action.
    3777             :  *
    3778             :  * \param[in] action  The action being executed.
    3779             :  */
    3780           0 : void server::backend_action_set::execute_action(QString const & action)
    3781             : {
    3782           0 :     if(has_action(action))
    3783             :     {
    3784             :         // the plugin itself expects the action name without the namespace
    3785             :         // so we remove it here before we run the callback
    3786             :         //
    3787           0 :         plugins::plugin * p(dynamic_cast<plugins::plugin *>(f_actions[action]));
    3788           0 :         if(p) // always expected to be defined
    3789             :         {
    3790           0 :             QString const namespace_name(p->get_plugin_name());
    3791             :             // the +2 is to skip the '::'
    3792           0 :             f_actions[action]->on_backend_action(action.mid(namespace_name.length() + 2));
    3793             :         }
    3794             :     }
    3795           0 : }
    3796             : 
    3797             : 
    3798             : /** \brief Retrieve the name of the plugin of a given action.
    3799             :  *
    3800             :  * This function retrieves the name of the plugin linked to a certain
    3801             :  * action.
    3802             :  *
    3803             :  * \param[in] action  The action of which we are interested by the plugin.
    3804             :  *
    3805             :  * \return The name of the plugin, if the action is defined, otherwise "".
    3806             :  */
    3807           0 : QString server::backend_action_set::get_plugin_name(QString const & action)
    3808             : {
    3809           0 :     if(has_action(action))
    3810             :     {
    3811           0 :         plugins::plugin * p(dynamic_cast<plugins::plugin *>(f_actions[action]));
    3812           0 :         if(p) // always expected to be defined
    3813             :         {
    3814           0 :             return p->get_plugin_name();
    3815             :         }
    3816             :     }
    3817             : 
    3818           0 :     return QString();
    3819             : }
    3820             : 
    3821             : 
    3822             : /** \brief Display the list of actions.
    3823             :  *
    3824             :  * This function can be used to display a list of actions.
    3825             :  *
    3826             :  * \warning
    3827             :  * This function is definitely not re-entrant (although it can
    3828             :  * be called any number of times by the same thread with the
    3829             :  * same result.)
    3830             :  */
    3831           0 : void server::backend_action_set::display()
    3832             : {
    3833           0 :     f_actions["list"] = nullptr;
    3834           0 :     for(actions_map_t::const_iterator it(f_actions.begin()); it != f_actions.end(); ++it)
    3835             :     {
    3836           0 :         std::cout << "  " << it.key() << std::endl;
    3837             :     }
    3838           0 :     f_actions.remove("list");
    3839           0 : }
    3840             : 
    3841             : 
    3842           6 : } // namespace snap
    3843             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13