daemon/dtnd.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2004-2006 Intel Corporation
       
     3  * 
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  * 
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  * 
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 #ifdef HAVE_CONFIG_H
       
    18 #  include <dtn-config.h>
       
    19 #endif
       
    20 
       
    21 #include <errno.h>
       
    22 #include <string>
       
    23 #include <sys/time.h>
       
    24 
       
    25 #include <oasys/debug/Log.h>
       
    26 #include <oasys/io/NetUtils.h>
       
    27 #include <oasys/tclcmd/ConsoleCommand.h>
       
    28 #include <oasys/tclcmd/TclCommand.h>
       
    29 #include <oasys/thread/Timer.h>
       
    30 #include <oasys/util/App.h>
       
    31 #include <oasys/util/Getopt.h>
       
    32 #include <oasys/util/StringBuffer.h>
       
    33 
       
    34 #include "applib/APIServer.h"
       
    35 #include "cmd/TestCommand.h"
       
    36 #include "servlib/DTNServer.h"
       
    37 #include "storage/DTNStorageConfig.h"
       
    38 #include "bundling/BundleDaemon.h"
       
    39 
       
    40 #include "bundling/S10Logger.h"
       
    41 
       
    42 extern const char* dtn_version;
       
    43 
       
    44 /**
       
    45  * Namespace for the dtn daemon source code.
       
    46  */
       
    47 namespace dtn {
       
    48 
       
    49 /**
       
    50  * Thin class that implements the daemon itself.
       
    51  */
       
    52 class DTND : public oasys::App {
       
    53 public:
       
    54     DTND();
       
    55     int main(int argc, char* argv[]);
       
    56 
       
    57 protected:
       
    58     TestCommand*          testcmd_;
       
    59     oasys::ConsoleCommand* consolecmd_;
       
    60     DTNStorageConfig      storage_config_;
       
    61     
       
    62     // virtual from oasys::App
       
    63     void fill_options();
       
    64     
       
    65     void init_testcmd(int argc, char* argv[]);
       
    66     void run_console();
       
    67 };
       
    68 
       
    69 //----------------------------------------------------------------------
       
    70 DTND::DTND()
       
    71     : App("DTND", "dtnd", dtn_version),
       
    72       testcmd_(NULL),
       
    73       consolecmd_(NULL),
       
    74       storage_config_("storage",			// command name
       
    75                       "berkeleydb",			// storage type
       
    76                       "DTN",				// DB name
       
    77                       INSTALL_LOCALSTATEDIR "/dtn/db")	// DB directory
       
    78 {
       
    79     // override default logging settings
       
    80     loglevel_ = oasys::LOG_NOTICE;
       
    81     debugpath_ = "~/.dtndebug";
       
    82     
       
    83     // override defaults from oasys storage config
       
    84     storage_config_.db_max_tx_ = 1000;
       
    85 
       
    86     testcmd_    = new TestCommand();
       
    87     consolecmd_ = new oasys::ConsoleCommand("dtn% ");
       
    88 }
       
    89 
       
    90 //----------------------------------------------------------------------
       
    91 void
       
    92 DTND::fill_options()
       
    93 {
       
    94     fill_default_options(DAEMONIZE_OPT | CONF_FILE_OPT);
       
    95     
       
    96     opts_.addopt(
       
    97         new oasys::BoolOpt('t', "tidy", &storage_config_.tidy_,
       
    98                            "clear database and initialize tables on startup"));
       
    99 
       
   100     opts_.addopt(
       
   101         new oasys::BoolOpt(0, "init-db", &storage_config_.init_,
       
   102                            "initialize database on startup"));
       
   103 
       
   104     opts_.addopt(
       
   105         new oasys::InAddrOpt(0, "console-addr", &consolecmd_->addr_, "<addr>",
       
   106                              "set the console listening addr (default off)"));
       
   107     
       
   108     opts_.addopt(
       
   109         new oasys::UInt16Opt(0, "console-port", &consolecmd_->port_, "<port>",
       
   110                              "set the console listening port (default off)"));
       
   111     
       
   112     opts_.addopt(
       
   113         new oasys::IntOpt('i', 0, &testcmd_->id_, "<id>",
       
   114                           "set the test id"));
       
   115 }
       
   116 
       
   117 //----------------------------------------------------------------------
       
   118 void
       
   119 DTND::init_testcmd(int argc, char* argv[])
       
   120 {
       
   121     for (int i = 0; i < argc; ++i) {
       
   122         testcmd_->argv_.append(argv[i]);
       
   123         testcmd_->argv_.append(" ");
       
   124     }
       
   125 
       
   126     testcmd_->bind_vars();
       
   127     oasys::TclCommandInterp::instance()->reg(testcmd_);
       
   128 }
       
   129 
       
   130 //----------------------------------------------------------------------
       
   131 void
       
   132 DTND::run_console()
       
   133 {
       
   134     // launch the console server
       
   135     if (consolecmd_->port_ != 0) {
       
   136         log_info_p("/dtnd", "starting console on %s:%d",
       
   137                    intoa(consolecmd_->addr_), consolecmd_->port_);
       
   138         
       
   139         oasys::TclCommandInterp::instance()->
       
   140             command_server(consolecmd_->prompt_.c_str(),
       
   141                            consolecmd_->addr_, consolecmd_->port_);
       
   142     }
       
   143     
       
   144     if (daemonize_ || (consolecmd_->stdio_ == false)) {
       
   145         oasys::TclCommandInterp::instance()->event_loop();
       
   146     } else {
       
   147         oasys::TclCommandInterp::instance()->
       
   148             command_loop(consolecmd_->prompt_.c_str());
       
   149     }
       
   150 }
       
   151 
       
   152 //----------------------------------------------------------------------
       
   153 int
       
   154 DTND::main(int argc, char* argv[])
       
   155 {
       
   156     init_app(argc, argv);
       
   157 
       
   158     log_notice_p("/dtnd", "DTN daemon starting up... (pid %d)", getpid());
       
   159 
       
   160 
       
   161     if (oasys::TclCommandInterp::init(argv[0], "/dtn/tclcmd") != 0)
       
   162     {
       
   163         log_crit_p("/dtnd", "Can't init TCL");
       
   164         notify_and_exit(1);
       
   165     }
       
   166 
       
   167     // stop thread creation b/c of initialization dependencies
       
   168     oasys::Thread::activate_start_barrier();
       
   169 
       
   170     DTNServer* dtnserver = new DTNServer("/dtnd", &storage_config_);
       
   171     APIServer* apiserver = new APIServer();
       
   172 
       
   173     dtnserver->init();
       
   174 
       
   175     oasys::TclCommandInterp::instance()->reg(consolecmd_);
       
   176     init_testcmd(argc, argv);
       
   177 
       
   178     if (! dtnserver->parse_conf_file(conf_file_, conf_file_set_)) {
       
   179         log_err_p("/dtnd", "error in configuration file, exiting...");
       
   180         notify_and_exit(1);
       
   181     }
       
   182 
       
   183     if (storage_config_.init_)
       
   184     {
       
   185         log_notice_p("/dtnd", "initializing persistent data store");
       
   186     }
       
   187 
       
   188     if (! dtnserver->init_datastore()) {
       
   189         log_err_p("/dtnd", "error initializing data store, exiting...");
       
   190         notify_and_exit(1);
       
   191     }
       
   192     
       
   193     // If we're running as --init-db, make an empty database and exit
       
   194     if (storage_config_.init_ && !storage_config_.tidy_)
       
   195     {
       
   196         dtnserver->close_datastore();
       
   197         log_info_p("/dtnd", "database initialization complete.");
       
   198         notify_and_exit(0);
       
   199     }
       
   200     
       
   201     if (BundleDaemon::instance()->local_eid().equals(EndpointID::NULL_EID()))
       
   202     {
       
   203         log_err_p("/dtnd", "no local eid specified; use the 'route local_eid' command");
       
   204         notify_and_exit(1);
       
   205     }
       
   206 	s10_setlocal(BundleDaemon::instance()->local_eid().c_str());
       
   207 	s10_daemon(S10_STARTING);
       
   208 
       
   209     // if we've daemonized, now is the time to notify our parent
       
   210     // process that we've successfully initialized
       
   211     if (daemonize_) {
       
   212         daemonizer_.notify_parent(0);
       
   213     }
       
   214     
       
   215     dtnserver->start();
       
   216     if (apiserver->enabled()) {
       
   217         apiserver->bind_listen_start(apiserver->local_addr(), 
       
   218                                      apiserver->local_port());
       
   219     }
       
   220     oasys::Thread::release_start_barrier(); // run blocked threads
       
   221 
       
   222     // if the test script specified something to run for the test,
       
   223     // then execute it now
       
   224     if (testcmd_->initscript_.length() != 0) {
       
   225         oasys::TclCommandInterp::instance()->
       
   226             exec_command(testcmd_->initscript_.c_str());
       
   227     }
       
   228 
       
   229     // allow startup messages to be flushed to standard-out before
       
   230     // the prompt is displayed
       
   231     oasys::Thread::yield();
       
   232     usleep(500000);
       
   233     
       
   234     run_console();
       
   235 
       
   236     log_notice_p("/dtnd", "command loop exited... shutting down daemon");
       
   237 
       
   238     apiserver->stop();
       
   239     
       
   240     oasys::TclCommandInterp::shutdown();
       
   241     dtnserver->shutdown();
       
   242     
       
   243     // close out servers
       
   244     delete dtnserver;
       
   245     // don't delete apiserver; keep it around so slow APIClients can finish
       
   246     
       
   247     // give other threads (like logging) a moment to catch up before exit
       
   248     oasys::Thread::yield();
       
   249     sleep(1);
       
   250     
       
   251     // kill logging
       
   252     oasys::Log::shutdown();
       
   253     
       
   254     return 0;
       
   255 }
       
   256 
       
   257 } // namespace dtn
       
   258 
       
   259 int
       
   260 main(int argc, char* argv[])
       
   261 {
       
   262     dtn::DTND dtnd;
       
   263     dtnd.main(argc, argv);
       
   264 }