IBR-DTNSuite 0.6

daemon/src/Main.cpp

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include <ibrcommon/data/BLOB.h>
00004 #include <ibrcommon/data/File.h>
00005 #include <ibrcommon/AutoDelete.h>
00006 #include <ibrcommon/net/vinterface.h>
00007 #include <ibrcommon/Logger.h>
00008 #include <ibrcommon/net/LinkManager.h>
00009 #include <ibrdtn/utils/Clock.h>
00010 #include <list>
00011 
00012 #include "core/BundleCore.h"
00013 #include "core/EventSwitch.h"
00014 #include "core/BundleStorage.h"
00015 #include "core/MemoryBundleStorage.h"
00016 #include "core/SimpleBundleStorage.h"
00017 
00018 #include "core/Node.h"
00019 #include "core/EventSwitch.h"
00020 #include "core/GlobalEvent.h"
00021 #include "core/NodeEvent.h"
00022 
00023 #include "routing/BaseRouter.h"
00024 #include "routing/StaticRoutingExtension.h"
00025 #include "routing/NeighborRoutingExtension.h"
00026 #include "routing/epidemic/EpidemicRoutingExtension.h"
00027 #include "routing/flooding/FloodRoutingExtension.h"
00028 #include "routing/RetransmissionExtension.h"
00029 
00030 #include "net/UDPConvergenceLayer.h"
00031 #include "net/TCPConvergenceLayer.h"
00032 
00033 #ifdef HAVE_SQLITE
00034 #include "core/SQLiteBundleStorage.h"
00035 #endif
00036 
00037 #ifdef HAVE_LIBCURL
00038 #include "net/HTTPConvergenceLayer.h"
00039 #endif
00040 
00041 #ifdef HAVE_LOWPAN_SUPPORT
00042 #include "net/LOWPANConvergenceLayer.h"
00043 #endif
00044 
00045 #include "net/IPNDAgent.h"
00046 
00047 #include "api/ApiServer.h"
00048 
00049 #include "Configuration.h"
00050 #include "EchoWorker.h"
00051 #include "CapsuleWorker.h"
00052 #include "Notifier.h"
00053 #include "DevNull.h"
00054 #include "StatisticLogger.h"
00055 #include "Component.h"
00056 
00057 #ifdef WITH_BUNDLE_SECURITY
00058 #include "security/SecurityManager.h"
00059 #include "security/SecurityKeyManager.h"
00060 #endif
00061 
00062 #ifdef WITH_TLS
00063 #include "security/SecurityCertificateManager.h"
00064 #include "security/TLSStreamComponent.h"
00065 #endif
00066 
00067 #ifdef HAVE_LIBDAEMON
00068 #include <libdaemon/daemon.h>
00069 #include <string.h>
00070 #endif
00071 
00072 #include <csignal>
00073 #include <sys/types.h>
00074 #include <syslog.h>
00075 #include <set>
00076 #include <pwd.h>
00077 
00078 using namespace dtn::core;
00079 using namespace dtn::daemon;
00080 using namespace dtn::utils;
00081 using namespace dtn::net;
00082 
00083 #include "Debugger.h"
00084 
00085 #define UNIT_MB * 1048576
00086 
00091 // logging options
00092 unsigned char logopts = ibrcommon::Logger::LOG_DATETIME | ibrcommon::Logger::LOG_LEVEL;
00093 
00094 // error filter
00095 const unsigned char logerr = ibrcommon::Logger::LOGGER_ERR | ibrcommon::Logger::LOGGER_CRIT;
00096 
00097 // logging filter, everything but debug, err and crit
00098 const unsigned char logstd = ~(ibrcommon::Logger::LOGGER_DEBUG | ibrcommon::Logger::LOGGER_ERR | ibrcommon::Logger::LOGGER_CRIT);
00099 
00100 // syslog filter, everything but DEBUG and NOTICE
00101 const unsigned char logsys = ~(ibrcommon::Logger::LOGGER_DEBUG | ibrcommon::Logger::LOGGER_NOTICE);
00102 
00103 // debug off by default
00104 bool _debug = false;
00105 
00106 // on interruption do this!
00107 void sighandler(int signal)
00108 {
00109         switch (signal)
00110         {
00111         case SIGTERM:
00112         case SIGINT:
00113                 dtn::core::GlobalEvent::raise(dtn::core::GlobalEvent::GLOBAL_SHUTDOWN);
00114                 break;
00115         case SIGUSR1:
00116                 // activate debugging
00117                 // init logger
00118                 ibrcommon::Logger::setVerbosity(99);
00119                 IBRCOMMON_LOGGER(info) << "debug level set to 99" << IBRCOMMON_LOGGER_ENDL;
00120 
00121                 if (!_debug)
00122                 {
00123                         ibrcommon::Logger::addStream(std::cout, ibrcommon::Logger::LOGGER_DEBUG, logopts);
00124                         _debug = true;
00125                 }
00126                 break;
00127         case SIGUSR2:
00128                 // activate debugging
00129                 // init logger
00130                 ibrcommon::Logger::setVerbosity(0);
00131                 IBRCOMMON_LOGGER(info) << "debug level set to 0" << IBRCOMMON_LOGGER_ENDL;
00132                 break;
00133         case SIGHUP:
00134                 // send shutdown signal to unbound threads
00135                 dtn::core::GlobalEvent::raise(dtn::core::GlobalEvent::GLOBAL_RELOAD);
00136                 break;
00137         default:
00138                 // dummy handler
00139                 break;
00140         }
00141 }
00142 
00143 void switchUser(Configuration &config)
00144 {
00145         try {
00146                 // get the username if set
00147                 std::string username = config.getUser();
00148 
00149                 // resolve the username to a valid user id
00150                 struct passwd *pw = getpwnam(username.c_str());
00151 
00152                 if (pw != NULL)
00153                 {
00154                         if (setuid( pw->pw_uid ) < 0) return;
00155                         setgid( pw->pw_gid );
00156 
00157                         IBRCOMMON_LOGGER(info) << "Switching user to " << username << IBRCOMMON_LOGGER_ENDL;
00158                         return;
00159                 }
00160         } catch (const Configuration::ParameterNotSetException&) { }
00161 
00162         try {
00163                 setuid( config.getUID() );
00164                 IBRCOMMON_LOGGER(info) << "Switching UID to " << config.getUID() << IBRCOMMON_LOGGER_ENDL;
00165         } catch (const Configuration::ParameterNotSetException&) { }
00166 
00167         try {
00168                 setgid( config.getGID() );
00169                 IBRCOMMON_LOGGER(info) << "Switching GID to " << config.getGID() << IBRCOMMON_LOGGER_ENDL;
00170         } catch (const Configuration::ParameterNotSetException&) { }
00171 }
00172 
00173 void setGlobalVars(Configuration &config)
00174 {
00175     // set the timezone
00176     dtn::utils::Clock::timezone = config.getTimezone();
00177 
00178     // set local eid
00179     dtn::core::BundleCore::local = config.getNodename();
00180     IBRCOMMON_LOGGER(info) << "Local node name: " << config.getNodename() << IBRCOMMON_LOGGER_ENDL;
00181 
00182     // set block size limit
00183     dtn::core::BundleCore::blocksizelimit = config.getLimit("blocksize");
00184     if (dtn::core::BundleCore::blocksizelimit > 0)
00185     {
00186         IBRCOMMON_LOGGER(info) << "Block size limited to " << dtn::core::BundleCore::blocksizelimit << " bytes" << IBRCOMMON_LOGGER_ENDL;
00187     }
00188 }
00189 
00190 void initialize_blobs(Configuration &config)
00191 {
00192     try {
00193         // the configured BLOB path
00194         ibrcommon::File blob_path = config.getPath("blob");
00195 
00196         // check if the BLOB path exists
00197         if (blob_path.exists())
00198         {
00199                 if (blob_path.isDirectory())
00200                 {
00201                         IBRCOMMON_LOGGER(info) << "using BLOB path: " << blob_path.getPath() << IBRCOMMON_LOGGER_ENDL;
00202                         ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), false);
00203                 }
00204                 else
00205                 {
00206                         IBRCOMMON_LOGGER(warning) << "BLOB path exists, but is not a directory! Fallback to memory based mode." << IBRCOMMON_LOGGER_ENDL;
00207                 }
00208         }
00209         else
00210         {
00211                 // try to create the BLOB path
00212                 ibrcommon::File::createDirectory(blob_path);
00213 
00214                 if (blob_path.exists())
00215                 {
00216                         IBRCOMMON_LOGGER(info) << "using BLOB path: " << blob_path.getPath() << IBRCOMMON_LOGGER_ENDL;
00217                         ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), false);
00218                 }
00219                 else
00220                 {
00221                         IBRCOMMON_LOGGER(warning) << "Could not create BLOB path! Fallback to memory based mode." << IBRCOMMON_LOGGER_ENDL;
00222                 }
00223         }
00224     } catch (const Configuration::ParameterNotSetException&) {
00225     }
00226 }
00227 
00228 void createBundleStorage(BundleCore &core, Configuration &conf, std::list< dtn::daemon::Component* > &components)
00229 {
00230         dtn::core::BundleStorage *storage = NULL;
00231 
00232 #ifdef HAVE_SQLITE
00233         if (conf.getStorage() == "sqlite")
00234         {
00235                 try {
00236                         // new methods for blobs
00237                         ibrcommon::File path = conf.getPath("storage");
00238 
00239                         // create workdir if needed
00240                         if (!path.exists())
00241                         {
00242                                 ibrcommon::File::createDirectory(path);
00243                         }
00244 
00245                         IBRCOMMON_LOGGER(info) << "using sqlite bundle storage in " << path.getPath() << IBRCOMMON_LOGGER_ENDL;
00246 
00247                         dtn::core::SQLiteBundleStorage *sbs = new dtn::core::SQLiteBundleStorage(path, conf.getLimit("storage") );
00248 
00249                         // use sqlite storage as BLOB provider, auto delete off
00250                         ibrcommon::BLOB::changeProvider(sbs, false);
00251 
00252                         components.push_back(sbs);
00253                         storage = sbs;
00254                 } catch (const Configuration::ParameterNotSetException&) {
00255                         IBRCOMMON_LOGGER(error) << "storage for bundles" << IBRCOMMON_LOGGER_ENDL;
00256                         exit(-1);
00257                 }
00258         }
00259 #endif
00260 
00261         if ((conf.getStorage() == "simple") || (conf.getStorage() == "default"))
00262         {
00263                 // default behavior if no bundle storage is set
00264                 try {
00265                         // new methods for blobs
00266                         ibrcommon::File path = conf.getPath("storage");
00267 
00268                         // create workdir if needed
00269                         if (!path.exists())
00270                         {
00271                                 ibrcommon::File::createDirectory(path);
00272                         }
00273 
00274                         IBRCOMMON_LOGGER(info) << "using simple bundle storage in " << path.getPath() << IBRCOMMON_LOGGER_ENDL;
00275 
00276                         dtn::core::SimpleBundleStorage *sbs = new dtn::core::SimpleBundleStorage(path, conf.getLimit("storage"), conf.getLimit("storage_buffer"));
00277 
00278                         // initialize BLOB mechanism
00279                         initialize_blobs(conf);
00280 
00281                         components.push_back(sbs);
00282                         storage = sbs;
00283                 } catch (const Configuration::ParameterNotSetException&) {
00284                         IBRCOMMON_LOGGER(info) << "using bundle storage in memory-only mode" << IBRCOMMON_LOGGER_ENDL;
00285 
00286                         dtn::core::MemoryBundleStorage *sbs = new dtn::core::MemoryBundleStorage(conf.getLimit("storage"));
00287 
00288                         // initialize BLOB mechanism
00289                         initialize_blobs(conf);
00290 
00291                         components.push_back(sbs);
00292                         storage = sbs;
00293                 }
00294         }
00295 
00296         if (storage == NULL)
00297         {
00298                 IBRCOMMON_LOGGER(error) << "bundle storage module \"" << conf.getStorage() << "\" do not exists!" << IBRCOMMON_LOGGER_ENDL;
00299                 exit(-1);
00300         }
00301 
00302         // set the storage in the core
00303         core.setStorage(storage);
00304 }
00305 
00306 void createConvergenceLayers(BundleCore &core, Configuration &conf, std::list< dtn::daemon::Component* > &components, dtn::net::IPNDAgent *ipnd)
00307 {
00308         // get the configuration of the convergence layers
00309         const std::list<Configuration::NetConfig> &nets = conf.getNetwork().getInterfaces();
00310 
00311         // local cl map
00312         std::map<Configuration::NetConfig::NetType, dtn::net::ConvergenceLayer*> _cl_map;
00313 
00314         // create the convergence layers
00315         for (std::list<Configuration::NetConfig>::const_iterator iter = nets.begin(); iter != nets.end(); iter++)
00316         {
00317                 const Configuration::NetConfig &net = (*iter);
00318 
00319                 try {
00320                         switch (net.type)
00321                         {
00322                                 case Configuration::NetConfig::NETWORK_UDP:
00323                                 {
00324                                         try {
00325                                                 UDPConvergenceLayer *udpcl = new UDPConvergenceLayer( net.interface, net.port );
00326                                                 core.addConvergenceLayer(udpcl);
00327                                                 components.push_back(udpcl);
00328                                                 if (ipnd != NULL) ipnd->addService(udpcl);
00329 
00330                                                 IBRCOMMON_LOGGER(info) << "UDP ConvergenceLayer added on " << net.interface.toString() << ":" << net.port << IBRCOMMON_LOGGER_ENDL;
00331                                         } catch (const ibrcommon::Exception &ex) {
00332                                                 IBRCOMMON_LOGGER(error) << "Failed to add UDP ConvergenceLayer on " << net.interface.toString() << ": " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00333                                         }
00334 
00335                                         break;
00336                                 }
00337 
00338                                 case Configuration::NetConfig::NETWORK_TCP:
00339                                 {
00340                                         // look for an earlier instance of
00341                                         std::map<Configuration::NetConfig::NetType, dtn::net::ConvergenceLayer*>::iterator it = _cl_map.find(net.type);
00342 
00343                                         if (it == _cl_map.end())
00344                                         {
00345                                                 try {
00346                                                         TCPConvergenceLayer *tcpcl = new TCPConvergenceLayer();
00347                                                         tcpcl->bind(net.interface, net.port);
00348 
00349                                                         core.addConvergenceLayer(tcpcl);
00350                                                         components.push_back(tcpcl);
00351                                                         if (ipnd != NULL) ipnd->addService(tcpcl);
00352                                                         _cl_map[net.type] = tcpcl;
00353                                                         IBRCOMMON_LOGGER(info) << "TCP ConvergenceLayer added on " << net.interface.toString() << ":" << net.port << IBRCOMMON_LOGGER_ENDL;
00354                                                 } catch (const ibrcommon::Exception &ex) {
00355                                                         IBRCOMMON_LOGGER(error) << "Failed to add TCP ConvergenceLayer on " << net.interface.toString() << ": " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00356                                                 }
00357                                         }
00358                                         else
00359                                         {
00360                                                 ConvergenceLayer *cl = it->second;
00361                                                 TCPConvergenceLayer &tcpcl = dynamic_cast<TCPConvergenceLayer&>(*(cl));
00362                                                 tcpcl.bind(net.interface, net.port);
00363                                         }
00364 
00365                                         break;
00366                                 }
00367 
00368 #ifdef HAVE_LIBCURL
00369                                 case Configuration::NetConfig::NETWORK_HTTP:
00370                                 {
00371                                         try {
00372                                                 HTTPConvergenceLayer *httpcl = new HTTPConvergenceLayer( net.url );
00373                                                 core.addConvergenceLayer(httpcl);
00374                                                 components.push_back(httpcl);
00375 
00376                                                 IBRCOMMON_LOGGER(info) << "HTTP ConvergenceLayer added, Server: " << net.url << IBRCOMMON_LOGGER_ENDL;
00377                                         } catch (const ibrcommon::Exception &ex) {
00378                                                 IBRCOMMON_LOGGER(error) << "Failed to add HTTP ConvergenceLayer, Server: " << net.url << ": " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00379                                         }
00380                                         break;
00381                                 }
00382 #endif
00383 
00384 #ifdef HAVE_LOWPAN_SUPPORT
00385                                 case Configuration::NetConfig::NETWORK_LOWPAN:
00386                                 {
00387                                         try {
00388                                                 LOWPANConvergenceLayer *lowpancl = new LOWPANConvergenceLayer( net.interface, net.port );
00389                                                 core.addConvergenceLayer(lowpancl);
00390                                                 components.push_back(lowpancl);
00391                                                 if (ipnd != NULL) ipnd->addService(lowpancl);
00392 
00393                                                 IBRCOMMON_LOGGER(info) << "LOWPAN ConvergenceLayer added on " << net.interface.toString() << ":" << net.port << IBRCOMMON_LOGGER_ENDL;
00394                                         } catch (const ibrcommon::Exception &ex) {
00395                                                 IBRCOMMON_LOGGER(error) << "Failed to add LOWPAN ConvergenceLayer on " << net.interface.toString() << ": " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00396                                         }
00397 
00398                                         break;
00399                                 }
00400 #endif
00401 
00402                                 default:
00403                                         break;
00404                         }
00405                 } catch (const std::exception &ex) {
00406                         IBRCOMMON_LOGGER(error) << "Error: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00407                 }
00408         }
00409 }
00410 
00411 int __daemon_run(Configuration &conf)
00412 {
00413         // catch process signals
00414         signal(SIGINT, sighandler);
00415         signal(SIGTERM, sighandler);
00416         signal(SIGHUP, sighandler);
00417         signal(SIGQUIT, sighandler);
00418         signal(SIGUSR1, sighandler);
00419         signal(SIGUSR2, sighandler);
00420 
00421         sigset_t blockset;
00422         sigemptyset(&blockset);
00423         sigaddset(&blockset, SIGPIPE);
00424         ::sigprocmask(SIG_BLOCK, &blockset, NULL);
00425 
00426         // enable timestamps in logging if requested
00427         if (conf.getLogger().display_timestamps())
00428         {
00429                 logopts = (~(ibrcommon::Logger::LOG_DATETIME) & logopts) | ibrcommon::Logger::LOG_TIMESTAMP;
00430         }
00431 
00432         // init syslog
00433         ibrcommon::Logger::enableAsync(); // enable asynchronous logging feature (thread-safe)
00434         ibrcommon::Logger::enableSyslog("ibrdtn-daemon", LOG_PID, LOG_DAEMON, logsys);
00435 
00436         if (!conf.getDebug().quiet())
00437         {
00438                 // add logging to the cout
00439                 ibrcommon::Logger::addStream(std::cout, logstd, logopts);
00440 
00441                 // add logging to the cerr
00442                 ibrcommon::Logger::addStream(std::cerr, logerr, logopts);
00443         }
00444 
00445         // greeting
00446         IBRCOMMON_LOGGER(info) << "IBR-DTN daemon " << conf.version() << IBRCOMMON_LOGGER_ENDL;
00447 
00448         // activate debugging
00449         if (conf.getDebug().enabled() && !conf.getDebug().quiet())
00450         {
00451                 // init logger
00452                 ibrcommon::Logger::setVerbosity(conf.getDebug().level());
00453 
00454                 IBRCOMMON_LOGGER(info) << "debug level set to " << conf.getDebug().level() << IBRCOMMON_LOGGER_ENDL;
00455 
00456                 ibrcommon::Logger::addStream(std::cout, ibrcommon::Logger::LOGGER_DEBUG, logopts);
00457 
00458                 _debug = true;
00459         }
00460 
00461         // load the configuration file
00462         conf.load();
00463 
00464         // logfile output stream
00465         ofstream logfile_stream;
00466 
00467         try {
00468                 const ibrcommon::File &lf = conf.getLogger().getLogfile();
00469                 logfile_stream.open(lf.getPath().c_str(), std::ios::out | std::ios::app);
00470                 logfile_stream << "IBR-DTN daemon " << conf.version() << std::endl;
00471                 ibrcommon::Logger::addStream(logfile_stream, ~(ibrcommon::Logger::LOGGER_DEBUG), logopts);
00472                 IBRCOMMON_LOGGER(info) << "use logfile for output: " << lf.getPath() << IBRCOMMON_LOGGER_ENDL;
00473         } catch (const Configuration::ParameterNotSetException&) { };
00474 
00475         // switch the user is requested
00476         switchUser(conf);
00477 
00478         // set global vars
00479         setGlobalVars(conf);
00480 
00481 #ifdef WITH_BUNDLE_SECURITY
00482         const dtn::daemon::Configuration::Security &sec = conf.getSecurity();
00483 
00484         if (sec.enabled())
00485         {
00486                 // initialize the key manager for the security extensions
00487                 dtn::security::SecurityKeyManager::getInstance().initialize( sec.getPath(), sec.getCA(), sec.getKey() );
00488         }
00489 #endif
00490 
00491         // list of components
00492         std::list< dtn::daemon::Component* > components;
00493 
00494         // create a notifier if configured
00495         try {
00496                 components.push_back( new dtn::daemon::Notifier( conf.getNotifyCommand() ) );
00497         } catch (const Configuration::ParameterNotSetException&) {
00498 
00499         }
00500 
00501         // create the bundle core object
00502         BundleCore &core = BundleCore::getInstance();
00503 
00504         // create the event switch object
00505         dtn::core::EventSwitch &esw = dtn::core::EventSwitch::getInstance();
00506 
00507         // create a storage for bundles
00508         createBundleStorage(core, conf, components);
00509 
00510         // initialize the DiscoveryAgent
00511         dtn::net::IPNDAgent *ipnd = NULL;
00512 
00513         if (conf.getDiscovery().enabled())
00514         {
00515                 // get the discovery port
00516                 int disco_port = conf.getDiscovery().port();
00517                 bool multicast = false;
00518 
00519                 // collect all interfaces of convergence layer instances
00520                 std::set<ibrcommon::vinterface> interfaces;
00521 
00522                 const std::list<Configuration::NetConfig> &nets = conf.getNetwork().getInterfaces();
00523                 for (std::list<Configuration::NetConfig>::const_iterator iter = nets.begin(); iter != nets.end(); iter++)
00524                 {
00525                         const Configuration::NetConfig &net = (*iter);
00526                         interfaces.insert(net.interface);
00527                 }
00528 
00529                 try {
00530                         const ibrcommon::vaddress addr = conf.getDiscovery().address();
00531                         multicast = addr.isMulticast();
00532                         ipnd = new dtn::net::IPNDAgent( disco_port, addr );
00533                 } catch (const Configuration::ParameterNotFoundException&) {
00534                         ipnd = new dtn::net::IPNDAgent( disco_port, ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, "255.255.255.255") );
00535                 }
00536 
00537                 for (std::set<ibrcommon::vinterface>::const_iterator iter = interfaces.begin(); iter != interfaces.end(); iter++)
00538                 {
00539                         const ibrcommon::vinterface &i = (*iter);
00540                         if (i.empty() && multicast)
00541                         {
00542                                 IBRCOMMON_LOGGER(warning) << "Multicast discovery will not work with bind on ANY interfaces." << IBRCOMMON_LOGGER_ENDL;
00543                         }
00544                         else
00545                         {
00546                                 // add interfaces to discovery
00547                                 ipnd->bind(*iter);
00548                         }
00549                 }
00550 
00551                 components.push_back(ipnd);
00552         }
00553         else
00554         {
00555                 IBRCOMMON_LOGGER(info) << "Discovery disabled" << IBRCOMMON_LOGGER_ENDL;
00556         }
00557 
00558         // create the base router
00559         dtn::routing::BaseRouter *router = new dtn::routing::BaseRouter(core.getStorage());
00560 
00561         // add routing extensions
00562         switch (conf.getNetwork().getRoutingExtension())
00563         {
00564         case Configuration::FLOOD_ROUTING:
00565         {
00566                 IBRCOMMON_LOGGER(info) << "Using flooding routing extensions" << IBRCOMMON_LOGGER_ENDL;
00567                 dtn::routing::FloodRoutingExtension *flooding = new dtn::routing::FloodRoutingExtension();
00568                 router->addExtension( flooding );
00569                 break;
00570         }
00571 
00572         case Configuration::EPIDEMIC_ROUTING:
00573         {
00574                 IBRCOMMON_LOGGER(info) << "Using epidemic routing extensions" << IBRCOMMON_LOGGER_ENDL;
00575                 router->addExtension( new dtn::routing::EpidemicRoutingExtension() );
00576                 break;
00577         }
00578 
00579         default:
00580                 IBRCOMMON_LOGGER(info) << "Using default routing extensions" << IBRCOMMON_LOGGER_ENDL;
00581                 break;
00582         }
00583 
00584         // add standard routing modules
00585         router->addExtension( new dtn::routing::StaticRoutingExtension( conf.getNetwork().getStaticRoutes() ) );
00586         router->addExtension( new dtn::routing::NeighborRoutingExtension() );
00587         router->addExtension( new dtn::routing::RetransmissionExtension() );
00588 
00589         components.push_back(router);
00590 
00591         // enable or disable forwarding of bundles
00592         if (conf.getNetwork().doForwarding())
00593         {
00594                 IBRCOMMON_LOGGER(info) << "Forwarding of bundles enabled." << IBRCOMMON_LOGGER_ENDL;
00595                 BundleCore::forwarding = true;
00596         }
00597         else
00598         {
00599                 IBRCOMMON_LOGGER(info) << "Forwarding of bundles disabled." << IBRCOMMON_LOGGER_ENDL;
00600                 BundleCore::forwarding = false;
00601         }
00602 
00603         // enable netlink manager (watchdog for network interfaces)
00604         if (conf.getNetwork().doDynamicRebind())
00605         {
00606                 ibrcommon::LinkManager::initialize();
00607         }
00608 
00609 #ifdef WITH_TLS
00610         /* enable TLS support */
00611         if ( conf.getSecurity().doTLS() )
00612         {
00613                 components.push_back(new dtn::security::TLSStreamComponent());
00614                 components.push_back(new dtn::security::SecurityCertificateManager());
00615                 IBRCOMMON_LOGGER(info) << "TLS security for TCP convergence layer enabled" << IBRCOMMON_LOGGER_ENDL;
00616         }
00617 #endif
00618 
00619         try {
00620                 // initialize all convergence layers
00621                 createConvergenceLayers(core, conf, components, ipnd);
00622         } catch (const std::exception&) {
00623                 return -1;
00624         }
00625 
00626         if (conf.doAPI())
00627         {
00628                 Configuration::NetConfig lo = conf.getAPIInterface();
00629 
00630                 try {
00631                         ibrcommon::File socket = conf.getAPISocket();
00632 
00633                         try {
00634                                 // use unix domain sockets for API
00635                                 components.push_back( new dtn::api::ApiServer(socket) );
00636                                 IBRCOMMON_LOGGER(info) << "API initialized using unix domain socket: " << socket.getPath() << IBRCOMMON_LOGGER_ENDL;
00637                         } catch (const ibrcommon::vsocket_exception&) {
00638                                 IBRCOMMON_LOGGER(error) << "Unable to bind to unix domain socket " << socket.getPath() << ". API not initialized!" << IBRCOMMON_LOGGER_ENDL;
00639                                 exit(-1);
00640                         }
00641                 }
00642                 catch (const Configuration::ParameterNotSetException&)
00643                 {
00644                         try {
00645                                 // instance a API server, first create a socket
00646                                 components.push_back( new dtn::api::ApiServer(lo.interface, lo.port) );
00647                                 IBRCOMMON_LOGGER(info) << "API initialized using tcp socket: " << lo.interface.toString() << ":" << lo.port << IBRCOMMON_LOGGER_ENDL;
00648                         } catch (const ibrcommon::vsocket_exception&) {
00649                                 IBRCOMMON_LOGGER(error) << "Unable to bind to " << lo.interface.toString() << ":" << lo.port << ". API not initialized!" << IBRCOMMON_LOGGER_ENDL;
00650                                 exit(-1);
00651                         }
00652                 }
00653         }
00654         else
00655         {
00656                 IBRCOMMON_LOGGER(info) << "API disabled" << IBRCOMMON_LOGGER_ENDL;
00657         }
00658 
00659         // create a statistic logger if configured
00660         if (conf.getStatistic().enabled())
00661         {
00662                 try {
00663                         if (conf.getStatistic().type() == "stdout")
00664                         {
00665                                 components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_STDOUT, conf.getStatistic().interval() ) );
00666                         }
00667                         else if (conf.getStatistic().type() == "syslog")
00668                         {
00669                                 components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_SYSLOG, conf.getStatistic().interval() ) );
00670                         }
00671                         else if (conf.getStatistic().type() == "plain")
00672                         {
00673                                 components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_FILE_PLAIN, conf.getStatistic().interval(), conf.getStatistic().logfile() ) );
00674                         }
00675                         else if (conf.getStatistic().type() == "csv")
00676                         {
00677                                 components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_FILE_CSV, conf.getStatistic().interval(), conf.getStatistic().logfile() ) );
00678                         }
00679                         else if (conf.getStatistic().type() == "stat")
00680                         {
00681                                 components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_FILE_STAT, conf.getStatistic().interval(), conf.getStatistic().logfile() ) );
00682                         }
00683                         else if (conf.getStatistic().type() == "udp")
00684                         {
00685                                 components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_UDP, conf.getStatistic().interval(), conf.getStatistic().address(), conf.getStatistic().port() ) );
00686                         }
00687                 } catch (const Configuration::ParameterNotSetException&) {
00688                         IBRCOMMON_LOGGER(error) << "StatisticLogger: Parameter statistic_file is not set! Fallback to stdout logging." << IBRCOMMON_LOGGER_ENDL;
00689                         components.push_back( new StatisticLogger( dtn::daemon::StatisticLogger::LOGGER_STDOUT, conf.getStatistic().interval() ) );
00690                 }
00691         }
00692 
00693         // initialize core component
00694         core.initialize();
00695 
00696         // initialize the event switch
00697         esw.initialize();
00698 
00702         for (std::list< dtn::daemon::Component* >::iterator iter = components.begin(); iter != components.end(); iter++ )
00703         {
00704                 IBRCOMMON_LOGGER_DEBUG(20) << "Initialize component " << (*iter)->getName() << IBRCOMMON_LOGGER_ENDL;
00705                 (*iter)->initialize();
00706         }
00707 
00708         // run core component
00709         core.startup();
00710 
00714         for (std::list< dtn::daemon::Component* >::iterator iter = components.begin(); iter != components.end(); iter++ )
00715         {
00716                 IBRCOMMON_LOGGER_DEBUG(20) << "Startup component " << (*iter)->getName() << IBRCOMMON_LOGGER_ENDL;
00717                 (*iter)->startup();
00718         }
00719 
00720         // Debugger
00721         Debugger debugger;
00722 
00723         // add echo module
00724         EchoWorker echo;
00725 
00726         // add bundle-in-bundle endpoint
00727         CapsuleWorker capsule;
00728 
00729         // add DevNull module
00730         DevNull devnull;
00731 
00732         // announce static nodes, create a list of static nodes
00733         list<Node> static_nodes = conf.getNetwork().getStaticNodes();
00734 
00735         for (list<Node>::iterator iter = static_nodes.begin(); iter != static_nodes.end(); iter++)
00736         {
00737                 core.addConnection(*iter);
00738         }
00739 
00740 #ifdef HAVE_LIBDAEMON
00741         if (conf.getDaemon().daemonize())
00742         {
00743                 /* Send OK to parent process */
00744                 daemon_retval_send(0);
00745                 daemon_log(LOG_INFO, "Sucessfully started");
00746         }
00747 #endif
00748 
00749         // run the event switch loop forever
00750         esw.loop();
00751 
00752         IBRCOMMON_LOGGER(info) << "shutdown dtn node" << IBRCOMMON_LOGGER_ENDL;
00753 
00754         // send shutdown signal to unbound threads
00755         dtn::core::GlobalEvent::raise(dtn::core::GlobalEvent::GLOBAL_SHUTDOWN);
00756 
00760         for (std::list< dtn::daemon::Component* >::iterator iter = components.begin(); iter != components.end(); iter++ )
00761         {
00762                 IBRCOMMON_LOGGER_DEBUG(20) << "Terminate component " << (*iter)->getName() << IBRCOMMON_LOGGER_ENDL;
00763                 (*iter)->terminate();
00764         }
00765 
00766         // terminate event switch component
00767         esw.terminate();
00768 
00769         // terminate core component
00770         core.terminate();
00771 
00772         // delete all components
00773         for (std::list< dtn::daemon::Component* >::iterator iter = components.begin(); iter != components.end(); iter++ )
00774         {
00775                 delete (*iter);
00776         }
00777 
00778         // stop the asynchronous logger
00779         ibrcommon::Logger::stop();
00780 
00781         return 0;
00782 };
00783 
00784 static char* __daemon_pidfile__ = NULL;
00785 
00786 static const char* __daemon_pid_file_proc__(void) {
00787         return __daemon_pidfile__;
00788 }
00789 
00790 int main(int argc, char *argv[])
00791 {
00792         // create a configuration
00793         Configuration &conf = Configuration::getInstance();
00794 
00795         // load parameter into the configuration
00796         conf.params(argc, argv);
00797 
00798 #ifdef HAVE_LIBDAEMON
00799         if (conf.getDaemon().daemonize())
00800         {
00801                 int ret = 0;
00802                 pid_t pid;
00803 
00804 #ifdef HAVE_DAEMON_RESET_SIGS
00805                 /* Reset signal handlers */
00806                 if (daemon_reset_sigs(-1) < 0) {
00807                         daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno));
00808                         return 1;
00809                 }
00810 
00811                 /* Unblock signals */
00812                 if (daemon_unblock_sigs(-1) < 0) {
00813                         daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno));
00814                         return 1;
00815                 }
00816 #endif
00817 
00818                 /* Set identification string for the daemon for both syslog and PID file */
00819                 daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
00820 
00821                 /* set the pid file path */
00822                 try {
00823                         std::string p = conf.getDaemon().getPidFile().getPath();
00824                         __daemon_pidfile__ = new char[p.length() + 1];
00825                         ::strcpy(__daemon_pidfile__, p.c_str());
00826                         daemon_pid_file_proc = __daemon_pid_file_proc__;
00827                 } catch (const Configuration::ParameterNotSetException&) { };
00828 
00829                 /* Check if we are called with -k parameter */
00830                 if (conf.getDaemon().kill_daemon())
00831                 {
00832                         int ret;
00833 
00834                         /* Kill daemon with SIGTERM */
00835 
00836                         /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */
00837                         if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0)
00838                                 daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno));
00839 
00840                         return ret < 0 ? 1 : 0;
00841                 }
00842 
00843                 /* Check that the daemon is not rung twice a the same time */
00844                 if ((pid = daemon_pid_file_is_running()) >= 0) {
00845                         daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid);
00846                         return 1;
00847                 }
00848 
00849                 /* Prepare for return value passing from the initialization procedure of the daemon process */
00850                 if (daemon_retval_init() < 0) {
00851                         daemon_log(LOG_ERR, "Failed to create pipe.");
00852                         return 1;
00853                 }
00854 
00855                 /* Do the fork */
00856                 if ((pid = daemon_fork()) < 0) {
00857 
00858                         /* Exit on error */
00859                         daemon_retval_done();
00860                         return 1;
00861 
00862                 } else if (pid) { /* The parent */
00863                         int ret;
00864 
00865                         /* Wait for 20 seconds for the return value passed from the daemon process */
00866                         if ((ret = daemon_retval_wait(20)) < 0) {
00867                                 daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno));
00868                                 return 255;
00869                         }
00870 
00871                         //daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret);
00872                         return ret;
00873 
00874                 } else { /* The daemon */
00875                         /* Close FDs */
00876                         if (daemon_close_all(-1) < 0) {
00877                                 daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
00878 
00879                                 /* Send the error condition to the parent process */
00880                                 daemon_retval_send(1);
00881                                 goto finish;
00882                         }
00883 
00884                         /* Create the PID file */
00885                         if (daemon_pid_file_create() < 0) {
00886                                 daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
00887                                 daemon_retval_send(2);
00888                                 goto finish;
00889                         }
00890 
00891                         /* Initialize signal handling */
00892                         if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGUSR1, SIGUSR2, 0) < 0) {
00893                                 daemon_log(LOG_ERR, "Could not register signal handlers (%s).", strerror(errno));
00894                                 daemon_retval_send(3);
00895                                 goto finish;
00896                         }
00897 
00898                         ret = __daemon_run(conf);
00899 
00900         finish:
00901                         /* Do a cleanup */
00902                         daemon_log(LOG_INFO, "Exiting...");
00903                         daemon_retval_send(255);
00904                         daemon_signal_done();
00905                         daemon_pid_file_remove();
00906                 }
00907 
00908                 return ret;
00909         } else {
00910 #endif
00911                 // run the daemon
00912                 return __daemon_run(conf);
00913 #ifdef HAVE_LIBDAEMON
00914         }
00915 #endif
00916 }