LCOV - code coverage report
Current view: top level - config - ccsession.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 260 312 83.3 %
Date: 2012-05-15 Functions: 27 32 84.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 472 1000 47.2 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : 
      17                 :            : #include <stdexcept>
      18                 :            : #include <stdlib.h>
      19                 :            : #include <string.h>
      20                 :            : #include <sys/time.h>
      21                 :            : #include <ctype.h>
      22                 :            : 
      23                 :            : #include <algorithm>
      24                 :            : #include <cerrno>
      25                 :            : #include <fstream>
      26                 :            : #include <iostream>
      27                 :            : #include <set>
      28                 :            : #include <sstream>
      29                 :            : #include <string>
      30                 :            : 
      31                 :            : #include <boost/bind.hpp>
      32                 :            : #include <boost/foreach.hpp>
      33                 :            : 
      34                 :            : #include <cc/data.h>
      35                 :            : #include <module_spec.h>
      36                 :            : #include <cc/session.h>
      37                 :            : #include <exceptions/exceptions.h>
      38                 :            : 
      39                 :            : #include <config/config_log.h>
      40                 :            : #include <config/ccsession.h>
      41                 :            : 
      42                 :            : #include <log/logger_support.h>
      43                 :            : #include <log/logger_specification.h>
      44                 :            : #include <log/logger_manager.h>
      45                 :            : #include <log/logger_name.h>
      46                 :            : 
      47                 :            : using namespace std;
      48                 :            : 
      49                 :            : using isc::data::Element;
      50                 :            : using isc::data::ConstElementPtr;
      51                 :            : using isc::data::ElementPtr;
      52                 :            : using isc::data::JSONError;
      53                 :            : 
      54                 :            : namespace isc {
      55                 :            : namespace config {
      56                 :            : 
      57                 :            : /// Creates a standard config/command protocol answer message
      58                 :            : ConstElementPtr
      59                 :        146 : createAnswer() {
      60         [ +  - ]:        146 :     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
      61         [ +  - ]:        146 :     ElementPtr answer_content = Element::createList();
      62         [ +  - ]:        292 :     answer_content->add(Element::create(0));
      63 [ +  - ][ +  - ]:        292 :     answer->set("result", answer_content);
      64                 :            : 
      65                 :        146 :     return (answer);
      66                 :            : }
      67                 :            : 
      68                 :            : ConstElementPtr
      69                 :         63 : createAnswer(const int rcode, ConstElementPtr arg) {
      70 [ +  + ][ +  + ]:         63 :     if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
         [ +  + ][ +  + ]
      71 [ +  - ][ +  - ]:          4 :         isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
      72                 :            :     }
      73         [ +  - ]:         61 :     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
      74         [ +  - ]:         61 :     ElementPtr answer_content = Element::createList();
      75         [ +  - ]:        122 :     answer_content->add(Element::create(rcode));
      76         [ +  - ]:        122 :     answer_content->add(arg);
      77 [ +  - ][ +  - ]:        122 :     answer->set("result", answer_content);
      78                 :            : 
      79                 :         61 :     return (answer);
      80                 :            : }
      81                 :            : 
      82                 :            : ConstElementPtr
      83                 :         75 : createAnswer(const int rcode, const std::string& arg) {
      84         [ +  - ]:         75 :     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
      85         [ +  - ]:         75 :     ElementPtr answer_content = Element::createList();
      86         [ +  - ]:        150 :     answer_content->add(Element::create(rcode));
      87 [ +  - ][ +  - ]:        150 :     answer_content->add(Element::create(arg));
      88 [ +  - ][ +  - ]:        150 :     answer->set("result", answer_content);
      89                 :            : 
      90                 :         75 :     return (answer);
      91                 :            : }
      92                 :            : 
      93                 :            : ConstElementPtr
      94                 :        169 : parseAnswer(int &rcode, ConstElementPtr msg) {
      95   [ +  +  +  + ]:        672 :     if (msg &&
         [ +  + ][ +  + ]
      96                 :        168 :         msg->getType() == Element::map &&
      97 [ +  - ][ +  - ]:        335 :         msg->contains("result")) {
         [ +  + ][ #  # ]
      98         [ +  - ]:        162 :         ConstElementPtr result = msg->get("result");
      99         [ +  + ]:        162 :         if (result->getType() != Element::list) {
     100 [ +  - ][ +  - ]:          4 :             isc_throw(CCSessionError, "Result element in answer message is not a list");
                 [ +  - ]
     101 [ +  - ][ -  + ]:        320 :         } else if (result->get(0)->getType() != Element::integer) {
     102 [ #  # ][ #  # ]:          0 :             isc_throw(CCSessionError, "First element of result is not an rcode in answer message");
                 [ #  # ]
     103                 :            :         }
     104 [ +  - ][ +  - ]:        160 :         rcode = result->get(0)->intValue();
     105 [ +  - ][ +  + ]:        160 :         if (result->size() > 1) {
     106 [ +  + ][ +  - ]:        148 :             if (rcode == 0 || result->get(1)->getType() == Element::string) {
         [ +  + ][ +  + ]
                 [ +  + ]
     107         [ +  - ]:        104 :                 return (result->get(1));
     108                 :            :             } else {
     109 [ +  - ][ +  - ]:          2 :                 isc_throw(CCSessionError, "Error description in result with rcode != 0 is not a string");
                 [ +  - ]
     110                 :            :             }
     111                 :            :         } else {
     112         [ +  + ]:         55 :             if (rcode == 0) {
     113                 :            :                 return (ElementPtr());
     114                 :            :             } else {
     115 [ +  - ][ +  - ]:          2 :                 isc_throw(CCSessionError, "Result with rcode != 0 does not have an error description");
                 [ +  - ]
     116                 :            :             }
     117                 :            :         }
     118                 :            :     } else {
     119 [ +  - ][ +  - ]:         14 :         isc_throw(CCSessionError, "No result part in answer message");
     120                 :            :     }
     121                 :            : }
     122                 :            : 
     123                 :            : ConstElementPtr
     124                 :          1 : createCommand(const std::string& command) {
     125         [ +  - ]:          2 :     return (createCommand(command, ElementPtr()));
     126                 :            : }
     127                 :            : 
     128                 :            : ConstElementPtr
     129                 :        176 : createCommand(const std::string& command, ConstElementPtr arg) {
     130                 :        176 :     ElementPtr cmd = Element::createMap();
     131         [ +  - ]:        176 :     ElementPtr cmd_parts = Element::createList();
     132 [ +  - ][ +  - ]:        352 :     cmd_parts->add(Element::create(command));
     133         [ +  + ]:        176 :     if (arg) {
     134         [ +  - ]:        350 :         cmd_parts->add(arg);
     135                 :            :     }
     136 [ +  - ][ +  - ]:        352 :     cmd->set("command", cmd_parts);
     137                 :        176 :     return (cmd);
     138                 :            : }
     139                 :            : 
     140                 :            : std::string
     141                 :         27 : parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
     142   [ +  +  +  + ]:        105 :     if (command &&
         [ +  + ][ +  + ]
     143                 :         26 :         command->getType() == Element::map &&
     144 [ +  - ][ +  - ]:         52 :         command->contains("command")) {
         [ +  + ][ #  # ]
     145         [ +  - ]:         23 :         ConstElementPtr cmd = command->get("command");
     146         [ +  + ]:         87 :         if (cmd->getType() == Element::list &&
           [ +  +  +  + ]
                 [ +  + ]
     147         [ +  - ]:         21 :             cmd->size() > 0 &&
     148 [ +  - ][ +  + ]:         43 :             cmd->get(0)->getType() == Element::string) {
     149 [ +  - ][ +  + ]:         19 :             if (cmd->size() > 1) {
     150 [ +  - ][ +  - ]:         12 :                 arg = cmd->get(1);
     151                 :            :             } else {
     152         [ +  - ]:          7 :                 arg = Element::createMap();
     153                 :            :             }
     154 [ +  - ][ +  - ]:         38 :             return (cmd->get(0)->stringValue());
     155                 :            :         } else {
     156 [ +  - ][ +  - ]:          8 :             isc_throw(CCSessionError, "Command part in command message missing, empty, or not a list");
                 [ +  - ]
     157                 :            :         }
     158                 :            :     } else {
     159 [ +  - ][ +  - ]:          8 :         isc_throw(CCSessionError, "Command Element empty or not a map with \"command\"");
     160                 :            :     }
     161                 :            : }
     162                 :            : 
     163                 :            : namespace {
     164                 :            : // Temporary workaround functions for missing functionality in
     165                 :            : // getValue() (main problem described in ticket #993)
     166                 :            : // This returns either the value set for the given relative id,
     167                 :            : // or its default value
     168                 :            : // (intentially defined here so this interface does not get
     169                 :            : // included in ConfigData as it is)
     170                 :          0 : ConstElementPtr getValueOrDefault(ConstElementPtr config_part,
     171                 :            :                                   const std::string& relative_id,
     172                 :            :                                   const ConfigData& config_data,
     173                 :            :                                   const std::string& full_id) {
     174         [ #  # ]:          0 :     if (config_part->contains(relative_id)) {
     175                 :          0 :         return config_part->get(relative_id);
     176                 :            :     } else {
     177                 :          0 :         return config_data.getDefaultValue(full_id);
     178                 :            :     }
     179                 :            : }
     180                 :            : 
     181                 :            : // Prefix name with "b10-".
     182                 :            : //
     183                 :            : // In BIND 10, modules have names taken from the .spec file, which are typically
     184                 :            : // names starting with a capital letter (e.g. "Resolver", "Auth" etc.).  The
     185                 :            : // names of the associated binaries are derived from the module names, being
     186                 :            : // prefixed "b10-" and having the first letter of the module name lower-cased
     187                 :            : // (e.g. "b10-resolver", "b10-auth").  (It is a required convention that there
     188                 :            : // be this relationship between the names.)
     189                 :            : //
     190                 :            : // Within the binaries the root loggers are named after the binaries themselves.
     191                 :            : // (The reason for this is that the name of the logger is included in the
     192                 :            : // message logged, so making it clear which message comes from which BIND 10
     193                 :            : // process.) As logging is configured using module names, the configuration code
     194                 :            : // has to match these with the corresponding logger names. This function
     195                 :            : // converts a module name to a root logger name by lowercasing the first letter
     196                 :            : // of the module name and prepending "b10-".
     197                 :            : //
     198                 :            : // \param instring String to convert.  (This may be empty, in which case
     199                 :            : //        "b10-" will be returned.)
     200                 :            : //
     201                 :            : // \return Converted string.
     202                 :            : std::string
     203                 :         27 : b10Prefix(const std::string& instring) {
     204                 :         54 :     std::string result = instring;
     205         [ +  - ]:         27 :     if (!result.empty()) {
     206                 :         27 :         result[0] = tolower(result[0]);
     207                 :            :     }
     208 [ +  - ][ +  - ]:         54 :     return (std::string("b10-") + result);
     209                 :            : }
     210                 :            : 
     211                 :            : // Reads a output_option subelement of a logger configuration,
     212                 :            : // and sets the values thereing to the given OutputOption struct,
     213                 :            : // or defaults values if they are not provided (from config_data).
     214                 :            : void
     215                 :          0 : readOutputOptionConf(isc::log::OutputOption& output_option,
     216                 :            :                      ConstElementPtr output_option_el,
     217                 :            :                      const ConfigData& config_data)
     218                 :            : {
     219                 :            :     ConstElementPtr destination_el = getValueOrDefault(output_option_el,
     220                 :            :                                     "destination", config_data,
     221 [ #  # ][ #  # ]:          0 :                                     "loggers/output_options/destination");
     222 [ #  # ][ #  # ]:          0 :     output_option.destination = isc::log::getDestination(destination_el->stringValue());
     223                 :            :     ConstElementPtr output_el = getValueOrDefault(output_option_el,
     224                 :            :                                     "output", config_data,
     225 [ #  # ][ #  # ]:          0 :                                     "loggers/output_options/output");
                 [ #  # ]
     226         [ #  # ]:          0 :     if (output_option.destination == isc::log::OutputOption::DEST_CONSOLE) {
     227 [ #  # ][ #  # ]:          0 :         output_option.stream = isc::log::getStream(output_el->stringValue());
     228         [ #  # ]:          0 :     } else if (output_option.destination == isc::log::OutputOption::DEST_FILE) {
     229         [ #  # ]:          0 :         output_option.filename = output_el->stringValue();
     230         [ #  # ]:          0 :     } else if (output_option.destination == isc::log::OutputOption::DEST_SYSLOG) {
     231         [ #  # ]:          0 :         output_option.facility = output_el->stringValue();
     232                 :            :     }
     233                 :            :     output_option.flush = getValueOrDefault(output_option_el,
     234                 :            :                               "flush", config_data,
     235 [ #  # ][ #  # ]:          0 :                               "loggers/output_options/flush")->boolValue();
         [ #  # ][ #  # ]
     236                 :            :     output_option.maxsize = getValueOrDefault(output_option_el,
     237                 :            :                                 "maxsize", config_data,
     238 [ #  # ][ #  # ]:          0 :                                 "loggers/output_options/maxsize")->intValue();
         [ #  # ][ #  # ]
     239                 :            :     output_option.maxver = getValueOrDefault(output_option_el,
     240                 :            :                                "maxver", config_data,
     241 [ #  # ][ #  # ]:          0 :                                "loggers/output_options/maxver")->intValue();
         [ #  # ][ #  # ]
     242                 :          0 : }
     243                 :            : 
     244                 :            : // Reads a full 'loggers' configuration, and adds the loggers therein
     245                 :            : // to the given vector, fills in blanks with defaults from config_data
     246                 :            : void
     247                 :          0 : readLoggersConf(std::vector<isc::log::LoggerSpecification>& specs,
     248                 :            :                 ConstElementPtr logger,
     249                 :            :                 const ConfigData& config_data)
     250                 :            : {
     251                 :            :     // Read name, adding prefix as required.
     252 [ #  # ][ #  # ]:          0 :     std::string lname = logger->get("name")->stringValue();
     253                 :            : 
     254                 :            :     ConstElementPtr severity_el = getValueOrDefault(logger,
     255                 :            :                                       "severity", config_data,
     256 [ #  # ][ #  # ]:          0 :                                       "loggers/severity");
                 [ #  # ]
     257                 :            :     isc::log::Severity severity = isc::log::getSeverity(
     258 [ #  # ][ #  # ]:          0 :                                       severity_el->stringValue());
     259                 :            :     int dbg_level = getValueOrDefault(logger, "debuglevel",
     260                 :            :                                       config_data,
     261 [ #  # ][ #  # ]:          0 :                                       "loggers/debuglevel")->intValue();
         [ #  # ][ #  # ]
     262                 :            :     bool additive = getValueOrDefault(logger, "additive", config_data,
     263 [ #  # ][ #  # ]:          0 :                                       "loggers/additive")->boolValue();
         [ #  # ][ #  # ]
     264                 :            : 
     265                 :            :     isc::log::LoggerSpecification logger_spec(
     266                 :            :         lname, severity, dbg_level, additive
     267                 :          0 :     );
     268                 :            : 
     269 [ #  # ][ #  # ]:          0 :     if (logger->contains("output_options")) {
                 [ #  # ]
     270 [ #  # ][ #  # ]:          0 :         BOOST_FOREACH(ConstElementPtr output_option_el,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     271                 :            :                       logger->get("output_options")->listValue()) {
     272                 :            :             // create outputoptions
     273                 :          0 :             isc::log::OutputOption output_option;
     274                 :            :             readOutputOptionConf(output_option,
     275                 :            :                                  output_option_el,
     276         [ #  # ]:          0 :                                  config_data);
     277                 :            :             logger_spec.addOutputOption(output_option);
     278                 :            :         }
     279                 :            :     }
     280                 :            : 
     281                 :            :     specs.push_back(logger_spec);
     282                 :          0 : }
     283                 :            : 
     284                 :            : // Copies the map for a logger, changing the name of the logger in the process.
     285                 :            : // This is used because the map being copied is "const", so in order to
     286                 :            : // change the name we need to create a new one.
     287                 :            : //
     288                 :            : // \param cur_logger Logger being copied.
     289                 :            : // \param new_name New value of the "name" element at the top level.
     290                 :            : //
     291                 :            : // \return Pointer to the map with the updated element.
     292                 :            : ConstElementPtr
     293                 :         11 : copyLogger(ConstElementPtr& cur_logger, const std::string& new_name) {
     294                 :            : 
     295                 :            :     // Since we'll only be updating one first-level element and subsequent
     296                 :            :     // use won't change the contents of the map, a shallow map copy is enough.
     297                 :         11 :     ElementPtr new_logger(Element::createMap());
     298 [ +  - ][ +  - ]:         11 :     new_logger->setValue(cur_logger->mapValue());
     299 [ +  - ][ +  - ]:         22 :     new_logger->set("name", Element::create(new_name));
                 [ +  - ]
     300                 :            : 
     301                 :         11 :     return (new_logger);
     302                 :            : }
     303                 :            : 
     304                 :            : 
     305                 :            : } // end anonymous namespace
     306                 :            : 
     307                 :            : 
     308                 :            : ConstElementPtr
     309                 :         19 : getRelatedLoggers(ConstElementPtr loggers) {
     310                 :            :     // Keep a list of names for easier lookup later
     311                 :            :     std::set<std::string> our_names;
     312         [ +  - ]:         19 :     const std::string& root_name = isc::log::getRootLoggerName();
     313                 :            : 
     314         [ +  - ]:         19 :     ElementPtr result = isc::data::Element::createList();
     315                 :            : 
     316 [ +  - ][ +  + ]:        127 :     BOOST_FOREACH(ConstElementPtr cur_logger, loggers->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     317                 :            :         // Need to add the b10- prefix to names ready from the spec file.
     318 [ +  - ][ +  - ]:         54 :         const std::string cur_name = cur_logger->get("name")->stringValue();
                 [ +  - ]
     319         [ +  - ]:         54 :         const std::string mod_name = b10Prefix(cur_name);
     320 [ +  + ][ +  - ]:         27 :         if (mod_name == root_name || mod_name.find(root_name + ".") == 0) {
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
                 [ #  # ]
     321                 :            : 
     322                 :            :             // Note this name so that we don't add a wildcard that matches it.
     323                 :            :             our_names.insert(mod_name);
     324                 :            : 
     325                 :            :             // We want to store the logger with the modified name (i.e. with
     326                 :            :             // the b10- prefix).  As we are dealing with const loggers, we
     327                 :            :             // store a modified copy of the data.
     328 [ +  - ][ +  - ]:          8 :             result->add(copyLogger(cur_logger, mod_name));
     329 [ +  - ][ -  + ]:          8 :             LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS, CONFIG_LOG_EXPLICIT)
                 [ #  # ]
     330 [ #  # ][ #  # ]:          0 :                       .arg(cur_name);
     331                 :            : 
     332 [ +  - ][ +  + ]:         19 :         } else if (!cur_name.empty() && (cur_name[0] != '*')) {
                 [ +  + ]
     333                 :            :             // Not a wildcard logger and we are ignoring it.
     334 [ +  - ][ -  + ]:         11 :             LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
                 [ #  # ]
     335 [ #  # ][ #  # ]:          0 :                       CONFIG_LOG_IGNORE_EXPLICIT).arg(cur_name);
     336                 :            :         }
     337                 :            :     }
     338                 :            : 
     339                 :            :     // Now find the wildcard names (the one that start with "*").
     340 [ +  - ][ +  + ]:        127 :     BOOST_FOREACH(ConstElementPtr cur_logger, loggers->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     341 [ +  - ][ +  - ]:         54 :         std::string cur_name = cur_logger->get("name")->stringValue();
                 [ +  - ]
     342                 :            :         // If name is '*', or starts with '*.', replace * with root
     343                 :            :         // logger name.
     344 [ +  + ][ +  - ]:         56 :         if (cur_name == "*" || cur_name.length() > 1 &&
         [ +  + ][ +  + ]
                 [ +  + ]
     345                 :            :             cur_name[0] == '*' && cur_name[1] == '.') {
     346                 :            : 
     347                 :            :             // Substitute the "*" with the root name
     348         [ +  - ]:          8 :             std::string mod_name = cur_name;
     349         [ +  - ]:          4 :             mod_name.replace(0, 1, root_name);
     350                 :            : 
     351                 :            :             // Now add it to the result list, but only if a logger with
     352                 :            :             // that name was not configured explicitly.
     353         [ +  + ]:          4 :             if (our_names.find(mod_name) == our_names.end()) {
     354                 :            : 
     355                 :            :                 // We substitute the name here, but as we are dealing with
     356                 :            :                 // consts, we need to copy the data.
     357 [ +  - ][ +  - ]:          3 :                 result->add(copyLogger(cur_logger, mod_name));
     358 [ +  - ][ -  + ]:          3 :                 LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
                 [ #  # ]
     359 [ #  # ][ #  # ]:          0 :                           CONFIG_LOG_WILD_MATCH).arg(cur_name);
     360                 :            : 
     361 [ +  - ][ -  + ]:          2 :             } else if (!cur_name.empty() && (cur_name[0] == '*')) {
                 [ +  - ]
     362                 :            :                 // Is a wildcard and we are ignoring it (because the wildcard
     363                 :            :                 // expands to a specification that we already encountered when
     364                 :            :                 // processing explicit names).
     365 [ +  - ][ -  + ]:          1 :                 LOG_DEBUG(config_logger, DBG_CONFIG_PROCESS,
                 [ #  # ]
     366 [ #  # ][ #  # ]:          0 :                           CONFIG_LOG_IGNORE_WILD).arg(cur_name);
     367                 :            :             }
     368                 :            :         }
     369                 :            :     }
     370                 :         19 :     return (result);
     371                 :            : }
     372                 :            : 
     373                 :            : void
     374                 :        139 : default_logconfig_handler(const std::string& module_name,
     375                 :            :                           ConstElementPtr new_config,
     376                 :            :                           const ConfigData& config_data) {
     377         [ +  - ]:        139 :     config_data.getModuleSpec().validateConfig(new_config, true);
     378                 :            : 
     379                 :        139 :     std::vector<isc::log::LoggerSpecification> specs;
     380                 :            : 
     381 [ +  - ][ +  - ]:        139 :     if (new_config->contains("loggers")) {
                 [ +  + ]
     382 [ +  - ][ +  - ]:          4 :         ConstElementPtr loggers = getRelatedLoggers(new_config->get("loggers"));
                 [ +  - ]
     383 [ +  - ][ #  # ]:          2 :         BOOST_FOREACH(ConstElementPtr logger,
         [ #  # ][ +  - ]
         [ +  - ][ -  + ]
     384                 :            :                       loggers->listValue()) {
     385         [ #  # ]:          0 :             readLoggersConf(specs, logger, config_data);
     386                 :            :         }
     387                 :            :     }
     388                 :            : 
     389 [ +  - ][ +  - ]:        278 :     isc::log::LoggerManager logger_manager;
     390                 :            :     logger_manager.process(specs.begin(), specs.end());
     391                 :        139 : }
     392                 :            : 
     393                 :            : 
     394                 :            : ModuleSpec
     395                 :         39 : ModuleCCSession::readModuleSpecification(const std::string& filename) {
     396                 :         78 :     std::ifstream file;
     397                 :            :     ModuleSpec module_spec;
     398                 :            : 
     399                 :            :     // this file should be declared in a @something@ directive
     400         [ +  - ]:         39 :     file.open(filename.c_str());
     401         [ +  + ]:         39 :     if (!file) {
     402 [ +  - ][ +  - ]:          1 :         LOG_ERROR(config_logger, CONFIG_OPEN_FAIL).arg(filename).arg(strerror(errno));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     403 [ +  - ][ +  - ]:          2 :         isc_throw(CCSessionInitError, strerror(errno));
     404                 :            :     }
     405                 :            : 
     406                 :            :     try {
     407         [ +  + ]:         38 :         module_spec = moduleSpecFromFile(file, true);
     408                 :          0 :     } catch (const JSONError& pe) {
     409 [ #  # ][ #  # ]:          0 :         LOG_ERROR(config_logger, CONFIG_JSON_PARSE).arg(filename).arg(pe.what());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     410 [ #  # ][ #  # ]:          0 :         isc_throw(CCSessionInitError, pe.what());
     411      [ -  -  + ]:          2 :     } catch (const ModuleSpecError& dde) {
     412 [ -  + ][ +  - ]:          1 :         LOG_ERROR(config_logger, CONFIG_MOD_SPEC_FORMAT).arg(filename).arg(dde.what());
         [ -  + ][ -  + ]
         [ -  + ][ -  + ]
     413 [ -  + ][ -  + ]:          2 :         isc_throw(CCSessionInitError, dde.what());
     414                 :            :     }
     415         [ +  - ]:         37 :     file.close();
     416                 :         37 :     return (module_spec);
     417                 :            : }
     418                 :            : 
     419                 :            : void
     420                 :          0 : ModuleCCSession::startCheck() {
     421                 :            :     // data available on the command channel.  process it in the synchronous
     422                 :            :     // mode.
     423                 :          0 :     checkCommand();
     424                 :            : 
     425                 :            :     // start asynchronous read again.
     426         [ #  # ]:          0 :     session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
     427                 :          0 : }
     428                 :            : 
     429                 :         31 : ModuleCCSession::ModuleCCSession(
     430                 :            :     const std::string& spec_file_name,
     431                 :            :     isc::cc::AbstractSession& session,
     432                 :            :     isc::data::ConstElementPtr(*config_handler)(
     433                 :            :         isc::data::ConstElementPtr new_config),
     434                 :            :     isc::data::ConstElementPtr(*command_handler)(
     435                 :            :         const std::string& command, isc::data::ConstElementPtr args),
     436                 :            :     bool start_immediately,
     437                 :            :     bool handle_logging
     438                 :            :     ) :
     439                 :            :     started_(false),
     440                 :         35 :     session_(session)
     441                 :            : {
     442         [ +  + ]:         31 :     module_specification_ = readModuleSpecification(spec_file_name);
     443                 :         58 :     setModuleSpec(module_specification_);
     444                 :            : 
     445 [ +  - ][ +  - ]:         87 :     module_name_ = module_specification_.getFullSpec()->get("module_name")->stringValue();
                 [ +  - ]
     446                 :         29 :     config_handler_ = config_handler;
     447                 :         29 :     command_handler_ = command_handler;
     448                 :            : 
     449         [ +  - ]:         29 :     session_.establish(NULL);
     450 [ +  - ][ +  - ]:         29 :     session_.subscribe(module_name_, "*");
                 [ +  - ]
     451                 :            : 
     452                 :            :     // send the data specification
     453                 :            :     ConstElementPtr spec_msg = createCommand("module_spec",
     454 [ +  - ][ +  - ]:         29 :                                              module_specification_.getFullSpec());
     455 [ +  - ][ +  - ]:         87 :     unsigned int seq = session_.group_sendmsg(spec_msg, "ConfigManager");
         [ +  - ][ +  - ]
     456                 :            : 
     457                 :            :     ConstElementPtr answer, env;
     458         [ +  - ]:         29 :     session_.group_recvmsg(env, answer, false, seq);
     459                 :            :     int rcode;
     460         [ +  - ]:         29 :     ConstElementPtr err = parseAnswer(rcode, answer);
     461         [ -  + ]:         29 :     if (rcode != 0) {
     462 [ #  # ][ #  # ]:          0 :         LOG_ERROR(config_logger, CONFIG_MOD_SPEC_REJECT).arg(answer->str());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     463 [ #  # ][ #  # ]:          0 :         isc_throw(CCSessionInitError, answer->str());
                 [ #  # ]
     464                 :            :     }
     465                 :            : 
     466 [ +  - ][ +  - ]:         58 :     setLocalConfig(Element::fromJSON("{}"));
     467                 :            :     // get any stored configuration from the manager
     468         [ +  + ]:         29 :     if (config_handler_) {
     469 [ +  - ][ +  - ]:         10 :         ConstElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
                 [ +  - ]
     470 [ +  - ][ +  - ]:         15 :         seq = session_.group_sendmsg(cmd, "ConfigManager");
         [ +  - ][ +  - ]
     471         [ +  - ]:          5 :         session_.group_recvmsg(env, answer, false, seq);
     472         [ +  - ]:          5 :         ConstElementPtr new_config = parseAnswer(rcode, answer);
     473         [ +  + ]:          5 :         if (rcode == 0) {
     474         [ +  - ]:          4 :             handleConfigUpdate(new_config);
     475                 :            :         } else {
     476 [ +  - ][ +  - ]:          1 :             LOG_ERROR(config_logger, CONFIG_GET_FAIL).arg(new_config->str());
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     477 [ +  - ][ +  - ]:          2 :             isc_throw(CCSessionInitError, answer->str());
                 [ +  - ]
     478                 :            :         }
     479                 :            :     }
     480                 :            : 
     481                 :            :     // Keep track of logging settings automatically
     482         [ +  + ]:         28 :     if (handle_logging) {
     483 [ +  - ][ +  + ]:          2 :         addRemoteConfig("Logging", default_logconfig_handler, false);
     484                 :            :     }
     485                 :            : 
     486         [ +  + ]:         27 :     if (start_immediately) {
     487         [ +  - ]:         10 :         start();
     488                 :            :     }
     489                 :            : 
     490                 :         27 : }
     491                 :            : 
     492                 :         27 : ModuleCCSession::~ModuleCCSession() {
     493                 :            :     try {
     494         [ +  + ]:         27 :         sendStopping();
     495                 :          2 :     } catch (const std::exception& exc) {
     496 [ -  + ][ +  - ]:          2 :         LOG_ERROR(config_logger,
                 [ -  + ]
     497 [ -  + ][ -  + ]:          1 :                   CONFIG_CCSESSION_STOPPING).arg(exc.what());
     498 [ +  - ][ #  # ]:          1 :     } catch (...) {
     499 [ #  # ][ #  # ]:          0 :         LOG_ERROR(config_logger,
                 [ #  # ]
     500         [ #  # ]:          0 :                   CONFIG_CCSESSION_STOPPING_UNKNOWN);
     501                 :            :     }
     502                 :         41 : };
     503                 :            : 
     504                 :            : void
     505                 :         14 : ModuleCCSession::start() {
     506         [ +  + ]:         14 :     if (started_) {
     507 [ +  - ][ +  - ]:          4 :         isc_throw(CCSessionError, "Module CC session already started");
     508                 :            :     }
     509                 :            : 
     510                 :            :     // register callback for asynchronous read
     511         [ +  - ]:         12 :     session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
     512                 :            : 
     513                 :         12 :     started_ = true;
     514                 :         12 : }
     515                 :            : 
     516                 :            : /// Validates the new config values, if they are correct,
     517                 :            : /// call the config handler with the values that have changed
     518                 :            : /// If that results in success, store the new config
     519                 :            : ConstElementPtr
     520                 :          7 : ModuleCCSession::handleConfigUpdate(ConstElementPtr new_config) {
     521                 :            :     ConstElementPtr answer;
     522         [ +  - ]:          7 :     ElementPtr errors = Element::createList();
     523         [ -  + ]:          7 :     if (!config_handler_) {
     524 [ #  # ][ #  # ]:          0 :         answer = createAnswer(1, module_name_ + " does not have a config handler");
                 [ #  # ]
     525         [ +  + ]:          7 :     } else if (!module_specification_.validateConfig(new_config, false,
     526         [ +  - ]:          7 :                                                       errors)) {
     527   [ +  -  +  - ]:          2 :         std::stringstream ss;
     528         [ +  - ]:          1 :         ss << "Error in config validation: ";
     529 [ +  - ][ +  + ]:          5 :         BOOST_FOREACH(ConstElementPtr error, errors->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     530 [ +  - ][ +  - ]:          1 :             ss << error->stringValue();
     531                 :            :         }
     532 [ +  - ][ +  - ]:          2 :         answer = createAnswer(2, ss.str());
     533                 :            :     } else {
     534                 :            :         // remove the values that have not changed
     535         [ +  - ]:          6 :         ConstElementPtr diff = removeIdentical(new_config, getLocalConfig());
     536                 :            :         // handle config update
     537 [ +  - ][ +  - ]:          6 :         answer = config_handler_(diff);
     538                 :            :         int rcode;
     539         [ +  - ]:          6 :         parseAnswer(rcode, answer);
     540         [ +  + ]:          6 :         if (rcode == 0) {
     541                 :          5 :             ElementPtr local_config = getLocalConfig();
     542         [ +  - ]:          5 :             isc::data::merge(local_config, diff);
     543                 :          5 :             setLocalConfig(local_config);
     544                 :            :         }
     545                 :            :     }
     546                 :          7 :     return (answer);
     547                 :            : }
     548                 :            : 
     549                 :            : bool
     550                 :          0 : ModuleCCSession::hasQueuedMsgs() const {
     551                 :          0 :     return (session_.hasQueuedMsgs());
     552                 :            : }
     553                 :            : 
     554                 :            : ConstElementPtr
     555                 :          8 : ModuleCCSession::checkConfigUpdateCommand(const std::string& target_module,
     556                 :            :                                           ConstElementPtr arg)
     557                 :            : {
     558         [ +  + ]:          8 :     if (target_module == module_name_) {
     559         [ +  - ]:          3 :         return (handleConfigUpdate(arg));
     560                 :            :     } else {
     561                 :            :         // ok this update is not for us, if we have this module
     562                 :            :         // in our remote config list, update that
     563         [ +  - ]:          5 :         updateRemoteConfig(target_module, arg);
     564                 :            :         // we're not supposed to answer to this, so return
     565                 :            :         return (ElementPtr());
     566                 :            :     }
     567                 :            : }
     568                 :            : 
     569                 :            : ConstElementPtr
     570                 :          8 : ModuleCCSession::checkModuleCommand(const std::string& cmd_str,
     571                 :            :                                     const std::string& target_module,
     572                 :            :                                     ConstElementPtr arg) const
     573                 :            : {
     574         [ +  + ]:          8 :     if (target_module == module_name_) {
     575         [ +  + ]:          7 :         if (command_handler_) {
     576                 :          6 :             ElementPtr errors = Element::createList();
     577 [ +  - ][ +  + ]:         12 :             if (module_specification_.validateCommand(cmd_str,
     578                 :            :                                                        arg,
     579                 :          6 :                                                        errors)) {
     580         [ +  - ]:          5 :                 return (command_handler_(cmd_str, arg));
     581                 :            :             } else {
     582   [ +  -  +  - ]:          2 :                 std::stringstream ss;
     583         [ +  - ]:          1 :                 ss << "Error in command validation: ";
     584 [ +  - ][ +  + ]:          5 :                 BOOST_FOREACH(ConstElementPtr error,
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     585                 :            :                               errors->listValue()) {
     586 [ +  - ][ +  - ]:          1 :                     ss << error->stringValue();
     587                 :            :                 }
     588         [ +  - ]:          1 :                 return (createAnswer(3, ss.str()));
     589                 :            :             }
     590                 :            :         } else {
     591                 :            :             return (createAnswer(1,
     592                 :            :                                  "Command given but no "
     593         [ +  - ]:          1 :                                  "command handler for module"));
     594                 :            :         }
     595                 :            :     }
     596                 :            :     return (ElementPtr());
     597                 :            : }
     598                 :            : 
     599                 :            : int
     600                 :         19 : ModuleCCSession::checkCommand() {
     601                 :            :     ConstElementPtr cmd, routing, data;
     602 [ +  - ][ +  + ]:         19 :     if (session_.group_recvmsg(routing, data, true)) {
     603                 :            : 
     604                 :            :         /* ignore result messages (in case we're out of sync, to prevent
     605                 :            :          * pingpongs */
     606 [ +  + ][ +  - ]:         18 :         if (data->getType() != Element::map || data->contains("result")) {
         [ +  - ][ -  + ]
         [ +  + ][ +  + ]
                 [ #  # ]
     607                 :            :             return (0);
     608                 :            :         }
     609                 :            :         ConstElementPtr arg;
     610                 :            :         ConstElementPtr answer;
     611                 :            :         try {
     612         [ +  + ]:         33 :             std::string cmd_str = parseCommand(arg, data);
     613 [ +  - ][ +  - ]:         48 :             std::string target_module = routing->get("group")->stringValue();
                 [ +  - ]
     614         [ +  + ]:         16 :             if (cmd_str == "config_update") {
     615 [ +  - ][ +  - ]:          8 :                 answer = checkConfigUpdateCommand(target_module, arg);
     616                 :            :             } else {
     617 [ +  - ][ +  - ]:          8 :                 answer = checkModuleCommand(cmd_str, target_module, arg);
     618                 :            :             }
     619         [ +  - ]:          2 :         } catch (const CCSessionError& re) {
     620 [ -  + ][ +  - ]:          1 :             LOG_ERROR(config_logger, CONFIG_CCSESSION_MSG).arg(re.what());
         [ -  + ][ -  + ]
                 [ -  + ]
     621      [ -  +  - ]:          1 :         } catch (const std::exception& stde) {
     622                 :            :             // No matter what unexpected error happens, we do not want
     623                 :            :             // to crash because of an incoming event, so we log the
     624                 :            :             // exception and continue to run
     625 [ #  # ][ #  # ]:          0 :             LOG_ERROR(config_logger, CONFIG_CCSESSION_MSG_INTERNAL).arg(stde.what());
         [ #  # ][ #  # ]
                 [ #  # ]
     626                 :            :         }
     627 [ +  - ][ +  + ]:         34 :         if (!isNull(answer)) {
     628         [ +  - ]:         10 :             session_.reply(routing, answer);
     629                 :            :         }
     630                 :            :     }
     631                 :            : 
     632                 :            :     return (0);
     633                 :            : }
     634                 :            : 
     635                 :            : ModuleSpec
     636                 :         21 : ModuleCCSession::fetchRemoteSpec(const std::string& module, bool is_filename) {
     637         [ +  + ]:         21 :     if (is_filename) {
     638                 :            :         // It is a filename, simply load it.
     639                 :          8 :         return (readModuleSpecification(module));
     640                 :            :     } else {
     641                 :            :         // It's module name, request it from config manager
     642                 :            : 
     643                 :            :         // Send the command
     644                 :            :         ConstElementPtr cmd(createCommand("get_module_spec",
     645                 :         13 :                             Element::fromJSON("{\"module_name\": \"" + module +
     646 [ +  - ][ +  - ]:         39 :                                               "\"}")));
         [ +  - ][ +  - ]
     647 [ +  - ][ +  - ]:         39 :         unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
         [ +  - ][ +  - ]
     648                 :            :         ConstElementPtr env, answer;
     649         [ +  - ]:         13 :         session_.group_recvmsg(env, answer, false, seq);
     650                 :            :         int rcode;
     651         [ +  - ]:         13 :         ConstElementPtr spec_data = parseAnswer(rcode, answer);
     652 [ +  - ][ -  + ]:         26 :         if (rcode == 0 && spec_data) {
                 [ +  - ]
     653                 :            :             // received OK, construct the spec out of it
     654         [ +  + ]:         13 :             ModuleSpec spec = ModuleSpec(spec_data);
     655   [ +  -  +  + ]:         24 :             if (module != spec.getModuleName()) {
     656                 :            :                 // It's a different module!
     657 [ +  - ][ +  - ]:          2 :                 isc_throw(CCSessionError, "Module name mismatch");
                 [ +  - ]
     658                 :            :             }
     659                 :            :             return (spec);
     660                 :            :         } else {
     661 [ #  # ][ #  # ]:          0 :             isc_throw(CCSessionError, "Error getting config for " +
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     662                 :            :                       module + ": " + answer->str());
     663                 :            :         }
     664                 :            :     }
     665                 :            : }
     666                 :            : 
     667                 :            : std::string
     668                 :         21 : ModuleCCSession::addRemoteConfig(const std::string& spec_name,
     669                 :            :                                  void (*handler)(const std::string& module,
     670                 :            :                                                  ConstElementPtr,
     671                 :            :                                                  const ConfigData&),
     672                 :            :                                  bool spec_is_filename)
     673                 :            : {
     674                 :            :     // First get the module name, specification and default config
     675                 :         21 :     const ModuleSpec rmod_spec(fetchRemoteSpec(spec_name, spec_is_filename));
     676         [ +  - ]:         23 :     const std::string module_name(rmod_spec.getModuleName());
     677         [ +  - ]:         19 :     ConfigData rmod_config(rmod_spec);
     678                 :            : 
     679                 :            :     // Get the current configuration values from config manager
     680                 :            :     ConstElementPtr cmd(createCommand("get_config",
     681                 :            :                         Element::fromJSON("{\"module_name\": \"" +
     682 [ +  - ][ +  - ]:         57 :                                           module_name + "\"}")));
         [ +  - ][ +  - ]
                 [ +  - ]
     683 [ +  - ][ +  - ]:         57 :     const unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
         [ +  - ][ +  - ]
     684                 :            : 
     685                 :            :     ConstElementPtr env, answer;
     686         [ +  + ]:         19 :     session_.group_recvmsg(env, answer, false, seq);
     687                 :            :     int rcode;
     688         [ +  + ]:         18 :     ConstElementPtr new_config = parseAnswer(rcode, answer);
     689                 :            :     ElementPtr local_config;
     690 [ +  + ][ +  + ]:         33 :     if (rcode == 0 && new_config) {
                 [ +  + ]
     691                 :            :         // Merge the received config into existing local config
     692         [ +  - ]:         15 :         local_config = rmod_config.getLocalConfig();
     693         [ +  - ]:         15 :         isc::data::merge(local_config, new_config);
     694                 :            :         rmod_config.setLocalConfig(local_config);
     695                 :            :     } else {
     696 [ +  - ][ +  - ]:          4 :         isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     697                 :            :     }
     698                 :            : 
     699                 :            :     // all ok, add it
     700         [ +  - ]:         15 :     remote_module_configs_[module_name] = rmod_config;
     701         [ +  + ]:         15 :     if (handler) {
     702                 :         22 :         remote_module_handlers_[module_name] = handler;
     703         [ +  - ]:         11 :         handler(module_name, local_config, rmod_config);
     704                 :            :     }
     705                 :            : 
     706                 :            :     // Make sure we get updates in future
     707 [ +  - ][ +  - ]:         15 :     session_.subscribe(module_name);
                 [ +  - ]
     708                 :         15 :     return (module_name);
     709                 :            : }
     710                 :            : 
     711                 :            : void
     712                 :         13 : ModuleCCSession::removeRemoteConfig(const std::string& module_name) {
     713                 :            :     std::map<std::string, ConfigData>::iterator it;
     714                 :            : 
     715                 :         13 :     it = remote_module_configs_.find(module_name);
     716         [ +  - ]:         13 :     if (it != remote_module_configs_.end()) {
     717                 :         13 :         remote_module_configs_.erase(it);
     718                 :         13 :         remote_module_handlers_.erase(module_name);
     719 [ +  - ][ +  - ]:         13 :         session_.unsubscribe(module_name);
     720                 :            :     }
     721                 :         13 : }
     722                 :            : 
     723                 :            : ConstElementPtr
     724                 :          9 : ModuleCCSession::getRemoteConfigValue(const std::string& module_name,
     725                 :            :                                       const std::string& identifier) const
     726                 :            : {
     727                 :            :     std::map<std::string, ConfigData>::const_iterator it =
     728                 :         18 :         remote_module_configs_.find(module_name);
     729                 :            : 
     730         [ +  + ]:          9 :     if (it != remote_module_configs_.end()) {
     731                 :          8 :         return ((*it).second.getValue(identifier));
     732                 :            :     } else {
     733 [ +  - ][ +  - ]:          2 :         isc_throw(CCSessionError,
         [ +  - ][ +  - ]
     734                 :            :                   "Remote module " + module_name + " not found.");
     735                 :            :     }
     736                 :            : }
     737                 :            : 
     738                 :            : void
     739                 :          5 : ModuleCCSession::updateRemoteConfig(const std::string& module_name,
     740                 :            :                                     ConstElementPtr new_config)
     741                 :            : {
     742                 :            :     std::map<std::string, ConfigData>::iterator it;
     743                 :            : 
     744                 :          5 :     it = remote_module_configs_.find(module_name);
     745         [ +  - ]:          5 :     if (it != remote_module_configs_.end()) {
     746                 :          5 :         ElementPtr rconf = (*it).second.getLocalConfig();
     747         [ +  - ]:          5 :         isc::data::merge(rconf, new_config);
     748                 :            :         std::map<std::string, RemoteHandler>::iterator hit =
     749                 :         10 :             remote_module_handlers_.find(module_name);
     750         [ +  + ]:          5 :         if (hit != remote_module_handlers_.end()) {
     751         [ +  - ]:          4 :             hit->second(module_name, new_config, it->second);
     752                 :            :         }
     753                 :            :     }
     754                 :          5 : }
     755                 :            : 
     756                 :            : void
     757                 :         27 : ModuleCCSession::sendStopping() {
     758                 :            :     // Inform the configuration manager that this module is stopping
     759                 :            :     ConstElementPtr cmd(createCommand("stopping",
     760                 :            :                                       Element::fromJSON(
     761                 :            :                                           "{\"module_name\": \"" +
     762 [ +  - ][ +  - ]:         81 :                                           module_name_ + "\"}")));
         [ +  - ][ +  - ]
     763                 :            :     // It's just an FYI, configmanager is not expected to respond.
     764 [ +  - ][ +  - ]:         81 :     session_.group_sendmsg(cmd, "ConfigManager");
         [ +  - ][ +  + ]
     765                 :         26 : }
     766                 :            : 
     767                 :            : }
     768                 :        111 : }

Generated by: LCOV version 1.9