--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/DTNServer.cc Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2004-2006 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <dtn-config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <oasys/storage/BerkeleyDBStore.h>
+#include <oasys/io/FileUtils.h>
+
+#include "DTNServer.h"
+
+#include "bundling/BundleDaemon.h"
+
+#include "contacts/InterfaceTable.h"
+#include "contacts/ContactManager.h"
+
+#include "cmd/CompletionNotifier.h"
+#include "cmd/BundleCommand.h"
+#include "cmd/InterfaceCommand.h"
+#include "cmd/LinkCommand.h"
+#include "cmd/ParamCommand.h"
+#include "cmd/RegistrationCommand.h"
+#include "cmd/RouteCommand.h"
+#include "cmd/DiscoveryCommand.h"
+#include "cmd/ProphetCommand.h"
+#include "cmd/ShutdownCommand.h"
+#include "cmd/StorageCommand.h"
+#include "cmd/ECLACommand.h"
+#include "cmd/SecurityCommand.h"
+
+#include "conv_layers/ConvergenceLayer.h"
+#include "discovery/DiscoveryTable.h"
+
+#include "naming/SchemeTable.h"
+
+#include "reg/AdminRegistration.h"
+#include "reg/RegistrationTable.h"
+
+#include "routing/BundleRouter.h"
+
+#include "storage/BundleStore.h"
+#include "storage/ProphetStore.h"
+#include "storage/LinkStore.h"
+#include "storage/GlobalStore.h"
+#include "storage/RegistrationStore.h"
+#include "storage/DTNStorageConfig.h"
+#include "bundling/S10Logger.h"
+
+//#include <oasys/storage/MySQLStore.h>
+//#include <oasys/storage/PostgresqlStore.h>
+
+namespace dtn {
+
+DTNServer::DTNServer(const char* logpath,
+ DTNStorageConfig* storage_config)
+ : Logger("DTNServer", "%s", logpath),
+ init_(false),
+ in_shutdown_(0),
+ storage_config_(storage_config),
+ store_(0)
+{}
+
+DTNServer::~DTNServer()
+{
+ s10_daemon(S10_EXITING);
+ log_notice("daemon exiting...");
+}
+
+void
+DTNServer::init()
+{
+ ASSERT(oasys::Thread::start_barrier_enabled());
+
+ init_commands();
+ init_components();
+}
+
+void
+DTNServer::start()
+{
+ BundleDaemon* daemon = BundleDaemon::instance();
+ daemon->start();
+ log_debug("started dtn server");
+}
+
+bool
+DTNServer::init_datastore()
+{
+ if (storage_config_->tidy_)
+ {
+ storage_config_->init_ = true; // init is implicit with tidy
+ }
+ store_ = new oasys::DurableStore("/dtn/storage");
+ int err = store_->create_store(*storage_config_);
+ if (err != 0) {
+ log_crit("error creating storage system");
+ return false;
+ }
+
+ if (storage_config_->tidy_)
+ {
+ // remove bundle data directory (the db contents are cleaned
+ // up by the implementation)
+ if (!tidy_dir(storage_config_->payload_dir_.c_str())) {
+ return false;
+ }
+ }
+
+ if (storage_config_->init_)
+ {
+ if (!init_dir(storage_config_->payload_dir_.c_str())) {
+ return false;
+ }
+ }
+
+ if (!validate_dir(storage_config_->payload_dir_.c_str())) {
+ return false;
+ }
+
+ if ((GlobalStore::init(*storage_config_, store_) != 0) ||
+ (BundleStore::init(*storage_config_, store_) != 0) ||
+ (ProphetStore::init(*storage_config_, store_) != 0) ||
+ (LinkStore::init(*storage_config_, store_) != 0) ||
+ (RegistrationStore::init(*storage_config_, store_) != 0))
+ {
+ log_crit("error initializing data store");
+ return false;
+ }
+
+ // load in the global store here since that will check the
+ // database version and exit if there's a mismatch
+ if (!GlobalStore::instance()->load()) {
+ return false;
+ }
+
+ return true;
+}
+
+bool
+DTNServer::parse_conf_file(std::string& conf_file,
+ bool conf_file_set)
+{
+ // Check the supplied config file and/or check for defaults, as
+ // long as the user didn't explicitly call with no conf file
+ if (conf_file.size() != 0)
+ {
+ if (!oasys::FileUtils::readable(conf_file.c_str(), logpath()))
+ {
+ log_err("configuration file \"%s\" not readable",
+ conf_file.c_str());
+ return false;
+ }
+ }
+ else if (!conf_file_set)
+ {
+ const char* default_conf[] = { INSTALL_SYSCONFDIR "/dtn.conf",
+ "daemon/dtn.conf",
+ 0 };
+ conf_file.clear();
+ for (int i=0; default_conf[i] != 0; ++i)
+ {
+ if (oasys::FileUtils::readable(default_conf[i], logpath()))
+ {
+ conf_file.assign(default_conf[i]);
+ break;
+ }
+ }
+ if (conf_file.size() == 0)
+ {
+ log_warn("can't read default config file "
+ "(tried " INSTALL_SYSCONFDIR "/dtn.conf "
+ "and daemon/dtn.conf)...");
+ }
+ }
+
+ if (conf_file.size() == 0) {
+ log_info("No config file specified.");
+ return false;
+ }
+
+ log_info("parsing configuration file %s...", conf_file.c_str());
+ if (oasys::TclCommandInterp::instance()->exec_file(conf_file.c_str()) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void
+DTNServer::init_commands()
+{
+ oasys::TclCommandInterp* interp = oasys::TclCommandInterp::instance();
+
+ CompletionNotifier::create();
+ interp->reg(new BundleCommand());
+ interp->reg(new InterfaceCommand());
+ interp->reg(new LinkCommand());
+ interp->reg(new ParamCommand());
+ interp->reg(new RegistrationCommand());
+ interp->reg(new RouteCommand());
+ interp->reg(new DiscoveryCommand());
+ interp->reg(new ProphetCommand());
+ interp->reg(new ShutdownCommand(this, "shutdown"));
+ interp->reg(new ShutdownCommand(this, "quit"));
+ interp->reg(new StorageCommand(storage_config_));
+
+#if defined(XERCES_C_ENABLED) && defined(EXTERNAL_CL_ENABLED)
+ interp->reg(new ECLACommand());
+#endif
+
+#ifdef BSP_ENABLED
+ interp->reg(new SecurityCommand());
+#endif
+
+ log_debug("registered dtn commands");
+}
+
+void
+DTNServer::init_components()
+{
+ SchemeTable::create();
+ ConvergenceLayer::init_clayers();
+ InterfaceTable::init();
+ BundleDaemon::init();
+ DiscoveryTable::init();
+
+ log_debug("intialized dtn components");
+}
+
+void
+DTNServer::close_datastore()
+{
+ log_notice("closing persistent data store");
+
+ RegistrationStore::instance()->close();
+ LinkStore::instance()->close();
+ ProphetStore::instance()->close();
+ BundleStore::instance()->close();
+ GlobalStore::instance()->close();
+
+ delete_z(store_);
+}
+
+void
+DTNServer::shutdown()
+{
+ log_notice("shutting down dtn server");
+
+ // make sure only one thread does this
+ u_int32_t old_val = atomic_incr_ret(&in_shutdown_);
+ if (old_val != 1) {
+ log_warn("second thread called DTNServer::shutdown... spinning forever");
+ while (1) {
+ sleep(1000000);
+ }
+ }
+
+ oasys::Notifier done("/dtnserver/shutdown");
+ log_info("DTNServer shutdown called, posting shutdown request to daemon");
+ BundleDaemon::instance()->post_and_wait(new ShutdownRequest(), &done);
+
+ DiscoveryTable::instance()->shutdown();
+ close_datastore();
+}
+
+void
+DTNServer::set_app_shutdown(ShutdownProc proc, void* data)
+{
+ BundleDaemon::instance()->set_app_shutdown(proc, data);
+}
+
+bool
+DTNServer::init_dir(const char* dirname)
+{
+ struct stat st;
+ int statret;
+
+ statret = stat(dirname, &st);
+ if (statret == -1 && errno == ENOENT)
+ {
+ if (mkdir(dirname, 0700) != 0) {
+ log_crit("can't create directory %s: %s",
+ dirname, strerror(errno));
+ return false;
+ }
+ }
+ else if (statret == -1)
+ {
+ log_crit("invalid path %s: %s", dirname, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool
+DTNServer::tidy_dir(const char* dir)
+{
+ char cmd[256];
+ struct stat st;
+
+ std::string dirname(dir);
+ oasys::FileUtils::abspath(&dirname);
+
+ if (stat(dirname.c_str(), &st) == 0)
+ {
+ snprintf(cmd, sizeof(cmd), "/bin/rm -rf %s", dirname.c_str());
+ log_notice("tidy option removing directory '%s'", cmd);
+
+ if (system(cmd))
+ {
+ log_crit("error removing directory %s", dirname.c_str());
+ return false;
+ }
+
+ }
+ else if (errno == ENOENT)
+ {
+ log_debug("directory already removed %s", dirname.c_str());
+ }
+ else
+ {
+ log_crit("invalid directory name %s: %s", dirname.c_str(), strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool
+DTNServer::validate_dir(const char* dirname)
+{
+ struct stat st;
+
+ if (stat(dirname, &st) == 0 && S_ISDIR(st.st_mode))
+ {
+ log_debug("directory validated: %s", dirname);
+ }
+ else
+ {
+ log_crit("invalid directory name %s: %s", dirname, strerror(errno));
+ return false;
+ }
+
+ if (access(dirname, R_OK | W_OK | X_OK) == 0)
+ {
+ log_debug("directory access validated: %s", dirname);
+ }
+ else
+ {
+ log_crit("access failed on directory %s: %s",
+ dirname, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace dtn