00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <unistd.h>
00020
00021 #include <oasys/storage/BerkeleyDBStore.h>
00022 #include <oasys/io/FileUtils.h>
00023
00024 #include "config.h"
00025 #include "DTNServer.h"
00026
00027 #include "applib/APIServer.h"
00028
00029 #include "bundling/BundleDaemon.h"
00030
00031 #include "contacts/InterfaceTable.h"
00032 #include "contacts/ContactManager.h"
00033
00034 #include "cmd/CompletionNotifier.h"
00035 #include "cmd/BundleCommand.h"
00036 #include "cmd/InterfaceCommand.h"
00037 #include "cmd/LinkCommand.h"
00038 #include "cmd/ParamCommand.h"
00039 #include "cmd/RegistrationCommand.h"
00040 #include "cmd/RouteCommand.h"
00041 #include "cmd/DiscoveryCommand.h"
00042 #include "cmd/ProphetCommand.h"
00043 #include "cmd/ShutdownCommand.h"
00044 #include "cmd/StorageCommand.h"
00045
00046 #include "conv_layers/ConvergenceLayer.h"
00047 #include "discovery/DiscoveryTable.h"
00048
00049 #include "naming/SchemeTable.h"
00050
00051 #include "reg/AdminRegistration.h"
00052 #include "reg/RegistrationTable.h"
00053
00054 #include "routing/BundleRouter.h"
00055
00056 #include "storage/BundleStore.h"
00057 #include "storage/LinkStore.h"
00058 #include "storage/GlobalStore.h"
00059 #include "storage/RegistrationStore.h"
00060 #include "storage/DTNStorageConfig.h"
00061
00062
00063
00064
00065 namespace dtn {
00066
00067 DTNServer::DTNServer(const char* logpath,
00068 DTNStorageConfig* storage_config)
00069 : Logger("DTNServer", logpath),
00070 init_(false),
00071 in_shutdown_(0),
00072 storage_config_(storage_config),
00073 store_(0)
00074 {}
00075
00076 DTNServer::~DTNServer()
00077 {
00078 log_notice("daemon exiting...");
00079 }
00080
00081 void
00082 DTNServer::init()
00083 {
00084 ASSERT(oasys::Thread::start_barrier_enabled());
00085
00086 init_commands();
00087 init_components();
00088 }
00089
00090 void
00091 DTNServer::start()
00092 {
00093 BundleDaemon* daemon = BundleDaemon::instance();
00094 daemon->start();
00095 log_debug("started dtn server");
00096 }
00097
00098 bool
00099 DTNServer::init_datastore()
00100 {
00101 if (storage_config_->tidy_)
00102 {
00103 storage_config_->init_ = true;
00104 }
00105 store_ = new oasys::DurableStore("/dtn/storage");
00106 int err = store_->create_store(*storage_config_);
00107 if (err != 0) {
00108 log_crit("error creating storage system");
00109 return false;
00110 }
00111
00112 if (storage_config_->tidy_)
00113 {
00114
00115
00116 if (!tidy_dir(storage_config_->payload_dir_.c_str())) {
00117 return false;
00118 }
00119 }
00120
00121 if (storage_config_->init_)
00122 {
00123 if (!init_dir(storage_config_->payload_dir_.c_str())) {
00124 return false;
00125 }
00126 }
00127
00128 if (!validate_dir(storage_config_->payload_dir_.c_str())) {
00129 return false;
00130 }
00131
00132 if ((GlobalStore::init(*storage_config_, store_) != 0) ||
00133 (BundleStore::init(*storage_config_, store_) != 0) ||
00134 (LinkStore::init(*storage_config_, store_) != 0) ||
00135 (RegistrationStore::init(*storage_config_, store_) != 0))
00136 {
00137 log_crit("error initializing data store");
00138 return false;
00139 }
00140
00141
00142
00143 if (!GlobalStore::instance()->load()) {
00144 return false;
00145 }
00146
00147 return true;
00148 }
00149
00150 bool
00151 DTNServer::parse_conf_file(std::string& conf_file,
00152 bool conf_file_set)
00153 {
00154
00155
00156 if (conf_file.size() != 0)
00157 {
00158 if (!oasys::FileUtils::readable(conf_file.c_str(), logpath()))
00159 {
00160 log_err("configuration file \"%s\" not readable",
00161 conf_file.c_str());
00162 return false;
00163 }
00164 }
00165 else if (!conf_file_set)
00166 {
00167 const char* default_conf[] = { "/etc/dtn.conf",
00168 "daemon/dtn.conf",
00169 0 };
00170 conf_file.clear();
00171 for (int i=0; default_conf[i] != 0; ++i)
00172 {
00173 if (oasys::FileUtils::readable(default_conf[i], logpath()))
00174 {
00175 conf_file.assign(default_conf[i]);
00176 break;
00177 }
00178 }
00179 if (conf_file.size() == 0)
00180 {
00181 log_warn("can't read default config file "
00182 "(tried /etc/dtn.conf and daemon/dtn.conf)...");
00183 }
00184 }
00185
00186 if (conf_file.size() == 0) {
00187 log_info("No config file specified.");
00188 return false;
00189 }
00190
00191 log_info("parsing configuration file %s...", conf_file.c_str());
00192 if (oasys::TclCommandInterp::instance()->exec_file(conf_file.c_str()) != 0)
00193 {
00194 return false;
00195 }
00196
00197 return true;
00198 }
00199
00200 void
00201 DTNServer::init_commands()
00202 {
00203 oasys::TclCommandInterp* interp = oasys::TclCommandInterp::instance();
00204
00205 CompletionNotifier::create();
00206 interp->reg(new BundleCommand());
00207 interp->reg(new InterfaceCommand());
00208 interp->reg(new LinkCommand());
00209 interp->reg(new ParamCommand());
00210 interp->reg(new RegistrationCommand());
00211 interp->reg(new RouteCommand());
00212 interp->reg(new DiscoveryCommand());
00213 interp->reg(new ProphetCommand());
00214 interp->reg(new ShutdownCommand(this, "shutdown"));
00215 interp->reg(new ShutdownCommand(this, "quit"));
00216 interp->reg(new StorageCommand(storage_config_));
00217
00218 log_debug("registered dtn commands");
00219 }
00220
00221 void
00222 DTNServer::init_components()
00223 {
00224 SchemeTable::create();
00225 ConvergenceLayer::init_clayers();
00226 InterfaceTable::init();
00227 BundleDaemon::init();
00228 DiscoveryTable::init();
00229
00230 log_debug("intialized dtn components");
00231 }
00232
00233 void
00234 DTNServer::close_datastore()
00235 {
00236 log_notice("closing persistent data store");
00237
00238 RegistrationStore::instance()->close();
00239 LinkStore::instance()->close();
00240 BundleStore::instance()->close();
00241 GlobalStore::instance()->close();
00242
00243 delete_z(store_);
00244 }
00245
00246 void
00247 DTNServer::shutdown()
00248 {
00249 log_notice("shutting down dtn server");
00250
00251
00252 u_int32_t old_val = atomic_incr_ret(&in_shutdown_);
00253 if (old_val != 1) {
00254 while (1) {
00255 sleep(1000000);
00256 }
00257 }
00258
00259 oasys::Notifier done("/dtnserver/shutdown");
00260 log_info("DTNServer shutdown called, posting shutdown request to daemon");
00261 BundleDaemon::instance()->post_and_wait(new ShutdownRequest(), &done);
00262
00263 DiscoveryTable::instance()->shutdown();
00264 close_datastore();
00265 }
00266
00267 void
00268 DTNServer::set_app_shutdown(ShutdownProc proc, void* data)
00269 {
00270 BundleDaemon::instance()->set_app_shutdown(proc, data);
00271 }
00272
00273 bool
00274 DTNServer::init_dir(const char* dirname)
00275 {
00276 struct stat st;
00277 int statret;
00278
00279 statret = stat(dirname, &st);
00280 if (statret == -1 && errno == ENOENT)
00281 {
00282 if (mkdir(dirname, 0700) != 0) {
00283 log_crit("can't create directory %s: %s",
00284 dirname, strerror(errno));
00285 return false;
00286 }
00287 }
00288 else if (statret == -1)
00289 {
00290 log_crit("invalid path %s: %s", dirname, strerror(errno));
00291 return false;
00292 }
00293
00294 return true;
00295 }
00296
00297 bool
00298 DTNServer::tidy_dir(const char* dir)
00299 {
00300 char cmd[256];
00301 struct stat st;
00302
00303 std::string dirname(dir);
00304 oasys::FileUtils::abspath(&dirname);
00305
00306 if (stat(dirname.c_str(), &st) == 0)
00307 {
00308 snprintf(cmd, sizeof(cmd), "/bin/rm -rf %s", dirname.c_str());
00309 log_notice("tidy option removing directory '%s'", cmd);
00310
00311 if (system(cmd))
00312 {
00313 log_crit("error removing directory %s", dirname.c_str());
00314 return false;
00315 }
00316
00317 }
00318 else if (errno == ENOENT)
00319 {
00320 log_debug("directory already removed %s", dirname.c_str());
00321 }
00322 else
00323 {
00324 log_crit("invalid directory name %s: %s", dirname.c_str(), strerror(errno));
00325 return false;
00326 }
00327
00328 return true;
00329 }
00330
00331 bool
00332 DTNServer::validate_dir(const char* dirname)
00333 {
00334 struct stat st;
00335
00336 if (stat(dirname, &st) == 0 && S_ISDIR(st.st_mode))
00337 {
00338 log_debug("directory validated: %s", dirname);
00339 }
00340 else
00341 {
00342 log_crit("invalid directory name %s: %s", dirname, strerror(errno));
00343 return false;
00344 }
00345
00346 if (access(dirname, R_OK | W_OK | X_OK) == 0)
00347 {
00348 log_debug("directory access validated: %s", dirname);
00349 }
00350 else
00351 {
00352 log_crit("access failed on directory %s: %s",
00353 dirname, strerror(errno));
00354 return false;
00355 }
00356
00357 return true;
00358 }
00359
00360 }